CFile是一种在磁盘上的存放了数据和其相关B-树索引的列式存储结构,在一个DiskRowSet中每一列和DeltaFile都会映射到一个CFile上,此外DIskRowSet的布隆过滤器也会被存储在CFile中,如果这张表含有复合主键,那么与其相关的ad-hoc index也会被存储在各自的CFile中。
尽管叫CFile,一个CFile也并不一定和真实文件系统中的一个文件一一对应,CFiles和文件系统之间的映射由BlockManager来抽象实现,一个CFile被写入单个的BlockManager Block(不要把它和CFile blocks搞混淆,CFile blocks存在于CFiles中,稍后会对其进行详细的讨论)
一个CFile由一个header,一些blocks,和一个footer组成,可能会有一些不同类型的blocks,每类都有着不同的格式:data blocks(数据块),nullable data blocks(可空数据块),index blocks(索引块),和dictionary blocks(字典块).
其中数据块由一些连续的值组成,每个值都都被分配了一个ordinal index(序数索引),或者一个offset(偏移量),例如,一个CFile的前三块可能具有序号索引范围[0,55],[56,132]和[133,511].
为了高效的对一个CFile内任意的序数进行索引,一个相对起始序数索引的位置索引可能会被包含在data block中,CFile index文档部分对此有更详细的解释。
对于内部数据有序的CFiles(比如一个包含了主键列的CFile),它可能会创建一个value index(值索引).值索引能够更高效地在CFile中寻找任意的值,有关详细信息请参阅CFile index文档。
CFile header,blocks和footer被没有间隔地连续写入一个文件中。
field | width (bytes) | notes |
---|---|---|
magic | 8 | see below |
length | 4 | 32-bit unsigned length of the following Protobuf message |
message | variable | encoded CFileHeaderPB Protobuf message |
checksum | 4 | optional CRC-32 checksum of magic, length, and message |
field | width (bytes) | notes |
---|---|---|
checksum | 4 | optional CRC-32 checksum of message, magic, and length |
magic | 8 | see below |
message | variable | encoded CFileFooterPB Protobuf message |
length | 4 | unsigned 32-bit length of the preceding Protobuf message |
CFile header和Footer都包含一个magic字符串来指明版本号.
version | string |
---|---|
CFile v1 | kuducfil |
CFile v2 | kuducfl2 |
field | width (bytes) | notes |
---|---|---|
data | variable | encoded data values |
checksum | 4 | optional CRC-32 checksum of the data |
如果Cfile被配置为使用压缩算法,那么将会在压缩编码后再计算循环冗余检测码.
被标记为可空的列将会被存放在Nullable Data Block中,将会有一个bitmap来表明那些行(或序数偏移量)为空或者非空。
field | width (bytes) | notes |
---|---|---|
value count | variable | LEB128 encoded count of values |
bitmap length | variable | LEB128 encoded length of the following null bitmap |
null bitmap | variable | RLE encoded bitmap |
data | variable | encoded non-null data values |
checksum | 4 | optional CRC-32 checksum of the value count, bitmap length, null bitmap, and data |
校验码可以被选择性的写或者更改,当对 header, data, 或者 footer使用checksums时,CFileFooterPB message 会使用incompatible_features bitset 中的一个"checksum"位来让reader知道校验码的存在。
如果在读数据前发现校验码的存在,那么reader可以选择性的使用校验码来验证数据的正确性.
block数据在存储之前被编码。如果使用了压缩算法,则首先对块数据进行编码,然后再进行压缩。
数据块大小限制为--cfile-default-block-size
字节,如果超出范围CFile添加将增加新块。
最简单的编码方式,以原本形式存放数值.
固定宽度(整数)类型的纯文本编码由小字节序值组成,后包含两个小字节序 uint32
s 的trailer来表明值的数量和其在block中的序数位置。
BINARY或STRING(可变宽度)列的纯文本编码方式如下:
ordinal position | little-endian uint32 |
---|---|
num values | little-endian uint32 |
offsets position | little-endian uint32 |
values | sequential values with no padding |
offsets | group-varint frame-of-reference encoded value offsets |
字典编码可用于BINARY或STRING列。CFile中的所有字典编码块共有一个相同的字典。如果字典变满(不太理解这句话),CFile中的后续块将切换为纯文本编码。字典被存储为纯文本编码的二进制块,并且编码后的码子被存储为 bitshuffle encoded uint32
s
目前用于BINARY
和STRING
数据块。这或多或少是基于LevelDB数据块使用的编码格式。
Starts with a header of four Group Varint encoded uint32
s:(这部分没有合适的翻译,直接使用原文更准确)
field |
---|
number of elements |
ordinal position |
restart interval |
unused |
Followed by prefix-compressed values. Each value is stored relative to the value preceding it using the following format:
field | type |
---|---|
shared_bytes |
varint32 |
unshared_bytes |
varint32 |
delta |
char[unshared_bytes] |
Periodically there will be a "restart point" which is necessary for faster binary searching. At a "restart point", shared_bytes
is 0 but otherwise the encoding is the same.
At the end of the block is a trailer with the offsets of the restart points:
field | type |
---|---|
restart_points |
uint32[num_restarts] |
num_restarts |
uint32 |
The restart points are offsets relative to the start of the block, including the header.
可以作用于整数和bool类型,其具有简单的格式:以小段序列unint32存放值的数量和其序号偏移量,接着是Run-length 编码的数据.如果数据不适用于Run-length 编码,将自动回退到bit-packed (literal) 编码.
适用于整数类型,Bitshuffle编码的块自动进行LZ4压缩,因此不建议进行额外的压缩.
用于内部的UINT32
blocks,因为kudu的列数据不支持无符号整数,所以这种编码方式不适用于列数据.
Starts with a header of four group-varint encoded uint32
s:
field |
---|
number of elements |
minimum element |
ordinal position |
unused |
ordinal position是指当前file中第一个item的ordinal position,比如,如果当前file中第一个data block的ordinal position为0,如果这个data block又包含400个值,那么第二个data block的ordinal position就是400.
Followed by the actual data, each set of 4 integers using group-varint. The last group is padded with 0s. Each integer is relative to the min element in the header.(不会很好的翻译,直接贴原文)
CFile可以选择性的包含 positional (ordinal) index (序数索引)和 value index(值索引),Positional indexes用于解决像"查找这个CFile中包含第N项的data block"这样的询问,而Value indexes用于处理像"查找这个Cfile中包含 123 的data block".只有在数据有序时CFile中才会有 Value indexes(比如包含主键).
序数索引和值索引被组织成一个以index blocks(索引块)构成的B-Tree,当写入data block时,entries会被加到叶子节点的后边,当叶子节点的大小达到上限时,它将被添加到树上方的另一个索引块中,并启动一个新叶子,如果中间索引块填满,它将创建一个新的中间块并涌入到更高层的块。
例如:
[Int 0]
-----------------------------
| |
[Int 1] [Int 2]
----------------- --------------
| | | | |
[Leaf 0] ... [Leaf N] [Leaf N+1] [Leaf N+2]
在这个例子中,我们写入N个叶子节点块,他们已经填满了编号为Int 1的中间节点,此时writer会闯进一个Int 0节点来指向int 1,.其他两个叶子块(N + 1和N + 2)将被写入新的中间节点(Int 2),当file写入完成后,INT2 也会涌向INT 0(这句翻译可能有问题)。
请注意,此策略不会产生完全平衡的B树,而是在每个level的所有节点上产生100%的“填充因子”,除了写入的最后一个节点。
对于两种类型的索引,索引块的编码方式类似:
...
key: vint64 for positional, otherwise varint-length-prefixed string
offset: vint64
block size: vint32
(fixed32)
(fixed32)
...
These offsets are relative to the start of the block.
A IndexBlockTrailerPB protobuf
使用后序遍历来写入索引块,并且索引块可以与数据块交叉(??)
trailer protobuf 包含了一个field来指明一个block是B-Tree的一个叶子节点还是中间节点,reader可以以此判断指针是指向另一个索引块还是数据块.
Every DeltaFile in a DiskRowSet is written to a CFile; in fact, a DeltaFile is just a wrapper around CFile which specializes it for REDO and UNDO delta data. The deltas associated with a row update are grouped into a RowChangeList and written to as a binary values to the underlying CFile. Each value is prefixed with a DeltaKey, which consists of the ordinal row index (within the DiskRowSet), and the timestamp. The CFile includes a value index so that the delta belonging to a specific row can be located efficiently.
BloomFile is a wrapper around CFile which stores a bloomfilter datastructure.