protected int eraseBlobs(List<BlobItem> blobItemList, BlobContainerClient blobContainerClient,
      Set<Pair<Short, Short>> deletedContainers, Supplier<Boolean> stopCompaction) {
    int numBlobsPurged = 0;
    long now = System.currentTimeMillis();
    long gracePeriod = TimeUnit.DAYS.toMillis(cloudConfig.cloudCompactionGracePeriodDays);
    Iterator<BlobItem> blobItemIterator = blobItemList.iterator();
    /*
        while (blobItemIterator.hasNext() && !stopCompaction.get()) invokes stopCompaction once per blob.
        while (!stopCompaction.get() && blobItemIterator.hasNext()) invokes stopCompaction twice per blob.
        Useful to know for testCompactPartitionDisown.
     */
    while (blobItemIterator.hasNext() && !stopCompaction.get()) {
      BlobItem blobItem = blobItemIterator.next();
      Map<String, String> metadata = blobItem.getMetadata();
      Pair<Short, Short> accountContainerIds = new Pair<>(Short.parseShort(metadata.get(CloudBlobMetadata.FIELD_ACCOUNT_ID)),
          Short.parseShort(metadata.get(CloudBlobMetadata.FIELD_CONTAINER_ID)));
      boolean eraseBlob = false;
      String eraseReason;

      if (metadata.containsKey(CloudBlobMetadata.FIELD_DELETION_TIME)) {
        long deletionTime = Long.parseLong(metadata.get(CloudBlobMetadata.FIELD_DELETION_TIME));
        eraseBlob = (deletionTime + gracePeriod) < now;
        eraseReason = String.format("%s: (%s + %s) < %s", CloudBlobMetadata.FIELD_DELETION_TIME, deletionTime, gracePeriod, now);
      } else if (metadata.containsKey(CloudBlobMetadata.FIELD_EXPIRATION_TIME)) {
        long expirationTime = Long.parseLong(metadata.get(CloudBlobMetadata.FIELD_EXPIRATION_TIME));
        eraseBlob = expirationTime < now; // no grace-period for expired blobs; just get rid of them
        eraseReason = String.format("%s: %s < %s", CloudBlobMetadata.FIELD_EXPIRATION_TIME, expirationTime, now);
      } else if (deletedContainers.contains(accountContainerIds)) {
        eraseBlob = true;
        eraseReason = String.format("account = %s, deleted_container = %s", accountContainerIds.getFirst(), accountContainerIds.getSecond());
      } else {
        // nothing to do, blob cannot be deleted
        eraseReason = String.format("No reason to erase blob %s", blobItem.getName());
      }

      if (eraseBlob) {
        if (cloudConfig.cloudCompactionDryRunEnabled) {
          logger.trace("[DRY-RUN][COMPACT] Can erase blob {} from Azure blob storage because {}", blobItem.getName(), eraseReason);
          numBlobsPurged += 1;
        } else {
          int status = eraseBlob(blobContainerClient.getBlobClient(blobItem.getName()), eraseReason);
          if (status == HttpStatus.SC_ACCEPTED) {
            numBlobsPurged += 1;
            azureMetrics.blobCompactionSuccessRate.mark();
          } else {
            azureMetrics.blobCompactionErrorCount.inc();
          }
        }
      } else {
        logger.trace("[COMPACT] Cannot erase blob {} from Azure blob storage because condition not met: {}", blobItem.getName(), eraseReason);
      }

    }
    return numBlobsPurged;
  }
Erases blobs from a given list of blobs in cloud
@param blobItemList List of blobs in a container
@param blobContainerClient BlobContainer client
@return The number of blobs erased
ambry-cloud/src/main/java/com/github/ambry/cloud/azure/AzureCloudDestinationSync.java