Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f12e814

Browse files
committed
Fix commit_ts for standby
Module initialization was still not completely correct after commit 6b61955, per crash report from Takashi Ohnishi. To fix, instead of trying to monkey around with the value of the GUC setting directly, add a separate boolean flag that enables the feature on a standby, but only for the startup (recovery) process, when it sees that its master server has the feature enabled. Discussion: http://www.postgresql.org/message-id/ca44c6c7f9314868bdc521aea4f77cbf@MP-MSGSS-MBX004.msg.nttdata.co.jp Also change the deactivation routine to delete all segment files rather than leaving the last one around. (This doesn't need separate WAL-logging, because on recovery we execute the same deactivation routine anyway.) In passing, clean up the code structure somewhat, particularly so that xlog.c doesn't know so much about when to activate/deactivate the feature. Thanks to Fujii Masao for testing and Petr Jelínek for off-list discussion. Back-patch to 9.5, where commit_ts was introduced.
1 parent bf4817e commit f12e814

File tree

5 files changed

+84
-65
lines changed

5 files changed

+84
-65
lines changed

src/backend/access/transam/commit_ts.c

+73-34
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,23 @@ CommitTimestampShared *commitTsShared;
9393
/* GUC variable */
9494
bool 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+
96104
static void SetXidCommitTsInPage(TransactionId xid, int nsubxids,
97105
TransactionId *subxids, TimestampTz ts,
98106
RepOriginId nodeid, int pageno);
99107
static void TransactionIdSetCommitTs(TransactionId xid, TimestampTz ts,
100108
RepOriginId nodeid, int slotno);
101109
static int ZeroCommitTsPage(int pageno, bool writeXlog);
102110
static bool CommitTsPagePrecedes(int page1, int page2);
111+
static void ActivateCommitTs(void);
112+
static void DeactivateCommitTs(bool do_wal);
103113
static void WriteZeroPageXlogRec(int pageno);
104114
static void WriteTruncateXlogRec(int pageno);
105115
static 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,
136142
void
137143
TransactionTreeSetCommitTsData(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
*/
538546
void
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
*/
564561
void
565562
CompleteCommitTsInitialization(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
588614
ActivateCommitTs(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
645674
DeactivateCommitTs(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
}

src/backend/access/transam/twophase.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2131,7 +2131,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
21312131

21322132
TransactionTreeSetCommitTsData(xid, nchildren, children,
21332133
replorigin_session_origin_timestamp,
2134-
replorigin_session_origin, false, false);
2134+
replorigin_session_origin, false);
21352135

21362136
/*
21372137
* We don't currently try to sleep before flush here ... nor is there any

src/backend/access/transam/xact.c

+2-4
Original file line numberDiff line numberDiff line change
@@ -1237,8 +1237,7 @@ RecordTransactionCommit(void)
12371237

12381238
TransactionTreeSetCommitTsData(xid, nchildren, children,
12391239
replorigin_session_origin_timestamp,
1240-
replorigin_session_origin,
1241-
false, false);
1240+
replorigin_session_origin, false);
12421241
}
12431242

12441243
/*
@@ -5333,8 +5332,7 @@ xact_redo_commit(xl_xact_parsed_commit *parsed,
53335332

53345333
/* Set the transaction commit timestamp and metadata */
53355334
TransactionTreeSetCommitTsData(xid, parsed->nsubxacts, parsed->subxacts,
5336-
commit_time, origin_id,
5337-
true, false);
5335+
commit_time, origin_id, false);
53385336

53395337
if (standbyState == STANDBY_DISABLED)
53405338
{

src/backend/access/transam/xlog.c

+5-21
Original file line numberDiff line numberDiff line change
@@ -6567,7 +6567,7 @@ StartupXLOG(void)
65676567
* maintained during recovery and need not be started yet.
65686568
*/
65696569
StartupCLOG();
6570-
StartupCommitTs();
6570+
StartupCommitTs(ControlFile->track_commit_timestamp);
65716571
StartupSUBTRANS(oldestActiveXID);
65726572

65736573
/*
@@ -7336,7 +7336,7 @@ StartupXLOG(void)
73367336
if (standbyState == STANDBY_DISABLED)
73377337
{
73387338
StartupCLOG();
7339-
StartupCommitTs();
7339+
StartupCommitTs(false);
73407340
StartupSUBTRANS(oldestActiveXID);
73417341
}
73427342

@@ -9456,25 +9456,9 @@ xlog_redo(XLogReaderState *record)
94569456
ControlFile->minRecoveryPointTLI = ThisTimeLineID;
94579457
}
94589458

9459-
/*
9460-
* Update the commit timestamp tracking. If there was a change it
9461-
* needs to be activated or deactivated accordingly.
9462-
*/
9463-
if (track_commit_timestamp != xlrec.track_commit_timestamp)
9464-
{
9465-
track_commit_timestamp = xlrec.track_commit_timestamp;
9466-
ControlFile->track_commit_timestamp = track_commit_timestamp;
9467-
if (track_commit_timestamp)
9468-
ActivateCommitTs();
9469-
else
9470-
9471-
/*
9472-
* We can't create a new WAL record here, but that's OK as
9473-
* master did the WAL logging already and we will replay the
9474-
* record from master in case we crash.
9475-
*/
9476-
DeactivateCommitTs(false);
9477-
}
9459+
CommitTsParameterChange(xlrec.track_commit_timestamp,
9460+
ControlFile->track_commit_timestamp);
9461+
ControlFile->track_commit_timestamp = xlrec.track_commit_timestamp;
94789462

94799463
UpdateControlFile();
94809464
LWLockRelease(ControlFileLock);

src/include/access/commit_ts.h

+3-5
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ extern bool check_track_commit_timestamp(bool *newval, void **extra,
2424

2525
extern void TransactionTreeSetCommitTsData(TransactionId xid, int nsubxids,
2626
TransactionId *subxids, TimestampTz timestamp,
27-
RepOriginId nodeid,
28-
bool replaying_xlog, bool write_xlog);
27+
RepOriginId nodeid, bool write_xlog);
2928
extern bool TransactionIdGetCommitTsData(TransactionId xid,
3029
TimestampTz *ts, RepOriginId *nodeid);
3130
extern TransactionId GetLatestCommitTsData(TimestampTz *ts,
@@ -35,9 +34,8 @@ extern Size CommitTsShmemBuffers(void);
3534
extern Size CommitTsShmemSize(void);
3635
extern void CommitTsShmemInit(void);
3736
extern void BootStrapCommitTs(void);
38-
extern void StartupCommitTs(void);
39-
extern void ActivateCommitTs(void);
40-
extern void DeactivateCommitTs(bool do_wal);
37+
extern void StartupCommitTs(bool force_enable);
38+
extern void CommitTsParameterChange(bool xlrecvalue, bool pgcontrolvalue);
4139
extern void CompleteCommitTsInitialization(void);
4240
extern void ShutdownCommitTs(void);
4341
extern void CheckPointCommitTs(void);

0 commit comments

Comments
 (0)