GreenPlum AOCO列存如何将数据刷写磁盘
AOCO列存表每个字段一个文件,前面我们介绍了列存表如何加载数据页,本文我们重点介绍AOCO表如何进行刷写。AOCO表进行insert、update、delete会产生脏数据,和heap表的异步脏页刷写不同,AOCO表的数据时同步刷写的。也就是在AOCO表向datum_buffer放入数据后,立即将其从datum_buffer写入largeWriteMemory,最后将数据从largeWriteMemory写入磁盘。
Delete不会导致AOCO列存表段文件的刷写,update本质上是delete + insert操作,所以我们这里仅关注insert。
1、AOCO写相关结构体
我们先看下insert相关的结构体及其之间关系。如下图所示:
1)ExecInsert->aocs_insert对AOCO表进行插入,入参有AOCSInsertDesc(为AOCO列存插入服务)和TupleTableSlot(存有需要插入的tuple)。我们重点关注AOCSInsertDesc结构体
2)Relation aoi_rel存有表的相关元数据,包括pg_class系统表等。
3)char *compType为压缩算法
4)compLevel为压缩级别。和3)的值一起来自pg_appendonly系统表。
5)使用时使用pg_attribute_encoding系统表,初始化到DatumStreamWrite中
6)最主要的就是DatumStreamWrite结构,ds数组描述所有字段。
下面我们看下DatumStreamWrite结构:
1)maxAoBlockSize为页大小,来自pg_attribute_encoding系统表的options中。
2)maxAoHeaderSize:列存页的header大小,分为Original和Dense*类型。Original类型:AoHeader_RegularSize(8)+ crc(8) + firstRowNum(8);Dense*:AoHeader_LongSize(16) + crc(8) + firstRowNum(8)
create_datumstreamwrite函数中:
3)AppendOnlyStorageAttributes ao_attr:存储层的属性值,包括压缩相关信息等,由函数create_datumstreamwrite->init_datumstream_info进行初始化,这些值就来自pg_attribute_encoding了。
4)AppendOnlyStroageWrite ao_write:将blockWrite中的数据写入ao_write中,此时需要初始化页头,然后将其刷些磁盘
5)DatumStreamBlockWrite blockWrite:临时存储页数据,不包括页头。
这里重点介绍ao_write和blockWrite。先看下blockWrite:
1)maxDataBlockSize:数据部分最大大小。
2)datum_buffer:用于存储数据,大小为datum_buffer_size。
3)datump:指向datum_buffer中的空闲空间
ao_write为真正刷写数据的缓冲:
1)maxBufferLen:来自DatumStreamWrite的maxAoBlockSize,一页大小,默认32KB
2)largeWriteLen:大小为2*maxBufferLen
3)regularHeaderlen:固定页头大小:AoHeader_RegularSize(8字节) + checksum(8字节)
4)currentCompleteHeaderLen:完整页头大小:
AppendOnlyStorageWrite_CompleteHeaderLen函数获取该页头完整大小
5)BufferedAppend bufferedAppend:保存写缓冲的数据。
6)currentBuffer:指向bufferedAppend.largeWriteMemory的某个位置,表示datum_buffer拷贝写入的位置。
BufferedAppend bufferedAppend:写缓冲
1)maxLargeWriteLen:ao_write的largeWriteLen值,也就是2个页大小。即largeWriteMemory大小。
2)memory:数据缓冲,3页大小
3)largeWriteMemory:memory起始位置开始2页大小,写入的起始位置。
4)afterBufferMemory:紧接着memory+2页大小开始1页大小。当largeWriteMemory空闲空间放不下时,放入这里。largeWriteMemory内容刷写后将这块数据拷贝到largeWriteMemory,使之连续。
2、AOCO列存insert操作
Insert操作的入口函数是aocs_insert:aocs_insert->aocs_insert_values:其主要流程如下图所示:
可以了解:会对每一列都分别进行处理。首先将datum中的内容拷贝到largeWriteMemory,若放不下,则先刷写掉largeWriteMemory内容,然后再进行拷贝。若仍旧空间不够,则触发大字段存储。大字段存储调用AppendOnlyStorageWrite_Content函数进行处理。
aocs_insert_values函数中,仅当largeWriteMemory满时才将其中内容刷写到磁盘上,若剩余的一点点,不满呢?什么时会刷写?答案是在函数aocs_insert_finish中进行刷写。调用时机ExecEndPlan->...->aocs_insert_finish: