diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index de77f14573..462f27fc04 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -3858,7 +3858,8 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows This parameter specifies the time stamp up to which recovery will proceed. The precise stopping point is also influenced by - . + and + . @@ -3939,6 +3940,27 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows + + recovery_target_use_origin_time (boolean) + + recovery_target_use_origin_time configuration parameter + + + + + Specifies whether to use the timestamp from the local commit + record (off), or, if one exists, to use + the timestamp as recorded by the origin, for commits that + arrive by logical replication from another server. + This allows a PITR recovery to have a single consistent + timestamp across multiple servers, if that is desirable. + Applies when + is specified. Default is on. + + + + recovery_target_timeline (string) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0a0771a18e..9c0c5e389c 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -275,6 +275,7 @@ char *recoveryEndCommand = NULL; char *archiveCleanupCommand = NULL; RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET; bool recoveryTargetInclusive = true; +bool recoveryTargetUseOriginTime = false; int recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE; TransactionId recoveryTargetXid; char *recovery_target_time_string; @@ -5840,25 +5841,81 @@ static bool getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; - uint8 xact_info = info & XLOG_XACT_OPMASK; uint8 rmid = XLogRecGetRmid(record); - if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT) + if (rmid == RM_XLOG_ID) { - *recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time; - return true; - } - if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT || - xact_info == XLOG_XACT_COMMIT_PREPARED)) - { - *recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time; - return true; + if (info == XLOG_RESTORE_POINT) + { + *recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time; + return true; + } + if (info == XLOG_CHECKPOINT_ONLINE || + info == XLOG_CHECKPOINT_SHUTDOWN) + { + *recordXtime = time_t_to_timestamptz(((CheckPoint *) XLogRecGetData(record))->time); + return true; + } + if (info == XLOG_END_OF_RECOVERY) + { + *recordXtime = ((xl_end_of_recovery *) XLogRecGetData(record))->end_time; + return true; + } } - if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT || - xact_info == XLOG_XACT_ABORT_PREPARED)) + if (rmid == RM_XACT_ID) { - *recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time; - return true; + uint8 xact_info = info & XLOG_XACT_OPMASK; + + if (xact_info == XLOG_XACT_COMMIT || + xact_info == XLOG_XACT_COMMIT_PREPARED) + { + if (recoveryTargetUseOriginTime) + { + xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record); + xl_xact_parsed_commit parsed; + + ParseCommitRecord(XLogRecGetInfo(record), + xlrec, + &parsed); + *recordXtime = parsed.origin_timestamp; + } + else + *recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time; + return true; + } + if (xact_info == XLOG_XACT_ABORT || + xact_info == XLOG_XACT_ABORT_PREPARED) + { + if (recoveryTargetUseOriginTime) + { + xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record); + xl_xact_parsed_abort parsed; + + ParseAbortRecord(XLogRecGetInfo(record), + xlrec, + &parsed); + *recordXtime = parsed.origin_timestamp; + } + else + *recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time; + return true; + } + if (xact_info == XLOG_XACT_PREPARE) + { + if (recoveryTargetUseOriginTime) + { + xl_xact_prepare *xlrec = (xl_xact_prepare *) XLogRecGetData(record); + xl_xact_parsed_prepare parsed; + + ParsePrepareRecord(XLogRecGetInfo(record), + xlrec, + &parsed); + *recordXtime = parsed.origin_timestamp; + } + else + *recordXtime = ((xl_xact_prepare *) XLogRecGetData(record))->prepared_at; + return true; + } } return false; } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index e91d5a3cfd..9693afc602 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1906,6 +1906,16 @@ static struct config_bool ConfigureNamesBool[] = NULL, NULL, NULL }, + { + {"recovery_target_use_origin_time", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + gettext_noop("Sets whether to use local or origin transaction time with recovery target."), + NULL + }, + &recoveryTargetUseOriginTime, + false, + NULL, NULL, NULL + }, + { {"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY, gettext_noop("Allows connections and queries during recovery."), diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index c0a560204b..65c6633c0d 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -84,6 +84,7 @@ extern char *recoveryRestoreCommand; extern char *recoveryEndCommand; extern char *archiveCleanupCommand; extern bool recoveryTargetInclusive; +extern bool recoveryTargetUseOriginTime; extern int recoveryTargetAction; extern int recovery_min_apply_delay; extern char *PrimaryConnInfo;