Пример #1
0
  @Test
  public void testNoStackOverflowErrorWithImmediateEventExecutorB() throws Exception {
    final Promise<Void>[] p = new DefaultPromise[128];
    for (int i = 0; i < p.length; i++) {
      final int finalI = i;
      p[i] = new DefaultPromise<Void>(ImmediateEventExecutor.INSTANCE);
      p[i].addListener(
          new FutureListener<Void>() {
            @Override
            public void operationComplete(Future<Void> future) throws Exception {
              DefaultPromise.notifyListener(
                  ImmediateEventExecutor.INSTANCE,
                  future,
                  new FutureListener<Void>() {
                    @Override
                    public void operationComplete(Future<Void> future) throws Exception {
                      if (finalI + 1 < p.length) {
                        p[finalI + 1].setSuccess(null);
                      }
                    }
                  });
            }
          });
    }

    p[0].setSuccess(null);

    for (Promise<Void> a : p) {
      assertThat(a.isSuccess(), is(true));
    }
  }
Пример #2
0
 @Test(expected = CancellationException.class)
 public void testCancellationExceptionIsThrownWhenBlockingGetWithTimeout()
     throws InterruptedException, ExecutionException, TimeoutException {
   final Promise<Void> promise = new DefaultPromise<Void>(ImmediateEventExecutor.INSTANCE);
   promise.cancel(false);
   promise.get(1, TimeUnit.SECONDS);
 }
Пример #3
0
  @Override
  public SEXP apply(Context context, Environment rho, FunctionCall call, PairList args) {

    PairList matchedArguments = ClosureDispatcher.matchArguments(formals, args);

    SEXP exprArgument = matchedArguments.findByTag(EXPR_ARGUMENT);
    SEXP envArgument = matchedArguments.findByTag(ENV_ARGUMENT);

    // Substitute handles ... in an idiosyncratic way:
    // Only the first argument is used, and there is no attempt to
    // match subsequent arguments against the 'env' argument.
    SEXP expr;
    if (exprArgument == Symbols.ELLIPSES) {

      SEXP ellipses = rho.getVariable(Symbols.ELLIPSES);
      if (ellipses == Null.INSTANCE) {
        expr = Null.INSTANCE;
      } else {
        PromisePairList.Node promisePairList = (PromisePairList.Node) ellipses;
        Promise promisedArg = (Promise) promisePairList.getValue();
        expr = promisedArg.getExpression();
      }
    } else {
      expr = exprArgument;
    }

    return substitute(expr, buildContext(context, rho, envArgument));
  }
Пример #4
0
  @Test
  public void testListenerNotifyOrder() throws Exception {
    EventExecutor executor = new TestEventExecutor();
    try {
      final BlockingQueue<FutureListener<Void>> listeners =
          new LinkedBlockingQueue<FutureListener<Void>>();
      int runs = 100000;

      for (int i = 0; i < runs; i++) {
        final Promise<Void> promise = new DefaultPromise<Void>(executor);
        final FutureListener<Void> listener1 =
            new FutureListener<Void>() {
              @Override
              public void operationComplete(Future<Void> future) throws Exception {
                listeners.add(this);
              }
            };
        final FutureListener<Void> listener2 =
            new FutureListener<Void>() {
              @Override
              public void operationComplete(Future<Void> future) throws Exception {
                listeners.add(this);
              }
            };
        final FutureListener<Void> listener4 =
            new FutureListener<Void>() {
              @Override
              public void operationComplete(Future<Void> future) throws Exception {
                listeners.add(this);
              }
            };
        final FutureListener<Void> listener3 =
            new FutureListener<Void>() {
              @Override
              public void operationComplete(Future<Void> future) throws Exception {
                listeners.add(this);
                future.addListener(listener4);
              }
            };

        GlobalEventExecutor.INSTANCE.execute(
            new Runnable() {
              @Override
              public void run() {
                promise.setSuccess(null);
              }
            });

        promise.addListener(listener1).addListener(listener2).addListener(listener3);

        assertSame("Fail 1 during run " + i + " / " + runs, listener1, listeners.take());
        assertSame("Fail 2 during run " + i + " / " + runs, listener2, listeners.take());
        assertSame("Fail 3 during run " + i + " / " + runs, listener3, listeners.take());
        assertSame("Fail 4 during run " + i + " / " + runs, listener4, listeners.take());
        assertTrue("Fail during run " + i + " / " + runs, listeners.isEmpty());
      }
    } finally {
      executor.shutdownGracefully(0, 0, TimeUnit.SECONDS).sync();
    }
  }
Пример #5
0
  protected void forwardToCoord(long seqno, Message msg) {
    if (is_coord) {
      forward(msg, seqno, false);
      return;
    }

    if (!running || flushing) {
      forward_table.put(seqno, msg);
      return;
    }

    if (!ack_mode) {
      forward_table.put(seqno, msg);
      forward(msg, seqno, false);
      return;
    }

    send_lock.lock();
    try {
      forward_table.put(seqno, msg);
      while (running && !flushing) {
        ack_promise.reset();
        forward(msg, seqno, true);
        if (!ack_mode || !running || flushing) break;
        Long ack = ack_promise.getResult(500);
        if ((Objects.equals(ack, seqno)) || !forward_table.containsKey(seqno)) break;
      }
    } finally {
      send_lock.unlock();
    }
  }
Пример #6
0
    public List<PingData> get(long timeout) throws InterruptedException {
      long start_time = System.currentTimeMillis(), time_to_wait = timeout;

      promise.getLock().lock();
      try {
        while (time_to_wait > 0 && !promise.hasResult()) {
          // if num_expected_srv_rsps > 0, then it overrides num_expected_rsps
          if (num_expected_srv_rsps > 0) {
            int received_srv_rsps = getNumServerResponses(ping_rsps);
            if (received_srv_rsps >= num_expected_srv_rsps)
              return new LinkedList<PingData>(ping_rsps);
          } else if (ping_rsps.size() >= num_expected_rsps) {
            return new LinkedList<PingData>(ping_rsps);
          }

          if (break_on_coord_rsp && containsCoordinatorResponse(ping_rsps))
            return new LinkedList<PingData>(ping_rsps);

          promise.getCond().await(time_to_wait, TimeUnit.MILLISECONDS);
          time_to_wait = timeout - (System.currentTimeMillis() - start_time);
        }
        return new LinkedList<PingData>(ping_rsps);
      } finally {
        promise.getLock().unlock();
      }
    }
Пример #7
0
 public OrPromise(Promise<?>... values) {
   this.values = values;
   Runnable callback = new OrPromiseCallback();
   for (Promise<?> value : values) {
     if (value != null) {
       value.addCallback(callback);
     } else {
       callback.run();
     }
   }
 }
  @Override
  protected void onPostExecute(RecipeEntity result) {
    if (delegate == null) {
      throw new IllegalStateException("Delegate should be initialized for the task to execute.");
    }

    if (mError == null) {
      delegate.resolve(result);
    } else {
      delegate.reject(mError);
    }
  }
Пример #9
0
 protected void deliver(Message msg, Event evt, SequencerHeader hdr) {
   Address sender = msg.getSrc();
   if (sender == null) {
     if (log.isErrorEnabled())
       log.error(local_addr + ": sender is null, cannot deliver " + "::" + hdr.getSeqno());
     return;
   }
   long msg_seqno = hdr.getSeqno();
   if (sender.equals(local_addr)) {
     forward_table.remove(msg_seqno);
     if (hdr.flush_ack) {
       ack_promise.setResult(msg_seqno);
       if (ack_mode && !flushing && threshold > 0 && ++num_acks >= threshold) {
         ack_mode = false;
         num_acks = 0;
       }
     }
   }
   if (!canDeliver(sender, msg_seqno)) {
     if (log.isWarnEnabled())
       log.warn(local_addr + ": dropped duplicate message " + sender + "::" + msg_seqno);
     return;
   }
   if (log.isTraceEnabled()) log.trace(local_addr + ": delivering " + sender + "::" + msg_seqno);
   up_prot.up(evt);
   delivered_bcasts++;
 }
Пример #10
0
  public AsyncFlow<R> recover(final IAction<Exception, R> action) {
    final Promise<R> resultPromise = new Promise<R>();

    promise.onDelivered(
        new Callback<R>() {

          public void onResult(R result) {

            resultPromise.deliver(result);
          }

          public void onFailure(Exception e) {

            R result;
            try {
              result = action.doAction(e);
            } catch (Exception e1) {
              resultPromise.deliverException(e1);
              return;
            }

            resultPromise.deliver(result);
          }
        });

    return new AsyncFlow<R>(resultPromise);
  }
Пример #11
0
  public <R1> AsyncFlow<R1> then(final IAsyncAction<R, R1> action) {
    final Promise<R1> resultPromise = new Promise<R1>();

    promise.onDelivered(
        new Callback<R>() {

          public void onResult(R result) {
            Promise<R1> newPromise = action.doAction(result);
            newPromise.onDelivered(
                new Callback<R1>() {

                  public void onResult(R1 result) {
                    resultPromise.deliver(result);
                  }

                  public void onFailure(Exception e) {
                    resultPromise.deliverException(e);
                  }
                });
          }

          public void onFailure(Exception e) {
            resultPromise.deliverException(e);
          }
        });

    return new AsyncFlow<R1>(resultPromise);
  }
Пример #12
0
  public AsyncFlow<R> returnInExecutor(final Executor executor) {
    final Promise<R> resultPromise = new Promise<R>();

    promise.onDelivered(
        new Callback<R>() {

          @Override
          public void onResult(final R result) {
            executor.execute(
                new Runnable() {

                  @Override
                  public void run() {
                    resultPromise.deliver(result);
                  }
                });
          }

          @Override
          public void onFailure(final Exception e) {
            executor.execute(
                new Runnable() {

                  @Override
                  public void run() {
                    resultPromise.deliverException(e);
                  }
                });
          }
        });

    return new AsyncFlow<R>(resultPromise);
  }
Пример #13
0
  public static Promise<Result> get(String symbol) {
    ActorRef stockSentimentActor =
        ActorManagerExtension.ActorManagerExtensionProvider.get(Akka.system())
            .getStockSentimentProxy();
    Future<Object> futureStockSentiments =
        Patterns.ask(stockSentimentActor, new StockSentimentActor.GetSentiment(symbol), timeout);
    Promise<Object> promiseSentiments = Promise.wrap(futureStockSentiments);

    return promiseSentiments
        .<Result>map(
            obj -> {
              StockSentimentActor.SendSentiment sendSentiment =
                  (StockSentimentActor.SendSentiment) obj;
              return Results.ok(sendSentiment.getSentiment());
            })
        .recover(StockSentiment::errorResponse);
  }
Пример #14
0
  protected void getState(Address target, long timeout, Callable<Boolean> flushInvoker)
      throws Exception {
    checkClosedOrNotConnected();
    if (!state_transfer_supported)
      throw new IllegalStateException(
          "fetching state will fail as state transfer is not supported. "
              + "Add one of the state transfer protocols to your configuration");

    if (target == null) target = determineCoordinator();
    if (target != null && local_addr != null && target.equals(local_addr)) {
      log.trace(
          local_addr
              + ": cannot get state from myself ("
              + target
              + "): probably the first member");
      return;
    }

    boolean initiateFlush = flushSupported() && flushInvoker != null;

    if (initiateFlush) {
      boolean successfulFlush = false;
      try {
        successfulFlush = flushInvoker.call();
      } catch (Throwable e) {
        successfulFlush = false; // http://jira.jboss.com/jira/browse/JGRP-759
      }
      if (!successfulFlush)
        throw new IllegalStateException(
            "Node " + local_addr + " could not flush the cluster for state retrieval");
    }

    state_promise.reset();
    StateTransferInfo state_info = new StateTransferInfo(target, timeout);
    long start = System.currentTimeMillis();
    down(new Event(Event.GET_STATE, state_info));
    StateTransferResult result = state_promise.getResult(state_info.timeout);

    if (initiateFlush) stopFlush();

    if (result == null)
      throw new StateTransferException(
          "timeout during state transfer (" + (System.currentTimeMillis() - start) + "ms)");
    if (result.hasException())
      throw new StateTransferException("state transfer failed", result.getException());
  }
Пример #15
0
 /**
  * Zips the values of this promise with <code>another</code>, and creates a new promise holding
  * the tuple of their results
  *
  * @param another
  */
 public <B> Promise<Tuple<A, B>> zip(Promise<B> another) {
   return wrap(wrapped().zip(another.wrapped()))
       .map(
           new Function<scala.Tuple2<A, B>, Tuple<A, B>>() {
             public Tuple<A, B> apply(scala.Tuple2<A, B> scalaTuple) {
               return new Tuple(scalaTuple._1, scalaTuple._2);
             }
           });
 }
Пример #16
0
 public JiraTickets tickets() throws ExecutionException, InterruptedException {
   List<JiraTicket> jiraTickets = new ArrayList<JiraTicket>();
   for (BasicIssue issuesKey : issuesKeys) {
     Promise<Issue> issuePromise = issueRestClient.getIssue(issuesKey.getKey());
     Issue i = issuePromise.get();
     JiraTicket ticket =
         new JiraTicket(
             i.getKey(),
             field(i, HOTFIX_TO),
             field(i, FIX_DETAILS),
             field(i, HOTFIX_FILES),
             field(i, HOTFIX_INSTRUCTIONS),
             field(i, HOTFIX_APPROVED_BY),
             field(i, VERIFICATION_DETAILS));
     jiraTickets.add(ticket);
   }
   return new JiraTickets(jiraTickets);
 }
Пример #17
0
  public void uploadAttachments(JiraTickets tickets)
      throws ExecutionException, InterruptedException, IOException {
    for (JiraTicket t : tickets) {
      Promise<Issue> issuePromise = issueRestClient.getIssue(t.getId());
      Issue i = issuePromise.get();
      File rollback = t.getRollback();
      File hotfix = t.getHotfix();

      if (rollback != null && rollback.canRead()) {
        issueRestClient.addAttachment(
            i.getAttachmentsUri(), FileUtils.openInputStream(rollback), rollback.getName());
      }

      if (hotfix != null && hotfix.canRead()) {
        issueRestClient.addAttachment(
            i.getAttachmentsUri(), FileUtils.openInputStream(hotfix), hotfix.getName());
      }
    }
  }
Пример #18
0
 protected void unblockAll() {
   flushing = false;
   send_lock.lock();
   try {
     send_cond.signalAll();
     ack_promise.setResult(null);
   } finally {
     send_lock.unlock();
   }
 }
Пример #19
0
 public static void main(String[] args) {
   System.out.println("*** Simple test");
   {
     ArrayList<String> out = new ArrayList<>();
     StreamSink<String> sa = new StreamSink<>();
     Promise<String> pa = new Promise<>(sa);
     StreamSink<String> sb = new StreamSink<>();
     Promise<String> pb = new Promise<>(sb);
     Promise<String> p = Promise.lift((a, b) -> a + " " + b, pa, pb);
     sa.send("Hello");
     p.thenDo(t -> System.out.println(t));
     sb.send("World");
   }
   System.out.println("*** Simultaneous case");
   {
     ArrayList<String> out = new ArrayList<>();
     StreamSink<String> sa = new StreamSink<>();
     Promise<String> pa = new Promise<>(sa);
     StreamSink<String> sb = new StreamSink<>();
     Promise<String> pb = new Promise<>(sb);
     Promise<String> p = Promise.lift((a, b) -> a + " " + b, pa, pb);
     p.thenDo(t -> System.out.println(t));
     Transaction.runVoid(
         () -> {
           sa.send("Hello");
           sb.send("World");
         });
   }
 }
Пример #20
0
  protected void stopFlusher() {
    flushing = false;
    Thread tmp = flusher;

    while (tmp != null && tmp.isAlive()) {
      tmp.interrupt();
      ack_promise.setResult(null);
      try {
        tmp.join();
      } catch (InterruptedException e) {
      }
    }
  }
Пример #21
0
 public void updateTickets(JiraTickets tickets) throws ExecutionException, InterruptedException {
   for (JiraTicket t : tickets) {
     Promise<Issue> issuePromise = issueRestClient.getIssue(t.getId());
     Issue i = issuePromise.get();
     // find transition (we need ID)
     Iterable<Transition> transitions =
         issueRestClient.getTransitions(i.getTransitionsUri()).get();
     String tName = "Hotfix Failed";
     if (t.isValid()) {
       tName = "Out On Dev";
     }
     Transition transition = find(transitions, tName);
     if (transition == null) {
       continue;
     }
     // prepare fields
     // List<FieldInput> fields = Arrays.asList(   new FieldInput("resolution",
     // ComplexIssueInputFieldValue.with("name", "RerunPass")));
     Comment comment = Comment.valueOf(StringUtils.join(t.getValidationMessages(), "\n"));
     issueRestClient.transition(i, new TransitionInput(transition.getId(), comment));
   }
 }
Пример #22
0
  public void sendDiscoveryRequest(String cluster_name, Promise promise, ViewId view_id)
      throws Exception {
    PingData data = null;
    PhysicalAddress physical_addr =
        (PhysicalAddress) down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr));

    if (view_id == null) {
      List<PhysicalAddress> physical_addrs = Arrays.asList(physical_addr);
      data = new PingData(local_addr, null, false, UUID.get(local_addr), physical_addrs);
    }

    PingHeader hdr = new PingHeader(PingHeader.GET_MBRS_REQ, data, cluster_name);
    hdr.view_id = view_id;

    Collection<PhysicalAddress> cluster_members = fetchClusterMembers(cluster_name);
    if (cluster_members == null) {
      Message msg = new Message(null); // multicast msg
      msg.setFlag(Message.OOB);
      msg.putHeader(getId(), hdr);
      sendMcastDiscoveryRequest(msg);
    } else {
      if (cluster_members.isEmpty()) { // if we don't find any members, return immediately
        if (promise != null) promise.setResult(null);
      } else {
        for (final Address addr : cluster_members) {
          if (addr.equals(physical_addr)) // no need to send the request to myself
          continue;
          final Message msg = new Message(addr, null, null);
          msg.setFlag(Message.OOB);
          msg.putHeader(this.id, hdr);
          if (log.isTraceEnabled())
            log.trace("[FIND_INITIAL_MBRS] sending discovery request to " + msg.getDest());
          if (!sendDiscoveryRequestsInParallel()) {
            down_prot.down(new Event(Event.MSG, msg));
          } else {
            timer.execute(
                new Runnable() {
                  public void run() {
                    try {
                      down_prot.down(new Event(Event.MSG, msg));
                    } catch (Exception ex) {
                      if (log.isErrorEnabled())
                        log.error("failed sending discovery request to " + addr + ": " + ex);
                    }
                  }
                });
          }
        }
      }
    }
  }
Пример #23
0
 private static void testPromiseListenerAddWhenComplete(Throwable cause)
     throws InterruptedException {
   final CountDownLatch latch = new CountDownLatch(1);
   final Promise<Void> promise = new DefaultPromise<Void>(ImmediateEventExecutor.INSTANCE);
   promise.addListener(
       new FutureListener<Void>() {
         @Override
         public void operationComplete(Future<Void> future) throws Exception {
           promise.addListener(
               new FutureListener<Void>() {
                 @Override
                 public void operationComplete(Future<Void> future) throws Exception {
                   latch.countDown();
                 }
               });
         }
       });
   if (cause == null) {
     promise.setSuccess(null);
   } else {
     promise.setFailure(cause);
   }
   latch.await();
 }
Пример #24
0
    public void addResponse(PingData rsp, boolean overwrite) {
      if (rsp == null) return;
      promise.getLock().lock();
      try {
        if (overwrite) ping_rsps.remove(rsp);

        // https://jira.jboss.org/jira/browse/JGRP-1179
        int index = ping_rsps.indexOf(rsp);
        if (index == -1) {
          ping_rsps.add(rsp);
          promise.getCond().signalAll();
        } else if (rsp.isCoord()) {
          PingData pr = ping_rsps.get(index);

          // Check if the already existing element is not server
          if (!pr.isCoord()) {
            ping_rsps.set(index, rsp);
            promise.getCond().signalAll();
          }
        }
      } finally {
        promise.getLock().unlock();
      }
    }
Пример #25
0
 public <F extends ListenableFuture<? extends I>> F track(final F job) {
   startedCount.incrementAndGet();
   if (!isAcceptingNewJobs()) job.cancel(completionPromise.wasCancelledWithInterruption());
   job.addListener(
       () -> {
         try {
           handleCompletedJob(job);
         } catch (Exception e) {
           abort(FunFuture.unwrapExecutionException(e));
         } finally {
           completedCount.incrementAndGet();
           checkDone();
         }
       },
       jobCompletionExecutor);
   return job;
 }
Пример #26
0
  public <Any> AsyncFlow<Any> inParallelWithNext(final IAsyncAction<R, Any> action) {
    final Promise<Any> resultPromise = new Promise<Any>();

    promise.onDelivered(
        new Callback<R>() {

          @SuppressWarnings("unused")
          public void onResult(R result) {
            Promise<Any> newPromise = action.doAction(result);
            resultPromise.deliver(); // force running rest chain before the action completed
          }

          public void onFailure(Exception e) {
            resultPromise.deliverException(e);
          }
        });

    return new AsyncFlow<Any>(resultPromise);
  }
  @Override
  public void add(final AsyncContextBase async, Promise<?> waitFor) {
    checkClosed();
    heirs.add(async);
    if (!async.isDaemon()) {
      nonDaemonHeirsCount++;
    }
    if (waitFor == null) {
      executor.execute(async);
    } else {
      waitFor.addCallback(
          new Runnable() {

            @Override
            public void run() {
              executor.execute(async);
            }
          });
    }
  }
Пример #28
0
  /**
   * Sends all messages currently in forward_table to the new coordinator (changing the dest field).
   * This needs to be done, so the underlying reliable unicast protocol (e.g. UNICAST) adds these
   * messages to its retransmission mechanism<br>
   * Note that we need to resend the messages in order of their seqnos ! We also need to prevent
   * other message from being inserted until we're done, that's why there's synchronization.<br>
   * Access to the forward_table doesn't need to be synchronized as there won't be any insertions
   * during flushing (all down-threads are blocked)
   */
  protected void flushMessagesInForwardTable() {
    if (is_coord) {
      for (Map.Entry<Long, Message> entry : forward_table.entrySet()) {
        Long key = entry.getKey();
        Message msg = entry.getValue();
        Buffer buf;
        try {
          buf = Util.streamableToBuffer(msg);
        } catch (Exception e) {
          log.error(Util.getMessage("FlushingBroadcastingFailed"), e);
          continue;
        }

        SequencerHeader hdr = new SequencerHeader(SequencerHeader.WRAPPED_BCAST, key);
        Message forward_msg = new Message(null, buf).putHeader(this.id, hdr);
        if (log.isTraceEnabled())
          log.trace(local_addr + ": flushing (broadcasting) " + local_addr + "::" + key);
        down_prot.down(new Event(Event.MSG, forward_msg));
      }
      return;
    }

    // for forwarded messages, we need to receive the forwarded message from the coordinator, to
    // prevent this case:
    // - V1={A,B,C}
    // - A crashes
    // - C installs V2={B,C}
    // - C forwards messages 3 and 4 to B (the new coord)
    // - B drops 3 because its view is still V1
    // - B installs V2
    // - B receives message 4 and broadcasts it
    // ==> C's message 4 is delivered *before* message 3 !
    // ==> By resending 3 until it is received, then resending 4 until it is received, we make sure
    // this won't happen
    // (see https://issues.jboss.org/browse/JGRP-1449)
    while (flushing && running && !forward_table.isEmpty()) {
      Map.Entry<Long, Message> entry = forward_table.firstEntry();
      final Long key = entry.getKey();
      Message msg = entry.getValue();
      Buffer buf;

      try {
        buf = Util.streamableToBuffer(msg);
      } catch (Exception e) {
        log.error(Util.getMessage("FlushingBroadcastingFailed"), e);
        continue;
      }

      while (flushing && running && !forward_table.isEmpty()) {
        SequencerHeader hdr = new SequencerHeader(SequencerHeader.FLUSH, key);
        Message forward_msg =
            new Message(coord, buf).putHeader(this.id, hdr).setFlag(Message.Flag.DONT_BUNDLE);
        if (log.isTraceEnabled())
          log.trace(
              local_addr
                  + ": flushing (forwarding) "
                  + local_addr
                  + "::"
                  + key
                  + " to coord "
                  + coord);
        ack_promise.reset();
        down_prot.down(new Event(Event.MSG, forward_msg));
        Long ack = ack_promise.getResult(500);
        if ((Objects.equals(ack, key)) || !forward_table.containsKey(key)) break;
      }
    }
  }
Пример #29
0
 /**
  * Copies the value or error from the source promise to the destination promise.
  *
  * @param source the source promise
  * @param dest the destination promise
  * @param <T> the value type for both promises
  */
 public static <T, S extends T> void propagateResult(
     final Promise<S> source, final SettablePromise<? super T> dest) {
   source.addListener(new PropagateResultListener<T, S>(source, dest));
 }
Пример #30
0
/** User: josh Date: 6/30/14 Time: 11:52 AM */
public abstract class AbstractCompletionTracker<I, O> {
  private final Executor jobCompletionExecutor;
  private final Promise<O> completionPromise = Promise.newPromise();
  private final AtomicLong startedCount = new AtomicLong();
  private final AtomicLong completedCount = new AtomicLong();
  private final AtomicBoolean markedComplete = new AtomicBoolean();

  public AbstractCompletionTracker(Executor jobCompletionExecutor) {
    this.jobCompletionExecutor = jobCompletionExecutor;
  }

  protected abstract void handleCompletedJob(ListenableFuture<? extends I> job) throws Exception;

  protected abstract O computeResult() throws Exception;

  public FunFuture<O> getCompletionFuture() {
    return completionPromise;
  }

  public boolean isAcceptingNewJobs() {
    return !isDone();
  }

  public boolean isDone() {
    return completionPromise.isDone();
  }

  public AbstractCompletionTracker<I, O> trackAll(
      Iterable<? extends ListenableFuture<? extends I>> futures) {
    for (ListenableFuture<? extends I> future : futures) {
      track(future);
    }
    return this;
  }

  public <F extends ListenableFuture<? extends I>> F track(final F job) {
    startedCount.incrementAndGet();
    if (!isAcceptingNewJobs()) job.cancel(completionPromise.wasCancelledWithInterruption());
    job.addListener(
        () -> {
          try {
            handleCompletedJob(job);
          } catch (Exception e) {
            abort(FunFuture.unwrapExecutionException(e));
          } finally {
            completedCount.incrementAndGet();
            checkDone();
          }
        },
        jobCompletionExecutor);
    return job;
  }

  /**
   * Completes the completion-future with the given exception, and causes all subsequently-submitted
   * jobs to be rejected/cancelled.
   *
   * @return true if this exception was applied to the completion of this tracker
   */
  protected boolean abort(Throwable e) {
    return completionPromise.setFailure(e);
  }

  public long getIncompleteJobCount() {
    return startedCount.get() - completedCount.get();
  }

  public long getCompletedJobCount() {
    return completedCount.get();
  }

  protected void checkDone() {
    if (allJobsDone() && markedComplete.compareAndSet(false, true)) {
      completionPromise.complete(this::computeResult);
    }
  }

  protected boolean allJobsDone() {
    return getIncompleteJobCount() == 0;
  }
}