Skip to content

Commit 8de6278

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 4ae0805 commit 8de6278

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
@@ -482,6 +482,12 @@ typedef enum ExclusiveBackupState
482482
EXCLUSIVE_BACKUP_STOPPING
483483
} ExclusiveBackupState;
484484

485+
/*
486+
* Session status of running backup, used for sanity checks in SQL-callable
487+
* functions to start and stop backups.
488+
*/
489+
static SessionBackupState sessionBackupState = SESSION_BACKUP_NONE;
490+
485491
/*
486492
* Shared state data for WAL insertion.
487493
*/
@@ -10249,13 +10255,17 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
1024910255

1025010256
/*
1025110257
* Mark that start phase has correctly finished for an exclusive backup.
10258+
* Session-level locks are updated as well to reflect that state.
1025210259
*/
1025310260
if (exclusive)
1025410261
{
1025510262
WALInsertLockAcquireExclusive();
1025610263
XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
1025710264
WALInsertLockRelease();
10265+
sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
1025810266
}
10267+
else
10268+
sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
1025910269

1026010270
/*
1026110271
* We're done. As a convenience, return the starting WAL location.
@@ -10310,6 +10320,15 @@ pg_stop_backup_callback(int code, Datum arg)
1031010320
WALInsertLockRelease();
1031110321
}
1031210322

10323+
/*
10324+
* Utility routine to fetch the session-level status of a backup running.
10325+
*/
10326+
SessionBackupState
10327+
get_backup_status(void)
10328+
{
10329+
return sessionBackupState;
10330+
}
10331+
1031310332
/*
1031410333
* do_pg_stop_backup is the workhorse of the user-visible pg_stop_backup()
1031510334
* function.
@@ -10477,6 +10496,9 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
1047710496
}
1047810497
WALInsertLockRelease();
1047910498

10499+
/* Clean up session-level lock */
10500+
sessionBackupState = SESSION_BACKUP_NONE;
10501+
1048010502
/*
1048110503
* Read and parse the START WAL LOCATION line (this code is pretty crude,
1048210504
* 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
@@ -43,8 +43,6 @@
4343
*/
4444
static StringInfo label_file;
4545
static StringInfo tblspc_map_file;
46-
static bool exclusive_backup_running = false;
47-
static bool nonexclusive_backup_running = false;
4846

4947
/*
5048
* Called when the backend exits with a running non-exclusive base backup,
@@ -79,10 +77,11 @@ pg_start_backup(PG_FUNCTION_ARGS)
7977
char *backupidstr;
8078
XLogRecPtr startpoint;
8179
DIR *dir;
80+
SessionBackupState status = get_backup_status();
8281

8382
backupidstr = text_to_cstring(backupid);
8483

85-
if (exclusive_backup_running || nonexclusive_backup_running)
84+
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
8685
ereport(ERROR,
8786
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8887
errmsg("a backup is already in progress in this session")));
@@ -97,7 +96,6 @@ pg_start_backup(PG_FUNCTION_ARGS)
9796
{
9897
startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
9998
dir, NULL, NULL, false, true);
100-
exclusive_backup_running = true;
10199
}
102100
else
103101
{
@@ -114,7 +112,6 @@ pg_start_backup(PG_FUNCTION_ARGS)
114112

115113
startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
116114
dir, NULL, tblspc_map_file, false, true);
117-
nonexclusive_backup_running = true;
118115

119116
before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
120117
}
@@ -148,23 +145,22 @@ Datum
148145
pg_stop_backup(PG_FUNCTION_ARGS)
149146
{
150147
XLogRecPtr stoppoint;
148+
SessionBackupState status = get_backup_status();
151149

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

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

166-
exclusive_backup_running = false;
167-
168164
PG_RETURN_LSN(stoppoint);
169165
}
170166

@@ -192,6 +188,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
192188

193189
bool exclusive = PG_GETARG_BOOL(0);
194190
XLogRecPtr stoppoint;
191+
SessionBackupState status = get_backup_status();
195192

196193
/* check to see if caller supports us returning a tuplestore */
197194
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
@@ -223,7 +220,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
223220

224221
if (exclusive)
225222
{
226-
if (nonexclusive_backup_running)
223+
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
227224
ereport(ERROR,
228225
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
229226
errmsg("non-exclusive backup in progress"),
@@ -234,14 +231,13 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
234231
* return NULL for both backup_label and tablespace_map.
235232
*/
236233
stoppoint = do_pg_stop_backup(NULL, true, NULL);
237-
exclusive_backup_running = false;
238234

239235
nulls[1] = true;
240236
nulls[2] = true;
241237
}
242238
else
243239
{
244-
if (!nonexclusive_backup_running)
240+
if (status != SESSION_BACKUP_NON_EXCLUSIVE)
245241
ereport(ERROR,
246242
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
247243
errmsg("non-exclusive backup is not in progress"),
@@ -252,7 +248,6 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
252248
* and tablespace map so they can be written to disk by the caller.
253249
*/
254250
stoppoint = do_pg_stop_backup(label_file->data, true, NULL);
255-
nonexclusive_backup_running = false;
256251
cancel_before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
257252

258253
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
@@ -274,15 +274,34 @@ extern void assign_max_wal_size(int newval, void *extra);
274274
extern void assign_checkpoint_completion_target(double newval, void *extra);
275275

276276
/*
277-
* Starting/stopping a base backup
277+
* Routines to start, stop, and get status of a base backup.
278278
*/
279+
280+
/*
281+
* Session-level status of base backups
282+
*
283+
* This is used in parallel with the shared memory status to control parallel
284+
* execution of base backup functions for a given session, be it a backend
285+
* dedicated to replication or a normal backend connected to a database. The
286+
* update of the session-level status happens at the same time as the shared
287+
* memory counters to keep a consistent global and local state of the backups
288+
* running.
289+
*/
290+
typedef enum SessionBackupState
291+
{
292+
SESSION_BACKUP_NONE,
293+
SESSION_BACKUP_EXCLUSIVE,
294+
SESSION_BACKUP_NON_EXCLUSIVE
295+
} SessionBackupState;
296+
279297
extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
280298
TimeLineID *starttli_p, StringInfo labelfile, DIR *tblspcdir,
281299
List **tablespaces, StringInfo tblspcmapfile, bool infotbssize,
282300
bool needtblspcmapfile);
283301
extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
284302
TimeLineID *stoptli_p);
285303
extern void do_pg_abort_backup(void);
304+
extern SessionBackupState get_backup_status(void);
286305

287306
/* File path names (all relative to $PGDATA) */
288307
#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