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.
This commit is contained in:
parent
6be799664a
commit
7bffc9b7bf
@ -4617,6 +4617,25 @@ xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure files supposed to be dropped are dropped */
|
/* Make sure files supposed to be dropped are dropped */
|
||||||
|
if (nrels > 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* First update minimum recovery point to cover this WAL record. Once
|
||||||
|
* a relation is deleted, there's no going back. The buffer manager
|
||||||
|
* enforces the WAL-first rule for normal updates to relation files,
|
||||||
|
* so that the minimum recovery point is always updated before the
|
||||||
|
* corresponding change in the data file is flushed to disk, but we
|
||||||
|
* have to do the same here since we're bypassing the buffer manager.
|
||||||
|
*
|
||||||
|
* Doing this before deleting the files means that if a deletion fails
|
||||||
|
* for some reason, you cannot start up the system even after restart,
|
||||||
|
* until you fix the underlying situation so that the deletion will
|
||||||
|
* succeed. Alternatively, we could update the minimum recovery point
|
||||||
|
* after deletion, but that would leave a small window where the
|
||||||
|
* WAL-first rule would be violated.
|
||||||
|
*/
|
||||||
|
XLogFlush(lsn);
|
||||||
|
|
||||||
for (i = 0; i < nrels; i++)
|
for (i = 0; i < nrels; i++)
|
||||||
{
|
{
|
||||||
SMgrRelation srel = smgropen(xnodes[i], InvalidBackendId);
|
SMgrRelation srel = smgropen(xnodes[i], InvalidBackendId);
|
||||||
@ -4627,13 +4646,15 @@ xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
|
|||||||
smgrdounlink(srel, true);
|
smgrdounlink(srel, true);
|
||||||
smgrclose(srel);
|
smgrclose(srel);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
|
* We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
|
||||||
* in normal operation. For example, in DROP DATABASE, we delete all the
|
* in normal operation. For example, in CREATE DATABASE, we copy all files
|
||||||
* files belonging to the database, and then commit the transaction. If we
|
* from the template database, and then commit the transaction. If we
|
||||||
* crash after all the files have been deleted but before the commit, you
|
* crash after all the files have been copied but before the commit, you
|
||||||
* have an entry in pg_database without any files. To minimize the window
|
* have files in the data directory without an entry in pg_database. To
|
||||||
|
* minimize the window
|
||||||
* for that, we use ForceSyncCommit() to rush the commit record to disk as
|
* for that, we use ForceSyncCommit() to rush the commit record to disk as
|
||||||
* quick as possible. We have the same window during recovery, and forcing
|
* quick as possible. We have the same window during recovery, and forcing
|
||||||
* an XLogFlush() (which updates minRecoveryPoint during recovery) helps
|
* an XLogFlush() (which updates minRecoveryPoint during recovery) helps
|
||||||
|
@ -482,6 +482,24 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||||||
*/
|
*/
|
||||||
smgrcreate(reln, MAIN_FORKNUM, true);
|
smgrcreate(reln, MAIN_FORKNUM, true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Before we perform the truncation, update minimum recovery point
|
||||||
|
* to cover this WAL record. Once the relation is truncated, there's
|
||||||
|
* no going back. The buffer manager enforces the WAL-first rule
|
||||||
|
* for normal updates to relation files, so that the minimum recovery
|
||||||
|
* point is always updated before the corresponding change in the
|
||||||
|
* data file is flushed to disk. We have to do the same manually
|
||||||
|
* here.
|
||||||
|
*
|
||||||
|
* Doing this before the truncation means that if the truncation fails
|
||||||
|
* for some reason, you cannot start up the system even after restart,
|
||||||
|
* until you fix the underlying situation so that the truncation will
|
||||||
|
* succeed. Alternatively, we could update the minimum recovery point
|
||||||
|
* after truncation, but that would leave a small window where the
|
||||||
|
* WAL-first rule could be violated.
|
||||||
|
*/
|
||||||
|
XLogFlush(lsn);
|
||||||
|
|
||||||
smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
|
smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
|
||||||
|
|
||||||
/* Also tell xlogutils.c about it */
|
/* Also tell xlogutils.c about it */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user