private void compressChunk(boolean outputDirectMemory) {
      // Do not compress metadata chunk or already compressed chunk.
      if (isMetadataChunk() || isChunkCompressed || !isBlobCompressible) {
        return;
      }

      // Note: compress() returns null if it failed.
      boolean isFullChunk = (buf.readableBytes() == routerConfig.routerMaxPutChunkSizeBytes);
      ByteBuf newBuffer = compressionService.compressChunk(buf, isFullChunk, outputDirectMemory);
      if (newBuffer != null) {
        buf.release();
        buf = newBuffer;
        isChunkCompressed = true;
      }
    }
Compress the buffer in "buf" field for data chunks.  It does not compress metadata chunks.
It also applies rules specified in config.
After compression, it replaces "buf" field and update isCompressed field in blob properties.
@param outputDirectMemory Whether the compression output should be direct memory (True) or heap memory (false).
                          If the next step is encryption, it should use Heap (since encryption takes an array).
                          If the next step is output to Netty, it should use direct memory.
ambry-router/src/main/java/com/github/ambry/router/PutOperation.java