前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GreenPlum AOCO列存读IO原理

GreenPlum AOCO列存读IO原理

作者头像
yzsDBA
发布2022-12-27 13:54:21
4110
发布2022-12-27 13:54:21
举报
文章被收录于专栏:PostgreSQL研究与原理解析

GreenPlum AOCO列存读IO原理

GP自带AOCO列存,它的IO和heap表的IO是分开的。Heap表的脏数据由checkpoint或后台write进程刷写,也就是FlushBuffer函数调用smgrwrite。由magnetic disk storage manager管理IO模块。但是AOCO列存则是由本身进行管理,由函数BufferedAppendWrite完成脏页的刷写。同理,AOCO列存的读也是由本身管理,由函数BufferedReadIo完成加载到内存。本文重点介绍AOCO是如何加载数据页的

1、相关结构体

我们先看下列存扫描涉及的相关结构体及其之间的关系,如下图所示:

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中的读偏移

2、blockRead中memory的管理

分为两种情况,一种是请求的block页全部在largeReadMemory中,另一种是被截断了,正好在largeReadMemory末尾位置仍旧不是完整的。

2.1 请求的block全部在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内存的某个位置

2.2 请求的block没全部在largeReadMemory

这种情况发生在重新获取包括firstRowNum或者整个block data的场景中:

1)当请求的大小超出largeReadMemory的时候,也就是需要的数据并没有全部加载进来,此时为了保证一个block连续,将头部内容拷贝到beoreBufferMemory中。当然需要先计算处理剩余多少,从beoreBufferMemory尾部开始放以便和后续的同一个block的内容连续。

2)此时在返回的页头是beoreBufferMemory中的指针,也就是数据是从beforeBufferMemory中开始的。

到此大概就了解了AOCO是如何加载数据的了,希望给大家带来一些启发。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 yanzongshuaiDBA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、相关结构体
  • 2、blockRead中memory的管理
    • 2.1 请求的block全部在largeReadMemory
      • 2.2 请求的block没全部在largeReadMemory
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档