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变量查看元组删除情况,即是否成功删除