예제 #1
0
  protected void handleConsumerReadyRequest(long requestId, Address address) {
    Owner requestor;
    final Owner source = new Owner(address, requestId);
    _consumerLock.lock();
    try {
      requestor = _runRequests.poll();
      // We don't add duplicate consumers - this allows for resubmission
      // if it is thought the message may have been dropped
      if (requestor == null && !_consumersAvailable.contains(source)) {
        _consumersAvailable.add(source);
      }
    } finally {
      _consumerLock.unlock();
    }

    if (requestor != null) {
      sendRequest(
          requestor.getAddress(), Type.CONSUMER_FOUND, source.getRequestId(), source.getAddress());
      sendRemoveRunRequest(requestor);
    } else {
      sendNewConsumerRequest(source);
    }
  }
예제 #2
0
  protected void handleView(View view) {
    this.view = view;
    if (log.isDebugEnabled()) log.debug("view=" + view);
    List<Address> members = view.getMembers();

    _consumerLock.lock();
    try {
      // This removes the consumers that were registered that are now gone
      Iterator<Owner> iterator = _consumersAvailable.iterator();
      while (iterator.hasNext()) {
        Owner owner = iterator.next();
        if (!members.contains(owner.getAddress())) {
          iterator.remove();
          sendRemoveConsumerRequest(owner);
        }
      }

      // This removes the tasks that those requestors are gone
      iterator = _runRequests.iterator();
      while (iterator.hasNext()) {
        Owner owner = iterator.next();
        if (!members.contains(owner.getAddress())) {
          iterator.remove();
          sendRemoveRunRequest(owner);
        }
      }

      synchronized (_awaitingReturn) {
        for (Entry<Owner, Runnable> entry : _awaitingReturn.entrySet()) {
          // The person currently servicing our request has gone down
          // without completing so we have to keep our request alive by
          // sending ours back to the coordinator
          Owner owner = entry.getKey();
          if (!members.contains(owner.getAddress())) {
            Runnable runnable = entry.getValue();
            // We need to register the request id before sending the request back to the coordinator
            // in case if our task gets picked up since another was removed
            _requestId.put(runnable, owner.getRequestId());
            _awaitingConsumer.add(runnable);
            sendToCoordinator(RUN_REQUEST, owner.getRequestId(), local_addr);
          }
        }
      }
    } finally {
      _consumerLock.unlock();
    }
  }
예제 #3
0
 protected void handleConsumerFoundResponse(long threadId, Address address) {
   final Runnable runnable = _awaitingConsumer.poll();
   // This is a representation of the server side owner running our task.
   Owner owner;
   if (runnable == null) {
     owner = new Owner(address, threadId);
     // For some reason we don't have a runnable anymore
     // so we have to send back to the coordinator that
     // the consumer is still available.  The runnable
     // would be removed on a cancel
     sendToCoordinator(Type.CONSUMER_READY, owner.getRequestId(), owner.getAddress());
   } else {
     final Long requestId = _requestId.get(runnable);
     if (requestId == null) {
       // requestId is not available - this means the result has been
       // returned already or it has been interrupted
       return;
     }
     owner = new Owner(address, requestId);
     _awaitingReturn.put(owner, runnable);
     // If local we pass along without serializing
     if (local_addr.equals(owner.getAddress())) {
       handleTaskSubmittedRequest(runnable, local_addr, requestId, threadId);
     } else {
       try {
         if (runnable instanceof DistributedFuture) {
           Callable<?> callable = ((DistributedFuture<?>) runnable).getCallable();
           sendThreadRequest(
               owner.getAddress(), threadId, Type.RUN_SUBMITTED, requestId, callable);
         } else {
           sendThreadRequest(
               owner.getAddress(), threadId, Type.RUN_SUBMITTED, requestId, runnable);
         }
       }
       // This relies on the Mesasge class to throw this when a
       // serialization issue occurs
       catch (IllegalArgumentException e) {
         ExecutorNotification notificiation = notifiers.remove(runnable);
         if (notificiation != null) {
           notificiation.throwableEncountered(e);
         }
         throw e;
       }
     }
   }
 }
예제 #4
0
  public Object down(Event evt) {
    switch (evt.getType()) {
      case ExecutorEvent.TASK_SUBMIT:
        Runnable runnable = evt.getArg();
        // We are limited to a number of concurrent request id's
        // equal to 2^63-1.  This is quite large and if it
        // overflows it will still be positive
        long requestId = Math.abs(counter.getAndIncrement());
        if (requestId == Long.MIN_VALUE) {
          // TODO: need to fix this it isn't safe for concurrent modifications
          counter.set(0);
          requestId = Math.abs(counter.getAndIncrement());
        }

        // Need to make sure to put the requestId in our map before
        // adding the runnable to awaiting consumer in case if
        // coordinator sent a consumer found and their original task
        // is no longer around
        // see https://issues.jboss.org/browse/JGRP-1744
        _requestId.put(runnable, requestId);

        _awaitingConsumer.add(runnable);

        sendToCoordinator(RUN_REQUEST, requestId, local_addr);
        break;
      case ExecutorEvent.CONSUMER_READY:
        Thread currentThread = Thread.currentThread();
        long threadId = currentThread.getId();
        _consumerId.put(threadId, PRESENT);
        try {
          for (; ; ) {
            CyclicBarrier barrier = new CyclicBarrier(2);
            _taskBarriers.put(threadId, barrier);

            // We only send to the coordinator that we are ready after
            // making the barrier, wait for request to come and let
            // us free
            sendToCoordinator(Type.CONSUMER_READY, threadId, local_addr);

            try {
              barrier.await();
              break;
            } catch (BrokenBarrierException e) {
              if (log.isDebugEnabled())
                log.debug(
                    "Producer timed out before we picked up"
                        + " the task, have to tell coordinator"
                        + " we are still good.");
            }
          }
          // This should always be non nullable since the latch
          // was freed
          runnable = _tasks.remove(threadId);
          _runnableThreads.put(runnable, currentThread);
          return runnable;
        } catch (InterruptedException e) {
          if (log.isDebugEnabled()) log.debug("Consumer " + threadId + " stopped via interrupt");
          sendToCoordinator(Type.CONSUMER_UNREADY, threadId, local_addr);
          Thread.currentThread().interrupt();
        } finally {
          // Make sure the barriers are cleaned up as well
          _taskBarriers.remove(threadId);
          _consumerId.remove(threadId);
        }
        break;
      case ExecutorEvent.TASK_COMPLETE:
        Object arg = evt.getArg();
        Throwable throwable = null;
        if (arg instanceof Object[]) {
          Object[] array = (Object[]) arg;
          runnable = (Runnable) array[0];
          throwable = (Throwable) array[1];
        } else {
          runnable = (Runnable) arg;
        }
        Owner owner = _running.remove(runnable);
        // This won't remove anything if owner doesn't come back
        _runnableThreads.remove(runnable);

        Object value = null;
        boolean exception = false;
        if (throwable != null) {
          // InterruptedException is special telling us that
          // we interrupted the thread while waiting but still got
          // a task therefore we have to reject it.
          if (throwable instanceof InterruptedException) {
            if (log.isDebugEnabled())
              log.debug("Run rejected due to interrupted exception returned");
            sendRequest(owner.address, Type.RUN_REJECTED, owner.requestId, null);
            break;
          }
          value = throwable;
          exception = true;
        } else if (runnable instanceof RunnableFuture<?>) {
          RunnableFuture<?> future = (RunnableFuture<?>) runnable;

          boolean interrupted = false;
          boolean gotValue = false;

          // We have the value, before we interrupt at least get it!
          while (!gotValue) {
            try {
              value = future.get();
              gotValue = true;
            } catch (InterruptedException e) {
              interrupted = true;
            } catch (ExecutionException e) {
              value = e.getCause();
              exception = true;
              gotValue = true;
            }
          }

          if (interrupted) {
            Thread.currentThread().interrupt();
          }
        }

        if (owner != null) {
          final Type type;
          final Object valueToSend;
          if (value == null) {
            type = Type.RESULT_SUCCESS;
            valueToSend = value;
          }
          // Both serializable values and exceptions would go in here
          else if (value instanceof Serializable
              || value instanceof Externalizable
              || value instanceof Streamable) {
            type = exception ? Type.RESULT_EXCEPTION : Type.RESULT_SUCCESS;
            valueToSend = value;
          }
          // This would happen if the value wasn't serializable,
          // so we have to send back to the client that the class
          // wasn't serializable
          else {
            type = Type.RESULT_EXCEPTION;
            valueToSend = new NotSerializableException(value.getClass().getName());
          }

          if (local_addr.equals(owner.getAddress())) {
            if (log.isTraceEnabled())
              log.trace(
                  "[redirect] <--> ["
                      + local_addr
                      + "] "
                      + type.name()
                      + " ["
                      + value
                      + (owner.requestId != -1 ? " request id: " + owner.requestId : "")
                      + "]");
            if (type == Type.RESULT_SUCCESS) {
              handleValueResponse(local_addr, owner.requestId, valueToSend);
            } else if (type == Type.RESULT_EXCEPTION) {
              handleExceptionResponse(local_addr, owner.requestId, (Throwable) valueToSend);
            }
          } else {
            sendRequest(owner.getAddress(), type, owner.requestId, valueToSend);
          }
        } else {
          if (log.isTraceEnabled()) {
            log.trace("Could not return result - most likely because it was interrupted");
          }
        }
        break;
      case ExecutorEvent.TASK_CANCEL:
        Object[] array = evt.getArg();
        runnable = (Runnable) array[0];

        if (_awaitingConsumer.remove(runnable)) {
          _requestId.remove(runnable);
          ExecutorNotification notification = notifiers.remove(runnable);
          if (notification != null) {
            notification.interrupted(runnable);
          }
          if (log.isTraceEnabled())
            log.trace("Cancelled task " + runnable + " before it was picked up");
          return Boolean.TRUE;
        }
        // This is guaranteed to not be null so don't take cost of auto unboxing
        else if (array[1] == Boolean.TRUE) {
          owner = removeKeyForValue(_awaitingReturn, runnable);
          if (owner != null) {
            Long requestIdValue = _requestId.remove(runnable);
            // We only cancel if the requestId is still available
            // this means the result hasn't been returned yet and
            // we still have a chance to interrupt
            if (requestIdValue != null) {
              if (requestIdValue != owner.getRequestId()) {
                log.warn("Cancelling requestId didn't match waiting");
              }
              sendRequest(owner.getAddress(), Type.INTERRUPT_RUN, owner.getRequestId(), null);
            }
          } else {
            if (log.isTraceEnabled()) log.warn("Couldn't interrupt server task: " + runnable);
          }
          ExecutorNotification notification = notifiers.remove(runnable);
          if (notification != null) {
            notification.interrupted(runnable);
          }
          return Boolean.TRUE;
        } else {
          return Boolean.FALSE;
        }
      case ExecutorEvent.ALL_TASK_CANCEL:
        array = evt.getArg();

        // This is a RunnableFuture<?> so this cast is okay
        @SuppressWarnings("unchecked")
        Set<Runnable> runnables = (Set<Runnable>) array[0];
        Boolean booleanValue = (Boolean) array[1];

        List<Runnable> notRan = new ArrayList<>();

        for (Runnable cancelRunnable : runnables) {
          // Removed from the consumer
          if (!_awaitingConsumer.remove(cancelRunnable) && booleanValue == Boolean.TRUE) {
            synchronized (_awaitingReturn) {
              owner = removeKeyForValue(_awaitingReturn, cancelRunnable);
              if (owner != null) {
                Long requestIdValue = _requestId.remove(cancelRunnable);
                if (requestIdValue != owner.getRequestId()) {
                  log.warn("Cancelling requestId didn't match waiting");
                }
                sendRequest(owner.getAddress(), Type.INTERRUPT_RUN, owner.getRequestId(), null);
              }
              ExecutorNotification notification = notifiers.remove(cancelRunnable);
              if (notification != null) {
                log.trace("Notifying listener");
                notification.interrupted(cancelRunnable);
              }
            }
          } else {
            _requestId.remove(cancelRunnable);
            notRan.add(cancelRunnable);
          }
        }
        return notRan;
      case Event.SET_LOCAL_ADDRESS:
        local_addr = evt.getArg();
        break;

      case Event.VIEW_CHANGE:
        handleView(evt.getArg());
        break;
    }
    return down_prot.down(evt);
  }