GreenPlum AOCO列存读IO原理
GP自带AOCO列存,它的IO和heap表的IO是分开的。Heap表的脏数据由checkpoint或后台write进程刷写,也就是FlushBuffer函数调用smgrwrite。由magnetic disk storage manager管理IO模块。但是AOCO列存则是由本身进行管理,由函数BufferedAppendWrite完成脏页的刷写。同理,AOCO列存的读也是由本身管理,由函数BufferedReadIo完成加载到内存。本文重点介绍AOCO是如何加载数据页的。
我们先看下列存扫描涉及的相关结构体及其之间的关系,如下图所示:
1)函数scan_begin->aocs_beginscan初始化AOCSScanDesc结构,该结构与IO相关的主要是columnScanInfo结构,包含proj_atts即扫描投影列的列号数组;ds数组大小是列的个数,也就是每个投影列为一个成员ds[i],即DatumStreamRead
2)DatumStreamRead描述每个AO列的读相关信息。包含:
(1)maxAoBlockSize表示最大AO块大小,该值大小来自pg_attribute_encoding系统表的option指定的大小。默认是32KB。
(2)buffer_beginp:指向一个block中的value头位置,将其值赋予blockRead的buffer_beginp。指向largeReadMemory某个位置。
acc->buffer_beginp=AppendOnlyStorageRead_GetBuffer(&acc->ao_read)
函数datumstreamread_block_get_ready中将其值给blockRead的buffer_beginp进行管理。
可以看出largeReadLen其实就是从磁盘上一次读入buffer的大小。
3)DatumStreamBlockRead:管理一个block中tuple的读取
4)AppendOnlyStorageRead:管理IO
(1)maxBufferLen:一个block大小,请求读的最大大小
(2)largeReadLen:2*maxBufferLen大小
(3)storageAttributes:每一列的属性,比如是否压缩、压缩算法、压缩级别等
(4)bufferedRead:这个是真正管理buffer的
5)BufferedRead:管理IO的buffer,包括
(1)maxBufferLen:1个block大小,请求读的最大大小
(2)maxLargeReadLen:2个block大小,IO的最大请求
(3)memory:总的IO buffer,大小是memoryLen,其实是上述2个值的和,即3个block大小
(4)beforeBufferMemory:memory的前一部分,用于使得block连续
(5)largeReadMemory:IO的内容都是加载到这里的
(6)largeReadPosition:seg文件的已读大小
(7)bufferOffset和bufferLen:bufferLen本次请求读的大小,bufferOffset为在largeReadMemory中的读偏移
分为两种情况,一种是请求的block页全部在largeReadMemory中,另一种是被截断了,正好在largeReadMemory末尾位置仍旧不是完整的。
1)BufferedReadIo一次从磁盘上读入2个页大小的内容到BufferedRead.largeReadMemory中
2)aocs_getnext函数需要从该buffer读取一个tuple:
(1)先读取最小页头(包含crc,但不包含firstRowNum),大小是16字节
(2)AppendOnlyStorageFormat_GetHeaderInfo函数获取页头信息,AppendOnlyStorageRead.storageAttributes.checksum标记是否开启了checksum
(3)若由firstRowNum,则页头大小需要申请24字节
(4)BufferReadGrowBuffer函数重新读取largeMemoryBuffer,将需要的页头大小扩展到24字节,并从中解析出数据部分大小。storageRead->current.overallBlockLen=页头+数据部分大小
(5)检查checksum
(6)返回value部分,每个value都由value头+数据组成,将这个值作为slot的value指针返回。
(7)实际上TupleSlot的datum值指向的是largeReadMemory内存的某个位置
这种情况发生在重新获取包括firstRowNum或者整个block data的场景中:
1)当请求的大小超出largeReadMemory的时候,也就是需要的数据并没有全部加载进来,此时为了保证一个block连续,将头部内容拷贝到beoreBufferMemory中。当然需要先计算处理剩余多少,从beoreBufferMemory尾部开始放以便和后续的同一个block的内容连续。
2)此时在返回的页头是beoreBufferMemory中的指针,也就是数据是从beforeBufferMemory中开始的。
到此大概就了解了AOCO是如何加载数据的了,希望给大家带来一些启发。
本文分享自 yanzongshuaiDBA 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!