diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index ca074da..59d19a0 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -557,6 +557,12 @@ StartupCommitTs(void)
TransactionId xid = ShmemVariableCache->nextXid;
int pageno = TransactionIdToCTsPage(xid);
+ if (track_commit_timestamp)
+ {
+ ActivateCommitTs();
+ return;
+ }
+
LWLockAcquire(CommitTsControlLock, LW_EXCLUSIVE);
/*
@@ -571,14 +577,30 @@ StartupCommitTs(void)
* This must be called ONCE during postmaster or standalone-backend startup,
* when commit timestamp is enabled. Must be called after recovery has
* finished.
+ */
+void
+CompleteCommitTsInitialization(void)
+{
+ if (!track_commit_timestamp)
+ DeactivateCommitTs(true);
+}
+
+/*
+ * This must be called when track_commit_timestamp is turned on.
+ * Note that this only happens during postmaster or standalone-backend startup
+ * or during WAL replay.
+ *
+ * The reason why this SLRU needs separate activation/deactivation functions is
+ * that it can be enabled/disabled during start and the activation/deactivation
+ * on master is propagated to slave via replay. Other SLRUs don't have this
+ * property and they can be just initialized during normal startup.
*
* This is in charge of creating the currently active segment, if it's not
* already there. The reason for this is that the server might have been
* running with this module disabled for a while and thus might have skipped
* the normal creation point.
*/
-void
-CompleteCommitTsInitialization(void)
+void ActivateCommitTs(void)
{
TransactionId xid = ShmemVariableCache->nextXid;
int pageno = TransactionIdToCTsPage(xid);
@@ -591,22 +613,6 @@ CompleteCommitTsInitialization(void)
LWLockRelease(CommitTsControlLock);
/*
- * If this module is not currently enabled, make sure we don't hand back
- * possibly-invalid data; also remove segments of old data.
- */
- if (!track_commit_timestamp)
- {
- LWLockAcquire(CommitTsLock, LW_EXCLUSIVE);
- ShmemVariableCache->oldestCommitTs = InvalidTransactionId;
- ShmemVariableCache->newestCommitTs = InvalidTransactionId;
- LWLockRelease(CommitTsLock);
-
- TruncateCommitTs(ReadNewTransactionId());
-
- return;
- }
-
- /*
* If CommitTs is enabled, but it wasn't in the previous server run, we
* need to set the oldest and newest values to the next Xid; that way, we
* will not try to read data that might not have been set.
@@ -641,6 +647,35 @@ CompleteCommitTsInitialization(void)
}
/*
+ * This must be called when track_commit_timestamp is turned off.
+ * Note that this only happens during postmaster or standalone-backend startup
+ * or during WAL replay.
+ *
+ * Resets CommitTs into invalid state to make sure we don't hand back
+ * possibly-invalid data; also removes segments of old data.
+ */
+void
+DeactivateCommitTs(bool do_wal)
+{
+ TransactionId xid = ShmemVariableCache->nextXid;
+ int pageno = TransactionIdToCTsPage(xid);
+
+ /*
+ * Re-Initialize our idea of the latest page number.
+ */
+ LWLockAcquire(CommitTsControlLock, LW_EXCLUSIVE);
+ CommitTsCtl->shared->latest_page_number = pageno;
+ LWLockRelease(CommitTsControlLock);
+
+ LWLockAcquire(CommitTsLock, LW_EXCLUSIVE);
+ ShmemVariableCache->oldestCommitTs = InvalidTransactionId;
+ ShmemVariableCache->newestCommitTs = InvalidTransactionId;
+ LWLockRelease(CommitTsLock);
+
+ TruncateCommitTs(ReadNewTransactionId(), do_wal);
+}
+
+/*
* This must be called ONCE during postmaster or standalone-backend shutdown
*/
void
@@ -705,7 +740,7 @@ ExtendCommitTs(TransactionId newestXact)
* Note that we don't need to flush XLOG here.
*/
void
-TruncateCommitTs(TransactionId oldestXact)
+TruncateCommitTs(TransactionId oldestXact, bool do_wal)
{
int cutoffPage;
@@ -721,7 +756,8 @@ TruncateCommitTs(TransactionId oldestXact)
return; /* nothing to remove */
/* Write XLOG record */
- WriteTruncateXlogRec(cutoffPage);
+ if (do_wal)
+ WriteTruncateXlogRec(cutoffPage);
/* Now we can remove the old CommitTs segment(s) */
SimpleLruTruncate(CommitTsCtl, cutoffPage);
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 5cc7e47..4117560 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -5587,6 +5587,21 @@ do { \
minValue))); \
} while(0)
+#define RecoveryRequiresBoolParameter(param_name, currValue, masterValue) \
+do { \
+ bool _currValue = (currValue); \
+ bool _masterValue = (masterValue); \
+ if (_currValue != _masterValue) \
+ ereport(ERROR, \
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \
+ errmsg("hot standby is not possible because it requires " \
+ "\"%s\" to be same on master and standby" \
+ "(master has \"%s\", standby has \"%s\")", \
+ param_name, \
+ _masterValue ? "true" : "false", \
+ _currValue ? "true" : "false"))); \
+} while(0)
+
/*
* Check to see if required parameters are set high enough on this server
* for various aspects of recovery operation.
@@ -5629,6 +5644,9 @@ CheckRequiredParameterValues(void)
RecoveryRequiresIntParameter("max_locks_per_transaction",
max_locks_per_xact,
ControlFile->max_locks_per_xact);
+ RecoveryRequiresBoolParameter("track_commit_timestamp",
+ track_commit_timestamp,
+ ControlFile->track_commit_timestamp);
}
}
@@ -8968,7 +8986,6 @@ xlog_redo(XLogReaderState *record)
ControlFile->max_locks_per_xact = xlrec.max_locks_per_xact;
ControlFile->wal_level = xlrec.wal_level;
ControlFile->wal_log_hints = wal_log_hints;
- ControlFile->track_commit_timestamp = track_commit_timestamp;
/*
* Update minRecoveryPoint to ensure that if recovery is aborted, we
@@ -8986,6 +9003,25 @@ xlog_redo(XLogReaderState *record)
ControlFile->minRecoveryPointTLI = ThisTimeLineID;
}
+ /*
+ * Update the commit timestamp tracking. If there was a change
+ * it needs to be activated or deactivated accordingly.
+ */
+ if (track_commit_timestamp != xlrec.track_commit_timestamp)
+ {
+ track_commit_timestamp = xlrec.track_commit_timestamp;
+ ControlFile->track_commit_timestamp = track_commit_timestamp;
+ if (track_commit_timestamp)
+ ActivateCommitTs();
+ else
+ /*
+ * Recovery can't create ne WAL records, but that's ok as
+ * master did the WAL logging and we will replay the record
+ * from master in case we crash here.
+ */
+ DeactivateCommitTs(false);
+ }
+
UpdateControlFile();
LWLockRelease(ControlFileLock);
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index e32e039..ced78ff 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -1077,7 +1077,7 @@ vac_truncate_clog(TransactionId frozenXID,
* checkpoint.
*/
TruncateCLOG(frozenXID);
- TruncateCommitTs(frozenXID);
+ TruncateCommitTs(frozenXID, true);
/*
* Update the wrap limit for GetNewTransactionId and creation of new
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index 903c82c..70ca968 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -39,11 +39,13 @@ extern Size CommitTsShmemSize(void);
extern void CommitTsShmemInit(void);
extern void BootStrapCommitTs(void);
extern void StartupCommitTs(void);
+extern void ActivateCommitTs(void);
+extern void DeactivateCommitTs(bool do_wal);
extern void CompleteCommitTsInitialization(void);
extern void ShutdownCommitTs(void);
extern void CheckPointCommitTs(void);
extern void ExtendCommitTs(TransactionId newestXact);
-extern void TruncateCommitTs(TransactionId oldestXact);
+extern void TruncateCommitTs(TransactionId oldestXact, bool do_wal);
extern void SetCommitTsLimit(TransactionId oldestXact,
TransactionId newestXact);
extern void AdvanceOldestCommitTs(TransactionId oldestXact);