PostgreSQL源码学习插入数据#2

database

本节介绍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

相关数据结构

void

heap_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

回到顶部