这篇文章主要为大家展示了“PostgreSQL如何获取事务号XID”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“PostgreSQL如何获取事务号XID”这篇文章吧。

主要解析了函数AssignTransactionId->GetNewTransactionId的实现逻辑。

在GetNewTransactionId函数中,检查是否可以安全的分配XID.
这可以防止由于XID wraparound而导致的灾难性数据丢失.
基本规则是:
如果超过了xidVacLimit,开始尝试强制autovacuum循环.
如果超过了xidWarnLimit,开始发出警告.
如果超过了xidStopLimit,拒绝执行事务,直至以单用户模式运行.
(这为DBA提供了一个逃生通道,使他们能够通过数据库早期的安全性检测,进入数据库进行维护)

ShmemVariableCache->xidVacLimit —> 200,000,561 —> 大于等于该值,触发自动vacuum
ShmemVariableCache->xidWarnLimit —> 2,136,484,208 —> 大于等于该值,系统报警
ShmemVariableCache->xidStopLimit —> 2,146,484,208 —> 大于等于该值,系统不允许执行事务,使用单用户模式处理

一、数据结构

TransactionState
事务状态结构体

/**transactionstates-transactionstatefromserverperspective*事务状态枚举-服务器视角的事务状态*/typedefenumTransState{TRANS_DEFAULT,/*idle空闲*/TRANS_START,/*transactionstarting事务启动*/TRANS_INPROGRESS,/*insideavalidtransaction进行中*/TRANS_COMMIT,/*commitinprogress提交中*/TRANS_ABORT,/*abortinprogress回滚中*/TRANS_PREPARE/*prepareinprogress准备中*/}TransState;/**transactionblockstates-transactionstateofclientqueries*事务块状态-客户端查询的事务状态**Note:thesubtransactionstatesareusedonlyfornon-topmost*transactions;theothersappearonlyinthetopmosttransaction.*注意:subtransaction只用于非顶层事务;其他字段用于顶层事务.*/typedefenumTBlockState{/*not-in-transaction-blockstates未进入事务块状态*/TBLOCK_DEFAULT,/*idle空闲*/TBLOCK_STARTED,/*runningsingle-querytransaction单个查询事务*//*transactionblockstates事务块状态*/TBLOCK_BEGIN,/*startingtransactionblock开始事务块*/TBLOCK_INPROGRESS,/*livetransaction进行中*/TBLOCK_IMPLICIT_INPROGRESS,/*livetransactionafterimplicitBEGIN隐式事务,进行中*/TBLOCK_PARALLEL_INPROGRESS,/*livetransactioninsideparallelworker并行worker中的事务,进行中*/TBLOCK_END,/*COMMITreceived接收到COMMIT*/TBLOCK_ABORT,/*failedxact,awaitingROLLBACK失败,等待ROLLBACK*/TBLOCK_ABORT_END,/*failedxact,ROLLBACKreceived失败,已接收ROLLBACK*/TBLOCK_ABORT_PENDING,/*livexact,ROLLBACKreceived进行中,接收到ROLLBACK*/TBLOCK_PREPARE,/*livexact,PREPAREreceived进行中,接收到PREPARE*//*subtransactionstates子事务状态*/TBLOCK_SUBBEGIN,/*startingasubtransaction开启*/TBLOCK_SUBINPROGRESS,/*livesubtransaction进行中*/TBLOCK_SUBRELEASE,/*RELEASEreceived接收到RELEASE*/TBLOCK_SUBCOMMIT,/*COMMITreceivedwhileTBLOCK_SUBINPROGRESS进行中,接收到COMMIT*/TBLOCK_SUBABORT,/*failedsubxact,awaitingROLLBACK失败,等待ROLLBACK*/TBLOCK_SUBABORT_END,/*failedsubxact,ROLLBACKreceived失败,已接收ROLLBACK*/TBLOCK_SUBABORT_PENDING,/*livesubxact,ROLLBACKreceived进行中,接收到ROLLBACK*/TBLOCK_SUBRESTART,/*livesubxact,ROLLBACKTOreceived进行中,接收到ROLLBACKTO*/TBLOCK_SUBABORT_RESTART/*failedsubxact,ROLLBACKTOreceived失败,已接收ROLLBACKTO*/}TBlockState;/**transactionstatestructure*事务状态结构体*/typedefstructTransactionStateData{//事务IDTransactionIdtransactionId;/*myXID,orInvalidifnone*///子事务IDSubTransactionIdsubTransactionId;/*mysubxactID*///保存点名称char*name;/*savepointname,ifany*///保存点级别intsavepointLevel;/*savepointlevel*///低级别的事务状态TransStatestate;/*low-levelstate*///高级别的事务状态TBlockStateblockState;/*high-levelstate*///事务嵌套深度intnestingLevel;/*transactionnestingdepth*///GUC上下文嵌套深度intgucNestLevel;/*GUCcontextnestingdepth*///事务生命周期上下文MemoryContextcurTransactionContext;/*myxact-lifetimecontext*///查询资源ResourceOwnercurTransactionOwner;/*myqueryresources*///按XID顺序保存的已提交的子事务IDTransactionId*childXids;/*subcommittedchildXIDs,inXIDorder*///childXids数组大小intnChildXids;/*#ofsubcommittedchildXIDs*///分配的childXids数组空间intmaxChildXids;/*allocatedsizeofchildXids[]*///上一个CurrentUserIdOidprevUser;/*previousCurrentUserIdsetting*///上一个SecurityRestrictionContextintprevSecContext;/*previousSecurityRestrictionContext*///上一事务是否只读?boolprevXactReadOnly;/*entry-timexactr/ostate*///是否处于Recovery?boolstartedInRecovery;/*didwestartinrecovery?*///XID是否已保存在WALRecord中?booldidLogXid;/*hasxidbeenincludedinWALrecord?*///Enter/ExitParallelMode计数器intparallelModeLevel;/*Enter/ExitParallelModecounter*///父事务状态structTransactionStateData*parent;/*backlinktoparent*/}TransactionStateData;//结构体指针typedefTransactionStateData*TransactionState;

ShmemVariableCache
VariableCache是共享内存中的一种数据结构,用于跟踪OID和XID分配状态。
ShmemVariableCache—>共享内存中的指针

/**VariableCacheisadatastructureinsharedmemorythatisusedtotrack*OIDandXIDassignmentstate.Forlargelyhistoricalreasons,thereis*justonestructwithdifferentfieldsthatareprotectedbydifferent*LWLocks.*VariableCache是共享内存中的一种数据结构,用于跟踪OID和XID分配状态。*由于历史原因,这个结构体有不同的字段,由不同的LWLocks保护。**Note:xidWrapLimitandoldestXidDBarenot"active"values,butare*usedjusttogenerateusefulmessageswhenxidWarnLimitorxidStopLimit*areexceeded.*注意:xidWrapLimit和oldestXidDB是不"活跃"的值,在xidWarnLimit或xidStopLimit*超出限制时用于产生有用的信息.*/typedefstructVariableCacheData{/**ThesefieldsareprotectedbyOidGenLock.*这些域字段通过OidGenLock字段保护*///下一个待分配的OIDOidnextOid;/*nextOIDtoassign*///在必须执行XLOGwork前可用OIDsuint32oidCount;/*OIDsavailablebeforemustdoXLOGwork*//**ThesefieldsareprotectedbyXidGenLock.*这些字段通过XidGenLock锁保护.*///下一个待分配的事务IDTransactionIdnextXid;/*nextXIDtoassign*///集群范围内最小datfrozenxidTransactionIdoldestXid;/*cluster-wideminimumdatfrozenxid*///在该XID开始强制执行autovacuumTransactionIdxidVacLimit;/*startforcingautovacuumshere*///在该XID开始提出警告TransactionIdxidWarnLimit;/*startcomplaininghere*///在该XID开外,拒绝生成下一个XIDTransactionIdxidStopLimit;/*refusetoadvancenextXidbeyondhere*///"世界末日"XID,需回卷TransactionIdxidWrapLimit;/*wheretheworldends*///持有最小datfrozenxid的DBOidoldestXidDB;/*databasewithminimumdatfrozenxid*//**ThesefieldsareprotectedbyCommitTsLock*这些字段通过CommitTsLock锁保护*/TransactionIdoldestCommitTsXid;TransactionIdnewestCommitTsXid;/**ThesefieldsareprotectedbyProcArrayLock.*这些字段通过ProcArrayLock锁保护*/TransactionIdlatestCompletedXid;/*newestXIDthathascommittedor*aborted*//**ThesefieldsareprotectedbyCLogTruncationLock*这些字段通过CLogTruncationLock锁保护*///clog中最古老的XIDTransactionIdoldestClogXid;/*oldestit'ssafetolookupinclog*/}VariableCacheData;//结构体指针typedefVariableCacheData*VariableCache;/*pointerto"variablecache"insharedmemory(setupbyshmem.c)*///共享内存中的指针(通过shmem.c设置)VariableCacheShmemVariableCache=NULL;二、源码解读

AssignTransactionId函数,给定的TransactionState分配一个新的持久化事务号XID,在此函数调用前,不会为事务分配XIDs.GetNewTransactionId是获取事务ID实际执行的地方,该函数从共享内存变量ShmemVariableCache中获取nextXid,+1后作为新的XID.

/**AllocatethenextXIDforanewtransactionorsubtransaction.*为新事务或新子事务分配XID**ThenewXIDisalsostoredintoMyPgXactbeforereturning.*在返回前,XID会存储在全局变量MyPgXact中**Note:whenthisiscalled,weareactuallyalreadyinsideavalid*transaction,sinceXIDsarenownotallocateduntilthetransaction*doessomething.Soitissafetodoadatabaselookupifwewantto*issueawarningaboutXIDwrap.*注意:在该函数调用时,我们实际上已在一个有效的事务中,因为XIDs在事务不做些事情前不会分配.*因此,如果我们想发出关于XIDwrap回卷的警告,那么进行数据库查找是安全的。*/TransactionIdGetNewTransactionId(boolisSubXact){TransactionIdxid;/**Workerssynchronizetransactionstateatthebeginningofeachparallel*operation,sowecan'taccountfornewXIDsafterthatpoint.*在每个并行操作前,ParallelWorkers同步事务状态,*因此我们不能在这时候请求XIDs*/if(IsInParallelMode())elog(ERROR,"cannotassignTransactionIdsduringaparalleloperation");/**Duringbootstrapinitialization,wereturnthespecialbootstrap*transactionid.*在宇宙初启时,返回特别的bootstrap事务ID*/if(IsBootstrapProcessingMode()){Assert(!isSubXact);MyPgXact->xid=BootstrapTransactionId;returnBootstrapTransactionId;//-->1}/*safetycheck,weshouldnevergetthisfarinaHSstandby*/*安全检查if(RecoveryInProgress())elog(ERROR,"cannotassignTransactionIdsduringrecovery");LWLockAcquire(XidGenLock,LW_EXCLUSIVE);//从共享内存中获取下一个XIDxid=ShmemVariableCache->nextXid;/*----------*Checktoseeifit'ssafetoassignanotherXID.Thisprotectsagainst*catastrophicdatalossduetoXIDwraparound.Thebasicrulesare:*检查是否可以安全的分配另外一个XID.*这可以防止由于XIDwraparound而导致的灾难性数据丢失.*基本规则是:**Ifwe'repastxidVacLimit,starttryingtoforceautovacuumcycles.*Ifwe'repastxidWarnLimit,startissuingwarnings.*Ifwe'repastxidStopLimit,refusetoexecutetransactions,unless*wearerunninginsingle-usermode(whichgivesanescapehatch*totheDBAwhosomehowgotpasttheearlierdefenses).*如果超过了xidVacLimit,开始尝试强制autovacuum循环.*如果超过了xidWarnLimit,开始发出警告.*如果超过了xidStopLimit,拒绝执行事务,直至以单用户模式运行.*(这为DBA提供了一个逃生通道,使他们能够通过数据库早期的安全性检测)**NotethatthiscodingalsoappearsinGetNewMultiXactId.*注意这部分代码在GetNewMultiXactId中也会出现.*----------*///TransactionIdFollowsOrEquals-->isid1logically>=id2?if(TransactionIdFollowsOrEquals(xid,ShmemVariableCache->xidVacLimit)){//xid>=ShmemVariableCache->xidVacLimit/**Forsafety'ssake,wereleaseXidGenLockwhilesendingsignals,*warnings,etc.Thisisnotsomuchbecausewecareabout*preservingconcurrencyinthissituation,astoavoidany*possibilityofdeadlockwhiledoingget_database_name().First,*copyallthesharedvalueswe'llneedinthispath.*为了安全起见,我们在发送信号、警告等时释放XidGenLock。*这并不是因为我们关心在这种情况下并发性,*而是因为在执行get_database_name()时要避免出现死锁*///获取相关XIDTransactionIdxidWarnLimit=ShmemVariableCache->xidWarnLimit;TransactionIdxidStopLimit=ShmemVariableCache->xidStopLimit;TransactionIdxidWrapLimit=ShmemVariableCache->xidWrapLimit;Oidoldest_datoid=ShmemVariableCache->oldestXidDB;LWLockRelease(XidGenLock);/**Toavoidswampingthepostmasterwithsignals,weissuetheautovac*requestonlyonceper64Ktransactionstarts.Thisstillgives*plentyofchancesbeforewegetintorealtrouble.*为了避免信号淹没postmaster,我们每64K事务开始时只发出一次autovac请求。*在我们陷入真正的麻烦之前,这仍然给了我们很多解决问题的机会。*/if(IsUnderPostmaster&&(xid%65536)==0)//每隔64K发一次SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);if(IsUnderPostmaster&&TransactionIdFollowsOrEquals(xid,xidStopLimit)){//xid>=ShmemVariableCache->xidStopLimitchar*oldest_datname=get_database_name(oldest_datoid);/*complainevenifthatDBhasdisappeared*///就算DB已消失,也要不停的警告:(if(oldest_datname)ereport(ERROR,(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),errmsg("databaseisnotacceptingcommandstoavoidwraparounddatalossindatabase\"%s\"",oldest_datname),errhint("Stopthepostmasterandvacuumthatdatabaseinsingle-usermode.\n""Youmightalsoneedtocommitorrollbackoldpreparedtransactions,ordropstalereplicationslots.")));elseereport(ERROR,(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),errmsg("databaseisnotacceptingcommandstoavoidwraparounddatalossindatabasewithOID%u",oldest_datoid),errhint("Stopthepostmasterandvacuumthatdatabaseinsingle-usermode.\n""Youmightalsoneedtocommitorrollbackoldpreparedtransactions,ordropstalereplicationslots.")));}elseif(TransactionIdFollowsOrEquals(xid,xidWarnLimit)){////xid>=ShmemVariableCache->xidWarnLimitchar*oldest_datname=get_database_name(oldest_datoid);/*complainevenifthatDBhasdisappeared*/if(oldest_datname)ereport(WARNING,(errmsg("database\"%s\"mustbevacuumedwithin%utransactions",oldest_datname,xidWrapLimit-xid),errhint("Toavoidadatabaseshutdown,executeadatabase-wideVACUUMinthatdatabase.\n""Youmightalsoneedtocommitorrollbackoldpreparedtransactions,ordropstalereplicationslots.")));elseereport(WARNING,(errmsg("databasewithOID%umustbevacuumedwithin%utransactions",oldest_datoid,xidWrapLimit-xid),errhint("Toavoidadatabaseshutdown,executeadatabase-wideVACUUMinthatdatabase.\n""Youmightalsoneedtocommitorrollbackoldpreparedtransactions,ordropstalereplicationslots.")));}/*Re-acquirelockandstartover*///重新获取锁并启动LWLockAcquire(XidGenLock,LW_EXCLUSIVE);xid=ShmemVariableCache->nextXid;}/**IfweareallocatingthefirstXIDofanewpageofthecommitlog,*zerooutthatcommit-logpagebeforereturning.Wemustdothiswhile*holdingXidGenLock,elseanotherxactcouldacquireandcommitalater*XIDbeforewezerothepage.Fortunately,apageofthecommitlog*holds32Kormoretransactions,sowedon'thavetodothisveryoften.*如果在clog的新page中分配第一个XID,返回前初始化clogpage.*必须在持有XidGenLock锁时执行这个操作,否则的话,*其他事务可能会请求该锁并在初始化page前提交了一个新事务.*幸运的是,提交日志的一个页面包含32K或更多的事务,所以我们不需要经常这样做。**Extendpg_subtransandpg_commit_tstoo.*同时扩展pg_subtrans和pg_commit_ts*/ExtendCLOG(xid);ExtendCommitTs(xid);ExtendSUBTRANS(xid);/**NowadvancethenextXidcounter.Thismustnothappenuntilafterwe*havesuccessfullycompletedExtendCLOG()---ifthatroutinefails,we*wantthenextincomingtransactiontotryitagain.Wecannotassign*moreXIDsuntilthereisCLOGspaceforthem.*现在可以更新nextXid计数器了.*这必须在我们成功完成ExtendCLOG()之后才能执行——如果该例程失败,*我们希望下一个进入的事务再次尝试。*不能分配更多的xid,除非有空闲的CLOG空间。*///ShmemVariableCache->nextXid++//if((ShmemVariableCache->nextXid)<FirstNormalTransactionId)//(ShmemVariableCache->nextXid)=FirstNormalTransactionId;TransactionIdAdvance(ShmemVariableCache->nextXid);/**WemuststorethenewXIDintothesharedProcArraybeforereleasing*XidGenLock.ThisensuresthateveryactiveXIDolderthan*latestCompletedXidispresentintheProcArray,whichisessentialfor*correctOldestXmintracking;seesrc/backend/access/transam/README.*在释放XidGenLock前,存储新的XID到共享数据结构ProcArray中.*这可以确保每一个活动的比latestCompletedXid旧的XID都会出现在ProcArray中,*这样可以减少OldestXmin的跟踪,请查看src/backend/access/transam/README.**NotethatreadersofPGXACTxidfieldsshouldbecarefultofetchthe*valueonlyonce,ratherthanassumetheycanreadavaluemultiple*timesandgetthesameanswereachtime.Noteweareassumingthat*TransactionIdandintfetch/storeareatomic.*要注意的是读取PGXACT.xid字段时小心只提取一次,*而不是假定可以多次读取该值而认为每次返回的值都一样.*同时我们假定TransactionId和int提取/写入是原子的.**Thesamecommentsapplytothesubxactxidcountandoverflowfields.*对于subxactxid计数器和溢出字段,参见上述注释.**Useofawritebarrierpreventsdangerouscoderearrangementinthis*function;otherbackendscouldotherwisee.g.beexaminingmysubxids*infoconcurrently,andwedon'twantthemtoseeaninvalid*intermediatestate,suchasanincrementednxidsbeforethearrayentry*isfilled.*在该函数中,进入堡垒进行写可以防止危险的事情出现.*否则其他后台进程可能会比如同步检查本进程的subxids信息,但我们不希望它们看到无效的中间状态,*例如,在数组条目被填充之前增加nxid。**Otherprocessesthatreadnxidsshoulddosobeforereadingxids*elementswithapg_read_barrier()inbetween,sothattheycanbesure*nottoreadanuninitializedarrayelement;see*src/backend/storage/lmgr/README.barrier.*其他读取nxids的进程应在使用pg_read_barrier()函数读取xids条目前执行相关操作,*这样可以确保它们不会读取到未经初始化的数组条目,查看src/backend/storage/lmgr/README.barrier说明.**Ifthere'snoroomtofitasubtransactionXIDintoPGPROC,setthe*cache-overflowedflaginstead.Thisforcesreaderstolookin*pg_subtranstomapsubtransactionXIDsuptotop-levelXIDs.Thereisa*race-conditionwindow,inthatthenewXIDwillnotappearasrunning*untilitsparentlinkhasbeenplacedintopg_subtrans.However,that*willhappenbeforeanyonecouldpossiblyhaveareasontoinquireabout*thestatusoftheXID,soitseemsOK.(Snapshotstakenduringthis*window*will*includetheparentXID,sotheywilldeliverthecorrect*answerlateronwhensomeonedoeshaveareasontoinquire.)*如果没有空间将子事务XID放入PGPROC中,则设置cache-overflow标志。*这可以强制readers查看pg_subtrans以将子事务xid映射到顶层xid。*有一个race-condition窗口,在它的父链接被放入pg_subtrans之前,新的XID不会显示为正在运行.*然而,在都有可能有理由查询XID的状态之前,这种情况就会发生,所以看起来是可以的。*(在这个窗口中拍摄的快照*将*包含父XID,因此当稍后有进程查询时,它们将提供正确的答案。)*/if(!isSubXact)MyPgXact->xid=xid;/*LWLockReleaseactsasbarrier*/else{intnxids=MyPgXact->nxids;if(nxids<PGPROC_MAX_CACHED_SUBXIDS){MyProc->subxids.xids[nxids]=xid;pg_write_barrier();MyPgXact->nxids=nxids+1;}elseMyPgXact->overflowed=true;}//释放锁LWLockRelease(XidGenLock);returnxid;}三、跟踪分析

执行txid_current,触发函数调用

14:26:26(xdb@[local]:5432)testdb=#begin;BEGIN14:26:50(xdb@[local]:5432)testdb=#*selecttxid_current_if_assigned();txid_current_if_assigned--------------------------(1row)14:26:55(xdb@[local]:5432)testdb=#*selecttxid_current();

启动gdb,设置断点

(gdb)bGetNewTransactionIdBreakpoint6at0x545e80:filevarsup.c,line56.(gdb)cContinuing.Breakpoint6,GetNewTransactionId(isSubXact=false)atvarsup.c:5656if(IsInParallelMode())(gdb)

查看调用栈

(gdb)bt#0GetNewTransactionId(isSubXact=false)atvarsup.c:56#10x0000000000546bd9inAssignTransactionId(s=0xf9c720<TopTransactionStateData>)atxact.c:557#20x000000000054693dinGetTopTransactionId()atxact.c:392#30x00000000009fe1f3intxid_current(fcinfo=0x254c7e0)attxid.c:443#40x00000000006cfebdinExecInterpExpr(state=0x254c6f8,econtext=0x254c3e8,isnull=0x7ffe3d4a31f7)atexecExprInterp.c:654#50x00000000006d1ac6inExecInterpExprStillValid(state=0x254c6f8,econtext=0x254c3e8,isNull=0x7ffe3d4a31f7)atexecExprInterp.c:1786#60x00000000007140ddinExecEvalExprSwitchContext(state=0x254c6f8,econtext=0x254c3e8,isNull=0x7ffe3d4a31f7)at../../../src/include/executor/executor.h:303#70x000000000071414binExecProject(projInfo=0x254c6f0)at../../../src/include/executor/executor.h:337#80x0000000000714323inExecResult(pstate=0x254c2d0)atnodeResult.c:136#90x00000000006e4c30inExecProcNodeFirst(node=0x254c2d0)atexecProcnode.c:445#100x00000000006d9974inExecProcNode(node=0x254c2d0)at../../../src/include/executor/executor.h:237#110x00000000006dc22dinExecutePlan(estate=0x254c0b8,planstate=0x254c2d0,use_parallel_mode=false,operation=CMD_SELECT,sendTuples=true,numberTuples=0,direction=ForwardScanDirection,dest=0x24ccf10,execute_once=true)atexecMain.c:1723#120x00000000006d9f5cinstandard_ExecutorRun(queryDesc=0x256b8e8,direction=ForwardScanDirection,count=0,execute_once=true)atexecMain.c:364#130x00000000006d9d7finExecutorRun(queryDesc=0x256b8e8,direction=ForwardScanDirection,count=0,execute_once=true)atexecMain.c:307#140x00000000008ccf5ainPortalRunSelect(portal=0x250c860,forward=true,count=0,dest=0x24ccf10)atpquery.c:932#150x00000000008ccbf3inPortalRun(portal=0x250c860,count=9223372036854775807,isTopLevel=true,run_once=true,dest=0x24ccf10,altdest=0x24ccf10,completionTag=0x7ffe3d4a3570"")atpquery.c:773#160x00000000008c6b1einexec_simple_query(query_string=0x24a6ec8"selecttxid_current();")atpostgres.c:1145#170x00000000008cae70inPostgresMain(argc=1,argv=0x24d2dc8,dbname=0x24d2c30"testdb",username=0x24a3ba8"xdb")atpostgres.c:4182---Type<return>tocontinue,orq<return>toquit---#180x000000000082642binBackendRun(port=0x24c8c00)atpostmaster.c:4361#190x0000000000825b8finBackendStartup(port=0x24c8c00)atpostmaster.c:4033#200x0000000000821f1cinServerLoop()atpostmaster.c:1706#210x00000000008217b4inPostmasterMain(argc=1,argv=0x24a1b60)atpostmaster.c:1379#220x00000000007488efinmain(argc=1,argv=0x24a1b60)atmain.c:228(gdb)

获取XidGenLock锁

(gdb)n63if(IsBootstrapProcessingMode())(gdb)71if(RecoveryInProgress())(gdb)74LWLockAcquire(XidGenLock,LW_EXCLUSIVE);(gdb)

获取共享内存变量ShmemVariableCache->nextXid —> 2409

(gdb)76xid=ShmemVariableCache->nextXid;(gdb)91if(TransactionIdFollowsOrEquals(xid,ShmemVariableCache->xidVacLimit))(gdb)p*ShmemVariableCache$16={nextOid=42628,oidCount=8191,nextXid=2409,oldestXid=561,xidVacLimit=200000561,xidWarnLimit=2136484208,xidStopLimit=2146484208,xidWrapLimit=2147484208,oldestXidDB=16400,oldestCommitTsXid=0,newestCommitTsXid=0,latestCompletedXid=2408,oldestClogXid=561}(gdb)

扩展clog

(gdb)n171ExtendCLOG(xid);(gdb)172ExtendCommitTs(xid);(gdb)173ExtendSUBTRANS(xid);(gdb)181TransactionIdAdvance(ShmemVariableCache->nextXid);(gdb)

ShmemVariableCache->nextXid++ —> 2410

(gdb)pShmemVariableCache->nextXid$17=2410

获取进程和事务信息

(gdb)n223volatilePGXACT*mypgxact=MyPgXact;(gdb)225if(!isSubXact)(gdb)226mypgxact->xid=xid;(gdb)

释放锁XidGenLock

(gdb)241LWLockRelease(XidGenLock);(gdb)p*ShmemVariableCache$18={nextOid=42628,oidCount=8191,nextXid=2410,oldestXid=561,xidVacLimit=200000561,xidWarnLimit=2136484208,xidStopLimit=2146484208,xidWrapLimit=2147484208,oldestXidDB=16400,oldestCommitTsXid=0,newestCommitTsXid=0,latestCompletedXid=2408,oldestClogXid=561}

返回xid(2409),完成调用.

(gdb)n243returnxid;(gdb)244}(gdb)AssignTransactionId(s=0xf9c720<TopTransactionStateData>)atxact.c:558558if(!isSubXact)(gdb)

以上是“PostgreSQL如何获取事务号XID”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!