Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 70461ca

Browse files
committed
Merge branch 'REL9_6_STABLE' into PGPRO9_6
2 parents ff5466a + 746ba76 commit 70461ca

File tree

11 files changed

+241
-195
lines changed

11 files changed

+241
-195
lines changed

src/backend/access/transam/xlog.c

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

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

503526
/*
504-
* exclusiveBackup is true if a backup started with pg_start_backup() is
505-
* in progress, and nonExclusiveBackups is a counter indicating the number
506-
* of streaming base backups currently in progress. forcePageWrites is set
507-
* to true when either of these is non-zero. lastBackupStart is the latest
508-
* checkpoint redo location used as a starting point for an online backup.
527+
* exclusiveBackupState indicates the state of an exclusive backup
528+
* (see comments of ExclusiveBackupState for more details).
529+
* nonExclusiveBackups is a counter indicating the number of streaming
530+
* base backups currently in progress. forcePageWrites is set to true
531+
* when either of these is non-zero. lastBackupStart is the latest
532+
* checkpoint redo location used as a starting point for an online
533+
* backup.
509534
*/
510-
bool exclusiveBackup;
535+
ExclusiveBackupState exclusiveBackupState;
511536
int nonExclusiveBackups;
512537
XLogRecPtr lastBackupStart;
513538

@@ -846,6 +871,7 @@ static void xlog_outrec(StringInfo buf, XLogReaderState *record);
846871
#endif
847872
static void xlog_outdesc(StringInfo buf, XLogReaderState *record);
848873
static void pg_start_backup_callback(int code, Datum arg);
874+
static void pg_stop_backup_callback(int code, Datum arg);
849875
static bool read_backup_label(XLogRecPtr *checkPointLoc,
850876
bool *backupEndRequired, bool *backupFromStandby);
851877
static bool read_tablespace_map(List **tablespaces);
@@ -9890,15 +9916,20 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
98909916
WALInsertLockAcquireExclusive();
98919917
if (exclusive)
98929918
{
9893-
if (XLogCtl->Insert.exclusiveBackup)
9919+
/*
9920+
* At first, mark that we're now starting an exclusive backup,
9921+
* to ensure that there are no other sessions currently running
9922+
* pg_start_backup() or pg_stop_backup().
9923+
*/
9924+
if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
98949925
{
98959926
WALInsertLockRelease();
98969927
ereport(ERROR,
98979928
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
98989929
errmsg("a backup is already in progress"),
98999930
errhint("Run pg_stop_backup() and try again.")));
99009931
}
9901-
XLogCtl->Insert.exclusiveBackup = true;
9932+
XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
99029933
}
99039934
else
99049935
XLogCtl->Insert.nonExclusiveBackups++;
@@ -10153,7 +10184,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
1015310184
{
1015410185
/*
1015510186
* Check for existing backup label --- implies a backup is already
10156-
* running. (XXX given that we checked exclusiveBackup above,
10187+
* running. (XXX given that we checked exclusiveBackupState above,
1015710188
* maybe it would be OK to just unlink any such label file?)
1015810189
*/
1015910190
if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
@@ -10234,6 +10265,16 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
1023410265
}
1023510266
PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
1023610267

10268+
/*
10269+
* Mark that start phase has correctly finished for an exclusive backup.
10270+
*/
10271+
if (exclusive)
10272+
{
10273+
WALInsertLockAcquireExclusive();
10274+
XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
10275+
WALInsertLockRelease();
10276+
}
10277+
1023710278
/*
1023810279
* We're done. As a convenience, return the starting WAL location.
1023910280
*/
@@ -10252,23 +10293,41 @@ pg_start_backup_callback(int code, Datum arg)
1025210293
WALInsertLockAcquireExclusive();
1025310294
if (exclusive)
1025410295
{
10255-
Assert(XLogCtl->Insert.exclusiveBackup);
10256-
XLogCtl->Insert.exclusiveBackup = false;
10296+
Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
10297+
XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
1025710298
}
1025810299
else
1025910300
{
1026010301
Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
1026110302
XLogCtl->Insert.nonExclusiveBackups--;
1026210303
}
1026310304

10264-
if (!XLogCtl->Insert.exclusiveBackup &&
10305+
if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
1026510306
XLogCtl->Insert.nonExclusiveBackups == 0)
1026610307
{
1026710308
XLogCtl->Insert.forcePageWrites = false;
1026810309
}
1026910310
WALInsertLockRelease();
1027010311
}
1027110312

10313+
/*
10314+
* Error cleanup callback for pg_stop_backup
10315+
*/
10316+
static void
10317+
pg_stop_backup_callback(int code, Datum arg)
10318+
{
10319+
bool exclusive = DatumGetBool(arg);
10320+
10321+
/* Update backup status on failure */
10322+
WALInsertLockAcquireExclusive();
10323+
if (exclusive)
10324+
{
10325+
Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
10326+
XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
10327+
}
10328+
WALInsertLockRelease();
10329+
}
10330+
1027210331
/*
1027310332
* do_pg_stop_backup is the workhorse of the user-visible pg_stop_backup()
1027410333
* function.
@@ -10331,20 +10390,91 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
1033110390
errmsg("WAL level not sufficient for making an online backup"),
1033210391
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
1033310392

10334-
/*
10335-
* OK to update backup counters and forcePageWrites
10336-
*/
10337-
WALInsertLockAcquireExclusive();
1033810393
if (exclusive)
1033910394
{
10340-
if (!XLogCtl->Insert.exclusiveBackup)
10395+
/*
10396+
* At first, mark that we're now stopping an exclusive backup,
10397+
* to ensure that there are no other sessions currently running
10398+
* pg_start_backup() or pg_stop_backup().
10399+
*/
10400+
WALInsertLockAcquireExclusive();
10401+
if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
1034110402
{
1034210403
WALInsertLockRelease();
1034310404
ereport(ERROR,
1034410405
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1034510406
errmsg("exclusive backup not in progress")));
1034610407
}
10347-
XLogCtl->Insert.exclusiveBackup = false;
10408+
XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
10409+
WALInsertLockRelease();
10410+
10411+
/*
10412+
* Remove backup_label. In case of failure, the state for an exclusive
10413+
* backup is switched back to in-progress.
10414+
*/
10415+
PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
10416+
{
10417+
/*
10418+
* Read the existing label file into memory.
10419+
*/
10420+
struct stat statbuf;
10421+
int r;
10422+
10423+
if (stat(BACKUP_LABEL_FILE, &statbuf))
10424+
{
10425+
/* should not happen per the upper checks */
10426+
if (errno != ENOENT)
10427+
ereport(ERROR,
10428+
(errcode_for_file_access(),
10429+
errmsg("could not stat file \"%s\": %m",
10430+
BACKUP_LABEL_FILE)));
10431+
ereport(ERROR,
10432+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
10433+
errmsg("a backup is not in progress")));
10434+
}
10435+
10436+
lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
10437+
if (!lfp)
10438+
{
10439+
ereport(ERROR,
10440+
(errcode_for_file_access(),
10441+
errmsg("could not read file \"%s\": %m",
10442+
BACKUP_LABEL_FILE)));
10443+
}
10444+
labelfile = palloc(statbuf.st_size + 1);
10445+
r = fread(labelfile, statbuf.st_size, 1, lfp);
10446+
labelfile[statbuf.st_size] = '\0';
10447+
10448+
/*
10449+
* Close and remove the backup label file
10450+
*/
10451+
if (r != 1 || ferror(lfp) || FreeFile(lfp))
10452+
ereport(ERROR,
10453+
(errcode_for_file_access(),
10454+
errmsg("could not read file \"%s\": %m",
10455+
BACKUP_LABEL_FILE)));
10456+
if (unlink(BACKUP_LABEL_FILE) != 0)
10457+
ereport(ERROR,
10458+
(errcode_for_file_access(),
10459+
errmsg("could not remove file \"%s\": %m",
10460+
BACKUP_LABEL_FILE)));
10461+
10462+
/*
10463+
* Remove tablespace_map file if present, it is created only if there
10464+
* are tablespaces.
10465+
*/
10466+
unlink(TABLESPACE_MAP);
10467+
}
10468+
PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
10469+
}
10470+
10471+
/*
10472+
* OK to update backup counters and forcePageWrites
10473+
*/
10474+
WALInsertLockAcquireExclusive();
10475+
if (exclusive)
10476+
{
10477+
XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
1034810478
}
1034910479
else
1035010480
{
@@ -10358,66 +10488,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
1035810488
XLogCtl->Insert.nonExclusiveBackups--;
1035910489
}
1036010490

10361-
if (!XLogCtl->Insert.exclusiveBackup &&
10491+
if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
1036210492
XLogCtl->Insert.nonExclusiveBackups == 0)
1036310493
{
1036410494
XLogCtl->Insert.forcePageWrites = false;
1036510495
}
1036610496
WALInsertLockRelease();
1036710497

10368-
if (exclusive)
10369-
{
10370-
/*
10371-
* Read the existing label file into memory.
10372-
*/
10373-
struct stat statbuf;
10374-
int r;
10375-
10376-
if (stat(BACKUP_LABEL_FILE, &statbuf))
10377-
{
10378-
if (errno != ENOENT)
10379-
ereport(ERROR,
10380-
(errcode_for_file_access(),
10381-
errmsg("could not stat file \"%s\": %m",
10382-
BACKUP_LABEL_FILE)));
10383-
ereport(ERROR,
10384-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
10385-
errmsg("a backup is not in progress")));
10386-
}
10387-
10388-
lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
10389-
if (!lfp)
10390-
{
10391-
ereport(ERROR,
10392-
(errcode_for_file_access(),
10393-
errmsg("could not read file \"%s\": %m",
10394-
BACKUP_LABEL_FILE)));
10395-
}
10396-
labelfile = palloc(statbuf.st_size + 1);
10397-
r = fread(labelfile, statbuf.st_size, 1, lfp);
10398-
labelfile[statbuf.st_size] = '\0';
10399-
10400-
/*
10401-
* Close and remove the backup label file
10402-
*/
10403-
if (r != 1 || ferror(lfp) || FreeFile(lfp))
10404-
ereport(ERROR,
10405-
(errcode_for_file_access(),
10406-
errmsg("could not read file \"%s\": %m",
10407-
BACKUP_LABEL_FILE)));
10408-
if (unlink(BACKUP_LABEL_FILE) != 0)
10409-
ereport(ERROR,
10410-
(errcode_for_file_access(),
10411-
errmsg("could not remove file \"%s\": %m",
10412-
BACKUP_LABEL_FILE)));
10413-
10414-
/*
10415-
* Remove tablespace_map file if present, it is created only if there
10416-
* are tablespaces.
10417-
*/
10418-
unlink(TABLESPACE_MAP);
10419-
}
10420-
1042110498
/*
1042210499
* Read and parse the START WAL LOCATION line (this code is pretty crude,
1042310500
* but we are not expecting any variability in the file format).
@@ -10654,7 +10731,7 @@ do_pg_abort_backup(void)
1065410731
Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
1065510732
XLogCtl->Insert.nonExclusiveBackups--;
1065610733

10657-
if (!XLogCtl->Insert.exclusiveBackup &&
10734+
if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
1065810735
XLogCtl->Insert.nonExclusiveBackups == 0)
1065910736
{
1066010737
XLogCtl->Insert.forcePageWrites = false;

src/backend/postmaster/autovacuum.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1895,6 +1895,8 @@ do_autovacuum(void)
18951895
ScanKeyData key;
18961896
TupleDesc pg_class_desc;
18971897
int effective_multixact_freeze_max_age;
1898+
bool did_vacuum = false;
1899+
bool found_concurrent_worker = false;
18981900

18991901
/*
19001902
* StartTransactionCommand and CommitTransactionCommand will automatically
@@ -2233,6 +2235,7 @@ do_autovacuum(void)
22332235
if (worker->wi_tableoid == relid)
22342236
{
22352237
skipit = true;
2238+
found_concurrent_worker = true;
22362239
break;
22372240
}
22382241
}
@@ -2359,6 +2362,8 @@ do_autovacuum(void)
23592362
}
23602363
PG_END_TRY();
23612364

2365+
did_vacuum = true;
2366+
23622367
/* the PGXACT flags are reset at the next end of transaction */
23632368

23642369
/* be tidy */
@@ -2396,8 +2401,25 @@ do_autovacuum(void)
23962401
/*
23972402
* Update pg_database.datfrozenxid, and truncate pg_clog if possible. We
23982403
* only need to do this once, not after each table.
2404+
*
2405+
* Even if we didn't vacuum anything, it may still be important to do
2406+
* this, because one indirect effect of vac_update_datfrozenxid() is to
2407+
* update ShmemVariableCache->xidVacLimit. That might need to be done
2408+
* even if we haven't vacuumed anything, because relations with older
2409+
* relfrozenxid values or other databases with older datfrozenxid values
2410+
* might have been dropped, allowing xidVacLimit to advance.
2411+
*
2412+
* However, it's also important not to do this blindly in all cases,
2413+
* because when autovacuum=off this will restart the autovacuum launcher.
2414+
* If we're not careful, an infinite loop can result, where workers find
2415+
* no work to do and restart the launcher, which starts another worker in
2416+
* the same database that finds no work to do. To prevent that, we skip
2417+
* this if (1) we found no work to do and (2) we skipped at least one
2418+
* table due to concurrent autovacuum activity. In that case, the other
2419+
* worker has already done it, or will do so when it finishes.
23992420
*/
2400-
vac_update_datfrozenxid();
2421+
if (did_vacuum || !found_concurrent_worker)
2422+
vac_update_datfrozenxid();
24012423

24022424
/* Finally close out the last transaction. */
24032425
CommitTransactionCommand();

0 commit comments

Comments
 (0)