Skip to content

Commit 7887453

Browse files
committed
Fix backup canceling
Assert-enabled build crashes but without asserts it works by wrong way: it may not reset forcing full page write and preventing from starting exclusive backup with the same name as cancelled. Patch replaces pair of booleans nonexclusive_backup_running/exclusive_backup_running to single enum to correctly describe backup state. Backpatch to 9.6 where bug was introduced Reported-by: David Steele Authors: Michael Paquier, David Steele Reviewed-by: Anastasia Lubennikova https://commitfest.postgresql.org/13/1068/
1 parent 457a444 commit 7887453

File tree

3 files changed

+52
-16
lines changed

3 files changed

+52
-16
lines changed

src/backend/access/transam/xlog.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,12 @@ typedef enum ExclusiveBackupState
503503
EXCLUSIVE_BACKUP_STOPPING
504504
} ExclusiveBackupState;
505505

506+
/*
507+
* Session status of running backup, used for sanity checks in SQL-callable
508+
* functions to start and stop backups.
509+
*/
510+
static SessionBackupState sessionBackupState = SESSION_BACKUP_NONE;
511+
506512
/*
507513
* Shared state data for WAL insertion.
508514
*/
@@ -10566,13 +10572,17 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
1056610572

1056710573
/*
1056810574
* Mark that start phase has correctly finished for an exclusive backup.
10575+
* Session-level locks are updated as well to reflect that state.
1056910576
*/
1057010577
if (exclusive)
1057110578
{
1057210579
WALInsertLockAcquireExclusive();
1057310580
XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
1057410581
WALInsertLockRelease();
10582+
sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
1057510583
}
10584+
else
10585+
sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
1057610586

1057710587
/*
1057810588
* We're done. As a convenience, return the starting WAL location.
@@ -10627,6 +10637,15 @@ pg_stop_backup_callback(int code, Datum arg)
1062710637
WALInsertLockRelease();
1062810638
}
1062910639

10640+
/*
10641+
* Utility routine to fetch the session-level status of a backup running.
10642+
*/
10643+
SessionBackupState
10644+
get_backup_status(void)
10645+
{
10646+
return sessionBackupState;
10647+
}
10648+
1063010649
/*
1063110650
* do_pg_stop_backup is the workhorse of the user-visible pg_stop_backup()
1063210651
* function.
@@ -10794,6 +10813,9 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
1079410813
}
1079510814
WALInsertLockRelease();
1079610815

10816+
/* Clean up session-level lock */
10817+
sessionBackupState = SESSION_BACKUP_NONE;
10818+
1079710819
/*
1079810820
* Read and parse the START WAL LOCATION line (this code is pretty crude,
1079910821
* but we are not expecting any variability in the file format).

src/backend/access/transam/xlogfuncs.c

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@
4242
*/
4343
static StringInfo label_file;
4444
static StringInfo tblspc_map_file;
45-
static bool exclusive_backup_running = false;
46-
static bool nonexclusive_backup_running = false;
4745

4846
/*
4947
* Called when the backend exits with a running non-exclusive base backup,
@@ -78,10 +76,11 @@ pg_start_backup(PG_FUNCTION_ARGS)
7876
char *backupidstr;
7977
XLogRecPtr startpoint;
8078
DIR *dir;
79+
SessionBackupState status = get_backup_status();
8180

8281
backupidstr = text_to_cstring(backupid);
8382

84-
if (exclusive_backup_running || nonexclusive_backup_running)
83+
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
8584
ereport(ERROR,
8685
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8786
errmsg("a backup is already in progress in this session")));
@@ -96,7 +95,6 @@ pg_start_backup(PG_FUNCTION_ARGS)
9695
{
9796
startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
9897
dir, NULL, NULL, false, true);
99-
exclusive_backup_running = true;
10098
}
10199
else
102100
{
@@ -113,7 +111,6 @@ pg_start_backup(PG_FUNCTION_ARGS)
113111

114112
startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
115113
dir, NULL, tblspc_map_file, false, true);
116-
nonexclusive_backup_running = true;
117114

118115
before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
119116
}
@@ -147,23 +144,22 @@ Datum
147144
pg_stop_backup(PG_FUNCTION_ARGS)
148145
{
149146
XLogRecPtr stoppoint;
147+
SessionBackupState status = get_backup_status();
150148

151-
if (nonexclusive_backup_running)
149+
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
152150
ereport(ERROR,
153151
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
154152
errmsg("non-exclusive backup in progress"),
155153
errhint("Did you mean to use pg_stop_backup('f')?")));
156154

157155
/*
158156
* Exclusive backups were typically started in a different connection, so
159-
* don't try to verify that exclusive_backup_running is set in this one.
160-
* Actual verification that an exclusive backup is in fact running is
161-
* handled inside do_pg_stop_backup.
157+
* don't try to verify that status of backup is set to
158+
* SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
159+
* exclusive backup is in fact running is handled inside do_pg_stop_backup.
162160
*/
163161
stoppoint = do_pg_stop_backup(NULL, true, NULL);
164162

165-
exclusive_backup_running = false;
166-
167163
PG_RETURN_LSN(stoppoint);
168164
}
169165

@@ -199,6 +195,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
199195
bool exclusive = PG_GETARG_BOOL(0);
200196
bool waitforarchive = PG_GETARG_BOOL(1);
201197
XLogRecPtr stoppoint;
198+
SessionBackupState status = get_backup_status();
202199

203200
/* check to see if caller supports us returning a tuplestore */
204201
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
@@ -230,7 +227,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
230227

231228
if (exclusive)
232229
{
233-
if (nonexclusive_backup_running)
230+
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
234231
ereport(ERROR,
235232
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
236233
errmsg("non-exclusive backup in progress"),
@@ -241,14 +238,13 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
241238
* return NULL for both backup_label and tablespace_map.
242239
*/
243240
stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
244-
exclusive_backup_running = false;
245241

246242
nulls[1] = true;
247243
nulls[2] = true;
248244
}
249245
else
250246
{
251-
if (!nonexclusive_backup_running)
247+
if (status != SESSION_BACKUP_NON_EXCLUSIVE)
252248
ereport(ERROR,
253249
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
254250
errmsg("non-exclusive backup is not in progress"),
@@ -259,7 +255,6 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
259255
* and tablespace map so they can be written to disk by the caller.
260256
*/
261257
stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
262-
nonexclusive_backup_running = false;
263258
cancel_before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
264259

265260
values[1] = CStringGetTextDatum(label_file->data);

src/include/access/xlog.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,15 +288,34 @@ extern void assign_max_wal_size(int newval, void *extra);
288288
extern void assign_checkpoint_completion_target(double newval, void *extra);
289289

290290
/*
291-
* Starting/stopping a base backup
291+
* Routines to start, stop, and get status of a base backup.
292292
*/
293+
294+
/*
295+
* Session-level status of base backups
296+
*
297+
* This is used in parallel with the shared memory status to control parallel
298+
* execution of base backup functions for a given session, be it a backend
299+
* dedicated to replication or a normal backend connected to a database. The
300+
* update of the session-level status happens at the same time as the shared
301+
* memory counters to keep a consistent global and local state of the backups
302+
* running.
303+
*/
304+
typedef enum SessionBackupState
305+
{
306+
SESSION_BACKUP_NONE,
307+
SESSION_BACKUP_EXCLUSIVE,
308+
SESSION_BACKUP_NON_EXCLUSIVE
309+
} SessionBackupState;
310+
293311
extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
294312
TimeLineID *starttli_p, StringInfo labelfile, DIR *tblspcdir,
295313
List **tablespaces, StringInfo tblspcmapfile, bool infotbssize,
296314
bool needtblspcmapfile);
297315
extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
298316
TimeLineID *stoptli_p);
299317
extern void do_pg_abort_backup(void);
318+
extern SessionBackupState get_backup_status(void);
300319

301320
/* File path names (all relative to $PGDATA) */
302321
#define BACKUP_LABEL_FILE "backup_label"

0 commit comments

Comments
 (0)