The PlainBuffer format is defined in Table Store to indicate row data, because it delivers better performance for serialization, and small object resolution, compared to Protocol Buffer.

Format definition

plainbuffer = tag_header row1  [row2]  [row3]
row = ( pk [attr] | [pk] attr | pk attr ) [tag_delete_marker] row_checksum;
pk = tag_pk cell_1 [cell_2] [cell_3]
attr  = tag_attr cell1 [cell_2] [cell_3]
cell = tag_cell cell_name [cell_value] [cell_op] [cell_ts] cell_checksum
cell_name = tag_cell_name  formated_value
cell_value = tag_cell_value formated_value
cell_op = tag_cell_op  cell_op_value
cell_ts = tag_cell_ts cell_ts_value
row_checksum = tag_row_checksum row_crc8
cell_checksum = tag_cell_checksum row_crc8

formated_value = value_type value_len value_data
value_type = int8
value_len = int32

cell_op_value = delete_all_version | delete_one_version
cell_ts_value = int64 
delete_all_version = 0x01 (1byte)
delete_one_version = 0x03 (1byte)

Tag value

tag_header = 0x75 (4byte)
tag_pk = 0x01 (1byte)
tag_attr = 0x02 (1byte)
tag_cell = 0x03 (1byte)
tag_cell_name = 0x04 (1byte)
tag_cell_value = 0x05 (1byte)
tag_cell_op = 0x06 (1byte)
tag_cell_ts = 0x07 (1byte)
tag_delete_marker = 0x08 (1byte)
tag_row_checksum = 0x09 (1byte)
tag_cell_checksum = 0x0A (1byte)

ValueType value

The values of value_type in formated_value are as follows:

VT_NULL = 0x6
VT_BLOB = 0x7
VT_INF_MIN = 0x9
VT_INF_MAX = 0xa

Calculate the checksum

The basic logic for calculating the checksum is as follows:

  • Calculate the name/value/type/time stamp of each cell.
  • Calculate the delete in the row. If delete mark exists in the row, supplement a single-byte 1; otherwise, supplement a single-byte 0.
  • Because the checksum is calculated for each cell, the cell checksum is used to calculate the row checksum, that is, the CRC operation is only performed on the checksums of cells in the row, not data in the row.
Java implementation:
Note The following code is from $tablestore-4.2.1-sources/com/alicloud/openservices/tablestore/core/protocol/ . For more information, see Java SDK.
public static byte getChecksum(byte crc, PlainBufferCell cell) throws IOException {

    if (cell.hasCellName()) {
        crc = crc8(crc, cell.getNameRawData());

    if (cell.hasCellValue()) {
        if (cell.isPk()) {
            crc = cell.getPkCellValue().getChecksum(crc);
        } else {
            crc = cell.getCellValue().getChecksum(crc);

    if (cell.hasCellTimestamp()) {
        crc = crc8(crc, cell.getCellTimestamp());

    if (cell.hasCellType()) {
        crc = crc8(crc, cell.getCellType());

    return crc;

public static byte getChecksum(byte crc, PlainBufferRow row) throws IOException {
    for (PlainBufferCell cell : row.getPrimaryKey()) {
        crc = crc8(crc, cell.getChecksum());

    for (PlainBufferCell cell : row.getCells()) {
        crc = crc8(crc, cell.getChecksum());

    byte del = 0;
    if (row.hasDeleteMarker()) {
        del = (byte)0x1;
    crc = crc8(crc, del);

    return crc;


A data row contains two primary key columns and four data columns. The primary key types are string and integer, and the data types are string, int, and double. The versions are 1001, 1002, and 1003. A column is also contained to delete all versions.

  • Primary key column:
    • [pk1:string:iampk]
    • [pk2:integer:100]
  • Attribute column:
    • [column1:string:bad:1001]
    • [column2:integer:128:1002]
    • [column3:double:34.2:1003]
    • [column4:del_all_versions]


  <HHeader starting>[0x75]
  <rimary key column starting>[0x1]
  <Attribute column starting>[0x2]