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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy