Protocol Buffers と比較して、PlainBuffer は小規模なオブジェクトのシリアル化および解決においてより優れたパフォーマンスを提供します。そのため、Tablestore ではデータのフォーマットに PlainBuffer が使用されています。
このドキュメントは、カスタム Tablestore SDK を実装する開発者、またはプロトコルレベルで生データの送受信をデバッグする開発者を対象としています。既存の SDK を使用するアプリケーション開発者は、PlainBuffer の内部構造を理解する必要はありません。
フォーマット定義
PlainBuffer メッセージは、ヘッダーの後に 1 行以上の行が続く構造です。各行にはプライマリキー列セクションと属性列セクションが含まれますが、操作によってはどちらも省略可能です(以下の文法定義を参照)。タグはフィールドのデリミタとして機能し、各タグが次に何が来るかをパーサに伝えます。これにより、パーサはバイトストリームを曖昧さなく読み進めることができます。
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)
タグ値
ほとんどのタグはフィールドの開始を示す 1 バイトですが、tag_header は 4 バイトです。パーサはタグを読み取り、次に続くフィールドの種類を判断したうえで、適切なバイト数を読み込み、次のタグへと進みます。
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 値
formated_value 内の value_type に指定可能な値は以下のとおりです。
VT_INTEGER = 0x0
VT_DOUBLE = 0x1
VT_BOOLEAN = 0x2
VT_STRING = 0x3
VT_NULL = 0x6
VT_BLOB = 0x7
VT_INF_MIN = 0x9
VT_INF_MAX = 0xa
VT_AUTO_INCREMENT = 0xb
チェックサム計算
チェックサムには CRC8 が使用されます。計算ロジックは以下のとおりです。
セルの名前、値、型、タイムスタンプがそのセルのチェックサムに寄与します。
行の削除マーカーは 1 バイト分の寄与があります。
0x1(行に削除マーカーがある場合)、0x0(削除マーカーがない場合)となります。行のチェックサムは、個々のセルのチェックサムに対して CRC8 を実行することで算出されます。生のセルデータに対しては実行されません。
Java 実装例:
以下のコードは、$tablestore-4.2.1-sources/com/alicloud/openservices/tablestore/core/protocol/PlainBufferCrc8.java から抽出したものです。詳細については、「インストール」をご参照ください。
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;
}
例
以下の行には、2 つのプライマリキー列と 4 つの属性列があります。
-
プライマリキー列:
[pk1:string:iampk]
[pk2:integer:100]
-
属性列:
[column1:string:bad:1001]
[column2:integer:128:1002]
[column3:double:34.2:1003]
[column4:del_all_versions]
エンコーディング:
<The start position for headers>[0x75]
<The start position for primary key columns>[0x1]
<Cell1>[0x3][0x4][0x3][3][pk1][0x5][0x3][5][iampk][_cell_checksum]
<Cell2>[0x3][0x4][0x3][3][pk2][0x5][0x0][8][100][_cell_checksum]
<The start position for attribute columns>[0x2]
<Cell1>[0x3][0x4][0x3][7][column1][0x5][0x3][3][bad][0x7][1001][_cell_checksum]
<Cell2>[0x3][0x4][0x3][7][column2][0x5][0x0][8][128][0x7][1002][_cell_checksum]
<Cell3>[0x3][0x4][0x3][7][column3][0x5][0x1][8][34.2][0x7][1003][_cell_checksum]
<Cell4>[0x3][0x4][0x3][7][column4][0x6][1][_cell_checksum]
[_row_check_sum]
最初のプライマリキーセルを 1 バイトずつ読み取り:
|
バイト |
タグ/フィールド |
意味 |
|
|
|
セルの開始 |
|
|
|
セル名が続く |
|
|
value_type |
|
|
|
value_len |
名前は 3 バイト長 |
|
|
value_data |
セル名: |
|
|
|
セル値が続く |
|
|
value_type |
|
|
|
value_len |
値は 5 バイト長 |
|
|
value_data |
セル値: |
|
|
|
名前、値、型、タイムスタンプに対するチェックサム |
2 番目のプライマリキー列のセルも同様の構造ですが、値の型は 0x0(VT_INTEGER)、value_len は 8(64 ビット整数)となります。
属性列のセルには、値の後にタイムスタンプフィールド(0x7 = tag_cell_ts)が追加されます。column4 には値がなく、0x6 タグ(tag_cell_op)の値が 1 であるため、すべてのバージョンを削除する操作(delete-all-versions)としてマークされています。