@Override
  public void startBlockEncoding(HFileBlockEncodingContext blkEncodingCtx, DataOutputStream out)
      throws IOException {
    if (blkEncodingCtx.getClass() != HFileBlockDefaultEncodingContext.class) {
      throw new IOException(
          this.getClass().getName()
              + " only accepts "
              + HFileBlockDefaultEncodingContext.class.getName()
              + " as the "
              + "encoding context.");
    }

    HFileBlockDefaultEncodingContext encodingCtx =
        (HFileBlockDefaultEncodingContext) blkEncodingCtx;
    encodingCtx.prepareEncoding(out);
    if (encodingCtx.getHFileContext().isIncludesTags()
        && encodingCtx.getHFileContext().isCompressTags()) {
      if (encodingCtx.getTagCompressionContext() != null) {
        // It will be overhead to create the TagCompressionContext again and again for every block
        // encoding.
        encodingCtx.getTagCompressionContext().clear();
      } else {
        try {
          TagCompressionContext tagCompressionContext =
              new TagCompressionContext(LRUDictionary.class, Byte.MAX_VALUE);
          encodingCtx.setTagCompressionContext(tagCompressionContext);
        } catch (Exception e) {
          throw new IOException("Failed to initialize TagCompressionContext", e);
        }
      }
    }
    StreamUtils.writeInt(out, 0); // DUMMY length. This will be updated in endBlockEncoding()
    blkEncodingCtx.setEncodingState(new BufferedDataBlockEncodingState());
  }
 @Override
 public int encode(Cell cell, HFileBlockEncodingContext encodingCtx, DataOutputStream out)
     throws IOException {
   BufferedDataBlockEncodingState state =
       (BufferedDataBlockEncodingState) encodingCtx.getEncodingState();
   int encodedKvSize = internalEncode(cell, (HFileBlockDefaultEncodingContext) encodingCtx, out);
   state.unencodedDataSizeWritten += encodedKvSize;
   return encodedKvSize;
 }
 @Override
 public void endBlockEncoding(
     HFileBlockEncodingContext encodingCtx,
     DataOutputStream out,
     byte[] uncompressedBytesWithHeader)
     throws IOException {
   BufferedDataBlockEncodingState state =
       (BufferedDataBlockEncodingState) encodingCtx.getEncodingState();
   // Write the unencodedDataSizeWritten (with header size)
   Bytes.putInt(
       uncompressedBytesWithHeader,
       HConstants.HFILEBLOCK_HEADER_SIZE + DataBlockEncoding.ID_SIZE,
       state.unencodedDataSizeWritten);
   if (encodingCtx.getDataBlockEncoding() != DataBlockEncoding.NONE) {
     encodingCtx.postEncoding(BlockType.ENCODED_DATA);
   } else {
     encodingCtx.postEncoding(BlockType.DATA);
   }
 }
 /**
  * Do the encoding, but do not cache the encoded data.
  *
  * @return encoded data block with header and checksum
  */
 public byte[] encodeData() {
   try {
     this.dataBlockEncoder.encodeKeyValues(getUncompressedBuffer(), encodingCtx);
   } catch (IOException e) {
     throw new RuntimeException(
         String.format(
             "Bug in encoding part of algorithm %s. "
                 + "Probably it requested more bytes than are available.",
             toString()),
         e);
   }
   return encodingCtx.getUncompressedBytesWithHeader();
 }