PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析
本篇内容主要讲解“PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析”吧!
一、数据结构宏定义
Vacuum和Analyze命令选项
/*----------------------*VacuumandAnalyzeStatements*Vacuum和Analyze命令选项**Eventhoughthesearenominallytwostatements,it'sconvenienttouse*justonenodetypeforboth.NotethatatleastoneofVACOPT_VACUUM*andVACOPT_ANALYZEmustbesetinoptions.*虽然在这里有两种不同的语句,但只需要使用统一的Node类型即可.*注意至少VACOPT_VACUUM/VACOPT_ANALYZE在选项中设置.*----------------------*/typedefenumVacuumOption{VACOPT_VACUUM=1<<0,/*doVACUUM*/VACOPT_ANALYZE=1<<1,/*doANALYZE*/VACOPT_VERBOSE=1<<2,/*printprogressinfo*/VACOPT_FREEZE=1<<3,/*FREEZEoption*/VACOPT_FULL=1<<4,/*FULL(non-concurrent)vacuum*/VACOPT_SKIP_LOCKED=1<<5,/*skipifcannotgetlock*/VACOPT_SKIPTOAST=1<<6,/*don'tprocesstheTOASTtable,ifany*/VACOPT_DISABLE_PAGE_SKIPPING=1<<7/*don'tskipanypages*/}VacuumOption;二、源码解读
HeapTupleSatisfiesVacuum
HeapTupleSatisfiesVacuum为VACUUM操作确定元组的状态.在这里,我们主要想知道的是一个元组是否可对所有正在运行中的事务可见.如可见,则不能通过VACUUM删除该元组.
主要处理流程如下:
0.获取tuple并执行相关校验
1.条件:插入事务未提交
1.1条件:无效的xmin,该元组已废弃可删除
1.2条件:旧版本(9.0-)的判断
1.3条件:xmin为当前事务ID
1.4条件:插入事务非当前事务,正在进行中
1.5条件:xmin事务确实已提交(通过clog判断)
1.6条件:其他情况
— 至此,可以确定xmin已提交
2.条件:xmax是无效的事务ID,直接返回LIVE
3.条件:xmax只是锁定
3.1条件:xmax事务未提交,分多事务&非多事务进行判断
3.2条件:只是锁定,返回LIVE
4.条件:存在子事务
4.1条件:xmax正在进行,返回事务进行中
4.2条件:xmax已提交,区分xmax在OldestXmin之前还是之后
4.3条件:xmax不在运行中/没有提交/没有回滚或崩溃,则设置xmax为无效事务ID
4.4默认返回LIVE
5.条件:xmax没有提交
5.1条件:删除过程中
5.2条件:通过clog判断,该事务已提交,设置事务标记位
5.3条件:其他情况,设置为无效事务ID
5.4默认返回LIVE
— 至此,可以确定xmax已提交
6.元组xmax≥OldestXmin,最近删除
7.默认元组已DEAD
/**HeapTupleSatisfiesVacuum**DeterminethestatusoftuplesforVACUUMpurposes.Here,what*wemainlywanttoknowisifatupleispotentiallyvisibleto*any**runningtransaction.Ifso,itcan'tberemovedyetbyVACUUM.*为VACUUM确定元组的状态.*在这里,我们主要想知道的是一个元组是否可对所有正在运行中的事务可见.*如可见,则不能通过VACUUM删除该元组.**OldestXminisacutoffXID(obtainedfromGetOldestXmin()).Tuples*deletedbyXIDs>=OldestXminaredeemed"recentlydead";theymight*stillbevisibletosomeopentransaction,sowecan'tremovethem,*evenifweseethatthedeletingtransactionhascommitted.*OldestXmin是一个cutoffXID(通过GetOldestXmin函数获得).*通过XIDs>=OldestXmin删除的元组被视为"最近死亡",它们可能仍然对某些正在进行中的事务可见,*因此就算删除事务已提交,我们仍然不能清除它们.*/HTSV_ResultHeapTupleSatisfiesVacuum(HeapTuplehtup,TransactionIdOldestXmin,Bufferbuffer){//获取tupleHeapTupleHeadertuple=htup->t_data;//校验Assert(ItemPointerIsValid(&htup->t_self));Assert(htup->t_tableOid!=InvalidOid);/**Hasinsertingtransactioncommitted?*插入事务已提交?**Iftheinsertingtransactionaborted,thenthetuplewasnevervisible*toanyothertransaction,sowecandeleteitimmediately.*如果插入事务已回滚,元组对其他事务均不可见,因此可以马上删除.*/if(!HeapTupleHeaderXminCommitted(tuple)){//1.插入事务未提交if(HeapTupleHeaderXminInvalid(tuple))//1-1.无效的xmin,该元组已废弃可删除returnHEAPTUPLE_DEAD;/*Usedbypre-9.0binaryupgrades*///用于9.0以前版本的升级,HEAP_MOVED_OFF&HEAP_MOVED_IN已不再使用elseif(tuple->t_infomask&HEAP_MOVED_OFF){TransactionIdxvac=HeapTupleHeaderGetXvac(tuple);if(TransactionIdIsCurrentTransactionId(xvac))returnHEAPTUPLE_DELETE_IN_PROGRESS;if(TransactionIdIsInProgress(xvac))returnHEAPTUPLE_DELETE_IN_PROGRESS;if(TransactionIdDidCommit(xvac)){SetHintBits(tuple,buffer,HEAP_XMIN_INVALID,InvalidTransactionId);returnHEAPTUPLE_DEAD;}SetHintBits(tuple,buffer,HEAP_XMIN_COMMITTED,InvalidTransactionId);}/*Usedbypre-9.0binaryupgrades*///用于9.0以前版本的升级elseif(tuple->t_infomask&HEAP_MOVED_IN){TransactionIdxvac=HeapTupleHeaderGetXvac(tuple);if(TransactionIdIsCurrentTransactionId(xvac))returnHEAPTUPLE_INSERT_IN_PROGRESS;if(TransactionIdIsInProgress(xvac))returnHEAPTUPLE_INSERT_IN_PROGRESS;if(TransactionIdDidCommit(xvac))SetHintBits(tuple,buffer,HEAP_XMIN_COMMITTED,InvalidTransactionId);else{SetHintBits(tuple,buffer,HEAP_XMIN_INVALID,InvalidTransactionId);returnHEAPTUPLE_DEAD;}}elseif(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple))){//1-3.xmin为当前事务IDif(tuple->t_infomask&HEAP_XMAX_INVALID)/*xidinvalid*///1-3-1.xmax无效,说明插入事务正在进行中returnHEAPTUPLE_INSERT_IN_PROGRESS;/*onlylocked?runinfomask-onlycheckfirst,forperformance*///只是锁定?性能考虑,首先执行infomask-only检查if(HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)||HeapTupleHeaderIsOnlyLocked(tuple))//1-3-2.锁定状态(如forupdate之类),事务正在进行中returnHEAPTUPLE_INSERT_IN_PROGRESS;/*insertedandthendeletedbysamexact*///插入,然后删除if(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))//1-3-3.插入,然后删除returnHEAPTUPLE_DELETE_IN_PROGRESS;/*deletingsubtransactionmusthaveaborted*///默认:插入事务正在进行中returnHEAPTUPLE_INSERT_IN_PROGRESS;}elseif(TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple))){//1-4.插入事务非当前事务,正在进行中/**It'dbepossibletodiscernbetweenINSERT/DELETEinprogress*herebylookingatxmax-butthatdoesn'tseembeneficialfor*themajorityofcallersandevendetrimentalforsome.We'd*ratherhavecallerslookat/waitforxminthanxmax.It's*alwayscorrecttoreturnINSERT_IN_PROGRESSbecausethat's*what'shappeningfromtheviewofotherbackends.*通过查看xmax,可以区分正在进行的插入/删除操作-但这对于大多数调用者并没有好处,甚至有害*我们宁愿让调用者查看/等待xmin而不是xmax。*返回INSERT_IN_PROGRESS总是正确的,因为这是从其他后台进程视图中看到正在发生的。*/returnHEAPTUPLE_INSERT_IN_PROGRESS;}elseif(TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))//1-5.xmin事务确实已提交(通过clog判断)SetHintBits(tuple,buffer,HEAP_XMIN_COMMITTED,HeapTupleHeaderGetRawXmin(tuple));else{//1-5.其他情况//既不在进行中,也没有提交,要么是回滚,要么是崩溃了/**NotinProgress,NotCommitted,soeitherAbortedorcrashed*///设置标记位SetHintBits(tuple,buffer,HEAP_XMIN_INVALID,InvalidTransactionId);//返回废弃标记returnHEAPTUPLE_DEAD;}/**Atthispointthexminisknowncommitted,butwemightnothave*beenabletosetthehintbityet;sowecannolongerAssertthat*it'sset.*在这个点上,xmin事务确认已提交,但这时候还是不能设置hintbit,*因此不能断定已设置标记.*/}/**Okay,theinsertercommitted,soitwasgoodatsomepoint.Nowwhat*aboutthedeletingtransaction?*插入数据的事务已提交,现在可以看看删除事务的状态了.*/if(tuple->t_infomask&HEAP_XMAX_INVALID)//-------2.xmax是无效的事务ID,直接返回LIVEreturnHEAPTUPLE_LIVE;if(HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)){//-------3.锁定/**"Deleting"xactreallyonlylockedit,sothetupleisliveinany*case.However,weshouldmakesurethateitherXMAX_COMMITTEDor*XMAX_INVALIDgetssetoncethexactisgone,toreducethecostsof*examiningthetupleforfuturexacts.*"Deleting"事务确实只是锁定该元组,因此该元组是存活状态.*但是,我们应该确保不管是XMAX_COMMITTED还是XMAX_INVALID标记,应该在事务完结后马上设置,*这样可以减少为了事务检查元组状态的成本.*/if(!(tuple->t_infomask&HEAP_XMAX_COMMITTED)){//3.1xmax事务未提交if(tuple->t_infomask&HEAP_XMAX_IS_MULTI){//3.1.1多事务/**Ifit'sapre-pg_upgradetuple,themultixactcannot*possiblyberunning;otherwisehavetocheck.*如果是pre-pg_upgrade元组,多事务不可能运行,否则的话,只能执行检查*/if(!HEAP_LOCKED_UPGRADED(tuple->t_infomask)&&MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),true))returnHEAPTUPLE_LIVE;//其他情况,根据clog重新设置事务状态标记位SetHintBits(tuple,buffer,HEAP_XMAX_INVALID,InvalidTransactionId);}else{//3.1.2非多事务if(TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))//xmax事务正在进行,返回LIVEreturnHEAPTUPLE_LIVE;//否则,根据clog重新设置事务状态标记位SetHintBits(tuple,buffer,HEAP_XMAX_INVALID,InvalidTransactionId);}}/**Wedon'treallycarewhetherxmaxdidcommit,abortorcrash.We*knowthatxmaxdidlockthetuple,butitdidnotandwillnever*actuallyupdateit.*我们确实不需要真正关心xmax是否提交/回滚/崩溃.*我们知道xmax事务锁定了元组,但没有而且"从未"更新过该元组.*///3.2只是锁定,返回LIVEreturnHEAPTUPLE_LIVE;}if(tuple->t_infomask&HEAP_XMAX_IS_MULTI){//4.存在子事务//获取删除事务号xmaxTransactionIdxmax=HeapTupleGetUpdateXid(tuple);/*alreadycheckedabove*/Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));/*notLOCKED_ONLY,soithastohaveanxmax*///根据上述xmax的判断,到这里可以肯定xmax是有效的Assert(TransactionIdIsValid(xmax));if(TransactionIdIsInProgress(xmax))//4.1xmax正在进行,返回进行中returnHEAPTUPLE_DELETE_IN_PROGRESS;elseif(TransactionIdDidCommit(xmax)){//4.2xmax已提交/**Themultixactmightstillberunningduetolockers.Ifthe*updaterisbelowthexidhorizon,wehavetoreturnDEAD*regardless--otherwisewecouldendupwithatuplewherethe*updaterhastoberemovedduetothehorizon,butisnotpruned*away.It'snotaproblemtoprunethattuple,becauseany*remaininglockerswillalsobepresentinnewertupleversions.*/if(!TransactionIdPrecedes(xmax,OldestXmin))//4.2.1xmax在OldestXmin之后,//表示在OldestXmin之后才删除,返回HEAPTUPLE_RECENTLY_DEADreturnHEAPTUPLE_RECENTLY_DEAD;//4.2.2xmax在OldestXmin之前,返回DEADreturnHEAPTUPLE_DEAD;}elseif(!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),false)){/**NotinProgress,NotCommitted,soeitherAbortedorcrashed.*MarktheXmaxasinvalid.*///4.3xmax不在运行中/没有提交/没有回滚或崩溃,则设置xmax为无效事务IDSetHintBits(tuple,buffer,HEAP_XMAX_INVALID,InvalidTransactionId);}//4.4默认返回LIVEreturnHEAPTUPLE_LIVE;}if(!(tuple->t_infomask&HEAP_XMAX_COMMITTED)){//5.xmax没有提交if(TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))//5.1删除过程中returnHEAPTUPLE_DELETE_IN_PROGRESS;elseif(TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))//5.2通过clog判断,该事务已提交,设置事务标记位SetHintBits(tuple,buffer,HEAP_XMAX_COMMITTED,HeapTupleHeaderGetRawXmax(tuple));else{/**NotinProgress,NotCommitted,soeitherAbortedorcrashed*///5.3其他情况,设置为无效事务IDSetHintBits(tuple,buffer,HEAP_XMAX_INVALID,InvalidTransactionId);//返回LIVEreturnHEAPTUPLE_LIVE;}/**Atthispointthexmaxisknowncommitted,butwemightnothave*beenabletosetthehintbityet;sowecannolongerAssertthat*it'sset.*///至此,xmax可以确认已提交}/**Deletercommitted,butperhapsitwasrecentenoughthatsomeopen*transactionscouldstillseethetuple.*/if(!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple),OldestXmin))//6.元组xmax≥OldestXmin,最近删除returnHEAPTUPLE_RECENTLY_DEAD;/*Otherwise,it'sdeadandremovable*///7.默认元组已DEADreturnHEAPTUPLE_DEAD;}
到此,相信大家对“PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。