PostgreSQL中PGPROC数据结构分析
本篇内容介绍了“PostgreSQL中PGPROC数据结构分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
一、数据结构宏定义
/**Note:MAX_BACKENDSislimitedto2^18-1becausethat'sthewidthreserved*forbufferreferencesinbuf_internals.h.Thislimitationcouldbelifted*byusinga64bitstate;butit'sunlikelytobeworthwhileas2^18-1*backendsexceedcurrentlyrealisticconfigurations.Evenifthatlimitation*wereremoved,westillcouldnota)exceed2^23-1becauseinval.cstores*thebackendIDasa3-bytesignedinteger,b)INT_MAX/4becausesomeplaces*compute4*MaxBackendswithoutanyoverflowcheck.Thisisrecheckedinthe*relevantGUCcheckhooksandinRegisterBackgroundWorker().*注意:MAX_BACKENDS限制为2^18-1,*这是因为该值为buf_internals.h中定义的缓存依赖的最大宽度.*该限制可以通过使用64bit的状态来提升,但它看起来并不值当.*如果去掉该限制,我们仍然不能够超过:*a)2^23-1,因为inval.c使用3个字节的有符号整数存储后台进程ID*b)INT_MAX/4,因为某些地方没有任何的溢出检查,直接计算4*MaxBackends的值.*该值会在相关的GUC检查钩子和RegisterBackgroundWorker()函数中检查.*/#defineMAX_BACKENDS0x3FFFF/*shmqueue.c*/typedefstructSHM_QUEUE{structSHM_QUEUE*prev;structSHM_QUEUE*next;}SHM_QUEUE;/**Aninvalidpgprocno.MustbelargerthanthemaximumnumberofPGPROC*structureswecouldpossiblyhave.SeecommentsforMAX_BACKENDS.*无效的pg进程号.*必须大于我们可能拥有的最大的PGPROC数目.*详细解释见MAX_BACKENDS*/#defineINVALID_PGPROCNOPG_INT32_MAX
LWLock
lwlock.c外的代码不应直接操作这个结构的内容,但我们必须声明该结构体以便将LWLocks合并到其他数据结构中。
/**Codeoutsideoflwlock.cshouldnotmanipulatethecontentsofthis*structuredirectly,butwehavetodeclareitheretoallowLWLockstobe*incorporatedintootherdatastructures.*lwlock.c外的代码不应直接操作这个结构的内容,*但我们必须声明该结构体以便将LWLocks合并到其他数据结构中。*/typedefstructLWLock{uint16tranche;/*trancheID*///独占/非独占locker的状态pg_atomic_uint32state;/*stateofexclusive/nonexclusivelockers*///正在等待的PGPROCs链表proclist_headwaiters;/*listofwaitingPGPROCs*/#ifdefLOCK_DEBUG//用于DEBUG//waiters的数量pg_atomic_uint32nwaiters;/*numberofwaiters*///锁的最后独占者structPGPROC*owner;/*lastexclusiveownerofthelock*/#endif}LWLock;
PGPROC
每个后台进程在共享内存中都有一个PGPROC结构体.
全局上也存在未使用的PGPROC结构体链表,用于重用以便为新的后台进程进行分配.
该数据结构的作用是:
PostgreSQL backend processes can't see each other's memory directly, nor can the postmaster see into PostgreSQL backend process memory. Yet they need some way to communicate and co-ordinate, and the postmaster needs a way to keep track of them.
简单来说作用是为了进程间协同和通讯以及postmaster的跟踪.
/**EachbackendhasaPGPROCstructinsharedmemory.Thereisalsoalistof*currently-unusedPGPROCstructsthatwillbereallocatedtonewbackends.*每个后台进程在共享内存中都有一个PGPROC结构体.*存在未使用的PGPROC结构体链表,用于为新的后台进程重新进行分配.**links:listlinkforanylistthePGPROCisin.Whenwaitingforalock,*thePGPROCislinkedintothatlock'swaitProcsqueue.ArecycledPGPROC*islinkedintoProcGlobal'sfreeProcslist.*links:PGPROC所在的链表的链接.*在等待锁时,PGPROC链接到该锁的waiProc队列中.*回收的PGPROC链接到ProcGlobal的freeProcs链表中.**Note:twophase.calsosetsupadummyPGPROCstructforeachcurrently*preparedtransaction.ThesePGPROCsappearintheProcArraydatastructure*sothatthepreparedtransactionsappeartobestillrunningandare*correctlyshownasholdinglocks.ApreparedtransactionPGPROCcanbe*distinguishedfromarealoneatneedbythefactthatithaspid==0.*Thesemaphoreandlock-activityfieldsinaprepared-xactPGPROCareunused,*butitsmyProcLocks[]listsarevalid.*注意:twophase.c也会为每一个当前已准备妥当的事务配置一个虚拟的PGPROC结构.*这些PGPROCs在数组ProcArray数据结构中出现,以便已准备的事务看起来仍在运行,*并正确的显示为持有锁.*已准备妥当的事务PGPROC与一个真正的PGPROC事实上的区别是pid==0.*在prepared-xactPGPROC中的信号量和活动锁域字段没有使用,但myProcLocks[]链表是有效的.*/structPGPROC{/*proc->linksMUSTBEFIRSTINSTRUCT(seeProcSleep,ProcWakeup,etc)*///proc->links必须是结构体的第一个域(参考ProcSleep,ProcWakeup...等)//如进程在链表中,这是链表的链接SHM_QUEUElinks;/*listlinkifprocessisinalist*///持有该PGPROC的procglobal链表数组PGPROC**procgloballist;/*procgloballistthatownsthisPGPROC*///可以休眠的信号量PGSemaphoresem;/*ONEsemaphoretosleepon*///状态为:STATUS_WAITING,STATUS_OKorSTATUS_ERRORintwaitStatus;/*STATUS_WAITING,STATUS_OKorSTATUS_ERROR*///进程通用的latchLatchprocLatch;/*genericlatchforprocess*///运行中的进程正在执行的最高层的事务本地ID,如无运行则为InvalidLocalTransactionIdLocalTransactionIdlxid;/*localidoftop-leveltransactioncurrently*beingexecutedbythisproc,ifrunning;*elseInvalidLocalTransactionId*///后台进程的ID,如为虚拟事务则为0intpid;/*Backend'sprocessID;0ifpreparedxact*/intpgprocno;/*Thesefieldsarezerowhileabackendisstillstartingup:*///------------这些域在进程正在启动时为0//已分配的后台进程的backendIDBackendIdbackendId;/*Thisbackend'sbackendID(ifassigned)*///该进程使用的数据库IDOiddatabaseId;/*OIDofdatabasethisbackendisusing*///使用该进程的角色IDOidroleId;/*OIDofroleusingthisbackend*///该进程使用的临时schemaOIDOidtempNamespaceId;/*OIDoftempschemathisbackendis*using*///如后台进程,则为TboolisBackgroundWorker;/*trueifbackgroundworker.*//**Whileinhotstandbymode,showsthataconflictsignalhasbeensent*forthecurrenttransaction.Set/clearedwhileholdingProcArrayLock,*thoughnotrequired.Accessedwithoutlock,ifneeded.*如在hotstandby模式,显示已为当前事务发送冲突信号.*尽管不需要,设置/清除持有的ProcArrayLock.*如需要,则在没有持有锁的情况下访问.*/boolrecoveryConflictPending;/*InfoaboutLWLocktheprocessiscurrentlywaitingfor,ifany.*///--------------进程正在等待的LWLock相关信息//等待LWlock,为TboollwWaiting;/*trueifwaitingforanLWlock*///正在等的LWLock锁模式uint8lwWaitMode;/*lwlockmodebeingwaitedfor*///等待链表中的位置proclist_nodelwWaitLink;/*positioninLWlockwaitlist*//*Supportforconditionvariables.*///--------------支持条件变量//CV等待链表中的位置proclist_nodecvWaitLink;/*positioninCVwaitlist*//*Infoaboutlocktheprocessiscurrentlywaitingfor,ifany.*///--------------进程正在等待的锁信息/*waitLockandwaitProcLockareNULLifnotcurrentlywaiting.*///如没有在等待,则waitLock和waitProcLock为NULL//休眠...等待的锁对象LOCK*waitLock;/*Lockobjectwe'resleepingon...*///等待锁的每个持锁人信息PROCLOCK*waitProcLock;/*Per-holderinfoforawaitedlock*///等待的所类型LOCKMODEwaitLockMode;/*typeoflockwe'rewaitingfor*///该进程已持有锁的类型位掩码LOCKMASKheldLocks;/*bitmaskforlocktypesalreadyheldonthis*lockobjectbythisbackend*//**Infotoallowustowaitforsynchronousreplication,ifneeded.*waitLSNisInvalidXLogRecPtrifnotwaiting;setonlybyuserbackend.*syncRepStatemustnotbetouchedexceptbyowningprocessorWALSender.*syncRepLinksusedonlywhileholdingSyncRepLock.*允许我们等待同步复制的相关信息.*如无需等待,则waitLSN为InvalidXLogRecPtr;仅允许由用户后台设置。*除非拥有process或WALSender,否则不能修改syncRepState。*仅在持有SyncRepLock时使用的syncrepink。*///---------------------//等待该LSN或者更高的LSNXLogRecPtrwaitLSN;/*waitingforthisLSNorhigher*///同步复制的等待状态intsyncRepState;/*waitstateforsyncrep*///如进程处于syncrep队列中,则该值保存链表链接SHM_QUEUEsyncRepLinks;/*listlinkifprocessisinsyncrepqueue*//**AllPROCLOCKobjectsforlocksheldorawaitedbythisbackendare*linkedintooneoftheselists,accordingtothepartitionnumberof*theirlock.*该后台进程持有或等待的锁相关的所有PROCLOCK对象链接在这些链表的末尾,*根据棣属于这些锁的分区号进行区分.*/SHM_QUEUEmyProcLocks[NUM_LOCK_PARTITIONS];//子事务的XIDsstructXidCachesubxids;/*cacheforsubtransactionXIDs*//*SupportforgroupXIDclearing.*//*true,ifmemberofProcArraygroupwaitingforXIDclear*///支持XID分组清除//如属于等待XID清理的ProcArray组,则为TboolprocArrayGroupMember;/*nextProcArraygroupmemberwaitingforXIDclear*///等待XID清理的下一个ProcArray组编号pg_atomic_uint32procArrayGroupNext;/**latesttransactionidamongthetransaction'smainXIDand*subtransactions*在事务主XID和子事务之间的最后的事务ID*/TransactionIdprocArrayGroupMemberXid;//进程的等待信息uint32wait_event_info;/*proc'swaitinformation*//*Supportforgrouptransactionstatusupdate.*///---------------支持组事务状态更新//clog组成员,则为TboolclogGroupMember;/*true,ifmemberofcloggroup*///下一个clog组成员pg_atomic_uint32clogGroupNext;/*nextcloggroupmember*///clog组成员事务IDTransactionIdclogGroupMemberXid;/*transactionidofcloggroupmember*///clog组成员的事务状态XidStatusclogGroupMemberXidStatus;/*transactionstatusofclog*groupmember*///属于clog组成员的事务ID的clogpageintclogGroupMemberPage;/*clogpagecorrespondingto*transactionidofcloggroupmember*///clog组成员已提交记录的WAL位置XLogRecPtrclogGroupMemberLsn;/*WALlocationofcommitrecordforclog*groupmember*//*Per-backendLWLock.Protectsfieldsbelow(butnotgroupfields).*///每一个后台进程一个LWLock.保护下面的域字段(非组字段)LWLockbackendLock;/*Lockmanagerdata,recordingfast-pathlockstakenbythisbackend.*///----------锁管理数据,记录该后台进程以最快路径获得的锁//每一个fast-pathslot的锁模式uint64fpLockBits;/*lockmodesheldforeachfast-pathslot*///reloids的slotsOidfpRelId[FP_LOCK_SLOTS_PER_BACKEND];/*slotsforreloids*///是否持有fast-pathVXID锁boolfpVXIDLock;/*areweholdingafast-pathVXIDlock?*///fast-pathVXID锁的lxidLocalTransactionIdfpLocalTransactionId;/*lxidforfast-pathVXID*lock*//**Supportforlockgroups.UseLockHashPartitionLockByProconthegroup*leadertogettheLWLockprotectingthesefields.*///---------支持锁组.//在组leader中使用LockHashPartitionLockByProc获取LWLock保护这些域//锁组的leader,如果"我"是其中一员PGPROC*lockGroupLeader;/*lockgroupleader,ifI'mamember*///如果"我"是leader,这是成员的链表dlist_headlockGroupMembers;/*listofmembers,ifI'maleader*///成员连接,如果"我"是其中一员dlist_nodelockGroupLink;/*mymemberlink,ifI'mamember*/};
MyProc
每个进程都有一个全局变量:MyProc
externPGDLLIMPORTPGPROC*MyProc;externPGDLLIMPORTstructPGXACT*MyPgXact;二、源码解读
N/A
三、跟踪分析启动两个Session,执行同样的SQL语句:
insertintot_wal_partition(c1,c2,c3)VALUES(0,'HASH0','HAHS0');
Session 1
启动gdb,开启跟踪
(gdb)bXLogInsertRecordBreakpoint1at0x54d122:filexlog.c,line970.(gdb)cContinuing.Breakpoint1,XLogInsertRecord(rdata=0xf9cc70<hdr_rdt>,fpw_lsn=0,flags=1'\001')atxlog.c:970970XLogCtlInsert*Insert=&XLogCtl->Insert;
查看内存中的数据结构
(gdb)p*MyProc$3={links={prev=0x0,next=0x0},procgloballist=0x7fa79c087c98,sem=0x7fa779fc81b8,waitStatus=0,procLatch={is_set=0,is_shared=true,owner_pid=1398},lxid=3,pid=1398,pgprocno=99,backendId=3,databaseId=16402,roleId=10,tempNamespaceId=0,isBackgroundWorker=false,recoveryConflictPending=false,lwWaiting=false,lwWaitMode=0'\000',lwWaitLink={next=0,prev=0},cvWaitLink={next=0,prev=0},waitLock=0x0,waitProcLock=0x0,waitLockMode=0,heldLocks=0,waitLSN=0,syncRepState=0,syncRepLinks={prev=0x0,next=0x0},myProcLocks={{prev=0x7fa79c09c588,next=0x7fa79c09c588},{prev=0x7fa79c09c598,next=0x7fa79c09c598},{prev=0x7fa79c09c5a8,next=0x7fa79c09c5a8},{prev=0x7fa79c09c5b8,next=0x7fa79c09c5b8},{prev=0x7fa79c09c5c8,next=0x7fa79c09c5c8},{prev=0x7fa79c09c5d8,next=0x7fa79c09c5d8},{prev=0x7fa79c09c5e8,next=0x7fa79c09c5e8},{prev=0x7fa79c09c5f8,next=0x7fa79c09c5f8},{prev=0x7fa79c09c608,next=0x7fa79c09c608},{prev=0x7fa79c09c618,next=0x7fa79c09c618},{prev=0x7fa79c09c628,next=0x7fa79c09c628},{prev=0x7fa79c09c638,next=0x7fa79c09c638},{prev=0x7fa79c09c648,next=0x7fa79c09c648},{prev=0x7fa79c09c658,next=0x7fa79c09c658},{prev=0x7fa79c09c668,next=0x7fa79c09c668},{prev=0x7fa79be25e70,next=0x7fa79be25e70}},subxids={xids={0<repeats64times>}},procArrayGroupMember=false,procArrayGroupNext={value=2147483647},procArrayGroupMemberXid=0,wait_event_info=0,clogGroupMember=false,clogGroupNext={value=2147483647},clogGroupMemberXid=0,clogGroupMemberXidStatus=0,clogGroupMemberPage=-1,clogGroupMemberLsn=0,backendLock={tranche=58,state={value=536870912},waiters={head=2147483647,tail=2147483647}},fpLockBits=196027139227648,fpRelId={0,0,0,0,0,2679,2610,2680,2611,17043,17040,17037,17034,17031,17028,17025},fpVXIDLock=true,fpLocalTransactionId=3,lockGroupLeader=0x0,lockGroupMembers={head={prev=0x7fa79c09c820,next=0x7fa79c09c820}},lockGroupLink={prev=0x0,next=0x0}}
注意:lwWaiting值为false,表示没有在等待LW Lock
Session 2
启动gdb,开启跟踪
(gdb)bheap_insertBreakpoint2at0x4df4d1:fileheapam.c,line2449.(gdb)cContinuing.^CProgramreceivedsignalSIGINT,Interrupt.0x00007fa7a7ee7a0binfutex_abstimed_wait(cancel=true,private=<optimizedout>,abstime=0x0,expected=0,futex=0x7fa779fc8138)at../nptl/sysdeps/unix/sysv/linux/sem_waitcommon.c:4343err=lll_futex_wait(futex,expected,private);
暂无法进入heap_insert
查看内存中的数据结构
(gdb)p*MyProc$36={links={prev=0x0,next=0x0},procgloballist=0x7fa79c087c98,sem=0x7fa779fc8138,waitStatus=0,procLatch={is_set=1,is_shared=true,owner_pid=1449},lxid=13,pid=1449,pgprocno=98,backendId=4,databaseId=16402,roleId=10,tempNamespaceId=0,isBackgroundWorker=false,recoveryConflictPending=false,lwWaiting=true,lwWaitMode=0'\000',lwWaitLink={next=114,prev=2147483647},cvWaitLink={next=0,prev=0},waitLock=0x0,waitProcLock=0x0,waitLockMode=0,heldLocks=0,waitLSN=0,syncRepState=0,syncRepLinks={prev=0x0,next=0x0},myProcLocks={{prev=0x7fa79c09c238,next=0x7fa79c09c238},{prev=0x7fa79c09c248,next=0x7fa79c09c248},{prev=0x7fa79c09c258,next=0x7fa79c09c258},{prev=0x7fa79c09c268,next=0x7fa79c09c268},{prev=0x7fa79c09c278,next=0x7fa79c09c278},{prev=0x7fa79c09c288,next=0x7fa79c09c288},{prev=0x7fa79c09c298,next=0x7fa79c09c298},{prev=0x7fa79c09c2a8,next=0x7fa79c09c2a8},{prev=0x7fa79c09c2b8,next=0x7fa79c09c2b8},{prev=0x7fa79c09c2c8,next=0x7fa79c09c2c8},{prev=0x7fa79c09c2d8,next=0x7fa79c09c2d8},{prev=0x7fa79c09c2e8,next=0x7fa79c09c2e8},{prev=0x7fa79c09c2f8,next=0x7fa79c09c2f8},{prev=0x7fa79c09c308,next=0x7fa79c09c308},{prev=0x7fa79be21870,next=0x7fa79be21870},{prev=0x7fa79c09c328,next=0x7fa79c09c328}},subxids={xids={0<repeats64times>}},procArrayGroupMember=false,procArrayGroupNext={value=2147483647},procArrayGroupMemberXid=0,wait_event_info=16777270,clogGroupMember=false,clogGroupNext={value=2147483647},clogGroupMemberXid=0,clogGroupMemberXidStatus=0,clogGroupMemberPage=-1,clogGroupMemberLsn=0,backendLock={tranche=58,state={value=536870912},waiters={head=2147483647,tail=2147483647}},fpLockBits=196027139227648,fpRelId={0,0,0,0,0,2655,2603,2680,2611,17043,17040,17037,17034,17031,17028,17025},fpVXIDLock=true,fpLocalTransactionId=13,lockGroupLeader=0x0,lockGroupMembers={head={prev=0x7fa79c09c4d0,next=0x7fa79c09c4d0}},lockGroupLink={prev=0x0,next=0x0}}
注意:
lwWaiting值为true,正在等待Session 1的LWLock.
lwWaitLink = {next = 114, prev = 2147483647},其中next = 114,这里的114是指全局变量ProcGlobal(类型为PROC_HDR)->allProcs数组下标为114的ITEM.
(gdb)pProcGlobal->allProcs[114]$41={links={prev=0x0,next=0x0},procgloballist=0x0,sem=0x7fa779fc8938,waitStatus=0,procLatch={is_set=0,is_shared=true,owner_pid=1351},lxid=0,pid=1351,pgprocno=114,backendId=-1,databaseId=0,roleId=0,tempNamespaceId=0,isBackgroundWorker=false,recoveryConflictPending=false,lwWaiting=true,lwWaitMode=1'\001',lwWaitLink={next=2147483647,prev=98},cvWaitLink={next=0,prev=0},waitLock=0x0,waitProcLock=0x0,waitLockMode=0,heldLocks=0,waitLSN=0,syncRepState=0,syncRepLinks={prev=0x0,next=0x0},myProcLocks={{prev=0x7fa79c09f738,next=0x7fa79c09f738},{prev=0x7fa79c09f748,next=0x7fa79c09f748},{prev=0x7fa79c09f758,next=0x7fa79c09f758},{prev=0x7fa79c09f768,next=0x7fa79c09f768},{prev=0x7fa79c09f778,next=0x7fa79c09f778},{prev=0x7fa79c09f788,next=0x7fa79c09f788},{prev=0x7fa79c09f798,next=0x7fa79c09f798},{prev=0x7fa79c09f7a8,next=0x7fa79c09f7a8},{prev=0x7fa79c09f7b8,next=0x7fa79c09f7b8},{prev=0x7fa79c09f7c8,next=0x7fa79c09f7c8},{prev=0x7fa79c09f7d8,next=0x7fa79c09f7d8},{prev=0x7fa79c09f7e8,next=0x7fa79c09f7e8},{prev=0x7fa79c09f7f8,next=0x7fa79c09f7f8},{prev=0x7fa79c09f808,next=0x7fa79c09f808},{prev=0x7fa79c09f818,next=0x7fa79c09f818},{prev=0x7fa79c09f828,next=0x7fa79c09f828}},subxids={xids={0<repeats64times>}},procArrayGroupMember=false,procArrayGroupNext={value=0},procArrayGroupMemberXid=0,wait_event_info=16777270,clogGroupMember=false,clogGroupNext={value=0},clogGroupMemberXid=0,clogGroupMemberXidStatus=0,clogGroupMemberPage=0,clogGroupMemberLsn=0,backendLock={tranche=58,state={value=536870912},waiters={head=2147483647,tail=2147483647}},fpLockBits=0,fpRelId={0<repeats16times>},fpVXIDLock=false,fpLocalTransactionId=0,lockGroupLeader=0x0,lockGroupMembers={head={prev=0x7fa79c09f9d0,next=0x7fa79c09f9d0}},lockGroupLink={prev=0x0,next=0x0}}
“PostgreSQL中PGPROC数据结构分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。