*/
static void
-xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid)
+xact_redo_commit(XLogRecPtr lsn, xl_xact_commit *xlrec, TransactionId xid)
{
TransactionId *sub_xids;
TransactionId max_xid;
}
/* Make sure files supposed to be dropped are dropped */
- for (i = 0; i < xlrec->nrels; i++)
+ if (xlrec->nrels > 0)
{
- SMgrRelation srel = smgropen(xlrec->xnodes[i]);
- ForkNumber fork;
+ /*
+ * 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 (fork = 0; fork <= MAX_FORKNUM; fork++)
+ for (i = 0; i < xlrec->nrels; i++)
{
- XLogDropRelation(xlrec->xnodes[i], fork);
- smgrdounlink(srel, fork, false, true);
+ SMgrRelation srel = smgropen(xlrec->xnodes[i]);
+ ForkNumber fork;
+
+ for (fork = 0; fork <= MAX_FORKNUM; fork++)
+ {
+ XLogDropRelation(xlrec->xnodes[i], fork);
+ smgrdounlink(srel, fork, false, true);
+ }
+ smgrclose(srel);
}
- smgrclose(srel);
}
}
{
xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
- xact_redo_commit(xlrec, record->xl_xid);
+ xact_redo_commit(lsn, xlrec, record->xl_xid);
}
else if (info == XLOG_XACT_ABORT)
{
{
xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) XLogRecGetData(record);
- xact_redo_commit(&xlrec->crec, xlrec->xid);
+ xact_redo_commit(lsn, &xlrec->crec, xlrec->xid);
RemoveTwoPhaseFile(xlrec->xid, false);
}
else if (info == XLOG_XACT_ABORT_PREPARED)
*/
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, false);
/* Also tell xlogutils.c about it */