Callback<Void> getCallback(final String blobId) {
    return (result, exception) -> {
      exception = exceptionMapper != null ? exceptionMapper.apply(exception) : exception;
      if (exception == null) {
        if (!blobIdToAck.containsKey(blobId)) {
          complete(
              new RouterException("Ack for unknown " + blobId + " arrived", RouterErrorCode.UnexpectedInternalError));
        } else if (blobIdToAck.put(blobId, true)) {
          // already acked once
          complete(new RouterException("Ack for " + blobId + " arrived more than once",
              RouterErrorCode.UnexpectedInternalError));
        } else if (ackedCount.incrementAndGet() >= numBlobIds) {
          // acked for the first time for this blob id and all the blob ids have been acked
          if (finalBlobId != null && finalOperation != null) {
            if (finalOperationReadyToDo.compareAndSet(false, true)) {
              // if final operation hasn't been started yet, then start it.
              blobIdToAck.put(finalBlobId, false);
              nonBlockingRouter.currentOperationsCount.incrementAndGet();
              finalOperation.accept(finalBlobId, getCallback(finalBlobId));
            }
            if (blobId.equals(finalBlobId)) {
              complete(null);
            }
          } else {
            // There is no final blob id to process, just complete it.
            complete(null);
          }
        }
      } else {
        complete(exception);
      }
    };
  }
Gets a {@link Callback} personalized for {@code blobId}.
@param blobId BlobId for which the
@return the {@link Callback} to be used with the {@link TtlUpdateOperation} and {@link UndeleteOperation} for {@code blobId}.
ambry-router/src/main/java/com/github/ambry/router/BatchOperationCallbackTracker.java