private CompletableFuture<Short> undeleteAsyncIfNeeded(BlobId blobId, short lifeVersion) {
    String blobKey = blobId.getID();
    // See note in deleteIfNeeded.
    if (!checkCacheState(blobKey, lifeVersion, BlobState.CREATED)) {
      return cloudDestination.undeleteBlobAsync(blobId, lifeVersion, this::preUndeleteValidation)
          .whenComplete((newLifeVersion, throwable) -> {
            if (throwable != null) {
              removeFromCache(blobKey);
            } else {
              addToCache(blobId.getID(), newLifeVersion, BlobState.CREATED);
            }
          });
    }
    return FutureUtils.completedExceptionally(
        new StoreException("Id " + blobId.getID() + " is already undeleted in cloud", StoreErrorCodes.IDUndeleted));
  }
Undelete the specified blob if needed depending on the cache state asynchronously.
@param blobId the blob to delete.
@param lifeVersion life version of the deleted blob.
@return a {@link CompletableFuture} that will eventually contain the final updated life version of the blob or the
        {@link CloudStorageException} or {@link StoreException} if an error occurred.
ambry-cloud/src/main/java/com/github/ambry/cloud/CloudBlobStore.java