@@ -93,13 +93,23 @@ CommitTimestampShared *commitTsShared;
9393/* GUC variable */
9494bool track_commit_timestamp ;
9595
96+ /*
97+ * When this is set, commit_ts is force-enabled during recovery. This is so
98+ * that a standby can replay WAL records coming from a master with the setting
99+ * enabled. (Note that this doesn't enable SQL access to the data; it's
100+ * effectively write-only until the GUC itself is enabled.)
101+ */
102+ static bool enable_during_recovery ;
103+
96104static void SetXidCommitTsInPage (TransactionId xid , int nsubxids ,
97105 TransactionId * subxids , TimestampTz ts ,
98106 RepOriginId nodeid , int pageno );
99107static void TransactionIdSetCommitTs (TransactionId xid , TimestampTz ts ,
100108 RepOriginId nodeid , int slotno );
101109static int ZeroCommitTsPage (int pageno , bool writeXlog );
102110static bool CommitTsPagePrecedes (int page1 , int page2 );
111+ static void ActivateCommitTs (void );
112+ static void DeactivateCommitTs (bool do_wal );
103113static void WriteZeroPageXlogRec (int pageno );
104114static void WriteTruncateXlogRec (int pageno );
105115static void WriteSetTimestampXlogRec (TransactionId mainxid , int nsubxids ,
@@ -122,10 +132,6 @@ static void WriteSetTimestampXlogRec(TransactionId mainxid, int nsubxids,
122132 * subtrans implementation changes in the future, we might want to revisit the
123133 * decision of storing timestamp info for each subxid.
124134 *
125- * The replaying_xlog parameter indicates whether the module should execute
126- * its write even if the feature is nominally disabled, because we're replaying
127- * a record generated from a master where the feature is enabled.
128- *
129135 * The write_xlog parameter tells us whether to include an XLog record of this
130136 * or not. Normally, this is called from transaction commit routines (both
131137 * normal and prepared) and the information will be stored in the transaction
@@ -136,18 +142,17 @@ static void WriteSetTimestampXlogRec(TransactionId mainxid, int nsubxids,
136142void
137143TransactionTreeSetCommitTsData (TransactionId xid , int nsubxids ,
138144 TransactionId * subxids , TimestampTz timestamp ,
139- RepOriginId nodeid ,
140- bool replaying_xlog , bool write_xlog )
145+ RepOriginId nodeid , bool write_xlog )
141146{
142147 int i ;
143148 TransactionId headxid ;
144149 TransactionId newestXact ;
145150
146- /* We'd better not try to write xlog during replay */
147- Assert (!( write_xlog && replaying_xlog ));
148-
149- /* No-op if feature not enabled, unless replaying WAL */
150- if (!track_commit_timestamp && !replaying_xlog )
151+ /*
152+ * No-op if the module is not enabled, but allow writes in a standby
153+ * during recovery.
154+ */
155+ if (!track_commit_timestamp && !enable_during_recovery )
151156 return ;
152157
153158 /*
@@ -534,40 +539,61 @@ ZeroCommitTsPage(int pageno, bool writeXlog)
534539/*
535540 * This must be called ONCE during postmaster or standalone-backend startup,
536541 * after StartupXLOG has initialized ShmemVariableCache->nextXid.
542+ *
543+ * Caller may choose to enable the feature even when it is turned off in the
544+ * configuration.
537545 */
538546void
539- StartupCommitTs (void )
547+ StartupCommitTs (bool force_enable )
540548{
541- TransactionId xid = ShmemVariableCache -> nextXid ;
542- int pageno = TransactionIdToCTsPage (xid );
543-
544- if (track_commit_timestamp )
545- {
546- ActivateCommitTs ();
547- return ;
548- }
549-
550- LWLockAcquire (CommitTsControlLock , LW_EXCLUSIVE );
551-
552549 /*
553- * Initialize our idea of the latest page number.
550+ * If the module is not enabled, there's nothing to do here. The module
551+ * could still be activated from elsewhere.
554552 */
555- CommitTsCtl -> shared -> latest_page_number = pageno ;
556-
557- LWLockRelease (CommitTsControlLock );
553+ if (track_commit_timestamp || force_enable )
554+ ActivateCommitTs ();
558555}
559556
560557/*
561558 * This must be called ONCE during postmaster or standalone-backend startup,
562- * when commit timestamp is enabled, after recovery has finished.
559+ * after recovery has finished.
563560 */
564561void
565562CompleteCommitTsInitialization (void )
566563{
564+ /*
565+ * If the feature is not enabled, turn it off for good. This also removes
566+ * any leftover data.
567+ */
567568 if (!track_commit_timestamp )
568569 DeactivateCommitTs (true);
569570}
570571
572+ /*
573+ * Activate or deactivate CommitTs' upon reception of a XLOG_PARAMETER_CHANGE
574+ * XLog record in a standby.
575+ */
576+ void
577+ CommitTsParameterChange (bool newvalue , bool oldvalue )
578+ {
579+ /*
580+ * If the commit_ts module is disabled in this server and we get word from
581+ * the master server that it is enabled there, activate it so that we can
582+ * replay future WAL records involving it; also mark it as active on
583+ * pg_control. If the old value was already set, we already did this, so
584+ * don't do anything.
585+ *
586+ * If the module is disabled in the master, disable it here too.
587+ */
588+ if (newvalue )
589+ {
590+ if (!track_commit_timestamp && !oldvalue )
591+ ActivateCommitTs ();
592+ }
593+ else if (oldvalue )
594+ DeactivateCommitTs (false);
595+ }
596+
571597/*
572598 * Activate this module whenever necessary.
573599 * This must happen during postmaster or standalong-backend startup,
@@ -584,7 +610,7 @@ CompleteCommitTsInitialization(void)
584610 * running with this module disabled for a while and thus might have skipped
585611 * the normal creation point.
586612 */
587- void
613+ static void
588614ActivateCommitTs (void )
589615{
590616 TransactionId xid = ShmemVariableCache -> nextXid ;
@@ -629,6 +655,9 @@ ActivateCommitTs(void)
629655 Assert (!CommitTsCtl -> shared -> page_dirty [slotno ]);
630656 LWLockRelease (CommitTsControlLock );
631657 }
658+
659+ /* We can now replay xlog records from this module */
660+ enable_during_recovery = true;
632661}
633662
634663/*
@@ -641,7 +670,7 @@ ActivateCommitTs(void)
641670 * Resets CommitTs into invalid state to make sure we don't hand back
642671 * possibly-invalid data; also removes segments of old data.
643672 */
644- void
673+ static void
645674DeactivateCommitTs (bool do_wal )
646675{
647676 TransactionId xid = ShmemVariableCache -> nextXid ;
@@ -659,7 +688,18 @@ DeactivateCommitTs(bool do_wal)
659688 ShmemVariableCache -> newestCommitTs = InvalidTransactionId ;
660689 LWLockRelease (CommitTsLock );
661690
662- TruncateCommitTs (ReadNewTransactionId (), do_wal );
691+ /*
692+ * Remove *all* files. This is necessary so that there are no leftover
693+ * files; in the case where this feature is later enabled after running
694+ * with it disabled for some time there may be a gap in the file sequence.
695+ * (We can probably tolerate out-of-sequence files, as they are going to
696+ * be overwritten anyway when we wrap around, but it seems better to be
697+ * tidy.)
698+ */
699+ (void ) SlruScanDirectory (CommitTsCtl , SlruScanDirCbDeleteAll , NULL );
700+
701+ /* No longer enabled on recovery */
702+ enable_during_recovery = false;
663703}
664704
665705/*
@@ -699,7 +739,7 @@ ExtendCommitTs(TransactionId newestXact)
699739 int pageno ;
700740
701741 /* nothing to do if module not enabled */
702- if (!track_commit_timestamp )
742+ if (!track_commit_timestamp && ! enable_during_recovery )
703743 return ;
704744
705745 /*
@@ -916,8 +956,7 @@ commit_ts_redo(XLogReaderState *record)
916956 subxids = NULL ;
917957
918958 TransactionTreeSetCommitTsData (setts -> mainxid , nsubxids , subxids ,
919- setts -> timestamp , setts -> nodeid , false,
920- true);
959+ setts -> timestamp , setts -> nodeid , true);
921960 if (subxids )
922961 pfree (subxids );
923962 }
0 commit comments