PostgreSQL中heap_insert依赖的函数有哪些
本篇内容主要讲解“PostgreSQL中heap_insert依赖的函数有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中heap_insert依赖的函数有哪些”吧!
一、数据结构静态变量
进程中全局共享
/**AnarrayofXLogRecDatastructs,toholdregistereddata.*XLogRecData结构体数组,存储已注册的数据*/staticXLogRecData*rdatas;//已使用的入口staticintnum_rdatas;/*entriescurrentlyused*///已分配的空间大小staticintmax_rdatas;/*allocatedsize*///是否调用XLogBeginInsert函数staticboolbegininsert_called=false;
registered_buffer
对于每一个使用XLogRegisterBuffer注册的每个数据块,填充到registered_buffer结构体中
/**ForeachblockreferenceregisteredwithXLogRegisterBuffer,wefillin*aregistered_bufferstruct.*对于每一个使用XLogRegisterBuffer注册的每个数据块,*填充到registered_buffer结构体中*/typedefstruct{//slot是否在使用?boolin_use;/*isthisslotinuse?*///REGBUF_*相关标记uint8flags;/*REGBUF_*flags*///定义关系和数据库的标识符RelFileNodernode;/*identifiestherelationandblock*///fork进程编号ForkNumberforkno;//块编号BlockNumberblock;//页内容Pagepage;/*pagecontent*///rdata链中的数据总大小uint32rdata_len;/*totallengthofdatainrdatachain*///使用该数据块注册的数据链头XLogRecData*rdata_head;/*headofthechainofdataregisteredwith*thisblock*///使用该数据块注册的数据链尾XLogRecData*rdata_tail;/*lastentryinthechain,or&rdata_headif*empty*///临时rdatas数据引用,用于存储XLogRecordAssemble()中使用的备份块数据XLogRecDatabkp_rdatas[2];/*temporaryrdatasusedtoholdreferencesto*backupblockdatainXLogRecordAssemble()*//*buffertostoreacompressedversionofbackupblockimage*///用于存储压缩版本的备份块镜像的缓存charcompressed_page[PGLZ_MAX_BLCKSZ];}registered_buffer;//registered_buffer指正staticregistered_buffer*registered_buffers;//已分配的大小staticintmax_registered_buffers;/*allocatedsize*///最大块号+1(当前注册块)staticintmax_registered_block_id=0;/*highestblock_id+1currently*registered*/
XLogCtlInsert
WAL插入记录时使用的共享数据结构
/**SharedstatedataforWALinsertion.*WAL插入记录时使用的共享数据结构*/typedefstructXLogCtlInsert{//包含CurrBytePos和PrevBytePos的lockslock_tinsertpos_lck;/*protectsCurrBytePosandPrevBytePos*//**CurrBytePosistheendofreservedWAL.Thenextrecordwillbe*insertedatthatposition.PrevBytePosisthestartpositionofthe*previouslyinserted(orrather,reserved)record-itiscopiedtothe*prev-linkofthenextrecord.Thesearestoredas"usablebyte*positions"ratherthanXLogRecPtrs(seeXLogBytePosToRecPtr()).*CurrBytePos是保留WAL的结束位置。*下一条记录将插入到那个位置。*PrevBytePos是先前插入(或者保留)记录的起始位置——它被复制到下一条记录的prev-link中。*这些存储为“可用字节位置”,而不是XLogRecPtrs(参见XLogBytePosToRecPtr())。*/uint64CurrBytePos;uint64PrevBytePos;/**Makesuretheaboveheavily-contendedspinlockandbytepositionsare*ontheirowncacheline.Inparticular,theRedoRecPtrandfullpage*writevariablesbelowshouldbeonadifferentcacheline.Theyare*readoneveryWALinsertion,butupdatedrarely,andwedon'twant*thosereadstostealthecachelinecontainingCurr/PrevBytePos.*确保以上激烈竞争的自旋锁和字节位置在它们自己的缓存line上。*特别是,RedoRecPtr和下面的全页写变量应该位于不同的缓存line上。*它们在每次插入WAL时都被读取,但很少更新,*我们不希望这些读取窃取包含Curr/PrevBytePos的缓存line。*/charpad[PG_CACHE_LINE_SIZE];/**fullPageWritesisthemastercopyusedbyallbackendstodetermine*whethertowritefull-pagetoWAL,insteadofusingprocess-localone.*Thisisrequiredbecause,whenfull_page_writesischangedbySIGHUP,*wemustWAL-logitbeforeitactuallyaffectsWAL-loggingbybackends.*CheckpointersetsatstartuporafterSIGHUP.*fullpagewrite是所有后台进程使用的主副本,*用于确定是否将整个页面写入WAL,而不是使用process-local副本。*这是必需的,因为当SIGHUP更改full_page_write时,*我们必须在它通过后台进程实际影响WAL-logging之前对其进行WAL-log记录。*Checkpointer检查点设置在启动或SIGHUP之后。**Toreadthesefields,youmustholdaninsertionlock.Tomodifythem,*youmustholdALLthelocks.*为了读取这些域,必须持有insertionlock.*如需更新,则需要持有所有这些lock.*///插入时的当前redopointXLogRecPtrRedoRecPtr;/*currentredopointforinsertions*///为PITR强制执行full-page写?boolforcePageWrites;/*forcingfull-pagewritesforPITR?*///是否全页写?boolfullPageWrites;/**exclusiveBackupStateindicatesthestateofanexclusivebackup(see*commentsofExclusiveBackupStateformoredetails).nonExclusiveBackups*isacounterindicatingthenumberofstreamingbasebackupscurrently*inprogress.forcePageWritesissettotruewheneitheroftheseis*non-zero.lastBackupStartisthelatestcheckpointredolocationused*asastartingpointforanonlinebackup.*exclusivesivebackupstate表示排他备份的状态*(有关详细信息,请参阅exclusivesivebackupstate的注释)。*非排他性备份是一个计数器,指示当前正在进行的流基础备份的数量。*forcePageWrites在这两个值都不为零时被设置为true。*lastBackupStart用作在线备份起点的最新检查点的重做位置。*/ExclusiveBackupStateexclusiveBackupState;intnonExclusiveBackups;XLogRecPtrlastBackupStart;/**WALinsertionlocks.*WAL写入锁*/WALInsertLockPadded*WALInsertLocks;}XLogCtlInsert;
XLogRecData
xloginsert.c中的函数构造一个XLogRecData结构体链用于标识最后的WAL记录
/**Thefunctionsinxloginsert.cconstructachainofXLogRecDatastructs*torepresentthefinalWALrecord.*xloginsert.c中的函数构造一个XLogRecData结构体链用于标识最后的WAL记录*/typedefstructXLogRecData{//链中的下一个结构体,如无则为NULLstructXLogRecData*next;/*nextstructinchain,orNULL*///rmgr数据的起始地址char*data;/*startofrmgrdatatoinclude*///rmgr数据大小uint32len;/*lengthofrmgrdatatoinclude*/}XLogRecData;
registered_buffer/registered_buffers
对于每一个使用XLogRegisterBuffer注册的每个数据块,填充到registered_buffer结构体中
/**ForeachblockreferenceregisteredwithXLogRegisterBuffer,wefillin*aregistered_bufferstruct.*对于每一个使用XLogRegisterBuffer注册的每个数据块,*填充到registered_buffer结构体中*/typedefstruct{//slot是否在使用?boolin_use;/*isthisslotinuse?*///REGBUF_*相关标记uint8flags;/*REGBUF_*flags*///定义关系和数据库的标识符RelFileNodernode;/*identifiestherelationandblock*///fork进程编号ForkNumberforkno;//块编号BlockNumberblock;//页内容Pagepage;/*pagecontent*///rdata链中的数据总大小uint32rdata_len;/*totallengthofdatainrdatachain*///使用该数据块注册的数据链头XLogRecData*rdata_head;/*headofthechainofdataregisteredwith*thisblock*///使用该数据块注册的数据链尾XLogRecData*rdata_tail;/*lastentryinthechain,or&rdata_headif*empty*///临时rdatas数据引用,用于存储XLogRecordAssemble()中使用的备份块数据XLogRecDatabkp_rdatas[2];/*temporaryrdatasusedtoholdreferencesto*backupblockdatainXLogRecordAssemble()*//*buffertostoreacompressedversionofbackupblockimage*///用于存储压缩版本的备份块镜像的缓存charcompressed_page[PGLZ_MAX_BLCKSZ];}registered_buffer;//registered_buffer指针(全局变量)staticregistered_buffer*registered_buffers;//已分配的大小staticintmax_registered_buffers;/*allocatedsize*///最大块号+1(当前注册块)staticintmax_registered_block_id=0;/*highestblock_id+1currently*registered*/二、源码解读
heap_insert
主要实现逻辑是插入元组到堆中,其中存在对WAL(XLog)进行处理的部分.
参见PostgreSQL 源码解读(104)- WAL#1(Insert & WAL-heap_insert函数#1)
XLogBeginInsert
开始构造WAL记录.
必须在调用XLogRegister*和XLogInsert()函数前调用.
/**BeginconstructingaWALrecord.Thismustbecalledbeforethe*XLogRegister*functionsandXLogInsert().*开始构造WAL记录.*必须在调用XLogRegister*和XLogInsert()函数前调用.*/voidXLogBeginInsert(void){//验证逻辑Assert(max_registered_block_id==0);Assert(mainrdata_last==(XLogRecData*)&mainrdata_head);Assert(mainrdata_len==0);/*cross-checkonwhetherweshouldbehereornot*///交叉校验是否应该在这里还是不应该在这里出现if(!XLogInsertAllowed())elog(ERROR,"cannotmakenewWALentriesduringrecovery");if(begininsert_called)elog(ERROR,"XLogBeginInsertwasalreadycalled");//变量赋值begininsert_called=true;}/**IsthisprocessallowedtoinsertnewWALrecords?*判断该进程是否允许插入新的WAL记录**Ordinarilythisisessentiallyequivalentto!RecoveryInProgress().*Butwealsohaveprovisionsforforcingtheresult"true"or"false"*withinspecificprocessesregardlessoftheglobalstate.*通常,这本质上等同于!recoverinprogress()。*但我们也有规定,无论全局状况如何,都要在特定进程中强制实现“正确”或“错误”的结果。*/boolXLogInsertAllowed(void){/**Ifvalueis"unconditionallytrue"or"unconditionallyfalse",just*returnit.Thisprovidesthenormalfastpathoncerecoveryisknown*done.*如果值为“无条件为真”或“无条件为假”,则返回。*这提供正常的快速判断路径。*/if(LocalXLogInsertAllowed>=0)return(bool)LocalXLogInsertAllowed;/**Else,mustchecktoseeifwe'restillinrecovery.*否则,必须检查是否处于恢复状态*/if(RecoveryInProgress())returnfalse;/**Onexitfromrecovery,resetto"unconditionallytrue",sincethereis*noneedtokeepchecking.*从恢复中退出,由于不需要继续检查,重置为"无条件为真"*/LocalXLogInsertAllowed=1;returntrue;}
XLogRegisterData
添加数据到正在构造的WAL记录中
/**AdddatatotheWALrecordthat'sbeingconstructed.*添加数据到正在构造的WAL记录中**Thedataisappendedtothe"mainchunk",availableatreplaywith*XLogRecGetData().*数据追加到"mainchunk"中,用于XLogRecGetData()函数回放*/voidXLogRegisterData(char*data,intlen){XLogRecData*rdata;//数据//验证是否已调用beginAssert(begininsert_called);//验证大小if(num_rdatas>=max_rdatas)elog(ERROR,"toomuchWALdata");rdata=&rdatas[num_rdatas++];rdata->data=data;rdata->len=len;/**weusethemainrdata_lastpointertotracktheendofthechain,sono*needtoclear'next'here.*使用mainrdata_last指针跟踪链条的结束点,在这里不需要清除next变量*/mainrdata_last->next=rdata;mainrdata_last=rdata;mainrdata_len+=len;}
XLogRegisterBuffer
在缓冲区中注册已构建的WAL记录的依赖,在WAL-logged操作更新每一个page时必须调用此函数
/**RegisterareferencetoabufferwiththeWALrecordbeingconstructed.*ThismustbecalledforeverypagethattheWAL-loggedoperationmodifies.*在缓冲区中注册已构建的WAL记录的依赖*在WAL-logged操作更新每一个page时必须调用此函数*/voidXLogRegisterBuffer(uint8block_id,Bufferbuffer,uint8flags){registered_buffer*regbuf;//缓冲/*NO_IMAGEdoesn'tmakesensewithFORCE_IMAGE*///NO_IMAGE不能与REGBUF_NO_IMAGE同时使用Assert(!((flags®BUF_FORCE_IMAGE)&&(flags&(REGBUF_NO_IMAGE))));Assert(begininsert_called);//块ID>最大已注册的缓冲区,报错if(block_id>=max_registered_block_id){if(block_id>=max_registered_buffers)elog(ERROR,"toomanyregisteredbuffers");max_registered_block_id=block_id+1;}//赋值regbuf=®istered_buffers[block_id];//获取TagBufferGetTag(buffer,®buf->rnode,®buf->forkno,®buf->block);regbuf->page=BufferGetPage(buffer);regbuf->flags=flags;regbuf->rdata_tail=(XLogRecData*)®buf->rdata_head;regbuf->rdata_len=0;/**Checkthatthispagehasn'talreadybeenregisteredwithsomeother*block_id.*检查该page是否已被其他block_id注册*/#ifdefUSE_ASSERT_CHECKING{inti;for(i=0;i<max_registered_block_id;i++)//循环检查{registered_buffer*regbuf_old=®istered_buffers[i];if(i==block_id||!regbuf_old->in_use)continue;Assert(!RelFileNodeEquals(regbuf_old->rnode,regbuf->rnode)||regbuf_old->forkno!=regbuf->forkno||regbuf_old->block!=regbuf->block);}}#endifregbuf->in_use=true;//标记为使用}/**BufferGetTag*Returnstherelfilenode,forknumberandblocknumberassociatedwith*abuffer.*返回与缓冲区相关的relfilenode,fork编号和块号*/voidBufferGetTag(Bufferbuffer,RelFileNode*rnode,ForkNumber*forknum,BlockNumber*blknum){BufferDesc*bufHdr;/*DothesamechecksasBufferGetBlockNumber.*///验证buffer已被pinnedAssert(BufferIsPinned(buffer));if(BufferIsLocal(buffer))bufHdr=GetLocalBufferDescriptor(-buffer-1);elsebufHdr=GetBufferDescriptor(buffer-1);/*pinned,soOKtoreadtagwithoutspinlock*///pinned,不需要spinlock读取tage*rnode=bufHdr->tag.rnode;*forknum=bufHdr->tag.forkNum;*blknum=bufHdr->tag.blockNum;}/**BufferIsLocal*Trueiffthebufferislocal(notvisibletootherbackends).*如缓冲区对其他后台进程不不可见,则为本地buffer*/#defineBufferIsLocal(buffer)((buffer)<0)#defineGetBufferDescriptor(id)(&BufferDescriptors[(id)].bufferdesc)#defineGetLocalBufferDescriptor(id)(&LocalBufferDescriptors[(id)])BufferDesc*LocalBufferDescriptors=NULL;BufferDescPadded*BufferDescriptors;
XLogRegisterBufData
在正在构造的WAL记录中添加buffer相关的数据.
/**Addbuffer-specificdatatotheWALrecordthat'sbeingconstructed.*在正在构造的WAL记录中添加buffer相关的数据.**Block_idmustreferenceablockpreviouslyregisteredwith*XLogRegisterBuffer().Ifthisiscalledmorethanonceforthesame*block_id,thedataisappended.*Block_id必须引用先前注册到XLogRegisterBuffer()中的数据块。*如果对同一个block_id不止一次调用,那么数据将会追加。**Themaximumamountofdatathatcanberegisteredperblockis65535*bytes.Thatshouldbeplenty;ifyouneedmorethanBLCKSZbytesto*reconstructthechangestothepage,youmightaswelljustlogafull*copyofit.(the"maindata"that'snotassociatedwithablockisnot*limited)*每个块可注册的最大大小是65535Bytes.*通常来说这已经足够了;如果需要大小比BLCKSZ字节更大的数据用于重建页面的变化,*那么需要整页进行拷贝.*(与数据块相关的"maindata"是不受限的)*/voidXLogRegisterBufData(uint8block_id,char*data,intlen){registered_buffer*regbuf;//注册的缓冲区XLogRecData*rdata;//数据Assert(begininsert_called);//XLogBeginInsert函数已调用/*findtheregisteredbufferstruct*///寻找已注册的缓存结构体regbuf=®istered_buffers[block_id];if(!regbuf->in_use)elog(ERROR,"noblockwithid%dregisteredwithWALinsertion",block_id);if(num_rdatas>=max_rdatas)elog(ERROR,"toomuchWALdata");rdata=&rdatas[num_rdatas++];rdata->data=data;rdata->len=len;regbuf->rdata_tail->next=rdata;regbuf->rdata_tail=rdata;regbuf->rdata_len+=len;}
XLogSetRecordFlags
为即将"到来"的WAL记录设置插入状态标记
XLOG_INCLUDE_ORIGIN 确定复制起点是否应该包含在记录中
XLOG_MARK_UNIMPORTANT 表示记录对于持久性并不重要,这可以避免触发WAL归档和其他后台活动
/**SetinsertstatusflagsfortheupcomingWALrecord.*为即将"到来"的WAL记录设置插入状态标记**Theflagsthatcanbeusedhereare:*-XLOG_INCLUDE_ORIGIN,todetermineifthereplicationoriginshouldbe*includedintherecord.*-XLOG_MARK_UNIMPORTANT,tosignalthattherecordisnotimportantfor*durability,whichallowstoavoidtriggeringWALarchivingandother*backgroundactivity.*标记用于:*-XLOG_INCLUDE_ORIGIN确定复制起点是否应该包含在记录中*-XLOG_MARK_UNIMPORTANT表示记录对于持久性并不重要,这可以避免触发WAL归档和其他后台活动。*/voidXLogSetRecordFlags(uint8flags){Assert(begininsert_called);curinsert_flags=flags;}三、跟踪分析
测试脚本如下
insertintot_wal_partition(c1,c2,c3)VALUES(0,'HASH0','HAHS0');
XLogBeginInsert
启动gdb,设置断点,进入XLogBeginInsert
(gdb)bXLogBeginInsertBreakpoint1at0x564897:filexloginsert.c,line122.(gdb)cContinuing.Breakpoint1,XLogBeginInsert()atxloginsert.c:122122Assert(max_registered_block_id==0);
校验,调用XLogInsertAllowed
122Assert(max_registered_block_id==0);(gdb)n123Assert(mainrdata_last==(XLogRecData*)&mainrdata_head);(gdb)124Assert(mainrdata_len==0);(gdb)127if(!XLogInsertAllowed())(gdb)stepXLogInsertAllowed()atxlog.c:81268126if(LocalXLogInsertAllowed>=0)(gdb)n8132if(RecoveryInProgress())(gdb)8139LocalXLogInsertAllowed=1;(gdb)8140returntrue;(gdb)8141}(gdb)
赋值,设置begininsert_called为T,返回
(gdb)XLogBeginInsert()atxloginsert.c:130130if(begininsert_called)(gdb)pbegininsert_called$1=false(gdb)n133begininsert_called=true;(gdb)134}(gdb)heap_insert(relation=0x7f5cc0338228,tup=0x29b2440,cid=0,options=0,bistate=0x0)atheapam.c:25672567XLogRegisterData((char*)&xlrec,SizeOfHeapInsert);(gdb)
XLogRegisterData
进入XLogRegisterData函数
(gdb)stepXLogRegisterData(data=0x7fff03ba99e0"\002",len=3)atxloginsert.c:327327Assert(begininsert_called);(gdb)p*data$2=2'\002'(gdb)p*(xl_heap_insert*)data$3={offnum=2,flags=0'\000'}
执行相关判断,并赋值
rdatas是XLogRecData结构体指针,全局静态变量:
static XLogRecData *rdatas;
(gdb)n329if(num_rdatas>=max_rdatas)(gdb)pnum_rdatas$4=0(gdb)pmax_rdatas$5=20(gdb)n331rdata=&rdatas[num_rdatas++];(gdb)prdatas[0]$6={next=0x0,data=0x0,len=0}(gdb)prdatas[1]$7={next=0x0,data=0x0,len=0}
相关结构体赋值
其中mainrdata_last是mainrdata_head的地址:
static XLogRecData *mainrdata_head;
static XLogRecData *mainrdata_last = (XLogRecData *) &mainrdata_head;
(gdb)n333rdata->data=data;(gdb)334rdata->len=len;(gdb)341mainrdata_last->next=rdata;(gdb)342mainrdata_last=rdata;(gdb)344mainrdata_len+=len;(gdb)345}
完成调用,回到heap_insert
(gdb)nheap_insert(relation=0x7f5cc0338228,tup=0x29b2440,cid=0,options=0,bistate=0x0)atheapam.c:25692569xlhdr.t_infomask2=heaptup->t_data->t_infomask2;
XLogRegisterBuffer
进入XLogRegisterBuffer
(gdb)stepXLogRegisterBuffer(block_id=0'\000',buffer=99,flags=8'\b')atxloginsert.c:218218Assert(!((flags®BUF_FORCE_IMAGE)&&(flags&(REGBUF_NO_IMAGE))));
判断block_id,设置max_registered_block_id变量等.
注:max_registered_buffers初始化为5
(gdb)n219Assert(begininsert_called);(gdb)221if(block_id>=max_registered_block_id)(gdb)pmax_registered_block_id$14=0(gdb)n223if(block_id>=max_registered_buffers)(gdb)pmax_registered_buffers$15=5(gdb)n225max_registered_block_id=block_id+1;(gdb)228regbuf=®istered_buffers[block_id];(gdb)pmax_registered_buffers$16=5(gdb)pmax_registered_block_id$17=1(gdb)n230BufferGetTag(buffer,®buf->rnode,®buf->forkno,®buf->block);(gdb)p*regbuf$18={in_use=false,flags=0'\000',rnode={spcNode=0,dbNode=0,relNode=0},forkno=MAIN_FORKNUM,block=0,page=0x0,rdata_len=0,rdata_head=0x0,rdata_tail=0x0,bkp_rdatas={{next=0x0,data=0x0,len=0},{next=0x0,data=0x0,len=0}},compressed_page='\000'<repeats8195times>}
获取buffer的tag
rnode/forkno/block
(gdb)n231regbuf->page=BufferGetPage(buffer);(gdb)p*regbuf$19={in_use=false,flags=0'\000',rnode={spcNode=1663,dbNode=16402,relNode=17034},forkno=MAIN_FORKNUM,block=0,page=0x0,rdata_len=0,rdata_head=0x0,rdata_tail=0x0,bkp_rdatas={{next=0x0,data=0x0,len=0},{next=0x0,data=0x0,len=0}},compressed_page='\000'<repeats8195times>}
设置flags等其他变量
(gdb)n232regbuf->flags=flags;(gdb)233regbuf->rdata_tail=(XLogRecData*)®buf->rdata_head;(gdb)234regbuf->rdata_len=0;(gdb)244for(i=0;i<max_registered_block_id;i++)(gdb)pregbuf->flags$21=8'\b'(gdb)p*regbuf->rdata_tail$23={next=0x0,data=0x292e1a8"",len=0}(gdb)pregbuf->rdata_len$24=0
检查该page是否已被其他block_id注册
最后设置in_use为T,返回XLogRegisterBufData
(gdb)n246registered_buffer*regbuf_old=®istered_buffers[i];(gdb)248if(i==block_id||!regbuf_old->in_use)(gdb)249continue;(gdb)244for(i=0;i<max_registered_block_id;i++)(gdb)258regbuf->in_use=true;(gdb)259}(gdb)heap_insert(relation=0x7f5cc0338228,tup=0x29b2440,cid=0,options=0,bistate=0x0)atheapam.c:25792579XLogRegisterBufData(0,(char*)&xlhdr,SizeOfHeapHeader);
XLogRegisterBufData
进入XLogRegisterBufData函数
(gdb)stepXLogRegisterBufData(block_id=0'\000',data=0x7fff03ba99d0"\003",len=5)atxloginsert.c:366366Assert(begininsert_called);
寻找已注册的缓存结构体
(gdb)n369regbuf=®istered_buffers[block_id];(gdb)370if(!regbuf->in_use)(gdb)p*regbuf$25={in_use=true,flags=8'\b',rnode={spcNode=1663,dbNode=16402,relNode=17034},forkno=MAIN_FORKNUM,block=0,page=0x7f5c93854380"\001",rdata_len=0,rdata_head=0x0,rdata_tail=0x292e1a8,bkp_rdatas={{next=0x0,data=0x0,len=0},{next=0x0,data=0x0,len=0}},compressed_page='\000'<repeats8195times>}(gdb)p*regbuf->page$26=1'\001'(gdb)n374if(num_rdatas>=max_rdatas)(gdb)
在正在构造的WAL记录中添加buffer相关的数据.
(gdb)n376rdata=&rdatas[num_rdatas++];(gdb)pnum_rdatas$27=1(gdb)pmax_rdatas$28=20(gdb)n378rdata->data=data;(gdb)379rdata->len=len;(gdb)381regbuf->rdata_tail->next=rdata;(gdb)382regbuf->rdata_tail=rdata;(gdb)383regbuf->rdata_len+=len;(gdb)384}(gdb)p*rdata$29={next=0x0,data=0x7fff03ba99d0"\003",len=5}(gdb)
完成调用,回到heap_insert
(gdb)nheap_insert(relation=0x7f5cc0338228,tup=0x29b2440,cid=0,options=0,bistate=0x0)atheapam.c:25832583heaptup->t_len-SizeofHeapTupleHeader);
继续调用XLogRegisterBufData函数注册tuple实际数据
2583heaptup->t_len-SizeofHeapTupleHeader);(gdb)n2581XLogRegisterBufData(0,(gdb)
XLogSetRecordFlags
为即将"到来"的WAL记录设置插入状态标记
(gdb)2586XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
逻辑很简单,设置标记位curinsert_flags
(gdb)stepXLogSetRecordFlags(flags=1'\001')atxloginsert.c:399399Assert(begininsert_called);(gdb)n400curinsert_flags=flags;(gdb)401}(gdb)heap_insert(relation=0x7f5cc0338228,tup=0x29b2440,cid=0,options=0,bistate=0x0)atheapam.c:25882588recptr=XLogInsert(RM_HEAP_ID,info);(gdb)
调用XLogInsert,插入WAL
(gdb)2590PageSetLSN(page,recptr);...
到此,相信大家对“PostgreSQL中heap_insert依赖的函数有哪些”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。