From 5743706f90140e6c31143fbdf435020d4ec49f45 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Thu, 13 Oct 2022 05:39:32 +0000 Subject: [PATCH v4] Add functions for xlogbackup.c to call back into xlog.c --- src/backend/access/transam/xlog.c | 208 +++++++++++++++++++----------- src/include/access/xlog.h | 12 ++ 2 files changed, 145 insertions(+), 75 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 27085b15a8..3df46b013a 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -8315,10 +8315,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(pg_backup_start_callback, (Datum) 0); @@ -8384,12 +8381,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) { @@ -8400,9 +8393,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, @@ -8435,13 +8426,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); /* @@ -8546,16 +8531,7 @@ static void pg_backup_start_callback(int code, Datum arg) { /* Update backup counters and forcePageWrites on failure */ - WALInsertLockAcquireExclusive(); - - Assert(XLogCtl->Insert.runningBackups > 0); - XLogCtl->Insert.runningBackups--; - - if (XLogCtl->Insert.runningBackups == 0) - { - XLogCtl->Insert.forcePageWrites = false; - } - WALInsertLockRelease(); + ResetXLogBackupActivity(NULL); } /* @@ -8592,6 +8568,7 @@ do_pg_backup_stop(BackupState *state, bool waitforarchive) int seconds_before_warning; int waits = 0; bool reported_waiting = false; + SessionBackupState session_backup_state = SESSION_BACKUP_NONE; Assert(state != NULL); @@ -8613,33 +8590,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(&session_backup_state); /* * If we are taking an online backup from the standby, we confirm that the @@ -8689,9 +8644,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, @@ -8703,11 +8656,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 { @@ -8725,7 +8674,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 @@ -8860,6 +8809,7 @@ void do_pg_abort_backup(int code, Datum arg) { bool emit_warning = DatumGetBool(arg); + SessionBackupState session_backup_state = SESSION_BACKUP_NONE; /* * Quick exit if session does not have a running backup. @@ -8867,17 +8817,7 @@ do_pg_abort_backup(int code, Datum arg) if (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(&session_backup_state); if (emit_warning) ereport(WARNING, @@ -8899,6 +8839,124 @@ register_persistent_abort_backup_handler(void) already_done = true; } +/* + * Utility routine to set the session-level status of a backup running. + */ +void +set_backup_status(SessionBackupState state) +{ + sessionBackupState = state; +} + +/* + * 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 optionally + * session-level status too. + */ +void +ResetXLogBackupActivity(SessionBackupState *session_backup_state) +{ + WALInsertLockAcquireExclusive(); + + Assert(XLogCtl->Insert.runningBackups > 0); + XLogCtl->Insert.runningBackups--; + + if (XLogCtl->Insert.runningBackups == 0) + { + XLogCtl->Insert.forcePageWrites = false; + } + + /* + * Set session-level lock if specified. + * + * 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. + */ + if (session_backup_state != NULL) + set_backup_status(*session_backup_state); + + 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..0d37a0b9e7 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -285,6 +285,18 @@ 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 set_backup_status(SessionBackupState state); + +/* + * 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(SessionBackupState *session_backup_state); +extern void SetXLogBackupActivity(void); /* File path names (all relative to $PGDATA) */ #define RECOVERY_SIGNAL_FILE "recovery.signal" -- 2.34.1