PostgreSQL源码学习插入数据#2
本节介绍heap_insert函数的代码流程
本节前置
toast机制:https://www.postgresql.org/docs/12/storage-toast.html
可见性映射表:https://www.postgresql.org/docs/12/storage-vm.html
事务一致性检查:https://www.postgresql.org/docs/12/transaction-iso.html
WAL机制:https://www.postgresql.org/docs/12/wal-intro.html
相关数据结构
voidheap_insert(Relation relation, HeapTuple tup, CommandId cid,
int options, BulkInsertState bistate);
heap_insert函数
//src/backend/access/heap/heapam.c/* 填充tuple header(xid,cid和一堆标志位等)。
若触发toast机制的话,tup为原始数据,heaptup为接下来应该插入的数据 */
heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
/* 返回tuple要插入的目标page的buffer,此buffer会上排他锁并且pin在共享内存中,
并且若page设置了全局可见,则会同时将visibility map page给pin在共享内存中,之后要对其进行修改*/
buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
InvalidBuffer, options, bistate,
&vmbuffer, NULL);
/* 检查一致性冲突 */
CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
/* 从这里开始直到修改被记录,不允许EREPORT(ERROR) */
START_CRIT_SECTION();
/* 插入数据,此函数的详细内容上节讲过 */
RelationPutHeapTuple(relation, buffer, heaptup,
(options & HEAP_INSERT_SPECULATIVE) != 0);
/* 清除page的全局可见标志,并且清除对应块的visibility map的VISIBILITYMAP_VALID_BITS标志
(清除VIALID_BITS意味着ALL_VISIBLE和ALL_FROZEN都被清除)*/
if (PageIsAllVisible(BufferGetPage(buffer)))
{
all_visible_cleared = true;
PageClearAllVisible(BufferGetPage(buffer));
visibilitymap_clear(relation,
ItemPointerGetBlockNumber(&(heaptup->t_self)),
vmbuffer, VISIBILITYMAP_VALID_BITS);
}
/* 标记此buffer为脏块,需要写磁盘 */
MarkBufferDirty(buffer);
/* XLOG相关流程 */
if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
{
/* 若是系统表元组,记录一条XLOG_HEAP2_NEW_CID记录 */
if (RelationIsAccessibleInLogicalDecoding(relation))
log_heap_new_cid(relation, heaptup);
/* 如果这是page中的第一条数据,那么给XlogInsert的flag设置XLOG_HEAP_INIT_PAGE标志位,
这样在redo时就能知道这里可以初始化一个page,设置了此标志那么同时buffer也会被init,
所以为XLogRegisterBuffer的flag设置REGBUF_WILL_INIT标志位 */
if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
{
info |= XLOG_HEAP_INIT_PAGE;
bufflags |= REGBUF_WILL_INIT;
}
/* 为xl_heap_insert赋值(略),添加一条xlog记录 */
XLogBeginInsert();
XLogRegisterData((char *) &xlrec, SizeOfHeapInsert);
/* 为xl_heap_header赋值(略),添加一条buf的xlog记录 */
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
XLogRegisterBufData(0,
(char *) heaptup->t_data + SizeofHeapTupleHeader,
heaptup->t_len - SizeofHeapTupleHeader);
/* 设定此条xlog的重要程度 */
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
/* 插入xlog记录 */
recptr = XLogInsert(RM_HEAP_ID, info);
/* 设置page的LSN */
PageSetLSN(page, recptr);
}
/* 至此算是数据操作和日志都已完成,可以使用ERROR了 */
END_CRIT_SECTION();
/* 解锁buffer并释放buffer和visibility map buffer的pin */
UnlockReleaseBuffer(buffer);
if (vmbuffer != InvalidBuffer)
ReleaseBuffer(vmbuffer);
/* 对cache中的无效信息(tuple)进行注册(Cache同步机制) */
CacheInvalidateHeapTuple(relation, heaptup, NULL);
/* 更新统计信息 */
pgstat_count_heap_insert(relation, 1);
/* 若之前在heap_prepare_insert函数中走了toast流程,需要修改一下t_self并释放heaptup */
if (heaptup != tup)
{
tup->t_self = heaptup->t_self;
heap_freetuple(heaptup);
}
以上是 PostgreSQL源码学习插入数据#2 的全部内容, 来源链接: utcz.com/z/533132.html