PostgreSQL的insert解析

其insert由函数heapam_tuple_insert完成。

1、首先需要从slot中取出tuple值,HeapTupleTableSlot.tuple

2、从relation中得到该记录即将插入表的OID:relation->rd_id,然后slot->tts_tableOid和tuple->t_tableOid更新为该OID

3、调用heap_insert将tuple插入heap 页中,这个过程中产生WAL日志并写入WAL BUFFER中:

  1)生成事务ID:xid

  2)调用函数heap_prepare_insert:设置tup->t_data的t_infomask和t_infomask2;tup->t_data->t_choice.t_heap.t_xmin为xid;

(tup->t_data)->t_choice.t_heap.t_field3.t_cid为入参cid

(tup->t_data)->t_choice.t_heap.t_xmax为0

即insert的xmin为事务ID,xmax为0

  3)调用RelationGetBufferForTuple,从fsm中找到一个满足空间大小的数据页,并将该数据页加载到内存,返回内存块的块号Buffer

  4)CheckForSerializableConflictIn隔离级别处理

  5)调用RelationPutHeapTuple从页面中最后一个free slot并将记录插入。如何找free slot,PageAddItemExtended完成。

  6)如果该页此时pd_flags & PD_ALL_VISIBLE,即该页内所有记录都可见,但此时插入了一个记录,需要清除该标签。

  7)标记该buffer为脏页,以供后续checkpoint刷脏

  8)生成WAL日志,并将WAL日志写入WAL BUFFER

  9)将此时lsn写入页头pd_lsn

4、更新tuple->t_self为slot->tts_tid,即记录在页内位置。

如何在页内找一个free slot由函数PageAddItemExtended完成。

1、计算出pd_linp数组的最大值后新增一个后的个数:

limit=[pg_lower-sizeof(PageHeader)]/Sizeof(ItemIdData)+1

2、如果页头中pd_flags & PD_HAS_FREE_LINES为TRUE,即该数组中有free slot,那么首先从这个数组中找一个可用的ItemIdData,从pd_linp[0]开始一个一个的进行判断,一旦(itemId)->lp_flags == LP_UNUSED && (itemId)->lp_len != 0,表明这个slot可用,那么取这个offsetNumber返回

3、如果该页中没有free slot,则在pd_linp[limit-1]当前最后一个ItemIdData后面添加一个ItemIdData,设置该ItemIdData的值将其lp_off指向pd_upper位置并调整其lp_len=tuple->t_len,lp_flags = LP_NORMAL

 

发布了289 篇原创文章 · 获赞 85 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/yanzongshuai/article/details/104486903