From 60f6029fa4f98b3663e7139e38ce26147e4fe796 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Fri, 14 Oct 2022 12:39:30 +0000 Subject: [PATCH v6] Add functions for xlogbackup.c to call back into xlog.c --- src/backend/access/transam/xlog.c | 194 +++++++++++++++++++---------- src/include/access/xlog.h | 1 + src/include/access/xlog_internal.h | 11 ++ 3 files changed, 141 insertions(+), 65 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0b7a0b5ac0..688e60c3c3 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -8313,10 +8313,7 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces, * forcePageWrites, to ensure adequate interlocking against * XLogInsertRecord(). */ - WALInsertLockAcquireExclusive(); - XLogCtl->Insert.runningBackups++; - XLogCtl->Insert.forcePageWrites = true; - WALInsertLockRelease(); + SetXLogBackupActivity(); /* Ensure we release forcePageWrites if fail below */ PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, DatumGetBool(false)); @@ -8382,12 +8379,8 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces, * to restore starting from the checkpoint is precisely the REDO * pointer. */ - LWLockAcquire(ControlFileLock, LW_SHARED); - state->checkpointloc = ControlFile->checkPoint; - state->startpoint = ControlFile->checkPointCopy.redo; - state->starttli = ControlFile->checkPointCopy.ThisTimeLineID; - checkpointfpw = ControlFile->checkPointCopy.fullPageWrites; - LWLockRelease(ControlFileLock); + GetCheckpointLocation(&state->checkpointloc, &state->startpoint, + &state->starttli, &checkpointfpw); if (backup_started_in_recovery) { @@ -8398,9 +8391,7 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces, * (i.e., since last restartpoint used as backup starting * checkpoint) contain full-page writes. */ - SpinLockAcquire(&XLogCtl->info_lck); - recptr = XLogCtl->lastFpwDisableRecPtr; - SpinLockRelease(&XLogCtl->info_lck); + recptr = GetlastFpwDisableRecPtr(); if (!checkpointfpw || state->startpoint <= recptr) ereport(ERROR, @@ -8433,13 +8424,7 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces, * taking a checkpoint right after another is not that expensive * either because only few buffers have been dirtied yet. */ - WALInsertLockAcquireExclusive(); - if (XLogCtl->Insert.lastBackupStart < state->startpoint) - { - XLogCtl->Insert.lastBackupStart = state->startpoint; - gotUniqueStartpoint = true; - } - WALInsertLockRelease(); + gotUniqueStartpoint = SetlastBackupStart(state->startpoint); } while (!gotUniqueStartpoint); /* @@ -8548,6 +8533,15 @@ get_backup_status(void) return sessionBackupState; } +/* + * Utility routine to reset the session-level status of a backup running. + */ +void +reset_backup_status(void) +{ + sessionBackupState = SESSION_BACKUP_NONE; +} + /* * do_pg_backup_stop * @@ -8594,33 +8588,11 @@ do_pg_backup_stop(BackupState *state, bool waitforarchive) * Note that CHECK_FOR_INTERRUPTS() must not occur while updating them. * Otherwise they can be updated inconsistently, and which might cause * do_pg_abort_backup() to fail. - */ - WALInsertLockAcquireExclusive(); - - /* - * It is expected that each do_pg_backup_start() call is matched by - * exactly one do_pg_backup_stop() call. - */ - Assert(XLogCtl->Insert.runningBackups > 0); - XLogCtl->Insert.runningBackups--; - - if (XLogCtl->Insert.runningBackups == 0) - { - XLogCtl->Insert.forcePageWrites = false; - } - - /* - * Clean up session-level lock. * - * You might think that WALInsertLockRelease() can be called before - * cleaning up session-level lock because session-level lock doesn't need - * to be protected with WAL insertion lock. But since - * CHECK_FOR_INTERRUPTS() can occur in it, session-level lock must be - * cleaned up before it. + * It is expected that each do_pg_backup_start() call is matched by exactly + * one do_pg_backup_stop() call. */ - sessionBackupState = SESSION_BACKUP_NONE; - - WALInsertLockRelease(); + ResetXLogBackupActivity(); /* * If we are taking an online backup from the standby, we confirm that the @@ -8670,9 +8642,7 @@ do_pg_backup_stop(BackupState *state, bool waitforarchive) * Check to see if all WAL replayed during online backup contain * full-page writes. */ - SpinLockAcquire(&XLogCtl->info_lck); - recptr = XLogCtl->lastFpwDisableRecPtr; - SpinLockRelease(&XLogCtl->info_lck); + recptr = GetlastFpwDisableRecPtr(); if (state->startpoint <= recptr) ereport(ERROR, @@ -8684,11 +8654,7 @@ do_pg_backup_stop(BackupState *state, bool waitforarchive) "Enable full_page_writes and run CHECKPOINT on the primary, " "and then try an online backup again."))); - - LWLockAcquire(ControlFileLock, LW_SHARED); - state->stoppoint = ControlFile->minRecoveryPoint; - state->stoptli = ControlFile->minRecoveryPointTLI; - LWLockRelease(ControlFileLock); + GetminRecoveryPoint(&state->stoppoint, &state->stoptli); } else { @@ -8706,7 +8672,7 @@ do_pg_backup_stop(BackupState *state, bool waitforarchive) * Given that we're not in recovery, InsertTimeLineID is set and can't * change, so we can read it without a lock. */ - state->stoptli = XLogCtl->InsertTimeLineID; + state->stoptli = GetWALInsertionTimeLine(); /* * Force a switch to a new xlog segment file, so that the backup is @@ -8850,17 +8816,7 @@ do_pg_abort_backup(int code, Datum arg) sessionBackupState != SESSION_BACKUP_RUNNING) return; - WALInsertLockAcquireExclusive(); - Assert(XLogCtl->Insert.runningBackups > 0); - XLogCtl->Insert.runningBackups--; - - if (XLogCtl->Insert.runningBackups == 0) - { - XLogCtl->Insert.forcePageWrites = false; - } - - sessionBackupState = SESSION_BACKUP_NONE; - WALInsertLockRelease(); + ResetXLogBackupActivity(); ereport(WARNING, (errmsg("aborting a running backup before exiting the backend"))); @@ -8881,6 +8837,114 @@ register_persistent_abort_backup_handler(void) already_done = true; } +/* + * Get the checkpoint location. + */ +void +GetCheckpointLocation(XLogRecPtr *loc, XLogRecPtr *redoloc, + TimeLineID *tli, bool *fpw) +{ + LWLockAcquire(ControlFileLock, LW_SHARED); + *loc = ControlFile->checkPoint; + *redoloc = ControlFile->checkPointCopy.redo; + *tli = ControlFile->checkPointCopy.ThisTimeLineID; + *fpw = ControlFile->checkPointCopy.fullPageWrites; + LWLockRelease(ControlFileLock); +} + +/* + * Get the minRecoveryPoint and minRecoveryPointTLI. + */ +void +GetminRecoveryPoint(XLogRecPtr *loc, TimeLineID *tli) +{ + LWLockAcquire(ControlFileLock, LW_SHARED); + *loc = ControlFile->minRecoveryPoint; + *tli = ControlFile->minRecoveryPointTLI; + LWLockRelease(ControlFileLock); +} + +/* + * Get the lastFpwDisableRecPtr. + */ +XLogRecPtr +GetlastFpwDisableRecPtr(void) +{ + XLogRecPtr recptr; + + SpinLockAcquire(&XLogCtl->info_lck); + recptr = XLogCtl->lastFpwDisableRecPtr; + SpinLockRelease(&XLogCtl->info_lck); + + return recptr; +} + +/* + * Set the lastBackupStar only if it is less than passed-in rectpr and return + * true. Otherwise return false. + * + * Note: For those who want to set lastBackupStar unconditionally, pass rectpr + * value as PG_UINT64_MAX, which is higher than any real XLogRecPtr value. + */ +bool +SetlastBackupStart(XLogRecPtr recptr) +{ + bool is_set = false; + + WALInsertLockAcquireExclusive(); + if (XLogCtl->Insert.lastBackupStart < recptr) + { + XLogCtl->Insert.lastBackupStart = recptr; + is_set = true; + } + WALInsertLockRelease(); + + return is_set; +} + +/* + * Reset backup activity such as runningBackups, forcePageWrites and + * session-level status. + */ +void +ResetXLogBackupActivity(void) +{ + WALInsertLockAcquireExclusive(); + + Assert(XLogCtl->Insert.runningBackups > 0); + XLogCtl->Insert.runningBackups--; + + if (XLogCtl->Insert.runningBackups == 0) + { + XLogCtl->Insert.forcePageWrites = false; + } + + /* + * Reset session-level lock. + * + * You might think that WALInsertLockRelease() can be called before + * cleaning up session-level lock because session-level lock doesn't need + * to be protected with WAL insertion lock. But since + * CHECK_FOR_INTERRUPTS() can occur in it, session-level lock must be + * cleaned up before it. + */ + reset_backup_status(); + + WALInsertLockRelease(); +} + +/* + * Set backup activity such as runningBackups and forcePageWrites. + */ +void +SetXLogBackupActivity(void) +{ + WALInsertLockAcquireExclusive(); + XLogCtl->Insert.runningBackups++; + XLogCtl->Insert.forcePageWrites = true; + WALInsertLockRelease(); +} + /* * Get latest WAL insert pointer */ diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 1fbd48fbda..b46adca291 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -285,6 +285,7 @@ extern void do_pg_backup_stop(BackupState *state, bool waitforarchive); extern void do_pg_abort_backup(int code, Datum arg); extern void register_persistent_abort_backup_handler(void); extern SessionBackupState get_backup_status(void); +extern void reset_backup_status(void); /* File path names (all relative to $PGDATA) */ #define RECOVERY_SIGNAL_FILE "recovery.signal" diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 44291b337b..d1f53d2512 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -401,4 +401,15 @@ extern PGDLLIMPORT bool InArchiveRecovery; extern PGDLLIMPORT bool StandbyMode; extern PGDLLIMPORT char *recoveryRestoreCommand; +/* + * Routines used by xlogbackup.c to call back into xlog.c during backup. + */ +extern void GetCheckpointLocation(XLogRecPtr *loc, XLogRecPtr *redoloc, + TimeLineID *tli, bool *fpw); +extern void GetminRecoveryPoint(XLogRecPtr *loc, TimeLineID *tli); +extern XLogRecPtr GetlastFpwDisableRecPtr(void); +extern bool SetlastBackupStart(XLogRecPtr recptr); +extern void ResetXLogBackupActivity(void); +extern void SetXLogBackupActivity(void); + #endif /* XLOG_INTERNAL_H */ -- 2.34.1