protected final void afterDecodingKeyValue(
     DataInputStream source, ByteBuffer dest, HFileBlockDefaultDecodingContext decodingCtx)
     throws IOException {
   if (decodingCtx.getHFileContext().isIncludesTags()) {
     int tagsLength = ByteBufferUtils.readCompressedInt(source);
     // Put as unsigned short
     dest.put((byte) ((tagsLength >> 8) & 0xff));
     dest.put((byte) (tagsLength & 0xff));
     if (tagsLength > 0) {
       TagCompressionContext tagCompressionContext = decodingCtx.getTagCompressionContext();
       // When tag compression is been used in this file, tagCompressionContext will have a not
       // null value passed.
       if (tagCompressionContext != null) {
         tagCompressionContext.uncompressTags(source, dest, tagsLength);
       } else {
         ByteBufferUtils.copyFromStreamToBuffer(dest, source, tagsLength);
       }
     }
   }
   if (decodingCtx.getHFileContext().isIncludesMvcc()) {
     long memstoreTS = -1;
     try {
       // Copy memstore timestamp from the data input stream to the byte
       // buffer.
       memstoreTS = WritableUtils.readVLong(source);
       ByteBufferUtils.writeVLong(dest, memstoreTS);
     } catch (IOException ex) {
       throw new RuntimeException(
           "Unable to copy memstore timestamp " + memstoreTS + " after decoding a key/value");
     }
   }
 }
  @Override
  public ByteBuffer decodeKeyValues(
      DataInputStream source, HFileBlockDecodingContext blkDecodingCtx) throws IOException {
    if (blkDecodingCtx.getClass() != HFileBlockDefaultDecodingContext.class) {
      throw new IOException(
          this.getClass().getName()
              + " only accepts "
              + HFileBlockDefaultDecodingContext.class.getName()
              + " as the decoding context.");
    }

    HFileBlockDefaultDecodingContext decodingCtx =
        (HFileBlockDefaultDecodingContext) blkDecodingCtx;
    if (decodingCtx.getHFileContext().isIncludesTags()
        && decodingCtx.getHFileContext().isCompressTags()) {
      if (decodingCtx.getTagCompressionContext() != null) {
        // It will be overhead to create the TagCompressionContext again and again for every block
        // decoding.
        decodingCtx.getTagCompressionContext().clear();
      } else {
        try {
          TagCompressionContext tagCompressionContext =
              new TagCompressionContext(LRUDictionary.class, Byte.MAX_VALUE);
          decodingCtx.setTagCompressionContext(tagCompressionContext);
        } catch (Exception e) {
          throw new IOException("Failed to initialize TagCompressionContext", e);
        }
      }
    }
    return internalDecodeKeyValues(source, 0, 0, decodingCtx);
  }