@Override
  public byte[] toBytes() {
    byte[] buf = null;
    switch (version) {
      case VERSION_0:
        int offsetSize = 8;
        int startOffsetSize = 8;
        byte[] sessionIdBytes = getSessionIdInBytes();
        byte[] storeKeyBytes = getStoreKeyInBytes();
        int size = VERSION_SIZE + SESSION_ID_LENGTH_SIZE + sessionIdBytes.length + offsetSize + startOffsetSize
            + storeKeyBytes.length;
        buf = new byte[size];
        ByteBuffer bufWrap = ByteBuffer.wrap(buf);
        // add version
        bufWrap.putShort(version);
        // add sessionId
        bufWrap.putInt(sessionIdBytes.length);
        bufWrap.put(sessionIdBytes);
        // add offset for journal based token
        bufWrap.putLong((type == FindTokenType.JournalBased) ? offset.getOffset() : UNINITIALIZED_OFFSET);
        // add index start offset for Index based token
        bufWrap.putLong((type == FindTokenType.IndexBased) ? offset.getOffset() : UNINITIALIZED_OFFSET);
        // add store key
        bufWrap.put(storeKeyBytes);
        break;
      case VERSION_1:
        byte[] offsetBytes = getOffsetInBytes();
        sessionIdBytes = getSessionIdInBytes();
        storeKeyBytes = getStoreKeyInBytes();
        size = VERSION_SIZE + SESSION_ID_LENGTH_SIZE + sessionIdBytes.length + TYPE_SIZE + offsetBytes.length
            + storeKeyBytes.length;
        buf = new byte[size];
        bufWrap = ByteBuffer.wrap(buf);
        // add version
        bufWrap.putShort(VERSION_1);
        // add sessionId
        bufWrap.putInt(sessionIdBytes.length);
        bufWrap.put(sessionIdBytes);
        // add type
        bufWrap.putShort((short) type.ordinal());
        // add offset
        bufWrap.put(offsetBytes);
        // add StoreKey
        bufWrap.put(storeKeyBytes);
        break;
      case VERSION_2:
        offsetBytes = getOffsetInBytes();
        sessionIdBytes = getSessionIdInBytes();
        byte[] incarnationIdBytes = getIncarnationIdInBytes();
        storeKeyBytes = getStoreKeyInBytes();
        size = VERSION_SIZE + TYPE_SIZE;
        if (type != FindTokenType.Uninitialized) {
          size +=
              INCARNATION_ID_LENGTH_SIZE + incarnationIdBytes.length + SESSION_ID_LENGTH_SIZE + sessionIdBytes.length
                  + offsetBytes.length;
          if (type == FindTokenType.JournalBased) {
            size += INCLUSIVE_BYTE_SIZE;
          } else if (type == FindTokenType.IndexBased) {
            size += storeKeyBytes.length;
          }
        }
        buf = new byte[size];
        bufWrap = ByteBuffer.wrap(buf);
        // add version
        bufWrap.putShort(VERSION_2);
        // add type
        bufWrap.putShort((short) type.ordinal());
        if (type != FindTokenType.Uninitialized) {
          // add incarnationId
          bufWrap.putInt(incarnationIdBytes.length);
          bufWrap.put(incarnationIdBytes);
          // add sessionId
          bufWrap.putInt(sessionIdBytes.length);
          bufWrap.put(sessionIdBytes);
          // add offset
          bufWrap.put(offsetBytes);
          if (type == FindTokenType.JournalBased) {
            bufWrap.put(getInclusive() ? (byte) 1 : (byte) 0);
          } else if (type == FindTokenType.IndexBased) {
            bufWrap.put(storeKeyBytes);
          }
        }
        break;
      case VERSION_3:
        offsetBytes = getOffsetInBytes();
        sessionIdBytes = getSessionIdInBytes();
        incarnationIdBytes = getIncarnationIdInBytes();
        storeKeyBytes = getStoreKeyInBytes();
        byte[] resetKeyBytes = getResetKeyInBytes();
        size = VERSION_SIZE + TYPE_SIZE;
        if (type != FindTokenType.Uninitialized) {
          size +=
              INCARNATION_ID_LENGTH_SIZE + incarnationIdBytes.length + SESSION_ID_LENGTH_SIZE + sessionIdBytes.length
                  + offsetBytes.length;
          if (type == FindTokenType.JournalBased) {
            size += INCLUSIVE_BYTE_SIZE;
          } else if (type == FindTokenType.IndexBased) {
            size += storeKeyBytes.length;
          }
          size += HAS_RESET_KEY_INFO_BYTE_SIZE;
          if (hasResetKeyInfo()) {
            size += resetKeyBytes.length + RESET_KEY_TYPE_SIZE + RESET_KEY_VERSION_SIZE;
          }
        }
        buf = new byte[size];
        bufWrap = ByteBuffer.wrap(buf);
        // add version
        bufWrap.putShort(VERSION_3);
        // add type
        bufWrap.putShort((short) type.ordinal());
        if (type != FindTokenType.Uninitialized) {
          // add incarnationId
          bufWrap.putInt(incarnationIdBytes.length);
          bufWrap.put(incarnationIdBytes);
          // add sessionId
          bufWrap.putInt(sessionIdBytes.length);
          bufWrap.put(sessionIdBytes);
          // add offset
          bufWrap.put(offsetBytes);
          if (type == FindTokenType.JournalBased) {
            bufWrap.put(getInclusive() ? (byte) 1 : (byte) 0);
          } else if (type == FindTokenType.IndexBased) {
            bufWrap.put(storeKeyBytes);
          }
          bufWrap.put(hasResetKeyInfo() ? (byte) 1 : (byte) 0);
          if (hasResetKeyInfo()) {
            // add reset key
            bufWrap.put(resetKeyBytes);
            // add reset key type
            bufWrap.putShort((short) resetKeyType.ordinal());
            // add reset key version
            bufWrap.putShort(resetKeyVersion);
          }
        }
        break;
    }
    return buf;
  }
Instantiating {@link StoreFindToken}
@param type the {@link FindTokenType} of the token
@param offset the offset that this token refers to
@param key The {@link StoreKey} that the token refers to
@param sessionId the sessionId of the store that this token refers to
@param incarnationId the incarnationId of the store that this token refers to
@param inclusive {@code true} if the offset is inclusive or in other words the blob at the given offset is inclusive.
                 {@code false} otherwise
@param version refers to the version of the token
@param resetKey The {@link StoreKey} at start offset of current index segment. When log segment on source node is
                compacted (and token becomes invalid), this key is used to find current valid log segment where
                {@link PersistentIndex#findEntriesSince(FindToken, long)} can start from.
@param resetKeyType The {@link PersistentIndex.IndexEntryType} associated with this reset key.
@param resetKeyVersion The life version of reset key.
ambry-store/src/main/java/com/github/ambry/store/StoreFindToken.java