@Override protected CompletableFuture<Void> doRun() { // The QueueProcessor is responsible with the processing of externally added Operations. It starts when the // OperationProcessor starts and is shut down as soon as doStop() is invoked. val queueProcessor = Futures .loop(this::isRunning, () -> throttle() .thenComposeAsync(v -> this.operationQueue.take(MAX_READ_AT_ONCE), this.executor) .thenAcceptAsync(this::processOperations, this.executor), this.executor); // The CommitProcessor is responsible with the processing of those Operations that have already been committed to // DurableDataLong and now need to be added to the in-memory State. // As opposed from the QueueProcessor, this needs to process all pending commits and not discard them, even when // we receive a stop signal (from doStop()), otherwise we could be left with an inconsistent in-memory state. val commitProcessor = Futures .loop(() -> isRunning() || this.commitQueue.size() > 0, () -> this.commitQueue.take(MAX_COMMIT_QUEUE_SIZE) .thenAcceptAsync(this::processCommits, this.executor), this.executor) .whenComplete((r, ex) -> { // The CommitProcessor is done. Safe to close its queue now, regardless of whether it failed or // shut down normally. this.commitQueue.close(); if (ex != null) { throw new CompletionException(ex); } }); return CompletableFuture.allOf(queueProcessor, commitProcessor) .exceptionally(this::iterationErrorHandler); }
this.metrics.currentState(this.operationQueue.size() + count, this.state.getPendingCount()); this.metrics.processOperations(count, processTimer.getElapsedMillis()); processTimer = new Timer(); // Reset this timer since we may be pulling in new operations.