private PartitionResponseInfo downloadBlobs(PartitionRequestInfo request, ByteArrayOutputStream downloadToStream) {
    List<MessageInfo> messageInfoList = new ArrayList<>();
    for (StoreKey storeKey : request.getBlobIds()) {
      // MessageInfo for the given store key is put in the cache in ReplicaMetadataRequest.
      // All store keys in GetRequest should already have MessageInfos in the cache.
      // If replication thread retries, it would send the ReplicaMetadataRequest again before the GetRequest.
      MessageInfo info = messageInfoCache.remove(storeKey);
      if (info == null) {
        logger.error("Failed to find MessageInfo for store key {} at partition {}", storeKey, request.getPartition());
        return new PartitionResponseInfo(request.getPartition(), ServerErrorCode.BlobNotFound);
      }

      try {
        azureSyncClient.downloadBlob((BlobId) storeKey, downloadToStream);
        messageInfoList.add(info);
        recoveryMetrics.blobDownloadByteRate.mark(info.getSize());
      } catch (CloudStorageException e) {
        logger.error("Failed to download blob {} due to {}", storeKey.getID(), e.getMessage());
        e.printStackTrace();
        return new PartitionResponseInfo(request.getPartition(), ServerErrorCode.IOError);
      }
    }
    List<MessageMetadata> messageMetadataList = new ArrayList<>();
    messageInfoList.forEach(info -> messageMetadataList.add(null)); // unused
    return new PartitionResponseInfo(request.getPartition(), messageInfoList, messageMetadataList);
  }
Downloads blobs from Azure Storage
@param request
@param downloadToStream
@return
ambry-cloud/src/main/java/com/github/ambry/cloud/RecoveryNetworkClient.java