Skip to content

Commit 022f2ff

Browse files
authored
Merge pull request #35 from eedalong/feature/docs
add docs
2 parents 21db35b + 470cccf commit 022f2ff

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

docs/bytebuffer_zh.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
## IoTDB CSharp Client ByteBuffer实现介绍
2+
在进行`RowRecords`以及`Tablet`的插入时,我们需要对多行RowRecord和Tablet进行序列化以进行发送。客户端中的序列化实现主要依赖于ByteBuffer完成。接下来我们介绍ByteBuffer的实现细节。本文包含如下几点内容:
3+
- 序列化的协议
4+
- C#与Java的大小端的差异
5+
- ByteBuffer内存倍增算法
6+
7+
### 一、序列化协议
8+
客户端向IoTDB服务器发送的序列化数据总体应该包含两个信息。
9+
- 数据类型
10+
- 数据本身
11+
12+
其中对于`字符串`的序列化时,我们需要再加入字符串的长度信息。即一个字符串的序列化完整结果为:
13+
14+
[类型][长度][数据内容]
15+
接下来我们分别介绍`RowRecord``Tablet`的序列化方式
16+
17+
#### 1.1 RowRecord
18+
我们对RowRecord进行序列化时,`伪代码`如下:
19+
20+
public byte[] value_to_bytes(List<TSDataType> data_types, List<string> values){
21+
ByteBuffer buffer = new ByteBuffer(values.Count);
22+
for(int i = 0;i < data_types.Count(); i++){
23+
buffer.add_type((data_types[i]);
24+
buffer.add_val(values[i]);
25+
}
26+
}
27+
28+
对于其序列化的结果格式如下:
29+
30+
[数据类型1][数据1][数据类型2][数据2]...[数据类型N][数据N]
31+
其中数据类型为自定义的`Enum`变量,分别如下:
32+
33+
public enum TSDataType{BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT, NONE};
34+
35+
#### 1.2. Tablet序列化
36+
使用`Tabelt`进行数据插入时有如下限制:
37+
38+
限制:Tablet中数据不能有空值
39+
由于向 `IoTDB`服务器发送`Tablet`数据插入请求时会携带`行数``列数`, `列数据类型`,所以`Tabelt`序列化时我们不需要加入数据类型信息。`Tablet``按照列进行序列化`,这是因为后端可以通过行数得知出当前列的元素个数,同时根据列类型来对数据进行解析。
40+
41+
## CSharp与Java序列化数据时的大小端差异
42+
由于Java序列化默认大端协议,而CSharp序列化默认得到小端序列。所以我们在CSharp中序列化数据之后,需要对数据进行反转这样后端才可以正常解析。同时当我们从后端获取到序列化的结果时(如`SessionDataset`),我们也需要对获得的数据进行反转以解析内容。这其中特例便是字符串的序列化,CSharp中对字符串的序列化结果为大端序,所以序列化字符串或者接收到字符串序列化结果时,不需要反转序列结果。
43+
44+
## ByteBuffer内存倍增法
45+
拥有数万行的Tablet的序列化结果可能有上百兆,为了能够高效的实现大`Tablet`的序列化,我们对ByteBuffer使用`内存倍增法`的策略来减少序列化过程中对于内存的申请和释放。即当当前的buffer的长度不足以放下序列化结果时,我们将当前buffer的内存`至少`扩增2倍。这极大的减少了内存的申请释放次数,加速了大Tablet的序列化速度。
46+
47+
private void extend_buffer(int space_need){
48+
if(write_pos + space_need >= total_length){
49+
total_length = max(space_need, total_length);
50+
byte[] new_buffer = new byte[total_length * 2];
51+
buffer.CopyTo(new_buffer, 0);
52+
buffer = new_buffer;
53+
total_length = 2 * total_length;
54+
}
55+
}
56+
同时在序列化`Tablet`时,我们首先根据Tablet的`行数``列数`以及每一列的数据类型估计当前`Tablet`序列化结果所需要的内存大小,并在初始化时进行内存的申请。这进一步的减少了内存的申请释放频率。
57+
58+
通过上述的策略,我们在一个有`20000`行的Tablet上进行测试时,序列化速度相比Naive数组长度动态生长实现算法具有约35倍的性能加速。
59+

0 commit comments

Comments
 (0)