Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit60a8b63

Browse files
committed
Fix an assertion failure related to an exclusive backup.
Previously multiple sessions could execute pg_start_backup() andpg_stop_backup() to start and stop an exclusive backup at the same time.This could trigger the assertion failure of"FailedAssertion("!(XLogCtl->Insert.exclusiveBackup)".This happend because, even while pg_start_backup() was startingan exclusive backup, other session could run pg_stop_backup()concurrently and mark the backup as not-in-progress unconditionally.This patch introduces ExclusiveBackupState indicating the state ofan exclusive backup. This state is used to ensure that there is onlyone session running pg_start_backup() or pg_stop_backup() atthe same time, to avoid the assertion failure.Back-patch to all supported versions.Author: Michael PaquierReviewed-By: Kyotaro Horiguchi and meReported-By: Andreas SeltenreichDiscussion: <87mvktojme.fsf@credativ.de>
1 parent8a70d8a commit60a8b63

File tree

1 file changed

+150
-73
lines changed
  • src/backend/access/transam

1 file changed

+150
-73
lines changed

‎src/backend/access/transam/xlog.c

Lines changed: 150 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,29 @@ typedef union WALInsertLockPadded
459459
charpad[PG_CACHE_LINE_SIZE];
460460
}WALInsertLockPadded;
461461

462+
/*
463+
* State of an exclusive backup, necessary to control concurrent activities
464+
* across sessions when working on exclusive backups.
465+
*
466+
* EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
467+
* running, to be more precise pg_start_backup() is not being executed for
468+
* an exclusive backup and there is no exclusive backup in progress.
469+
* EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
470+
* exclusive backup.
471+
* EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
472+
* running and an exclusive backup is in progress. pg_stop_backup() is
473+
* needed to finish it.
474+
* EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
475+
* exclusive backup.
476+
*/
477+
typedefenumExclusiveBackupState
478+
{
479+
EXCLUSIVE_BACKUP_NONE=0,
480+
EXCLUSIVE_BACKUP_STARTING,
481+
EXCLUSIVE_BACKUP_IN_PROGRESS,
482+
EXCLUSIVE_BACKUP_STOPPING
483+
}ExclusiveBackupState;
484+
462485
/*
463486
* Shared state data for WAL insertion.
464487
*/
@@ -500,13 +523,15 @@ typedef struct XLogCtlInsert
500523
boolfullPageWrites;
501524

502525
/*
503-
* exclusiveBackup is true if a backup started with pg_start_backup() is
504-
* in progress, and nonExclusiveBackups is a counter indicating the number
505-
* of streaming base backups currently in progress. forcePageWrites is set
506-
* to true when either of these is non-zero. lastBackupStart is the latest
507-
* checkpoint redo location used as a starting point for an online backup.
526+
* exclusiveBackupState indicates the state of an exclusive backup
527+
* (see comments of ExclusiveBackupState for more details).
528+
* nonExclusiveBackups is a counter indicating the number of streaming
529+
* base backups currently in progress. forcePageWrites is set to true
530+
* when either of these is non-zero. lastBackupStart is the latest
531+
* checkpoint redo location used as a starting point for an online
532+
* backup.
508533
*/
509-
boolexclusiveBackup;
534+
ExclusiveBackupStateexclusiveBackupState;
510535
intnonExclusiveBackups;
511536
XLogRecPtrlastBackupStart;
512537

@@ -845,6 +870,7 @@ static void xlog_outrec(StringInfo buf, XLogReaderState *record);
845870
#endif
846871
staticvoidxlog_outdesc(StringInfobuf,XLogReaderState*record);
847872
staticvoidpg_start_backup_callback(intcode,Datumarg);
873+
staticvoidpg_stop_backup_callback(intcode,Datumarg);
848874
staticboolread_backup_label(XLogRecPtr*checkPointLoc,
849875
bool*backupEndRequired,bool*backupFromStandby);
850876
staticboolread_tablespace_map(List**tablespaces);
@@ -9872,15 +9898,20 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
98729898
WALInsertLockAcquireExclusive();
98739899
if (exclusive)
98749900
{
9875-
if (XLogCtl->Insert.exclusiveBackup)
9901+
/*
9902+
* At first, mark that we're now starting an exclusive backup,
9903+
* to ensure that there are no other sessions currently running
9904+
* pg_start_backup() or pg_stop_backup().
9905+
*/
9906+
if (XLogCtl->Insert.exclusiveBackupState!=EXCLUSIVE_BACKUP_NONE)
98769907
{
98779908
WALInsertLockRelease();
98789909
ereport(ERROR,
98799910
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
98809911
errmsg("a backup is already in progress"),
98819912
errhint("Run pg_stop_backup() and try again.")));
98829913
}
9883-
XLogCtl->Insert.exclusiveBackup=true;
9914+
XLogCtl->Insert.exclusiveBackupState=EXCLUSIVE_BACKUP_STARTING;
98849915
}
98859916
else
98869917
XLogCtl->Insert.nonExclusiveBackups++;
@@ -10135,7 +10166,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
1013510166
{
1013610167
/*
1013710168
* Check for existing backup label --- implies a backup is already
10138-
* running. (XXX given that we checkedexclusiveBackup above,
10169+
* running. (XXX given that we checkedexclusiveBackupState above,
1013910170
* maybe it would be OK to just unlink any such label file?)
1014010171
*/
1014110172
if (stat(BACKUP_LABEL_FILE,&stat_buf)!=0)
@@ -10216,6 +10247,16 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
1021610247
}
1021710248
PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum)BoolGetDatum(exclusive));
1021810249

10250+
/*
10251+
* Mark that start phase has correctly finished for an exclusive backup.
10252+
*/
10253+
if (exclusive)
10254+
{
10255+
WALInsertLockAcquireExclusive();
10256+
XLogCtl->Insert.exclusiveBackupState=EXCLUSIVE_BACKUP_IN_PROGRESS;
10257+
WALInsertLockRelease();
10258+
}
10259+
1021910260
/*
1022010261
* We're done. As a convenience, return the starting WAL location.
1022110262
*/
@@ -10234,23 +10275,41 @@ pg_start_backup_callback(int code, Datum arg)
1023410275
WALInsertLockAcquireExclusive();
1023510276
if (exclusive)
1023610277
{
10237-
Assert(XLogCtl->Insert.exclusiveBackup);
10238-
XLogCtl->Insert.exclusiveBackup=false;
10278+
Assert(XLogCtl->Insert.exclusiveBackupState==EXCLUSIVE_BACKUP_STARTING);
10279+
XLogCtl->Insert.exclusiveBackupState=EXCLUSIVE_BACKUP_NONE;
1023910280
}
1024010281
else
1024110282
{
1024210283
Assert(XLogCtl->Insert.nonExclusiveBackups>0);
1024310284
XLogCtl->Insert.nonExclusiveBackups--;
1024410285
}
1024510286

10246-
if (!XLogCtl->Insert.exclusiveBackup&&
10287+
if (XLogCtl->Insert.exclusiveBackupState==EXCLUSIVE_BACKUP_NONE&&
1024710288
XLogCtl->Insert.nonExclusiveBackups==0)
1024810289
{
1024910290
XLogCtl->Insert.forcePageWrites= false;
1025010291
}
1025110292
WALInsertLockRelease();
1025210293
}
1025310294

10295+
/*
10296+
* Error cleanup callback for pg_stop_backup
10297+
*/
10298+
staticvoid
10299+
pg_stop_backup_callback(intcode,Datumarg)
10300+
{
10301+
boolexclusive=DatumGetBool(arg);
10302+
10303+
/* Update backup status on failure */
10304+
WALInsertLockAcquireExclusive();
10305+
if (exclusive)
10306+
{
10307+
Assert(XLogCtl->Insert.exclusiveBackupState==EXCLUSIVE_BACKUP_STOPPING);
10308+
XLogCtl->Insert.exclusiveBackupState=EXCLUSIVE_BACKUP_IN_PROGRESS;
10309+
}
10310+
WALInsertLockRelease();
10311+
}
10312+
1025410313
/*
1025510314
* do_pg_stop_backup is the workhorse of the user-visible pg_stop_backup()
1025610315
* function.
@@ -10313,20 +10372,91 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
1031310372
errmsg("WAL level not sufficient for making an online backup"),
1031410373
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
1031510374

10316-
/*
10317-
* OK to update backup counters and forcePageWrites
10318-
*/
10319-
WALInsertLockAcquireExclusive();
1032010375
if (exclusive)
1032110376
{
10322-
if (!XLogCtl->Insert.exclusiveBackup)
10377+
/*
10378+
* At first, mark that we're now stopping an exclusive backup,
10379+
* to ensure that there are no other sessions currently running
10380+
* pg_start_backup() or pg_stop_backup().
10381+
*/
10382+
WALInsertLockAcquireExclusive();
10383+
if (XLogCtl->Insert.exclusiveBackupState!=EXCLUSIVE_BACKUP_IN_PROGRESS)
1032310384
{
1032410385
WALInsertLockRelease();
1032510386
ereport(ERROR,
1032610387
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1032710388
errmsg("exclusive backup not in progress")));
1032810389
}
10329-
XLogCtl->Insert.exclusiveBackup= false;
10390+
XLogCtl->Insert.exclusiveBackupState=EXCLUSIVE_BACKUP_STOPPING;
10391+
WALInsertLockRelease();
10392+
10393+
/*
10394+
* Remove backup_label. In case of failure, the state for an exclusive
10395+
* backup is switched back to in-progress.
10396+
*/
10397+
PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum)BoolGetDatum(exclusive));
10398+
{
10399+
/*
10400+
* Read the existing label file into memory.
10401+
*/
10402+
structstatstatbuf;
10403+
intr;
10404+
10405+
if (stat(BACKUP_LABEL_FILE,&statbuf))
10406+
{
10407+
/* should not happen per the upper checks */
10408+
if (errno!=ENOENT)
10409+
ereport(ERROR,
10410+
(errcode_for_file_access(),
10411+
errmsg("could not stat file \"%s\": %m",
10412+
BACKUP_LABEL_FILE)));
10413+
ereport(ERROR,
10414+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
10415+
errmsg("a backup is not in progress")));
10416+
}
10417+
10418+
lfp=AllocateFile(BACKUP_LABEL_FILE,"r");
10419+
if (!lfp)
10420+
{
10421+
ereport(ERROR,
10422+
(errcode_for_file_access(),
10423+
errmsg("could not read file \"%s\": %m",
10424+
BACKUP_LABEL_FILE)));
10425+
}
10426+
labelfile=palloc(statbuf.st_size+1);
10427+
r=fread(labelfile,statbuf.st_size,1,lfp);
10428+
labelfile[statbuf.st_size]='\0';
10429+
10430+
/*
10431+
* Close and remove the backup label file
10432+
*/
10433+
if (r!=1||ferror(lfp)||FreeFile(lfp))
10434+
ereport(ERROR,
10435+
(errcode_for_file_access(),
10436+
errmsg("could not read file \"%s\": %m",
10437+
BACKUP_LABEL_FILE)));
10438+
if (unlink(BACKUP_LABEL_FILE)!=0)
10439+
ereport(ERROR,
10440+
(errcode_for_file_access(),
10441+
errmsg("could not remove file \"%s\": %m",
10442+
BACKUP_LABEL_FILE)));
10443+
10444+
/*
10445+
* Remove tablespace_map file if present, it is created only if there
10446+
* are tablespaces.
10447+
*/
10448+
unlink(TABLESPACE_MAP);
10449+
}
10450+
PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum)BoolGetDatum(exclusive));
10451+
}
10452+
10453+
/*
10454+
* OK to update backup counters and forcePageWrites
10455+
*/
10456+
WALInsertLockAcquireExclusive();
10457+
if (exclusive)
10458+
{
10459+
XLogCtl->Insert.exclusiveBackupState=EXCLUSIVE_BACKUP_NONE;
1033010460
}
1033110461
else
1033210462
{
@@ -10340,66 +10470,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
1034010470
XLogCtl->Insert.nonExclusiveBackups--;
1034110471
}
1034210472

10343-
if (!XLogCtl->Insert.exclusiveBackup&&
10473+
if (XLogCtl->Insert.exclusiveBackupState==EXCLUSIVE_BACKUP_NONE&&
1034410474
XLogCtl->Insert.nonExclusiveBackups==0)
1034510475
{
1034610476
XLogCtl->Insert.forcePageWrites= false;
1034710477
}
1034810478
WALInsertLockRelease();
1034910479

10350-
if (exclusive)
10351-
{
10352-
/*
10353-
* Read the existing label file into memory.
10354-
*/
10355-
structstatstatbuf;
10356-
intr;
10357-
10358-
if (stat(BACKUP_LABEL_FILE,&statbuf))
10359-
{
10360-
if (errno!=ENOENT)
10361-
ereport(ERROR,
10362-
(errcode_for_file_access(),
10363-
errmsg("could not stat file \"%s\": %m",
10364-
BACKUP_LABEL_FILE)));
10365-
ereport(ERROR,
10366-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
10367-
errmsg("a backup is not in progress")));
10368-
}
10369-
10370-
lfp=AllocateFile(BACKUP_LABEL_FILE,"r");
10371-
if (!lfp)
10372-
{
10373-
ereport(ERROR,
10374-
(errcode_for_file_access(),
10375-
errmsg("could not read file \"%s\": %m",
10376-
BACKUP_LABEL_FILE)));
10377-
}
10378-
labelfile=palloc(statbuf.st_size+1);
10379-
r=fread(labelfile,statbuf.st_size,1,lfp);
10380-
labelfile[statbuf.st_size]='\0';
10381-
10382-
/*
10383-
* Close and remove the backup label file
10384-
*/
10385-
if (r!=1||ferror(lfp)||FreeFile(lfp))
10386-
ereport(ERROR,
10387-
(errcode_for_file_access(),
10388-
errmsg("could not read file \"%s\": %m",
10389-
BACKUP_LABEL_FILE)));
10390-
if (unlink(BACKUP_LABEL_FILE)!=0)
10391-
ereport(ERROR,
10392-
(errcode_for_file_access(),
10393-
errmsg("could not remove file \"%s\": %m",
10394-
BACKUP_LABEL_FILE)));
10395-
10396-
/*
10397-
* Remove tablespace_map file if present, it is created only if there
10398-
* are tablespaces.
10399-
*/
10400-
unlink(TABLESPACE_MAP);
10401-
}
10402-
1040310480
/*
1040410481
* Read and parse the START WAL LOCATION line (this code is pretty crude,
1040510482
* but we are not expecting any variability in the file format).
@@ -10636,7 +10713,7 @@ do_pg_abort_backup(void)
1063610713
Assert(XLogCtl->Insert.nonExclusiveBackups>0);
1063710714
XLogCtl->Insert.nonExclusiveBackups--;
1063810715

10639-
if (!XLogCtl->Insert.exclusiveBackup&&
10716+
if (XLogCtl->Insert.exclusiveBackupState==EXCLUSIVE_BACKUP_NONE&&
1064010717
XLogCtl->Insert.nonExclusiveBackups==0)
1064110718
{
1064210719
XLogCtl->Insert.forcePageWrites= false;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp