fix_do_pg_abort_backup_v9.patch
application/octet-stream
Filename: fix_do_pg_abort_backup_v9.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v9
| File | + | − |
|---|---|---|
| src/backend/access/transam/xlog.c | 24 | 3 |
| src/backend/replication/basebackup.c | 9 | 3 |
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index e729180..f547c0e 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10636,8 +10636,14 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
{
WALInsertLockAcquireExclusive();
XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
- WALInsertLockRelease();
+
+ /*
+ * Set session-level lock. To avoid calling CHECK_FOR_INTERRUPTS by
+ * LWLockReleaseClearVar before changing the backup state we change
+ * it while holding the WAL insert lock.
+ */
sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
+ WALInsertLockRelease();
}
else
sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
@@ -10865,11 +10871,18 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
XLogCtl->Insert.forcePageWrites = false;
}
- WALInsertLockRelease();
- /* Clean up session-level lock */
+ /*
+ * Clean up session-level lock. To avoid calling CHECK_FOR_INTERRUPTS by
+ * LWLockReleaseClearVar before changing the backup state we change it
+ * while holding the WAL insert lock as this allows to keep backup counters
+ * kept in shared memory consistent with the state of the session starting
+ * or stopping a backup.
+ */
sessionBackupState = SESSION_BACKUP_NONE;
+ WALInsertLockRelease();
+
/*
* Read and parse the START WAL LOCATION line (this code is pretty crude,
* but we are not expecting any variability in the file format).
@@ -11107,8 +11120,16 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
void
do_pg_abort_backup(void)
{
+ /*
+ * Quick exit if session is not keeping around a non-exclusive backup
+ * already started.
+ */
+ if (sessionBackupState == SESSION_BACKUP_NONE)
+ return;
+
WALInsertLockAcquireExclusive();
Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
+ Assert(sessionBackupState == SESSION_BACKUP_NON_EXCLUSIVE);
XLogCtl->Insert.nonExclusiveBackups--;
if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index cbcb3db..9598b53 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -214,8 +214,8 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
/*
* Once do_pg_start_backup has been called, ensure that any failure causes
* us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_start_backup() and
- * do_pg_stop_backup() should be inside the error cleanup block!
+ * reason, *all* functionality between do_pg_start_backup() until
+ * do_pg_stop_backup() is done should be inside the error cleanup block!
*/
PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
@@ -324,10 +324,16 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
else
pq_putemptymessage('c'); /* CopyDone */
}
+
+ /*
+ * Finish the backup while still holding the cleanup callback to
+ * avoid inconsistent in-memory data should the this call fail
+ * before sessionBackupState is updated.
+ */
+ endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
}
PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
- endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
if (opt->includewal)
{