Example #1
0
 public Object up(Event evt) {
   switch (evt.getType()) {
     case Event.VIEW_CHANGE:
       handleView(evt.getArg());
       break;
   }
   return up_prot.up(evt);
 }
  public void handleView(View view) {
    Address oldCoord = coord;
    if (view.size() > 0) {
      coord = view.getMembers().iterator().next();
      is_coord = coord.equals(local_addr);
      if (log.isDebugEnabled())
        log.debug("local_addr=" + local_addr + ", coord=" + coord + ", is_coord=" + is_coord);
    }

    // If we got a new coordinator we have to send all the requests for
    // tasks and consumers again just incase they were missed when
    // coordinator went down
    // We are okay with duplicates since we don't add multiple times.
    // We also have a problem that if a task/consumer was picked up as the
    // consumer is changing we may have duplicates.  But this is technically
    // okay in that an extra consumer will reject and an extra task will just
    // be ran and return nowhere, but at least we won't lose data.
    if (oldCoord != coord) {
      for (Long requests : _requestId.values()) {
        sendToCoordinator(Type.RUN_REQUEST, requests, local_addr);
      }

      for (Long requests : _consumerId.keySet()) {
        sendToCoordinator(Type.CONSUMER_READY, requests, local_addr);
      }
    }

    if (num_backups > 0) {
      if (is_coord) {
        List<Address> new_backups = Util.pickNext(view.getMembers(), local_addr, num_backups);
        List<Address> new_members = null;
        synchronized (backups) {
          if (!backups.equals(new_backups)) {
            new_members = new ArrayList<Address>(new_backups);
            new_members.removeAll(backups);
            backups.clear();
            backups.addAll(new_backups);
          }
        }

        if (new_members != null && !new_members.isEmpty()) copyQueueTo(new_members);
      }
      // We keep what backups we have ourselves, so that when we become
      // the coordinator we don't update them again.  Technically we can
      // send multiple requests but don't if to prevent more message being
      // sent.
      else {
        List<Address> possiblebackups = Util.pickNext(view.getMembers(), coord, num_backups);

        boolean foundMyself = false;
        List<Address> myBackups = new ArrayList<Address>();
        for (Address backup : possiblebackups) {
          if (foundMyself) {
            myBackups.add(backup);
          } else if (backup.equals(local_addr)) {
            foundMyself = true;
          }
        }

        synchronized (backups) {
          backups.clear();
          backups.addAll(myBackups);
        }
      }
    }

    // Need to run this last so the backups are updated
    super.handleView(view);
  }
Example #3
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);
  }
Example #4
0
  public Object up(Event evt) {
    switch (evt.getType()) {
      case Event.MSG:
        Message msg = (Message) evt.getArg();
        ExecutorHeader hdr = (ExecutorHeader) msg.getHeader(id);
        if (hdr == null) break;

        Request req = (Request) msg.getObject();
        if (log.isTraceEnabled())
          log.trace("[" + local_addr + "] <-- [" + msg.getSrc() + "] " + req);
        switch (req.type) {
          case RUN_REQUEST:
            handleTaskRequest(req.request, (Address) req.object);
            break;
          case CONSUMER_READY:
            handleConsumerReadyRequest(req.request, (Address) req.object);
            break;
          case CONSUMER_UNREADY:
            handleConsumerUnreadyRequest(req.request, (Address) req.object);
            break;
          case CONSUMER_FOUND:
            handleConsumerFoundResponse(req.request, (Address) req.object);
            break;
          case RUN_SUBMITTED:
            RequestWithThread reqWT = (RequestWithThread) req;
            Object objectToRun = reqWT.object;
            Runnable runnable;
            if (objectToRun instanceof Runnable) {
              runnable = (Runnable) objectToRun;
            } else if (objectToRun instanceof Callable) {
              @SuppressWarnings("unchecked")
              Callable<Object> callable = (Callable<Object>) objectToRun;
              runnable = new FutureTask<>(callable);
            } else {
              log.error(
                  "Request of type "
                      + req.type
                      + " sent an object of "
                      + objectToRun
                      + " which is invalid");
              break;
            }

            handleTaskSubmittedRequest(runnable, msg.getSrc(), req.request, reqWT.threadId);
            break;
          case RUN_REJECTED:
            // We could make requests local for this, but is it really worth it
            handleTaskRejectedResponse(msg.getSrc(), req.request);
            break;
          case RESULT_SUCCESS:
            handleValueResponse(msg.getSrc(), req.request, req.object);
            break;
          case RESULT_EXCEPTION:
            handleExceptionResponse(msg.getSrc(), req.request, (Throwable) req.object);
            break;
          case INTERRUPT_RUN:
            // We could make requests local for this, but is it really worth it
            handleInterruptRequest(msg.getSrc(), req.request);
            break;
          case CREATE_CONSUMER_READY:
            Owner owner = new Owner((Address) req.object, req.request);
            handleNewConsumer(owner);
            break;
          case CREATE_RUN_REQUEST:
            owner = new Owner((Address) req.object, req.request);
            handleNewRunRequest(owner);
            break;
          case DELETE_CONSUMER_READY:
            owner = new Owner((Address) req.object, req.request);
            handleRemoveConsumer(owner);
            break;
          case DELETE_RUN_REQUEST:
            owner = new Owner((Address) req.object, req.request);
            handleRemoveRunRequest(owner);
            break;
          default:
            log.error("Request of type " + req.type + " not known");
            break;
        }
        return null;

      case Event.VIEW_CHANGE:
        handleView((View) evt.getArg());
        break;
    }
    return up_prot.up(evt);
  }