public CompletableFuture<Void> appendAsyncFrom(ReadableByteChannel channel, long size) {
      // Upload the blob corresponding to the current message index
      MessageInfo messageInfo = messageInfoList.get(messageIndex++);
      if (messageInfo.getSize() != size) {
        throw new IllegalStateException("Mismatched buffer length for blob: " + messageInfo.getStoreKey().getID());
      }
      ByteBuffer messageBuf = ByteBuffer.allocate((int) size);
      int bytesRead = 0;
      try {
        while (bytesRead < size) {
          int readResult = channel.read(messageBuf);
          if (readResult == -1) {
            return FutureUtils.completedExceptionally(new IOException(
                "Channel read returned -1 before reading expected number of bytes, blobId=" + messageInfo.getStoreKey()
                    .getID()));
          }
          bytesRead += readResult;
        }
        messageBuf.flip();
        return cloudBlobStore.putBlobAsync(messageInfo, messageBuf, size);
      } catch (IOException e) {
        return FutureUtils.completedExceptionally(new StoreException(e, StoreErrorCodes.IOError));
      }
    }
Appends the channel to the underlying write interface. Writes "size" number of bytes to the interface.
@param channel The channel from which data needs to be written from
@param size The amount of data in bytes to be written from the channel
@return a {@link CompletableFuture} that will eventually complete successfully once the bytes are written to the
        write interface or an exception if an error occurs.
ambry-cloud/src/main/java/com/github/ambry/cloud/CloudBlobStore.java