@Override
  public boolean deleteBlob(BlobId blobId, long deletionTime, short lifeVersion,
      CloudUpdateValidator unused) throws CloudStorageException, StoreException {
    Timer.Context storageTimer = azureMetrics.blobDeleteLatency.time();
    AzureBlobLayoutStrategy.BlobLayout blobLayout = azureBlobLayoutStrategy.getDataBlobLayout(blobId);
    String blobIdStr = blobLayout.blobFilePath;
    String errfmt = "Uninitialized string";
    try {
      // AzureBlobDeletePolicy.IMMEDIATE
      if (azureCloudConfig.azureBlobDeletePolicy.equals(AzureBlobDeletePolicy.IMMEDIATE)) {
        errfmt = "Failed to delete blob %s in Azure blob storage due to (%s)";
        int status = eraseBlob(createOrGetBlobStore(blobLayout.containerName).getBlobClient(blobLayout.blobFilePath),
            "CUSTOMER_DELETE_REQUEST");
        if(status != HttpStatus.SC_ACCEPTED) {
          // Throw CloudStorageException for operations that reached Azure, else StoreException.
          // Throw an error to halt replication. If we don't, then we risk orphan blobs in Azure costing storage.
          // The message here will be concatenated with errfmt string in the catch-clause.
          throw new CloudStorageException(String.format("%s error code", status), status);
        }
        azureMetrics.blobDeleteSuccessRate.mark();
        return true; // this return value is unused
      }

      // AzureBlobDeletePolicy.EVENTUAL
      BlobProperties blobPropertiesCached = getAzureBlobPropertiesCached(blobLayout).getProperties();
      Map<String, String> cloudMetadataCached = blobPropertiesCached.getMetadata();
      // lifeVersion must always be present
      short cloudlifeVersion = Short.parseShort(cloudMetadataCached.get(CloudBlobMetadata.FIELD_LIFE_VERSION));
      if (cloudlifeVersion > lifeVersion) {
        String error = String.format("Failed to update deleteTime of blob %s as it has a higher life version in cloud than replicated message: %s > %s",
            blobIdStr, cloudlifeVersion, lifeVersion);
        logger.trace(error);
        throw new StoreException(error, StoreErrorCodes.LifeVersionConflict);
      }
      if (cloudlifeVersion == lifeVersion && cloudMetadataCached.containsKey(CloudBlobMetadata.FIELD_DELETION_TIME)) {
        String error = String.format("Failed to update deleteTime of blob %s as it is marked for deletion in cloud", blobIdStr);
        logger.trace(error);
        throw new StoreException(error, StoreErrorCodes.IDDeleted);
      }
      errfmt = "Failed to update deleteTime of blob %s in Azure blob storage due to (%s)";
      Map<String, Object> newMetadata = new HashMap<>();
      newMetadata.put(CloudBlobMetadata.FIELD_DELETION_TIME, String.valueOf(deletionTime));
      newMetadata.put(CloudBlobMetadata.FIELD_LIFE_VERSION, lifeVersion);
      newMetadata.forEach((k,v) -> cloudMetadataCached.put(k, String.valueOf(v)));
      logger.trace("Updating deleteTime of blob {} in Azure blob storage ", blobLayout.blobFilePath);
      Response<Void> response = updateBlobMetadata(blobLayout, blobPropertiesCached);
      // Success rate is effective, success counter is ineffective because it just monotonically increases
      azureMetrics.blobDeleteSuccessRate.mark();
      logger.trace("Successfully updated deleteTime of blob {} in Azure blob storage with statusCode = {}, etag = {}",
          blobLayout.blobFilePath, response.getStatusCode(), response.getHeaders().get(HttpHeaderName.ETAG));
      return true;
    } catch (StoreException e) {
      azureMetrics.blobDeleteErrorCount.inc();
      throw e;
    } catch (Throwable t) {
      azureMetrics.blobDeleteErrorCount.inc();
      String error = String.format(errfmt, blobLayout, t.getMessage());
      logger.error(error);
      throw new CloudStorageException(error);
    } finally {
      storageTimer.stop();
      getThreadLocalMdCache().deleteObject(blobLayout.blobFilePath);
    } // try-catch
  }
Returns blob properties from Azure
@param blobLayout BlobLayout
@return Blob properties
@throws CloudStorageException
ambry-cloud/src/main/java/com/github/ambry/cloud/azure/AzureCloudDestinationSync.java