heap_update函数
参数:(Relation relation, Relation parentRelation, ItemPointer otid, HeapTuple newtup, CommandId cid, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, bool allow_update_self)
relation指的是需要更新元组的数据表,parentRelation是父数据表(???),otid指向待更新的元组,newtup是新的元组,cid更新的命令id,crosscheck快照,wait表示是否等待冲突的更新提交或者失败。
原作者指出最好使用simple_heap_update函数进行元组更新
1.调用RelationGetIndexAttrBitmap函数获取parentRelation或者 relation数据表的rd_indexattr和rd_idattr参数,这些参数储存着数据表的索引信息(哪几列有索引)。
2.根据数据表relation以及itempoint,获取旧的元组
3.调用HeapTupleSatisfiesUpdate函数,判断待更新元组的状态,相比于HeapTupleSatisfiesNow函数只判断元组是否有效,HeapTupleSatisfiesUpdate函数可以返回更多细节信息。
4.设置新元组的一系列信息,然后判断是否需要toast操作(只会在当前数据表已经存在toast表或者插入的新元组过长超过了存放的阈值)获得插入元组的页面号。
5.备份旧元组,因为内存中的旧元组属性可能会被修改,导致引起混淆。如果新元组在新page,需要设置新page的相关属性
开始更新操作
6.调用RelationPutHeapTuple函数,将元组和linepoint插入到对应页面的指定位置。
7.清理旧元组的infomask,并且设置元组的Xmax为当前事务,Cmax为当前命令,旧元组的t_ctid指向新元组。
8.设置buffer为脏块
9.写入日志
10.将元组在缓存中,设置为无效缓存,释放缓存。
11.更新统计信息。
12.return TM_OK.
简单的讲
1.函数花了很大的功夫先判断旧元组的状态,是否可以进行更新操作。
2.然后又去判断新元组是否可以存放在同一页以及是否需要toast功能
3.调用RelationPutHeapTuple函数,真正的将新元组插入到页面中
4.写日志
simple_heap_update函数
当不希望同时更新目标元组时,此函数可用于更新元组
参数:(Relation relation, ItemPointer otid, HeapTuple tup)
调用simple_heap_update函数,只需要提供三个参数,然后也是借用heap_update函数完成功能的实现,但是其他参数不用自己传入。
1.判断要修改的元组是否是“内置功能”,内置功能的元组不能修改。
2.调用heap_update函数,
heap_update(relation, NULL, otid, tup, GetCurrentCommandId(true),
InvalidSnapshot, true /* wait for commit */, &tmfd);
3.根据heap_update函数返回的TM_Result类型,获取更新操作的完成情况。
当前有效的tuple是指
((Xmin == my-transaction && 元组由当前事务插入 and
* Cmin < my-command && 插入的命令号小于当前的命令号 and
* (Xmax is null || 元组没有被删除 or
* (Xmax == my-transaction && 元组由当前事务删除 and
* Cmax >= my-command))) 删除事务的命令号大于当前的命令号
* || or or
* (Xmin is committed && 元组被其他已经提交的事务插入, and
* (Xmax is null || 元组没有被删除or
* (Xmax == my-transaction && 元组由当前事务删除 and
* Cmax >= my-command) || 删除的命令号大于当前命令号, or
* (Xmax != my-transaction && 删除元组不是当前事务 and
* Xmax is not committed)))) 删除元组的事务还没有提交
HeapTupleSatisfiesNow函数,根据上述规则判断当时时刻,tuple是否有效。
heap_lock_tuple函数
参数:(Relation relation, HeapTuple tuple, Buffer* buffer, CommandId cid, LockTupleMode mode, bool nowait, TM_FailureData *tmfd, bool allow_lock_self)
函数结果:
HeapTupleMayBeUpdated: lock was successfully acquired
HeapTupleSelfUpdated: lock failed because tuple updated by self
HeapTupleUpdated: lock failed because tuple updated by other xact
作用:对元组上共享锁或者排他锁。
对元组加锁之前,必须要获取buffer pin
heap_inplace_update函数
参数:(Relation relation, HeapTuple tuple)
tuple里面的t_self指向待更新的元组,而tuple自己里面存的是新元组
作用:原地更新元组,但是违反了MVCC和事务安全性,所以使用场景非常少。由于不能修改tuple的大小,我们只修改tuple的数据部分,不修改null bitmap和其他元组头部数据。
1.检查tuple是否合法以及原tuple和新tuple的大小是否相等,不合法或者不相等直接返回.
2.因为占用内存的空间相同,直接调用memcpy_s函数,将新元组这一块内存块拷贝过来,覆盖原来旧元组的位置
3.写日志。