这篇文章主要讲解了“postgresql中heap_insert函数有什么作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Postgresql中heap_
这篇文章主要讲解了“postgresql中heap_insert函数有什么作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Postgresql中heap_insert函数有什么作用”吧!
宏定义
包括Pointer/Page/XLOG_HEAP_INSERT/XLogRecPtr等
typedef char* Pointer;//指针
typedef Pointer Page;//Page
#define XLOG_HEAP_INSERT 0x00
typedef uint64 XLogRecPtr;
#define PageGetLSN(page) \
PageXLogRecPtrGet(((PageHeader) (page))->pd_lsn)
#define PageSetLSN(page, lsn) \
PageXLogRecPtrSet(((PageHeader) (page))->pd_lsn, lsn)
xl_heap_insert
插入时需要获知的信息结构
#define XLH_INSERT_ALL_VISIBLE_CLEARED (1<<0)
#define XLH_INSERT_LAST_IN_MULTI (1<<1)
#define XLH_INSERT_IS_SPECULATIVE (1<<2)
#define XLH_INSERT_CONTaiNS_NEW_TUPLE (1<<3)
//这是在插入时需要获知的信息
typedef struct xl_heap_insert
{
//元组在page中的偏移
OffsetNumber offnum;
uint8 flags; //标记位
//xl_heap_header & TUPLE DATA在备份块0中
} xl_heap_insert;
//xl_heap_insert大小
#define SizeOfHeapinsert (offsetof(xl_heap_insert, flags) + sizeof(uint8))
xl_heap_header
PG不会在WAL中存储插入/更新的元组的全部固定部分(HeapTupleHeaderData)
xl_heap_header是必须存储的结构.
typedef struct xl_heap_header
{
uint16 t_infomask2;//t_infomask2标记
uint16 t_infomask;//t_infomask标记
uint8 t_hoff;//t_hoff
} xl_heap_header;
//HeapHeader的大小
#define SizeOfHeapHeader (offsetof(xl_heap_header, t_hoff) + sizeof(uint8))
heap_insert的主要逻辑是插入元组到堆中,其中存在对WAL(XLog)进行处理的部分.
Oid
heap_insert(Relation relation, HeapTuple tup, CommandId cid,
int options, BulkInsertState bistate)
{
TransactionId xid = GetCurrentTransactionId();//事务id
HeapTuple heaptup;//Heap Tuple数据,亦即数据行
Buffer buffer;//数据缓存块
Buffer vmbuffer = InvalidBuffer;//vm缓冲块
bool all_visible_cleared = false;//标记
//插入前准备工作,比如设置t_infomask标记等
heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
//获取相应的buffer,详见上面的子函数解析
buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
InvalidBuffer, options, bistate,
&vmbuffer, NULL);
//检查序列化是否冲突
CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
//开始,变量+1
START_CRIT_SECTION();
//插入数据(详见上一节对该函数的解析)
RelationPutHeapTuple(relation, buffer, heaptup,
(options & HEAP_INSERT_SPECULATIVE) != 0);
//如Page is All Visible
if (PageIsAllVisible(BufferGetPage(buffer)))
{
//复位
all_visible_cleared = true;
PageClearAllVisible(BufferGetPage(buffer));
visibilitymap_clear(relation,
ItemPointerGetBlockNumber(&(heaptup->t_self)),
vmbuffer, VISIBILITYMAP_VALID_BITS);
}
//设置缓冲块为脏块
MarkBufferDirty(buffer);
//记录日志
if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
{
xl_heap_insert xlrec;
xl_heap_header xlhdr;
XLogRecPtr recptr;//uint64
Page page = BufferGetPage(buffer);//获取相应的Page
uint8 info = XLOG_HEAP_INSERT;//XLOG_HEAP_INSERT -> 0x00
int bufflags = 0;
if (RelationIsAccessibleInLogicalDecoding(relation))
log_heap_new_cid(relation, heaptup);
if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
{
info |= XLOG_HEAP_INIT_PAGE;
bufflags |= REGBUF_WILL_INIT;
}
//Item在页面中的偏移
xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
xlrec.flags = 0;//标记
if (all_visible_cleared)
xlrec.flags |= XLH_INSERT_ALL_VISIBLE_CLEARED;
if (options & HEAP_INSERT_SPECULATIVE)
xlrec.flags |= XLH_INSERT_IS_SPECULATIVE;
Assert(ItemPointerGetBlockNumber(&heaptup->t_self) == BufferGetBlockNumber(buffer));
if (RelationIsLogicallyLogged(relation))
{
xlrec.flags |= XLH_INSERT_CONTAINS_NEW_TUPLE;
bufflags |= REGBUF_KEEP_DATA;
}
XLogBeginInsert();//开始WAL插入
XLogReGISterData((char *) &xlrec, SizeOfHeapInsert);//注册数据
//设置标记
xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
xlhdr.t_infomask = heaptup->t_data->t_infomask;
xlhdr.t_hoff = heaptup->t_data->t_hoff;
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);//标记
XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);//tuple头部
XLogRegisterBufData(0,
(char *) heaptup->t_data + SizeofHeapTupleHeader,
heaptup->t_len - SizeofHeapTupleHeader);//tuple实际数据
//根据行级别上的原点进行过滤要有效得多
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
//插入数据
recptr = XLogInsert(RM_HEAP_ID, info);
//设置LSN
PageSetLSN(page, recptr);
}
//完成!
END_CRIT_SECTION();
//解锁Buffer,包括vm buffer
UnlockReleaseBuffer(buffer);
if (vmbuffer != InvalidBuffer)
ReleaseBuffer(vmbuffer);
//缓存操作后变“无效”的Tuple
CacheInvalidateHeapTuple(relation, heaptup, NULL);
//注意:speculative insertions也会统计(即使终止此事务)
//更新统计信息
pgstat_count_heap_insert(relation, 1);
if (heaptup != tup)
{
tup->t_self = heaptup->t_self;
heap_freetuple(heaptup);
}
return HeapTupleGetOid(tup);
}
测试脚本如下
-- Hash Partition
drop table if exists t_wal_partition;
create table t_wal_partition (c1 int not null,c2 varchar(40),c3 varchar(40)) partition by hash(c1);
create table t_wal_partition_1 partition of t_wal_partition for values with (modulus 6,remainder 0);
create table t_wal_partition_2 partition of t_wal_partition for values with (modulus 6,remainder 1);
create table t_wal_partition_3 partition of t_wal_partition for values with (modulus 6,remainder 2);
create table t_wal_partition_4 partition of t_wal_partition for values with (modulus 6,remainder 3);
create table t_wal_partition_5 partition of t_wal_partition for values with (modulus 6,remainder 4);
create table t_wal_partition_6 partition of t_wal_partition for values with (modulus 6,remainder 5);
-- 插入路由
-- delete from t_wal_partition where c1 = 0;
insert into t_wal_partition(c1,c2,c3) VALUES(0,'HASH0','HAHS0');
启动gdb,设置断点,进入heap_insert
(gdb) b heap_insert
Breakpoint 1 at 0x4df4d1: file heapam.c, line 2449.
(gdb) c
Continuing.
Breakpoint 1, heap_insert (relation=0x7f9c470a8bd8, tup=0x2908850, cid=0, options=0, bistate=0x0) at heapam.c:2449
2449 TransactionId xid = GetCurrentTransactionId();
构造Heap Tuple数据/获取相应的Buffer(102号)
2449 TransactionId xid = GetCurrentTransactionId();
(gdb) n
2452 Buffer vmbuffer = InvalidBuffer;
(gdb)
2453 bool all_visible_cleared = false;
(gdb)
2462 heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
(gdb)
2468 buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
(gdb)
2487 CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
(gdb) p *heaptup
$1 = {t_len = 172, t_self = {ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, t_tableOid = 1247,
t_data = 0x2908868}
(gdb) p buffer
$2 = 102
插入到Buffer中,标记Buffer为Dirty
(gdb) n
2490 START_CRIT_SECTION();
(gdb)
2493 (options & HEAP_INSERT_SPECULATIVE) != 0);
(gdb)
2492 RelationPutHeapTuple(relation, buffer, heaptup,
(gdb)
2495 if (PageIsAllVisible(BufferGetPage(buffer)))
(gdb)
2515 MarkBufferDirty(buffer);
(gdb)
2518 if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
(gdb)
进入WAL处理部分,获取page(位于1号Page)等信息
(gdb) n
2523 Page page = BufferGetPage(buffer);
(gdb)
2524 uint8 info = XLOG_HEAP_INSERT;
(gdb)
2525 int bufflags = 0;
(gdb)
2531 if (RelationIsAccessibleInLogicalDecoding(relation))
(gdb) p page
$3 = (Page) 0x7f9c1a505380 "\001"
(gdb) p *page
$4 = 1 '\001'
(gdb) p info
$5 = 0 '\000'
设置xl_heap_insert结构体
其中偏移=34,标记位为0x0
(gdb) n
2539 if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
(gdb)
2546 xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
(gdb)
2547 xlrec.flags = 0;
(gdb)
2548 if (all_visible_cleared)
(gdb)
2550 if (options & HEAP_INSERT_SPECULATIVE)
(gdb)
2552 Assert(ItemPointerGetBlockNumber(&heaptup->t_self) == BufferGetBlockNumber(buffer));
(gdb)
2559 if (RelationIsLogicallyLogged(relation) &&
(gdb)
(gdb) p xlrec
$6 = {offnum = 34, flags = 0 '\000'}
开始插入WAL,并注册相关数据
(gdb)
2566 XLogBeginInsert();
(gdb) n
2567 XLogRegisterData((char *) &xlrec, SizeOfHeapInsert);
(gdb)
2569 xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
(gdb) n
2570 xlhdr.t_infomask = heaptup->t_data->t_infomask;
(gdb) n
2571 xlhdr.t_hoff = heaptup->t_data->t_hoff;
(gdb)
2578 XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
(gdb)
2579 XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
(gdb)
2583 heaptup->t_len - SizeofHeapTupleHeader);
(gdb)
2581 XLogRegisterBufData(0,
(gdb)
2582 (char *) heaptup->t_data + SizeofHeapTupleHeader,
(gdb)
2581 XLogRegisterBufData(0,
(gdb)
2586 XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
(gdb)
2588 recptr = XLogInsert(RM_HEAP_ID, info);
(gdb)
(gdb) p xlhdr
$8 = {t_infomask2 = 30, t_infomask = 2057, t_hoff = 32 ' '}
调用XLogInsert,插入WAL,并设置LSN
(gdb) n
2590 PageSetLSN(page, recptr);
(gdb) p recptr
$9 = 5411089336
(gdb) p info
$10 = 0 '\000'
(gdb)
执行其他后续操作,完成函数调用
(gdb) n
2593 END_CRIT_SECTION();
(gdb)
2595 UnlockReleaseBuffer(buffer);
(gdb)
2596 if (vmbuffer != InvalidBuffer)
(gdb)
2605 CacheInvalidateHeapTuple(relation, heaptup, NULL);
(gdb)
2608 pgstat_count_heap_insert(relation, 1);
(gdb)
2614 if (heaptup != tup)
(gdb)
2620 return HeapTupleGetOid(tup);
(gdb)
2621 }
(gdb)
感谢各位的阅读,以上就是“PostgreSQL中heap_insert函数有什么作用”的内容了,经过本文的学习后,相信大家对PostgreSQL中heap_insert函数有什么作用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!
--结束END--
本文标题: PostgreSQL中heap_insert函数有什么作用
本文链接: https://www.lsjlt.com/news/64750.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0