private int compareTypeBytes(Cell key, Cell right) {
   if (key.getFamilyLength() + key.getQualifierLength() == 0
       && key.getTypeByte() == Type.Minimum.getCode()) {
     // left is "bigger", i.e. it appears later in the sorted order
     return 1;
   }
   if (right.getFamilyLength() + right.getQualifierLength() == 0
       && right.getTypeByte() == Type.Minimum.getCode()) {
     return -1;
   }
   return 0;
 }
    @Override
    public void write(Cell cell) throws IOException {
      if (encryptor == null) {
        super.write(cell);
        return;
      }

      byte[] iv = nextIv();
      encryptor.setIv(iv);
      encryptor.reset();

      // TODO: Check if this is a cell for an encrypted CF. If not, we can
      // write a 0 here to signal an unwrapped cell and just dump the KV bytes
      // afterward

      StreamUtils.writeRawVInt32(out, iv.length);
      out.write(iv);

      // TODO: Add support for WAL compression

      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      OutputStream cout = encryptor.createEncryptionStream(baos);

      int tlen = cell.getTagsLength();
      // Write the KeyValue infrastructure as VInts.
      StreamUtils.writeRawVInt32(cout, KeyValueUtil.keyLength(cell));
      StreamUtils.writeRawVInt32(cout, cell.getValueLength());
      // To support tags
      StreamUtils.writeRawVInt32(cout, tlen);

      // Write row, qualifier, and family
      StreamUtils.writeRawVInt32(cout, cell.getRowLength());
      cout.write(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
      StreamUtils.writeRawVInt32(cout, cell.getFamilyLength());
      cout.write(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
      StreamUtils.writeRawVInt32(cout, cell.getQualifierLength());
      cout.write(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
      // Write the rest ie. ts, type, value and tags parts
      StreamUtils.writeLong(cout, cell.getTimestamp());
      cout.write(cell.getTypeByte());
      cout.write(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
      if (tlen > 0) {
        cout.write(cell.getTagsArray(), cell.getTagsOffset(), tlen);
      }
      cout.close();

      StreamUtils.writeRawVInt32(out, baos.size());
      baos.writeTo(out);

      // Increment IV given the final payload length
      incrementIv(baos.size());
    }
 @Override
 public void write(Cell cell) throws IOException {
   checkFlushed();
   // Row
   write(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
   // Column family
   write(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
   // Qualifier
   write(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
   // Version
   this.out.write(Bytes.toBytes(cell.getTimestamp()));
   // Type
   this.out.write(cell.getTypeByte());
   // Value
   write(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
   // Tags
   write(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength());
   // MvccVersion
   this.out.write(Bytes.toBytes(cell.getMvccVersion()));
 }
    @Override
    public int seekToKeyInBlock(Cell seekCell, boolean seekBefore) {
      int rowCommonPrefix = 0;
      int familyCommonPrefix = 0;
      int qualCommonPrefix = 0;
      previous.invalidate();
      do {
        int comp;
        keyOnlyKV.setKey(current.keyBuffer, 0, current.keyLength);
        if (current.lastCommonPrefix != 0) {
          // The KV format has row key length also in the byte array. The
          // common prefix
          // includes it. So we need to subtract to find out the common prefix
          // in the
          // row part alone
          rowCommonPrefix = Math.min(rowCommonPrefix, current.lastCommonPrefix - 2);
        }
        if (current.lastCommonPrefix <= 2) {
          rowCommonPrefix = 0;
        }
        rowCommonPrefix += findCommonPrefixInRowPart(seekCell, keyOnlyKV, rowCommonPrefix);
        comp = compareCommonRowPrefix(seekCell, keyOnlyKV, rowCommonPrefix);
        if (comp == 0) {
          comp = compareTypeBytes(seekCell, keyOnlyKV);
          if (comp == 0) {
            // Subtract the fixed row key length and the family key fixed length
            familyCommonPrefix =
                Math.max(
                    0,
                    Math.min(
                        familyCommonPrefix,
                        current.lastCommonPrefix - (3 + keyOnlyKV.getRowLength())));
            familyCommonPrefix +=
                findCommonPrefixInFamilyPart(seekCell, keyOnlyKV, familyCommonPrefix);
            comp = compareCommonFamilyPrefix(seekCell, keyOnlyKV, familyCommonPrefix);
            if (comp == 0) {
              // subtract the rowkey fixed length and the family key fixed
              // length
              qualCommonPrefix =
                  Math.max(
                      0,
                      Math.min(
                          qualCommonPrefix,
                          current.lastCommonPrefix
                              - (3 + keyOnlyKV.getRowLength() + keyOnlyKV.getFamilyLength())));
              qualCommonPrefix +=
                  findCommonPrefixInQualifierPart(seekCell, keyOnlyKV, qualCommonPrefix);
              comp = compareCommonQualifierPrefix(seekCell, keyOnlyKV, qualCommonPrefix);
              if (comp == 0) {
                comp = CellComparator.compareTimestamps(seekCell, keyOnlyKV);
                if (comp == 0) {
                  // Compare types. Let the delete types sort ahead of puts;
                  // i.e. types
                  // of higher numbers sort before those of lesser numbers.
                  // Maximum
                  // (255)
                  // appears ahead of everything, and minimum (0) appears
                  // after
                  // everything.
                  comp = (0xff & keyOnlyKV.getTypeByte()) - (0xff & seekCell.getTypeByte());
                }
              }
            }
          }
        }
        if (comp == 0) { // exact match
          if (seekBefore) {
            if (!previous.isValid()) {
              // The caller (seekBefore) has to ensure that we are not at the
              // first key in the block.
              throw new IllegalStateException(
                  "Cannot seekBefore if "
                      + "positioned at the first key in the block: key="
                      + Bytes.toStringBinary(seekCell.getRowArray()));
            }
            moveToPrevious();
            return 1;
          }
          return 0;
        }

        if (comp < 0) { // already too large, check previous
          if (previous.isValid()) {
            moveToPrevious();
          } else {
            return HConstants.INDEX_KEY_MAGIC; // using optimized index key
          }
          return 1;
        }

        // move to next, if more data is available
        if (currentBuffer.hasRemaining()) {
          previous.copyFromNext(current);
          decodeNext();
          current.setKey(current.keyBuffer, current.memstoreTS);
        } else {
          break;
        }
      } while (true);

      // we hit the end of the block, not an exact match
      return 1;
    }