From 2ab3934f28fc986904afe8131aaa639713e4836c Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Thu, 6 Oct 2022 11:01:22 +0000 Subject: [PATCH v3] Add functions for xlogbackup.c to call back into xlog.c --- src/backend/access/transam/xlog.c | 191 ++++++++++++++++++++---------- src/include/access/xlog.h | 15 +++ 2 files changed, 142 insertions(+), 64 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 27085b15a8..3af9cc86c0 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(); + SetXLogBackupRelatedInfo(); /* Ensure we release forcePageWrites if fail below */ PG_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0); @@ -8356,6 +8353,8 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces, do { bool checkpointfpw; + ControlFileData *ControlFile; + /* * Force a CHECKPOINT. Aside from being necessary to prevent torn @@ -8384,6 +8383,8 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces, * to restore starting from the checkpoint is precisely the REDO * pointer. */ + ControlFile = GetControlFile(); + LWLockAcquire(ControlFileLock, LW_SHARED); state->checkpointloc = ControlFile->checkPoint; state->startpoint = ControlFile->checkPointCopy.redo; @@ -8400,9 +8401,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 +8434,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 +8539,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(); + ResetXLogBackupRelatedInfo(NULL); } /* @@ -8592,6 +8576,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 +8598,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(); + ResetXLogBackupRelatedInfo(&session_backup_state); /* * If we are taking an online backup from the standby, we confirm that the @@ -8684,14 +8647,13 @@ do_pg_backup_stop(BackupState *state, bool waitforarchive) if (backup_stopped_in_recovery) { XLogRecPtr recptr; + ControlFileData *ControlFile; /* * 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, @@ -8704,6 +8666,8 @@ do_pg_backup_stop(BackupState *state, bool waitforarchive) "and then try an online backup again."))); + ControlFile = GetControlFile(); + LWLockAcquire(ControlFileLock, LW_SHARED); state->stoppoint = ControlFile->minRecoveryPoint; state->stoptli = ControlFile->minRecoveryPointTLI; @@ -8725,7 +8689,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 +8824,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 +8832,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(); + ResetXLogBackupRelatedInfo(&session_backup_state); if (emit_warning) ereport(WARNING, @@ -8899,6 +8854,114 @@ 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 ControlFile. + */ +ControlFileData * +GetControlFile(void) +{ + return ControlFile; +} + +/* + * 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; +} + +/* + * Decrement runningBackups, reset forcePageWrites and session-level status of + * a backup running. + * + * NOTE: This function is tailor-made for use in xlogbackup.c. It doesn't reset + * the respective XLogCtl members directly, and acquires and releases locks. + * Hence be careful when using it elsewhere. + */ +void +ResetXLogBackupRelatedInfo(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(); +} + +/* + * Increment runningBackups and forcePageWrites. + * + * NOTE: This function is tailor-made for use in xlogbackup.c. It doesn't set + * the respective XLogCtl members directly, and acquires and releases locks. + * Hence be careful when using it elsewhere. + */ +void +SetXLogBackupRelatedInfo(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 dce265098e..8be7aa9c8e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -14,6 +14,7 @@ #include "access/xlogbackup.h" #include "access/xlogdefs.h" #include "access/xlogreader.h" +#include "catalog/pg_control.h" #include "datatype/timestamp.h" #include "lib/stringinfo.h" #include "nodes/pg_list.h" @@ -285,6 +286,20 @@ 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. + * + * NOTE: These functions are tailor-made for use in xlogbackup.c. They may or + * may not set or get the respective XLogCtl members directly, may acquire and + * release various locks. Hence be careful when using them elsewhere. + */ +extern ControlFileData *GetControlFile(void); +extern XLogRecPtr GetlastFpwDisableRecPtr(void); +extern bool SetlastBackupStart(XLogRecPtr recptr); +extern void ResetXLogBackupRelatedInfo(SessionBackupState* session_backup_state); +extern void SetXLogBackupRelatedInfo(void); /* File path names (all relative to $PGDATA) */ #define RECOVERY_SIGNAL_FILE "recovery.signal" -- 2.34.1