int compactPartition(String partitionPath, String fieldName, long queryStartTime, long queryEndTime)
      throws CloudStorageException {

    logger.info("Compacting partition {} for {} in time range {} - {}", partitionPath, fieldName,
        new Date(queryStartTime).toString(), new Date(queryEndTime).toString());
    // Iterate until returned list size < limit, time runs out or we get shut down
    int totalPurged = 0;
    long bucketTimeRange = TimeUnit.DAYS.toMillis(queryBucketDays);
    logger.debug("Dividing compaction query for {} into buckets of {} days", partitionPath, queryBucketDays);
    long bucketStartTime = queryStartTime;
    while (bucketStartTime < queryEndTime) {
      long bucketEndTime = Math.min(bucketStartTime + bucketTimeRange, queryEndTime);
      int numPurged = compactPartitionBucketed(partitionPath, fieldName, bucketStartTime, bucketEndTime);
      totalPurged += numPurged;

      bucketStartTime += bucketTimeRange;
      if (isShuttingDown()) {
        logger.debug("Shutting down for partition {}.", partitionPath);
        break;
      }

      if (totalPurged >= purgeLimit) {
        logger.debug("Reached limit for partition {} with {} blobs purged.", partitionPath, totalPurged);
        break;
      }
    }
    return totalPurged;
  }
Purge the inactive blobs in the specified partition.
Long time windows are divided into smaller buckets.
@param partitionPath the partition to compact.
@param fieldName the field name to query on. Allowed values are {@link CloudBlobMetadata#FIELD_DELETION_TIME}
                     and {@link CloudBlobMetadata#FIELD_EXPIRATION_TIME}.
@param queryStartTime the initial query start time, which will be adjusted as compaction progresses.
@param queryEndTime the query end time.
@return the number of blobs purged or found.
@throws CloudStorageException if the compaction fails.
ambry-cloud/src/main/java/com/github/ambry/cloud/azure/AzureStorageCompactor.java