diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml index 8c24ae2..fa580b7 100644 --- a/doc/src/sgml/recovery-config.sgml +++ b/doc/src/sgml/recovery-config.sgml @@ -349,6 +349,48 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows + + recovery_target_incomplete (enum) + + recovery_target_incomplete recovery parameter + + + + + Specifies what action the server should take once the recovery target is + not reached. The default is promote, which means recovery will + finish and the server will start to accept connections. pause means the recovery process will be paused. + Finally shutdown will stop the server if the recovery cannot proceed any further. + + + The intended use of the pause setting is to allow queries + to be executed against the database to check if this recovery target + is the most desirable point for recovery. + The paused state can be resumed by + using pg_xlog_replay_resume() (see + ), which then + causes recovery to end. If this recovery target is not the + desired stopping point, then shut down the server, change the + recovery target settings to a later target and restart to + continue recovery. + + + The shutdown setting is useful to have the instance ready + at the exact replay point desired. The instance will still be able to + replay more WAL records (and in fact will have to replay WAL records + since the last checkpoint next time it is started). + + + Note that because recovery.conf will not be renamed when + recovery_target_incomplete is set to shutdown, + any subsequent start will end with immediate shutdown unless the + configuration is changed or the recovery.conf file is + removed manually. + + + + diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 8379133..343f5b6 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -252,6 +252,7 @@ static char *archiveCleanupCommand = NULL; static RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET; static bool recoveryTargetInclusive = true; static RecoveryTargetAction recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE; +static RecoveryTargetIncomplete recoveryTargetIncomplete = RECOVERY_TARGET_INCOMPLETE_PROMOTE; static TransactionId recoveryTargetXid; static TimestampTz recoveryTargetTime; static char *recoveryTargetName; @@ -830,6 +831,7 @@ static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog); static bool recoveryStopsBefore(XLogReaderState *record); static bool recoveryStopsAfter(XLogReaderState *record); static void recoveryPausesHere(void); +static void IncompleteRecoveryPause(void); static bool recoveryApplyDelay(XLogReaderState *record); static void SetLatestXTime(TimestampTz xtime); static void SetCurrentChunkStartTime(TimestampTz xtime); @@ -5068,6 +5070,26 @@ readRecoveryCommandFile(void) recoveryTargetActionSet = true; } + else if (strcmp(item->name, "recovery_target_incomplete") == 0) + { + if (strcmp(item->value, "pause") == 0) + recoveryTargetIncomplete = RECOVERY_TARGET_INCOMPLETE_PAUSE; + else if (strcmp(item->value, "promote") == 0) + recoveryTargetIncomplete = RECOVERY_TARGET_INCOMPLETE_PROMOTE; + else if (strcmp(item->value, "shutdown") == 0) + recoveryTargetIncomplete = RECOVERY_TARGET_INCOMPLETE_SHUTDOWN; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for recovery parameter \"%s\": \"%s\"", + "recovery_target_incomplete", + item->value), + errhint("Valid values are \"pause\", \"promote\", and \"shutdown\"."))); + + ereport(DEBUG2, + (errmsg_internal("recovery_target_incomplete = '%s'", + item->value))); + } else if (strcmp(item->name, "recovery_target_timeline") == 0) { rtliGiven = true; @@ -5794,6 +5816,21 @@ SetRecoveryPause(bool recoveryPause) SpinLockRelease(&XLogCtl->info_lck); } +static void +IncompleteRecoveryPause(void) +{ + /* Pause recovery at end-of-the-wal when recovery target is not reached */ + ereport(LOG, + (errmsg("recovery has paused"), + errhint("Execute pg_xlog_replay_resume() to continue."))); + + while (RecoveryIsPaused()) + { + pg_usleep(1000000L); /* 1000 ms */ + HandleStartupProcInterrupts(); + } +} + /* * When recovery_min_apply_delay is set, we wait long enough to make sure * certain record types are applied at least that interval behind the master. @@ -7094,6 +7131,46 @@ StartupXLOG(void) break; } } + else + { + ereport(LOG, + (errmsg("recovery has reached end-of-the-wal and has not reached the recovery target yet"), + errhint("This could be due to corrupt or missing WAL files.\n" + "All the WAL files needed for the recovery must be available to proceed to the recovery target " + "Or you might need to choose an earlier recovery target."))); + + /* + * This is the position where we can choose to shutdown, pause + * or promote at the end-of-the-wal if the intended recovery + * target is not reached + */ + switch (recoveryTargetIncomplete) + { + + case RECOVERY_TARGET_INCOMPLETE_SHUTDOWN: + + /* + * exit with special return code to request shutdown + * of postmaster. Log messages issued from + * postmaster. + */ + + ereport(LOG, + (errmsg("shutdown at end-of-the-wal"))); + proc_exit(2); + + case RECOVERY_TARGET_INCOMPLETE_PAUSE: + + SetRecoveryPause(true); + IncompleteRecoveryPause(); + + /* drop into promote */ + + case RECOVERY_TARGET_INCOMPLETE_PROMOTE: + break; + } + + } /* Allow resource managers to do any required cleanup. */ for (rmid = 0; rmid <= RM_MAX_ID; rmid++) diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 8ad4d47..e46f50d 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -256,6 +256,17 @@ typedef enum } RecoveryTargetAction; /* + * Recovery target incomplete. + */ + +typedef enum +{ + RECOVERY_TARGET_INCOMPLETE_PAUSE, + RECOVERY_TARGET_INCOMPLETE_PROMOTE, + RECOVERY_TARGET_INCOMPLETE_SHUTDOWN +} RecoveryTargetIncomplete; + +/* * Method table for resource managers. * * This struct must be kept in sync with the PG_RMGR definition in