protected void doOperationTowardsMaybeCompositeBlob(final String blobIdStr, FutureResult<Void> futureResult,
      Callback<Void> callback, CompositeBlobOperationHelper helper, QuotaChargeCallback quotaChargeCallback) {
    // Can skip GET if we can determine this is not a metadata blob
    if (NonBlockingRouter.isMaybeMetadataBlob(blobIdStr)) {
      Callback<GetBlobResult> internalCallback = (GetBlobResult result, Exception exception) -> {
        if (exception != null) {
          nonBlockingRouter.completeOperation(futureResult, callback, null, exception, false);
        } else if (result != null && result.getBlobDataChannel() != null) {
          exception = new RouterException(
              String.format("GET blob call returned the blob instead of just the store keys (before {} )",
                  helper.getOpName()), RouterErrorCode.UnexpectedInternalError);
          nonBlockingRouter.completeOperation(futureResult, callback, null, exception, false);
        } else if (result.getBlobInfo() != null && helper.getAlreadyUpdated().apply(result.getBlobInfo())
            && canRelyOnMetadataForUpdate(result.getBlobInfo())) {
          // If we are here then we can rely that the metadata chunk was updated only after all data chunks were updated.
          // So this means we are sure that all data chunks are successfully updated.
          // Send an update for metadata chunk only to ensure that metadata chunk's update meets quorum.
          nonBlockingRouter.incrementOperationsCount(1);
          helper.getDoOperation().accept(blobIdStr, Collections.emptyList());
          routerMetrics.updateOptimizedCount.inc();
        } else {
          if (result.getBlobInfo() != null && helper.getAlreadyUpdated().apply(result.getBlobInfo())) {
            routerMetrics.updateUnOptimizedCount.inc();
          }
          List<String> blobIdStrs = new ArrayList<>();
          if (result != null && result.getBlobChunkIds() != null) {
            result.getBlobChunkIds().forEach(key -> blobIdStrs.add(key.getID()));
          }
          nonBlockingRouter.incrementOperationsCount(blobIdStrs.size());
          helper.getDoOperation().accept(blobIdStr, blobIdStrs);
        }
      };

      GetBlobOptions options = new GetBlobOptionsBuilder().operationType(GetBlobOptions.OperationType.All)
          .getOption(helper.getGetOption())
          .build();
      GetBlobOptionsInternal optionsInternal = new GetBlobOptionsInternal(options, true, helper.getMetrics());
      try {
        getBlob(blobIdStr, optionsInternal, internalCallback, quotaChargeCallback);
      } catch (RouterException e) {
        helper.getCompleteOperationAtException().accept(e);
      }
    } else {
      // do update directly on single blobId
      routerMetrics.skippedGetBlobCount.inc();
      helper.getDoOperation().accept(blobIdStr, Collections.emptyList());
    }
  }
A helper method to perform ttl update and undelete operation on a composite blob.
@param blobIdStr The ID of the blob that needs the ttl update in string form
                   permanent
@param futureResult A future that would contain the BlobId eventually.
@param callback The {@link Callback} which will be invoked on the completion of the request.
@param helper The {@link CompositeBlobOperationHelper} that carries other information about this operation.
@param quotaChargeCallback The {@link QuotaChargeCallback} object to help with quota enforcement.
ambry-router/src/main/java/com/github/ambry/router/OperationController.java