Skip to content

Commit 7d0b91a

Browse files
committed
RelationTruncate() must set DELAY_CHKPT_START.
Previously, it set only DELAY_CHKPT_COMPLETE. That was important, because it meant that if the XLOG_SMGR_TRUNCATE record preceded a XLOG_CHECKPOINT_ONLINE record in the WAL, then the truncation would also happen on disk before the XLOG_CHECKPOINT_ONLINE record was written. However, it didn't guarantee that the sync request for the truncation was processed before the XLOG_CHECKPOINT_ONLINE record was written. By setting DELAY_CHKPT_START, we guarantee that if an XLOG_SMGR_TRUNCATE record is written to WAL before the redo pointer of a concurrent checkpoint, the sync request queued by that operation must be processed by that checkpoint, rather than being left for the following one. This is a refinement of commit 412ad7a. Back-patch to all supported releases, like that commit. Author: Robert Haas <robertmhaas@gmail.com> Reported-by: Thomas Munro <thomas.munro@gmail.com> Discussion: https://postgr.es/m/CA%2BhUKG%2B-2rjGZC2kwqr2NMLBcEBp4uf59QT1advbWYF_uc%2B0Aw%40mail.gmail.com
1 parent 52c7a44 commit 7d0b91a

File tree

1 file changed

+26
-10
lines changed

1 file changed

+26
-10
lines changed

src/backend/catalog/storage.c

+26-10
Original file line numberDiff line numberDiff line change
@@ -326,20 +326,35 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
326326
RelationPreTruncate(rel);
327327

328328
/*
329-
* Make sure that a concurrent checkpoint can't complete while truncation
330-
* is in progress.
329+
* The code which follows can interact with concurrent checkpoints in two
330+
* separate ways.
331331
*
332-
* The truncation operation might drop buffers that the checkpoint
333-
* otherwise would have flushed. If it does, then it's essential that
334-
* the files actually get truncated on disk before the checkpoint record
335-
* is written. Otherwise, if reply begins from that checkpoint, the
332+
* First, the truncation operation might drop buffers that the checkpoint
333+
* otherwise would have flushed. If it does, then it's essential that the
334+
* files actually get truncated on disk before the checkpoint record is
335+
* written. Otherwise, if reply begins from that checkpoint, the
336336
* to-be-truncated blocks might still exist on disk but have older
337-
* contents than expected, which can cause replay to fail. It's OK for
338-
* the blocks to not exist on disk at all, but not for them to have the
339-
* wrong contents.
337+
* contents than expected, which can cause replay to fail. It's OK for the
338+
* blocks to not exist on disk at all, but not for them to have the wrong
339+
* contents. For this reason, we need to set DELAY_CHKPT_COMPLETE while
340+
* this code executes.
341+
*
342+
* Second, the call to smgrtruncate() below will in turn call
343+
* RegisterSyncRequest(). We need the sync request created by that call to
344+
* be processed before the checkpoint completes. CheckPointGuts() will
345+
* call ProcessSyncRequests(), but if we register our sync request after
346+
* that happens, then the WAL record for the truncation could end up
347+
* preceding the checkpoint record, while the actual sync doesn't happen
348+
* until the next checkpoint. To prevent that, we need to set
349+
* DELAY_CHKPT_START here. That way, if the XLOG_SMGR_TRUNCATE precedes
350+
* the redo pointer of a concurrent checkpoint, we're guaranteed that the
351+
* corresponding sync request will be processed before the checkpoint
352+
* completes.
340353
*/
354+
Assert(!MyProc->delayChkpt);
355+
MyProc->delayChkpt = true; /* DELAY_CHKPT_START */
341356
Assert(!MyProc->delayChkptEnd);
342-
MyProc->delayChkptEnd = true;
357+
MyProc->delayChkptEnd = true; /* DELAY_CHKPT_COMPLETE */
343358

344359
/*
345360
* We WAL-log the truncation before actually truncating, which means
@@ -387,6 +402,7 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
387402
smgrtruncate(RelationGetSmgr(rel), forks, nforks, blocks);
388403

389404
/* We've done all the critical work, so checkpoints are OK now. */
405+
MyProc->delayChkpt = false;
390406
MyProc->delayChkptEnd = false;
391407

392408
/*

0 commit comments

Comments
 (0)