华为openGauss数据库源码解析——堆表操作(2)

heapgettup_pagemode函数

作用:通过page-at-a-time模式,获取下一条元组,与heapgettup函数的区别是我们只在rs_vistuples数组里面进行扫描而不是扫描整个页面里面的元组。扫描逻辑与heapgettup基本相同。

rs_vistuples数组储存的是当前页面有效line_point的偏移量。

参数:(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)

1.首先根据ScanDirection进行分类Forword、Backward、no movement

Forword:

(2).如果scan没有初始化,就先对其进行初始化,设置line_index = 0,表示rs_vistuples数组中的第一个元组

已经初始化的scan,设置line_index = 当前扫描的位置加一。

(3).获取当前数组未扫描的数量lines_left

Backward:

(2).获取当前扫描的页码

(3).如果scan没有初始化,line_index就是当前数组中最大的那个索引,否则line_index = 当前扫描的位置减一。获取当前数组未扫描的数量lines_left = line_index+1.

No movement(重新获取记录):

(2).重新获取当前扫描的元组,获取当前的line_index

(3).返回

2.获取line_index所对应的偏移量,然后根据偏移量获取行指针line_point,然后再根据line_point获取对应元组,如果元组是压缩的,此时进行解压操作。

3.判断当前元组是否符合要求(是否有效),有效就返回

4.否则寻找下一个元组,如果rs_vistuples数组扫描完了,就扫描下一个page。直到找到有效的元组或者页全部扫描完。


heapgettup_pagemode。在第一次加载下一个页面时,加上页面共享锁,完成对页面上所有元组的可见性判断,然后将可见的元组位置保存起来,释放页面共享锁。后面每次直接从保存的可见性元组列表中返回下一条可见的元组,无须再对页面加共享,使用快照的查询,默认都使用该批量模式,因为元组的可见性在同一个快照中不会再发生变化。

heapgetpage。除了第一次加载下一个页面时需要批量校验元组可见性之外,在后面每一次返回该页面下一条元组时,都要重新对页面加共享锁,判断下一条元组的可见性。该模式的查询性能较批量模式要稍低,适用于对系统表的顺序扫描(系统表的可见性不参照查询快照,而是以实时的事务提交状态为准)。


heap_markpos函数

作用:标志当前扫描的元组,将当前扫描的元组信息存储在scan->rs_mctid和scan->rs_mindex中

heap_restrpos函数

作用:扫描回到之前标记的位置,同时返回标志位置的元组

1.判断标记的位置是否有效

2.设置当前扫描的位置为之前标记的位置(scan->rs_mctid和scan->rs_mindex)

3.通过heapgettup函数和heapgettup_pagemode函数,传入NoMovementScanDirection,获取当前位置的元组。

heapgetpage函数

作用:获取指定页面

1.释放当前扫描缓存,设置当前扫描的缓存为空

2.调用ReadBufferExtended函数获取页面信息,并且赋值给scan->rs_base.rs_cbuf(即当前扫描的缓存)

3.扫描这个页面,根据line_point将元组一个一个读取出来,并且设置元组的属性,然后将有效的元组存入rs_vistuples数组,方便page-at-a-time模式扫描

4.设置rs_ntuples即rs_vistuples数组中的数目。

heap_insert函数

作用:将元组插入到堆表中,并返回插入元组的Oid

参数(Relation relation, HeapTuple tup, CommandId cid, int options, BulkInsertState bistate)

1.首先调用heap_prepare_insert函数,对待插入元组的设置其元组头文件(HeapTupleHeader)的参数,比如说infomask, infomask2, t_xmin, cid , xmax, t_tableOid, t_bucketId

2.调用RelationGetBufferForTuple函数,获取有足够空间大小的page号,并且该page对应的buffer状态为pinned和并持有独占锁。

3.调用RelationPutHeapTuple函数,将元组放入到上面找到的page的指定位置中

4.设置该缓存块为脏块

5.记录日志信息

6.更新统计信息,表结构中插入元组数加一

7.返回插入元组的Oid。

RelationGetBufferForTuple函数

作用:为待插入的元组分配插入的page

1.根据fillfactor选项计算所需的额外自由空间,然后加上元组自身的大小,计算出插入元组需要的总空间。

2.首先获取当时数据表插入的目标page。

3.判断这个page是否可以放得下这个元组,放得下函数就结束返回当前页面

4.否则通过FSM获取下一个备选page,直到可以放下的page,或者不存在满足条件的page

5.如果不存在满足条件的page,那么拓展表(即为表建立一个新的page),对page进行初始化操作

6返回page号

RelationPutHeapTuple函数

作用:将元组和linepoint放在指定的页码上,并且修改页面的pd_lower和pd_upper

1.设置元组的t_xmin属性,并且调用PageAddItem函数将元组插入到page中,并返回元组在page中的偏移量

2.根据插入元组的page号和偏移量,更新元组的t_self使它指向自己存储的物理空间

PageAddItem函数

作用:将元组项item添加到页面page当中并返回item在page中的偏移量

1.先判断页面是否有误

2.获取页面下一个空闲的位置

3.根据传入的参数是否设置写入的偏移量和overwrite选项,进行分类讨论。最终确定需要插入的位置即页面偏移量

4.根据元组插入的位置是否在free space中,如果在就修改pd_lower的值,否则不修改

5.修改pd_upper的值

6.设置linepoint(itemID)的值

7.通过 memcpy_s函数,将数据放入到指定的位置

8.返回插入元组的偏移量。

memcpy_s函数

四个参数(void* const _Destination, rsize_t const _DestinationSize,void const* const _Source,rsize_t const _SourceSize)

rsize指的是unsigned long long ,void*指的是还没有确定类型的指针变量

_Destination指的是新的缓冲区

_DestinationSize指的是目标缓冲区的大小

_Source指的是要复制的缓冲区

_SourceSize指的是字符数

作用:复制_Source的_SourceSize字节到_Destination,通过调用memcpy(_Destination, _Source, _SourceSize)实现

heap_multi_insert函数

作用:批量插入多个元组,并且返回插入元组的数量

与循环调用heap_insert()相比,速度要快不少,因为对一个page的插入可以只写入一个WAL记录,而且也只需要对这个page,加锁、释放锁一次。

参数:(Relation relation, Relation parent, HeapTuple *tuples, int ntuples, CommandId cid, int options, BulkInsertState bistate, HeapMultiInsertExtraArgs *args)

1.循环调用heap_prepare_insert函数,对待插入元组的设置其元组头文件(HeapTupleHeader)的参数,比如说infomask, infomask2, t_xmin, cid , xmax, t_tableOid, t_bucketId

2.根据是否压缩、页面是否复制(is_compressed、tmpPageReplication),采用不同方法获取能够插入下一条元组的buffer,然后通过buffer找到page。

3.调用RelationPutHeapTuple函数,将元组放入到指定位置。

4.将元组插入到mlog-table(???)

5.在当前页循环获取剩余空闲空间大小是否可以继续插入一条元组,如果可以,调用RelationPutHeapTuple函数,将元组放入到指定位置。设置当前buffer为脏块

6.写入日志,释放缓存锁

7.寻找下一个buffer,直到将所有元组插入完毕

8.将所有插入元组的t_self指向当前存储的位置。

9.更新统计信息,然后返回插入元组的数量

heap_delete函数

作用:删除ItemPointer指向的一条元组

参数:(Relation relation, ItemPointer tid, CommandId cid, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, bool allow_delete_self)

1.首先根据ItemPointer获取待删除的元组所在的页。

2.获取元组的line_point,检查tid是否有效,获取待删除的元组信息

3.调用HeapTupleSatisfiesUpdate函数

simple_heap_delete函数

作用:删除line_point指向的一条元组

参数:(Relation relation, ItemPointer tid, int options)

1.调用tableam_tuple_delete函数获取TM_Result变量,(疑问,tableam_tuple_delete函数最后又会调用回heap_delete函数,导致前后两者没有区别)

2.根据TM_Result变量查看元组删除情况,即是否成功删除

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容