Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7bffc9b

Browse files
committed
Update minimum recovery point on truncation.
If a file is truncated, we must update minRecoveryPoint. Once a file is truncated, there's no going back; it would not be safe to stop recovery at a point earlier than that anymore. Per report from Kyotaro HORIGUCHI. Backpatch to 8.4. Before that, minRecoveryPoint was not updated during recovery at all.
1 parent 6be7996 commit 7bffc9b

File tree

2 files changed

+50
-11
lines changed

2 files changed

+50
-11
lines changed

src/backend/access/transam/xact.c

+32-11
Original file line numberDiff line numberDiff line change
@@ -4617,23 +4617,44 @@ xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
46174617
}
46184618

46194619
/* Make sure files supposed to be dropped are dropped */
4620-
for (i = 0; i < nrels; i++)
4620+
if (nrels > 0)
46214621
{
4622-
SMgrRelation srel = smgropen(xnodes[i], InvalidBackendId);
4623-
ForkNumber fork;
4622+
/*
4623+
* First update minimum recovery point to cover this WAL record. Once
4624+
* a relation is deleted, there's no going back. The buffer manager
4625+
* enforces the WAL-first rule for normal updates to relation files,
4626+
* so that the minimum recovery point is always updated before the
4627+
* corresponding change in the data file is flushed to disk, but we
4628+
* have to do the same here since we're bypassing the buffer manager.
4629+
*
4630+
* Doing this before deleting the files means that if a deletion fails
4631+
* for some reason, you cannot start up the system even after restart,
4632+
* until you fix the underlying situation so that the deletion will
4633+
* succeed. Alternatively, we could update the minimum recovery point
4634+
* after deletion, but that would leave a small window where the
4635+
* WAL-first rule would be violated.
4636+
*/
4637+
XLogFlush(lsn);
46244638

4625-
for (fork = 0; fork <= MAX_FORKNUM; fork++)
4626-
XLogDropRelation(xnodes[i], fork);
4627-
smgrdounlink(srel, true);
4628-
smgrclose(srel);
4639+
for (i = 0; i < nrels; i++)
4640+
{
4641+
SMgrRelation srel = smgropen(xnodes[i], InvalidBackendId);
4642+
ForkNumber fork;
4643+
4644+
for (fork = 0; fork <= MAX_FORKNUM; fork++)
4645+
XLogDropRelation(xnodes[i], fork);
4646+
smgrdounlink(srel, true);
4647+
smgrclose(srel);
4648+
}
46294649
}
46304650

46314651
/*
46324652
* We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
4633-
* in normal operation. For example, in DROP DATABASE, we delete all the
4634-
* files belonging to the database, and then commit the transaction. If we
4635-
* crash after all the files have been deleted but before the commit, you
4636-
* have an entry in pg_database without any files. To minimize the window
4653+
* in normal operation. For example, in CREATE DATABASE, we copy all files
4654+
* from the template database, and then commit the transaction. If we
4655+
* crash after all the files have been copied but before the commit, you
4656+
* have files in the data directory without an entry in pg_database. To
4657+
* minimize the window
46374658
* for that, we use ForceSyncCommit() to rush the commit record to disk as
46384659
* quick as possible. We have the same window during recovery, and forcing
46394660
* an XLogFlush() (which updates minRecoveryPoint during recovery) helps

src/backend/catalog/storage.c

+18
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,24 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
482482
*/
483483
smgrcreate(reln, MAIN_FORKNUM, true);
484484

485+
/*
486+
* Before we perform the truncation, update minimum recovery point
487+
* to cover this WAL record. Once the relation is truncated, there's
488+
* no going back. The buffer manager enforces the WAL-first rule
489+
* for normal updates to relation files, so that the minimum recovery
490+
* point is always updated before the corresponding change in the
491+
* data file is flushed to disk. We have to do the same manually
492+
* here.
493+
*
494+
* Doing this before the truncation means that if the truncation fails
495+
* for some reason, you cannot start up the system even after restart,
496+
* until you fix the underlying situation so that the truncation will
497+
* succeed. Alternatively, we could update the minimum recovery point
498+
* after truncation, but that would leave a small window where the
499+
* WAL-first rule could be violated.
500+
*/
501+
XLogFlush(lsn);
502+
485503
smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
486504

487505
/* Also tell xlogutils.c about it */

0 commit comments

Comments
 (0)