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)
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