@Override
  public UploadResult uploadBackup(
      Exhibitor exhibitor,
      BackupMetaData backup,
      File source,
      final Map<String, String> configValues)
      throws Exception {
    List<BackupMetaData> availableBackups = getAvailableBackups(exhibitor, configValues);
    if (availableBackups.contains(backup)) {
      return UploadResult.DUPLICATE;
    }

    RetryPolicy retryPolicy = makeRetryPolicy(configValues);
    Throttle throttle = makeThrottle(configValues);

    String key = toKey(backup);
    InitiateMultipartUploadRequest initRequest =
        new InitiateMultipartUploadRequest(configValues.get(CONFIG_BUCKET.getKey()), key);
    InitiateMultipartUploadResult initResponse = s3Client.initiateMultipartUpload(initRequest);

    CompressorIterator compressorIterator = compressor.compress(source);
    try {
      List<PartETag> eTags = Lists.newArrayList();
      int index = 0;
      for (; ; ) {
        ByteBuffer chunk = compressorIterator.next();
        if (chunk == null) {
          break;
        }
        throttle.throttle(chunk.limit());

        PartETag eTag = uploadChunkWithRetry(chunk, initResponse, index++, retryPolicy);
        eTags.add(eTag);
      }

      completeUpload(initResponse, eTags);
    } catch (Exception e) {
      abortUpload(initResponse);
      throw e;
    } finally {
      Closeables.closeQuietly(compressorIterator);
    }

    UploadResult result = UploadResult.SUCCEEDED;
    for (BackupMetaData existing : availableBackups) {
      if (existing.getName().equals(backup.getName())) {
        deleteBackup(exhibitor, existing, configValues);
        result = UploadResult.REPLACED_OLD_VERSION;
      }
    }
    return result;
  }
 private String toKey(BackupMetaData backup) {
   String name = backup.getName().replace(SEPARATOR, SEPARATOR_REPLACEMENT);
   return name + SEPARATOR + backup.getModifiedDate();
 }