77 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88 * Portions Copyright (c) 1994, Regents of the University of California
99 *
10- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.428 2010/07/03 20:43:57 tgl Exp $
10+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.429 2010/07/03 22:15:45 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -184,7 +184,6 @@ static RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
184184static bool recoveryTargetInclusive = true;
185185static TransactionId recoveryTargetXid ;
186186static TimestampTz recoveryTargetTime ;
187- static TimestampTz recoveryLastXTime = 0 ;
188187
189188/* options taken from recovery.conf for XLOG streaming */
190189static bool StandbyMode = false;
@@ -403,10 +402,10 @@ typedef struct XLogCtlData
403402
404403 /* end+1 of the last record replayed (or being replayed) */
405404 XLogRecPtr replayEndRecPtr ;
406- /* timestamp of last record replayed (or being replayed) */
407- TimestampTz recoveryLastXTime ;
408405 /* end+1 of the last record replayed */
409406 XLogRecPtr recoveryLastRecPtr ;
407+ /* timestamp of last COMMIT/ABORT record replayed (or being replayed) */
408+ TimestampTz recoveryLastXTime ;
410409
411410 slock_t info_lck ; /* locks shared variables shown above */
412411} XLogCtlData ;
@@ -554,6 +553,8 @@ static void readRecoveryCommandFile(void);
554553static void exitArchiveRecovery (TimeLineID endTLI ,
555554 uint32 endLogId , uint32 endLogSeg );
556555static bool recoveryStopsHere (XLogRecord * record , bool * includeThis );
556+ static void SetLatestXTime (TimestampTz xtime );
557+ static TimestampTz GetLatestXTime (void );
557558static void CheckRequiredParameterValues (void );
558559static void XLogReportParameters (void );
559560static void LocalSetXLogInsertAllowed (void );
@@ -5440,7 +5441,7 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
54405441 * *includeThis is set TRUE if we should apply this record before stopping.
54415442 *
54425443 * We also track the timestamp of the latest applied COMMIT/ABORT record
5443- * in recoveryLastXTime, for logging purposes.
5444+ * in XLogCtl-> recoveryLastXTime, for logging purposes.
54445445 * Also, some information is saved in recoveryStopXid et al for use in
54455446 * annotating the new timeline's history file.
54465447 */
@@ -5452,51 +5453,30 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
54525453 TimestampTz recordXtime ;
54535454
54545455 /* We only consider stopping at COMMIT or ABORT records */
5455- if (record -> xl_rmid == RM_XACT_ID )
5456+ if (record -> xl_rmid != RM_XACT_ID )
5457+ return false;
5458+ record_info = record -> xl_info & ~XLR_INFO_MASK ;
5459+ if (record_info == XLOG_XACT_COMMIT )
54565460 {
5457- record_info = record -> xl_info & ~XLR_INFO_MASK ;
5458- if (record_info == XLOG_XACT_COMMIT )
5459- {
5460- xl_xact_commit * recordXactCommitData ;
5461+ xl_xact_commit * recordXactCommitData ;
54615462
5462- recordXactCommitData = (xl_xact_commit * ) XLogRecGetData (record );
5463- recordXtime = recordXactCommitData -> xact_time ;
5464- }
5465- else if (record_info == XLOG_XACT_ABORT )
5466- {
5467- xl_xact_abort * recordXactAbortData ;
5468-
5469- recordXactAbortData = (xl_xact_abort * ) XLogRecGetData (record );
5470- recordXtime = recordXactAbortData -> xact_time ;
5471- }
5472- else
5473- return false;
5463+ recordXactCommitData = (xl_xact_commit * ) XLogRecGetData (record );
5464+ recordXtime = recordXactCommitData -> xact_time ;
54745465 }
5475- else if (record -> xl_rmid == RM_XLOG_ID )
5466+ else if (record_info == XLOG_XACT_ABORT )
54765467 {
5477- record_info = record -> xl_info & ~XLR_INFO_MASK ;
5478- if (record_info == XLOG_CHECKPOINT_SHUTDOWN ||
5479- record_info == XLOG_CHECKPOINT_ONLINE )
5480- {
5481- CheckPoint checkPoint ;
5468+ xl_xact_abort * recordXactAbortData ;
54825469
5483- memcpy (& checkPoint , XLogRecGetData (record ), sizeof (CheckPoint ));
5484- recoveryLastXTime = time_t_to_timestamptz (checkPoint .time );
5485- }
5486-
5487- /*
5488- * We don't want to stop recovery on a checkpoint record, but we do
5489- * want to update recoveryLastXTime. So return is unconditional.
5490- */
5491- return false;
5470+ recordXactAbortData = (xl_xact_abort * ) XLogRecGetData (record );
5471+ recordXtime = recordXactAbortData -> xact_time ;
54925472 }
54935473 else
54945474 return false;
54955475
54965476 /* Do we have a PITR target at all? */
54975477 if (recoveryTarget == RECOVERY_TARGET_UNSET )
54985478 {
5499- recoveryLastXTime = recordXtime ;
5479+ SetLatestXTime ( recordXtime ) ;
55005480 return false;
55015481 }
55025482
@@ -5564,37 +5544,56 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
55645544 }
55655545
55665546 if (recoveryStopAfter )
5567- recoveryLastXTime = recordXtime ;
5547+ SetLatestXTime ( recordXtime ) ;
55685548 }
55695549 else
5570- recoveryLastXTime = recordXtime ;
5550+ SetLatestXTime ( recordXtime ) ;
55715551
55725552 return stopsHere ;
55735553}
55745554
55755555/*
5576- * Returns bool with current recovery mode, a global state.
5556+ * Save timestamp of latest processed commit/abort record.
5557+ *
5558+ * We keep this in XLogCtl, not a simple static variable, so that it can be
5559+ * seen by processes other than the startup process. Note in particular
5560+ * that CreateRestartPoint is executed in the bgwriter.
55775561 */
5578- Datum
5579- pg_is_in_recovery ( PG_FUNCTION_ARGS )
5562+ static void
5563+ SetLatestXTime ( TimestampTz xtime )
55805564{
5581- PG_RETURN_BOOL (RecoveryInProgress ());
5565+ /* use volatile pointer to prevent code rearrangement */
5566+ volatile XLogCtlData * xlogctl = XLogCtl ;
5567+
5568+ SpinLockAcquire (& xlogctl -> info_lck );
5569+ xlogctl -> recoveryLastXTime = xtime ;
5570+ SpinLockRelease (& xlogctl -> info_lck );
55825571}
55835572
55845573/*
5585- * Returns timestamp of last recovered commit/abort record.
5574+ * Fetch timestamp of latest processed commit/abort record.
55865575 */
55875576static TimestampTz
5588- GetLatestXLogTime (void )
5577+ GetLatestXTime (void )
55895578{
55905579 /* use volatile pointer to prevent code rearrangement */
55915580 volatile XLogCtlData * xlogctl = XLogCtl ;
5581+ TimestampTz xtime ;
55925582
55935583 SpinLockAcquire (& xlogctl -> info_lck );
5594- recoveryLastXTime = xlogctl -> recoveryLastXTime ;
5584+ xtime = xlogctl -> recoveryLastXTime ;
55955585 SpinLockRelease (& xlogctl -> info_lck );
55965586
5597- return recoveryLastXTime ;
5587+ return xtime ;
5588+ }
5589+
5590+ /*
5591+ * Returns bool with current recovery mode, a global state.
5592+ */
5593+ Datum
5594+ pg_is_in_recovery (PG_FUNCTION_ARGS )
5595+ {
5596+ PG_RETURN_BOOL (RecoveryInProgress ());
55985597}
55995598
56005599/*
@@ -6078,7 +6077,8 @@ StartupXLOG(void)
60786077 }
60796078
60806079 /*
6081- * Initialize shared replayEndRecPtr and recoveryLastRecPtr.
6080+ * Initialize shared replayEndRecPtr, recoveryLastRecPtr, and
6081+ * recoveryLastXTime.
60826082 *
60836083 * This is slightly confusing if we're starting from an online
60846084 * checkpoint; we've just read and replayed the chekpoint record,
@@ -6091,6 +6091,7 @@ StartupXLOG(void)
60916091 SpinLockAcquire (& xlogctl -> info_lck );
60926092 xlogctl -> replayEndRecPtr = ReadRecPtr ;
60936093 xlogctl -> recoveryLastRecPtr = ReadRecPtr ;
6094+ xlogctl -> recoveryLastXTime = 0 ;
60946095 SpinLockRelease (& xlogctl -> info_lck );
60956096
60966097 /* Also ensure XLogReceiptTime has a sane value */
@@ -6140,6 +6141,7 @@ StartupXLOG(void)
61406141 bool recoveryContinue = true;
61416142 bool recoveryApply = true;
61426143 ErrorContextCallback errcontext ;
6144+ TimestampTz xtime ;
61436145
61446146 InRedo = true;
61456147
@@ -6210,7 +6212,6 @@ StartupXLOG(void)
62106212 */
62116213 SpinLockAcquire (& xlogctl -> info_lck );
62126214 xlogctl -> replayEndRecPtr = EndRecPtr ;
6213- xlogctl -> recoveryLastXTime = recoveryLastXTime ;
62146215 SpinLockRelease (& xlogctl -> info_lck );
62156216
62166217 /* If we are attempting to enter Hot Standby mode, process XIDs we see */
@@ -6243,10 +6244,11 @@ StartupXLOG(void)
62436244 ereport (LOG ,
62446245 (errmsg ("redo done at %X/%X" ,
62456246 ReadRecPtr .xlogid , ReadRecPtr .xrecoff )));
6246- if (recoveryLastXTime )
6247+ xtime = GetLatestXTime ();
6248+ if (xtime )
62476249 ereport (LOG ,
62486250 (errmsg ("last completed transaction was at log time %s" ,
6249- timestamptz_to_str (recoveryLastXTime ))));
6251+ timestamptz_to_str (xtime ))));
62506252 InRedo = false;
62516253 }
62526254 else
@@ -7553,6 +7555,7 @@ CreateRestartPoint(int flags)
75537555 CheckPoint lastCheckPoint ;
75547556 uint32 _logId ;
75557557 uint32 _logSeg ;
7558+ TimestampTz xtime ;
75567559
75577560 /* use volatile pointer to prevent code rearrangement */
75587561 volatile XLogCtlData * xlogctl = XLogCtl ;
@@ -7705,10 +7708,12 @@ CreateRestartPoint(int flags)
77057708 if (log_checkpoints )
77067709 LogCheckpointEnd (true);
77077710
7711+ xtime = GetLatestXTime ();
77087712 ereport ((log_checkpoints ? LOG : DEBUG2 ),
7709- (errmsg ("recovery restart point at %X/%X with latest known log time %s" ,
7710- lastCheckPoint .redo .xlogid , lastCheckPoint .redo .xrecoff ,
7711- timestamptz_to_str (GetLatestXLogTime ()))));
7713+ (errmsg ("recovery restart point at %X/%X" ,
7714+ lastCheckPoint .redo .xlogid , lastCheckPoint .redo .xrecoff ),
7715+ xtime ? errdetail ("last completed transaction was at log time %s" ,
7716+ timestamptz_to_str (xtime )) : 0 ));
77127717
77137718 LWLockRelease (CheckpointLock );
77147719
0 commit comments