新聞中心
本篇內(nèi)容主要講解“PostgreSQL中vacuum過程HeapTupleSatisfiesVacuum函數(shù)分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“PostgreSQL中vacuum過程HeapTupleSatisfiesVacuum函數(shù)分析”吧!
我們提供的服務(wù)有:做網(wǎng)站、成都網(wǎng)站建設(shè)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、黑龍江ssl等。為近1000家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的黑龍江網(wǎng)站制作公司
一、數(shù)據(jù)結(jié)構(gòu)
宏定義
Vacuum和Analyze命令選項
/* ---------------------- * Vacuum and Analyze Statements * Vacuum和Analyze命令選項 * * Even though these are nominally two statements, it's convenient to use * just one node type for both. Note that at least one of VACOPT_VACUUM * and VACOPT_ANALYZE must be set in options. * 雖然在這里有兩種不同的語句,但只需要使用統(tǒng)一的Node類型即可. * 注意至少VACOPT_VACUUM/VACOPT_ANALYZE在選項中設(shè)置. * ---------------------- */ typedef enum VacuumOption { VACOPT_VACUUM = 1 << 0, /* do VACUUM */ VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */ VACOPT_VERBOSE = 1 << 2, /* print progress info */ VACOPT_FREEZE = 1 << 3, /* FREEZE option */ VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */ VACOPT_SKIP_LOCKED = 1 << 5, /* skip if cannot get lock */ VACOPT_SKIPTOAST = 1 << 6, /* don't process the TOAST table, if any */ VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */ } VacuumOption;
二、源碼解讀
HeapTupleSatisfiesVacuum
HeapTupleSatisfiesVacuum為VACUUM操作確定元組的狀態(tài).在這里,我們主要想知道的是一個元組是否可對所有正在運行中的事務(wù)可見.如可見,則不能通過VACUUM刪除該元組.
主要處理流程如下:
0.獲取tuple并執(zhí)行相關(guān)校驗
1.條件:插入事務(wù)未提交
1.1條件:無效的xmin,該元組已廢棄可刪除
1.2條件:舊版本(9.0-)的判斷
1.3條件:xmin為當(dāng)前事務(wù)ID
1.4條件:插入事務(wù)非當(dāng)前事務(wù),正在進行中
1.5條件:xmin事務(wù)確實已提交(通過clog判斷)
1.6條件:其他情況
— 至此,可以確定xmin已提交
2.條件:xmax是無效的事務(wù)ID,直接返回LIVE
3.條件:xmax只是鎖定
3.1條件:xmax事務(wù)未提交,分多事務(wù)&非多事務(wù)進行判斷
3.2條件:只是鎖定,返回LIVE
4.條件:存在子事務(wù)
4.1條件:xmax正在進行,返回事務(wù)進行中
4.2條件:xmax已提交,區(qū)分xmax在OldestXmin之前還是之后
4.3條件:xmax不在運行中/沒有提交/沒有回滾或崩潰,則設(shè)置xmax為無效事務(wù)ID
4.4默認返回LIVE
5.條件:xmax沒有提交
5.1條件:刪除過程中
5.2條件:通過clog判斷,該事務(wù)已提交,設(shè)置事務(wù)標(biāo)記位
5.3條件:其他情況,設(shè)置為無效事務(wù)ID
5.4默認返回LIVE
— 至此,可以確定xmax已提交
6.元組xmax≥OldestXmin,最近刪除
7.默認元組已DEAD
/* * HeapTupleSatisfiesVacuum * * Determine the status of tuples for VACUUM purposes. Here, what * we mainly want to know is if a tuple is potentially visible to *any* * running transaction. If so, it can't be removed yet by VACUUM. * 為VACUUM確定元組的狀態(tài). * 在這里,我們主要想知道的是一個元組是否可對所有正在運行中的事務(wù)可見. * 如可見,則不能通過VACUUM刪除該元組. * * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might * still be visible to some open transaction, so we can't remove them, * even if we see that the deleting transaction has committed. * OldestXmin是一個cutoff XID(通過GetOldestXmin函數(shù)獲得). * 通過XIDs >= OldestXmin刪除的元組被視為"最近死亡",它們可能仍然對某些正在進行中的事務(wù)可見, * 因此就算刪除事務(wù)已提交,我們?nèi)匀徊荒芮宄鼈? */ HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer) { //獲取tuple HeapTupleHeader tuple = htup->t_data; //校驗 Assert(ItemPointerIsValid(&htup->t_self)); Assert(htup->t_tableOid != InvalidOid); /* * Has inserting transaction committed? * 插入事務(wù)已提交? * * If the inserting transaction aborted, then the tuple was never visible * to any other transaction, so we can delete it immediately. * 如果插入事務(wù)已回滾,元組對其他事務(wù)均不可見,因此可以馬上刪除. */ if (!HeapTupleHeaderXminCommitted(tuple)) { //1.插入事務(wù)未提交 if (HeapTupleHeaderXminInvalid(tuple)) //1-1.無效的xmin,該元組已廢棄可刪除 return HEAPTUPLE_DEAD; /* Used by pre-9.0 binary upgrades */ //用于9.0以前版本的升級,HEAP_MOVED_OFF&HEAP_MOVED_IN已不再使用 else if (tuple->t_infomask & HEAP_MOVED_OFF) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (TransactionIdIsCurrentTransactionId(xvac)) return HEAPTUPLE_DELETE_IN_PROGRESS; if (TransactionIdIsInProgress(xvac)) return HEAPTUPLE_DELETE_IN_PROGRESS; if (TransactionIdDidCommit(xvac)) { SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return HEAPTUPLE_DEAD; } SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, InvalidTransactionId); } /* Used by pre-9.0 binary upgrades */ //用于9.0以前版本的升級 else if (tuple->t_infomask & HEAP_MOVED_IN) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (TransactionIdIsCurrentTransactionId(xvac)) return HEAPTUPLE_INSERT_IN_PROGRESS; if (TransactionIdIsInProgress(xvac)) return HEAPTUPLE_INSERT_IN_PROGRESS; if (TransactionIdDidCommit(xvac)) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, InvalidTransactionId); else { SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return HEAPTUPLE_DEAD; } } else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple))) { //1-3.xmin為當(dāng)前事務(wù)ID if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ //1-3-1.xmax無效,說明插入事務(wù)正在進行中 return HEAPTUPLE_INSERT_IN_PROGRESS; /* only locked? run infomask-only check first, for performance */ //只是鎖定?性能考慮,首先執(zhí)行infomask-only檢查 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) || HeapTupleHeaderIsOnlyLocked(tuple)) //1-3-2.鎖定狀態(tài)(如for update之類),事務(wù)正在進行中 return HEAPTUPLE_INSERT_IN_PROGRESS; /* inserted and then deleted by same xact */ //插入,然后刪除 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple))) //1-3-3.插入,然后刪除 return HEAPTUPLE_DELETE_IN_PROGRESS; /* deleting subtransaction must have aborted */ //默認:插入事務(wù)正在進行中 return HEAPTUPLE_INSERT_IN_PROGRESS; } else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple))) { //1-4.插入事務(wù)非當(dāng)前事務(wù),正在進行中 /* * It'd be possible to discern between INSERT/DELETE in progress * here by looking at xmax - but that doesn't seem beneficial for * the majority of callers and even detrimental for some. We'd * rather have callers look at/wait for xmin than xmax. It's * always correct to return INSERT_IN_PROGRESS because that's * what's happening from the view of other backends. * 通過查看xmax,可以區(qū)分正在進行的插入/刪除操作 - 但這對于大多數(shù)調(diào)用者并沒有好處,甚至有害 * 我們寧愿讓調(diào)用者查看/等待xmin而不是xmax。 * 返回INSERT_IN_PROGRESS總是正確的,因為這是從其他后臺進程視圖中看到正在發(fā)生的。 */ return HEAPTUPLE_INSERT_IN_PROGRESS; } else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple))) //1-5.xmin事務(wù)確實已提交(通過clog判斷) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetRawXmin(tuple)); else { //1-5.其他情況 //既不在進行中,也沒有提交,要么是回滾,要么是崩潰了 /* * Not in Progress, Not Committed, so either Aborted or crashed */ //設(shè)置標(biāo)記位 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); //返回廢棄標(biāo)記 return HEAPTUPLE_DEAD; } /* * At this point the xmin is known committed, but we might not have * been able to set the hint bit yet; so we can no longer Assert that * it's set. * 在這個點上,xmin事務(wù)確認已提交,但這時候還是不能設(shè)置hint bit, * 因此不能斷定已設(shè)置標(biāo)記. */ } /* * Okay, the inserter committed, so it was good at some point. Now what * about the deleting transaction? * 插入數(shù)據(jù)的事務(wù)已提交,現(xiàn)在可以看看刪除事務(wù)的狀態(tài)了. */ if (tuple->t_infomask & HEAP_XMAX_INVALID) //------- 2.xmax是無效的事務(wù)ID,直接返回LIVE return HEAPTUPLE_LIVE; if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) { //------- 3.鎖定 /* * "Deleting" xact really only locked it, so the tuple is live in any * case. However, we should make sure that either XMAX_COMMITTED or * XMAX_INVALID gets set once the xact is gone, to reduce the costs of * examining the tuple for future xacts. * "Deleting"事務(wù)確實只是鎖定該元組,因此該元組是存活狀態(tài). * 但是,我們應(yīng)該確保不管是XMAX_COMMITTED還是XMAX_INVALID標(biāo)記,應(yīng)該在事務(wù)完結(jié)后馬上設(shè)置, * 這樣可以減少為了事務(wù)檢查元組狀態(tài)的成本. */ if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) { //3.1 xmax事務(wù)未提交 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { //3.1.1 多事務(wù) /* * If it's a pre-pg_upgrade tuple, the multixact cannot * possibly be running; otherwise have to check. * 如果是pre-pg_upgrade元組,多事務(wù)不可能運行,否則的話,只能執(zhí)行檢查 */ if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) && MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), true)) return HEAPTUPLE_LIVE; //其他情況,根據(jù)clog重新設(shè)置事務(wù)狀態(tài)標(biāo)記位 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); } else { //3.1.2 非多事務(wù) if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))) //xmax事務(wù)正在進行,返回LIVE return HEAPTUPLE_LIVE; //否則,根據(jù)clog重新設(shè)置事務(wù)狀態(tài)標(biāo)記位 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); } } /* * We don't really care whether xmax did commit, abort or crash. We * know that xmax did lock the tuple, but it did not and will never * actually update it. * 我們確實不需要真正關(guān)心xmax是否提交/回滾/崩潰. * 我們知道xmax事務(wù)鎖定了元組,但沒有而且"從未"更新過該元組. */ //3.2 只是鎖定,返回LIVE return HEAPTUPLE_LIVE; } if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { //4.存在子事務(wù) //獲取刪除事務(wù)號xmax TransactionId xmax = HeapTupleGetUpdateXid(tuple); /* already checked above */ Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)); /* not LOCKED_ONLY, so it has to have an xmax */ //根據(jù)上述xmax的判斷,到這里可以肯定xmax是有效的 Assert(TransactionIdIsValid(xmax)); if (TransactionIdIsInProgress(xmax)) //4.1 xmax正在進行,返回進行中 return HEAPTUPLE_DELETE_IN_PROGRESS; else if (TransactionIdDidCommit(xmax)) { //4.2 xmax已提交 /* * The multixact might still be running due to lockers. If the * updater is below the xid horizon, we have to return DEAD * regardless -- otherwise we could end up with a tuple where the * updater has to be removed due to the horizon, but is not pruned * away. It's not a problem to prune that tuple, because any * remaining lockers will also be present in newer tuple versions. */ if (!TransactionIdPrecedes(xmax, OldestXmin)) //4.2.1 xmax在OldestXmin之后, //表示在OldestXmin之后才刪除,返回HEAPTUPLE_RECENTLY_DEAD return HEAPTUPLE_RECENTLY_DEAD; //4.2.2 xmax在OldestXmin之前,返回DEAD return HEAPTUPLE_DEAD; } else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false)) { /* * Not in Progress, Not Committed, so either Aborted or crashed. * Mark the Xmax as invalid. */ //4.3 xmax不在運行中/沒有提交/沒有回滾或崩潰,則設(shè)置xmax為無效事務(wù)ID SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); } //4.4 默認返回LIVE return HEAPTUPLE_LIVE; } if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) { //5.xmax沒有提交 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))) //5.1 刪除過程中 return HEAPTUPLE_DELETE_IN_PROGRESS; else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple))) //5.2 通過clog判斷,該事務(wù)已提交,設(shè)置事務(wù)標(biāo)記位 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); else { /* * Not in Progress, Not Committed, so either Aborted or crashed */ //5.3 其他情況,設(shè)置為無效事務(wù)ID SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); //返回LIVE return HEAPTUPLE_LIVE; } /* * At this point the xmax is known committed, but we might not have * been able to set the hint bit yet; so we can no longer Assert that * it's set. */ //至此,xmax可以確認已提交 } /* * Deleter committed, but perhaps it was recent enough that some open * transactions could still see the tuple. */ if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin)) //6.元組xmax≥OldestXmin,最近刪除 return HEAPTUPLE_RECENTLY_DEAD; /* Otherwise, it's dead and removable */ //7. 默認元組已DEAD return HEAPTUPLE_DEAD; }
到此,相信大家對“PostgreSQL中vacuum過程HeapTupleSatisfiesVacuum函數(shù)分析”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
新聞標(biāo)題:PostgreSQL中vacuum過程HeapTupleSatisfiesVacuum函數(shù)分析
網(wǎng)站路徑:http://fisionsoft.com.cn/article/piocig.html