diff options
author | Robert Haas <rhaas@postgresql.org> | 2022-04-14 11:10:11 -0400 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2022-04-14 11:10:11 -0400 |
commit | d18c913b786c5ea82f7372c88cf2055050e5176a (patch) | |
tree | 8c87db7c8e81c860252ce6f8b1e2e10fbb4a2062 /src/backend | |
parent | 2275d044d0849251c5e0fa10ee16c73124731f5c (diff) | |
download | postgresql-d18c913b786c5ea82f7372c88cf2055050e5176a.tar.gz postgresql-d18c913b786c5ea82f7372c88cf2055050e5176a.zip |
Rethink the delay-checkpoint-end mechanism in the back-branches.
The back-patch of commit bbace5697df12398e87ffd9879171c39d27f5b33 had
the unfortunate effect of changing the layout of PGPROC in the
back-branches, which could break extensions. This happened because it
changed the delayChkpt from type bool to type int. So, change it back,
and add a new bool delayChkptEnd field instead. The new field should
fall within what used to be padding space within the struct, and so
hopefully won't cause any extensions to break.
Per report from Markus Wanner and discussion with Tom Lane and others.
Patch originally by me, somewhat revised by Markus Wanner per a
suggestion from Michael Paquier. A very similar patch was developed
by Kyotaro Horiguchi, but I failed to see the email in which that was
posted before writing one of my own.
Discussion: http://postgr.es/m/CA+Tgmoao-kUD9c5nG5sub3F7tbo39+cdr8jKaOVEs_1aBWcJ3Q@mail.gmail.com
Discussion: http://postgr.es/m/20220406.164521.17171257901083417.horikyota.ntt@gmail.com
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/transam/multixact.c | 6 | ||||
-rw-r--r-- | src/backend/access/transam/twophase.c | 15 | ||||
-rw-r--r-- | src/backend/access/transam/xact.c | 6 | ||||
-rw-r--r-- | src/backend/access/transam/xlog.c | 10 | ||||
-rw-r--r-- | src/backend/access/transam/xloginsert.c | 2 | ||||
-rw-r--r-- | src/backend/catalog/storage.c | 6 | ||||
-rw-r--r-- | src/backend/storage/buffer/bufmgr.c | 6 | ||||
-rw-r--r-- | src/backend/storage/ipc/procarray.c | 96 |
8 files changed, 100 insertions, 47 deletions
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 3e6443fd41c..7990b5e5dd9 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -3071,8 +3071,8 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB) * crash/basebackup, even though the state of the data directory would * require it. */ - Assert((MyProc->delayChkpt & DELAY_CHKPT_START) == 0); - MyProc->delayChkpt |= DELAY_CHKPT_START; + Assert(!MyProc->delayChkpt); + MyProc->delayChkpt = true; /* WAL log truncation */ WriteMTruncateXlogRec(newOldestMultiDB, @@ -3098,7 +3098,7 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB) /* Then offsets */ PerformOffsetsTruncation(oldestMulti, newOldestMulti); - MyProc->delayChkpt &= ~DELAY_CHKPT_START; + MyProc->delayChkpt = false; END_CRIT_SECTION(); LWLockRelease(MultiXactTruncationLock); diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 716c17c98f6..96ba51ab25b 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -476,8 +476,9 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid, } pgxact->xid = xid; pgxact->xmin = InvalidTransactionId; - proc->delayChkpt = 0; + proc->delayChkpt = false; pgxact->vacuumFlags = 0; + proc->delayChkptEnd = false; proc->pid = 0; proc->databaseId = databaseid; proc->roleId = owner; @@ -1170,8 +1171,8 @@ EndPrepare(GlobalTransaction gxact) START_CRIT_SECTION(); - Assert((MyProc->delayChkpt & DELAY_CHKPT_START) == 0); - MyProc->delayChkpt |= DELAY_CHKPT_START; + Assert(!MyProc->delayChkpt); + MyProc->delayChkpt = true; XLogBeginInsert(); for (record = records.head; record != NULL; record = record->next) @@ -1214,7 +1215,7 @@ EndPrepare(GlobalTransaction gxact) * checkpoint starting after this will certainly see the gxact as a * candidate for fsyncing. */ - MyProc->delayChkpt &= ~DELAY_CHKPT_START; + MyProc->delayChkpt = false; /* * Remember that we have this GlobalTransaction entry locked for us. If @@ -2287,8 +2288,8 @@ RecordTransactionCommitPrepared(TransactionId xid, START_CRIT_SECTION(); /* See notes in RecordTransactionCommit */ - Assert((MyProc->delayChkpt & DELAY_CHKPT_START) == 0); - MyProc->delayChkpt |= DELAY_CHKPT_START; + Assert(!MyProc->delayChkpt); + MyProc->delayChkpt = true; /* * Emit the XLOG commit record. Note that we mark 2PC commits as @@ -2336,7 +2337,7 @@ RecordTransactionCommitPrepared(TransactionId xid, TransactionIdCommitTree(xid, nchildren, children); /* Checkpoint can proceed now */ - MyProc->delayChkpt &= ~DELAY_CHKPT_START; + MyProc->delayChkpt = false; END_CRIT_SECTION(); diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index da6ce5a09e5..3055a707180 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -1308,9 +1308,9 @@ RecordTransactionCommit(void) * This makes checkpoint's determination of which xacts are delayChkpt * a bit fuzzy, but it doesn't matter. */ - Assert((MyProc->delayChkpt & DELAY_CHKPT_START) == 0); + Assert(!MyProc->delayChkpt); START_CRIT_SECTION(); - MyProc->delayChkpt |= DELAY_CHKPT_START; + MyProc->delayChkpt = true; SetCurrentTransactionStopTimestamp(); @@ -1411,7 +1411,7 @@ RecordTransactionCommit(void) */ if (markXidCommitted) { - MyProc->delayChkpt &= ~DELAY_CHKPT_START; + MyProc->delayChkpt = false; END_CRIT_SECTION(); } diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index d1c8e7d60bd..12f5a7567b7 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -9022,27 +9022,25 @@ CreateCheckPoint(int flags) * and we will correctly flush the update below. So we cannot miss any * xacts we need to wait for. */ - vxids = GetVirtualXIDsDelayingChkpt(&nvxids, DELAY_CHKPT_START); + vxids = GetVirtualXIDsDelayingChkpt(&nvxids); if (nvxids > 0) { do { pg_usleep(10000L); /* wait for 10 msec */ - } while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids, - DELAY_CHKPT_START)); + } while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids)); } pfree(vxids); CheckPointGuts(checkPoint.redo, flags); - vxids = GetVirtualXIDsDelayingChkpt(&nvxids, DELAY_CHKPT_COMPLETE); + vxids = GetVirtualXIDsDelayingChkptEnd(&nvxids); if (nvxids > 0) { do { pg_usleep(10000L); /* wait for 10 msec */ - } while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids, - DELAY_CHKPT_COMPLETE)); + } while (HaveVirtualXIDsDelayingChkptEnd(vxids, nvxids)); } pfree(vxids); diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 5cff486d9ea..b21679f09eb 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -904,7 +904,7 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std) /* * Ensure no checkpoint can change our view of RedoRecPtr. */ - Assert((MyProc->delayChkpt & DELAY_CHKPT_START) != 0); + Assert(MyProc->delayChkpt); /* * Update RedoRecPtr so that we can make the right decision diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 0eb14cc8856..d7c74105a4e 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -338,8 +338,8 @@ RelationTruncate(Relation rel, BlockNumber nblocks) * the blocks to not exist on disk at all, but not for them to have the * wrong contents. */ - Assert((MyProc->delayChkpt & DELAY_CHKPT_COMPLETE) == 0); - MyProc->delayChkpt |= DELAY_CHKPT_COMPLETE; + Assert(!MyProc->delayChkptEnd); + MyProc->delayChkptEnd = true; /* * We WAL-log the truncation before actually truncating, which means @@ -387,7 +387,7 @@ RelationTruncate(Relation rel, BlockNumber nblocks) smgrtruncate(rel->rd_smgr, forks, nforks, blocks); /* We've done all the critical work, so checkpoints are OK now. */ - MyProc->delayChkpt &= ~DELAY_CHKPT_COMPLETE; + MyProc->delayChkptEnd = false; /* * Update upper-level FSM pages to account for the truncation. This is diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 033ef46811f..b32184591f6 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -3647,8 +3647,8 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * essential that CreateCheckpoint waits for virtual transactions * rather than full transactionids. */ - Assert((MyProc->delayChkpt & DELAY_CHKPT_START) == 0); - MyProc->delayChkpt |= DELAY_CHKPT_START; + Assert(!MyProc->delayChkpt); + MyProc->delayChkpt = true; delayChkpt = true; lsn = XLogSaveBufferForHint(buffer, buffer_std); } @@ -3682,7 +3682,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) UnlockBufHdr(bufHdr, buf_state); if (delayChkpt) - MyProc->delayChkpt &= ~DELAY_CHKPT_START; + MyProc->delayChkpt = false; if (dirtied) { diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 725680f34fa..6ff8d8699b3 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -155,6 +155,11 @@ static void DisplayXidCache(void); #define xc_slow_answer_inc() ((void) 0) #endif /* XIDCACHE_DEBUG */ +static VirtualTransactionId *GetVirtualXIDsDelayingChkptGuts(int *nvxids, + int type); +static bool HaveVirtualXIDsDelayingChkptGuts(VirtualTransactionId *vxids, + int nvxids, int type); + /* Primitives for KnownAssignedXids array handling for standby */ static void KnownAssignedXidsCompress(bool force); static void KnownAssignedXidsAdd(TransactionId from_xid, TransactionId to_xid, @@ -435,8 +440,9 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) /* must be cleared with xid/xmin: */ pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK; - /* be sure this is cleared in abort */ - proc->delayChkpt = 0; + /* be sure these are cleared in abort */ + proc->delayChkpt = false; + proc->delayChkptEnd = false; proc->recoveryConflictPending = false; @@ -460,8 +466,9 @@ ProcArrayEndTransactionInternal(PGPROC *proc, PGXACT *pgxact, /* must be cleared with xid/xmin: */ pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK; - /* be sure this is cleared in abort */ - proc->delayChkpt = 0; + /* be sure these are cleared in abort */ + proc->delayChkpt = false; + proc->delayChkptEnd = false; proc->recoveryConflictPending = false; @@ -2274,26 +2281,28 @@ GetOldestSafeDecodingTransactionId(bool catalogOnly) } /* - * GetVirtualXIDsDelayingChkpt -- Get the VXIDs of transactions that are - * delaying checkpoint because they have critical actions in progress. + * GetVirtualXIDsDelayingChkptGuts -- Get the VXIDs of transactions that are + * delaying the start or end of a checkpoint because they have critical + * actions in progress. * * Constructs an array of VXIDs of transactions that are currently in commit - * critical sections, as shown by having specified delayChkpt bits set in their - * PGPROC. + * critical sections, as shown by having delayChkpt or delayChkptEnd set in + * their PGPROC. * * Returns a palloc'd array that should be freed by the caller. * *nvxids is the number of valid entries. * - * Note that because backends set or clear delayChkpt without holding any lock, - * the result is somewhat indeterminate, but we don't really care. Even in - * a multiprocessor with delayed writes to shared memory, it should be certain - * that setting of delayChkpt will propagate to shared memory when the backend - * takes a lock, so we cannot fail to see a virtual xact as delayChkpt if - * it's already inserted its commit record. Whether it takes a little while - * for clearing of delayChkpt to propagate is unimportant for correctness. + * Note that because backends set or clear delayChkpt and delayChkptEnd + * without holding any lock, the result is somewhat indeterminate, but we + * don't really care. Even in a multiprocessor with delayed writes to + * shared memory, it should be certain that setting of delayChkpt will + * propagate to shared memory when the backend takes a lock, so we cannot + * fail to see a virtual xact as delayChkpt if it's already inserted its + * commit record. Whether it takes a little while for clearing of + * delayChkpt to propagate is unimportant for correctness. */ -VirtualTransactionId * -GetVirtualXIDsDelayingChkpt(int *nvxids, int type) +static VirtualTransactionId * +GetVirtualXIDsDelayingChkptGuts(int *nvxids, int type) { VirtualTransactionId *vxids; ProcArrayStruct *arrayP = procArray; @@ -2313,7 +2322,8 @@ GetVirtualXIDsDelayingChkpt(int *nvxids, int type) int pgprocno = arrayP->pgprocnos[index]; PGPROC *proc = &allProcs[pgprocno]; - if ((proc->delayChkpt & type) != 0) + if (((type & DELAY_CHKPT_START) && proc->delayChkpt) || + ((type & DELAY_CHKPT_COMPLETE) && proc->delayChkptEnd)) { VirtualTransactionId vxid; @@ -2330,6 +2340,26 @@ GetVirtualXIDsDelayingChkpt(int *nvxids, int type) } /* + * GetVirtualXIDsDelayingChkpt - Get the VXIDs of transactions that are + * delaying the start of a checkpoint. + */ +VirtualTransactionId * +GetVirtualXIDsDelayingChkpt(int *nvxids) +{ + return GetVirtualXIDsDelayingChkptGuts(nvxids, DELAY_CHKPT_START); +} + +/* + * GetVirtualXIDsDelayingChkptEnd - Get the VXIDs of transactions that are + * delaying the end of a checkpoint. + */ +VirtualTransactionId * +GetVirtualXIDsDelayingChkptEnd(int *nvxids) +{ + return GetVirtualXIDsDelayingChkptGuts(nvxids, DELAY_CHKPT_COMPLETE); +} + +/* * HaveVirtualXIDsDelayingChkpt -- Are any of the specified VXIDs delaying? * * This is used with the results of GetVirtualXIDsDelayingChkpt to see if any @@ -2338,8 +2368,9 @@ GetVirtualXIDsDelayingChkpt(int *nvxids, int type) * Note: this is O(N^2) in the number of vxacts that are/were delaying, but * those numbers should be small enough for it not to be a problem. */ -bool -HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids, int type) +static bool +HaveVirtualXIDsDelayingChkptGuts(VirtualTransactionId *vxids, int nvxids, + int type) { bool result = false; ProcArrayStruct *arrayP = procArray; @@ -2357,7 +2388,8 @@ HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids, int type) GET_VXID_FROM_PGPROC(vxid, *proc); - if ((proc->delayChkpt & type) != 0 && + if ((((type & DELAY_CHKPT_START) && proc->delayChkpt) || + ((type & DELAY_CHKPT_COMPLETE) && proc->delayChkptEnd)) && VirtualTransactionIdIsValid(vxid)) { int i; @@ -2381,6 +2413,28 @@ HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids, int type) } /* + * HaveVirtualXIDsDelayingChkpt -- Are any of the specified VXIDs delaying + * the start of a checkpoint? + */ +bool +HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids) +{ + return HaveVirtualXIDsDelayingChkptGuts(vxids, nvxids, + DELAY_CHKPT_START); +} + +/* + * HaveVirtualXIDsDelayingChkptEnd -- Are any of the specified VXIDs delaying + * the end of a checkpoint? + */ +bool +HaveVirtualXIDsDelayingChkptEnd(VirtualTransactionId *vxids, int nvxids) +{ + return HaveVirtualXIDsDelayingChkptGuts(vxids, nvxids, + DELAY_CHKPT_COMPLETE); +} + +/* * BackendPidGetProc -- get a backend's PGPROC given its PID * * Returns NULL if not found. Note that it is up to the caller to be |