7
7
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
8
8
* Portions Copyright (c) 1994, Regents of the University of California
9
9
*
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 $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
@@ -184,7 +184,6 @@ static RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
184
184
static bool recoveryTargetInclusive = true;
185
185
static TransactionId recoveryTargetXid ;
186
186
static TimestampTz recoveryTargetTime ;
187
- static TimestampTz recoveryLastXTime = 0 ;
188
187
189
188
/* options taken from recovery.conf for XLOG streaming */
190
189
static bool StandbyMode = false;
@@ -403,10 +402,10 @@ typedef struct XLogCtlData
403
402
404
403
/* end+1 of the last record replayed (or being replayed) */
405
404
XLogRecPtr replayEndRecPtr ;
406
- /* timestamp of last record replayed (or being replayed) */
407
- TimestampTz recoveryLastXTime ;
408
405
/* end+1 of the last record replayed */
409
406
XLogRecPtr recoveryLastRecPtr ;
407
+ /* timestamp of last COMMIT/ABORT record replayed (or being replayed) */
408
+ TimestampTz recoveryLastXTime ;
410
409
411
410
slock_t info_lck ; /* locks shared variables shown above */
412
411
} XLogCtlData ;
@@ -554,6 +553,8 @@ static void readRecoveryCommandFile(void);
554
553
static void exitArchiveRecovery (TimeLineID endTLI ,
555
554
uint32 endLogId , uint32 endLogSeg );
556
555
static bool recoveryStopsHere (XLogRecord * record , bool * includeThis );
556
+ static void SetLatestXTime (TimestampTz xtime );
557
+ static TimestampTz GetLatestXTime (void );
557
558
static void CheckRequiredParameterValues (void );
558
559
static void XLogReportParameters (void );
559
560
static void LocalSetXLogInsertAllowed (void );
@@ -5440,7 +5441,7 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
5440
5441
* *includeThis is set TRUE if we should apply this record before stopping.
5441
5442
*
5442
5443
* 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.
5444
5445
* Also, some information is saved in recoveryStopXid et al for use in
5445
5446
* annotating the new timeline's history file.
5446
5447
*/
@@ -5452,51 +5453,30 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
5452
5453
TimestampTz recordXtime ;
5453
5454
5454
5455
/* 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 )
5456
5460
{
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 ;
5461
5462
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 ;
5474
5465
}
5475
- else if (record -> xl_rmid == RM_XLOG_ID )
5466
+ else if (record_info == XLOG_XACT_ABORT )
5476
5467
{
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 ;
5482
5469
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 ;
5492
5472
}
5493
5473
else
5494
5474
return false;
5495
5475
5496
5476
/* Do we have a PITR target at all? */
5497
5477
if (recoveryTarget == RECOVERY_TARGET_UNSET )
5498
5478
{
5499
- recoveryLastXTime = recordXtime ;
5479
+ SetLatestXTime ( recordXtime ) ;
5500
5480
return false;
5501
5481
}
5502
5482
@@ -5564,37 +5544,56 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
5564
5544
}
5565
5545
5566
5546
if (recoveryStopAfter )
5567
- recoveryLastXTime = recordXtime ;
5547
+ SetLatestXTime ( recordXtime ) ;
5568
5548
}
5569
5549
else
5570
- recoveryLastXTime = recordXtime ;
5550
+ SetLatestXTime ( recordXtime ) ;
5571
5551
5572
5552
return stopsHere ;
5573
5553
}
5574
5554
5575
5555
/*
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.
5577
5561
*/
5578
- Datum
5579
- pg_is_in_recovery ( PG_FUNCTION_ARGS )
5562
+ static void
5563
+ SetLatestXTime ( TimestampTz xtime )
5580
5564
{
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 );
5582
5571
}
5583
5572
5584
5573
/*
5585
- * Returns timestamp of last recovered commit/abort record.
5574
+ * Fetch timestamp of latest processed commit/abort record.
5586
5575
*/
5587
5576
static TimestampTz
5588
- GetLatestXLogTime (void )
5577
+ GetLatestXTime (void )
5589
5578
{
5590
5579
/* use volatile pointer to prevent code rearrangement */
5591
5580
volatile XLogCtlData * xlogctl = XLogCtl ;
5581
+ TimestampTz xtime ;
5592
5582
5593
5583
SpinLockAcquire (& xlogctl -> info_lck );
5594
- recoveryLastXTime = xlogctl -> recoveryLastXTime ;
5584
+ xtime = xlogctl -> recoveryLastXTime ;
5595
5585
SpinLockRelease (& xlogctl -> info_lck );
5596
5586
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 ());
5598
5597
}
5599
5598
5600
5599
/*
@@ -6078,7 +6077,8 @@ StartupXLOG(void)
6078
6077
}
6079
6078
6080
6079
/*
6081
- * Initialize shared replayEndRecPtr and recoveryLastRecPtr.
6080
+ * Initialize shared replayEndRecPtr, recoveryLastRecPtr, and
6081
+ * recoveryLastXTime.
6082
6082
*
6083
6083
* This is slightly confusing if we're starting from an online
6084
6084
* checkpoint; we've just read and replayed the chekpoint record,
@@ -6091,6 +6091,7 @@ StartupXLOG(void)
6091
6091
SpinLockAcquire (& xlogctl -> info_lck );
6092
6092
xlogctl -> replayEndRecPtr = ReadRecPtr ;
6093
6093
xlogctl -> recoveryLastRecPtr = ReadRecPtr ;
6094
+ xlogctl -> recoveryLastXTime = 0 ;
6094
6095
SpinLockRelease (& xlogctl -> info_lck );
6095
6096
6096
6097
/* Also ensure XLogReceiptTime has a sane value */
@@ -6140,6 +6141,7 @@ StartupXLOG(void)
6140
6141
bool recoveryContinue = true;
6141
6142
bool recoveryApply = true;
6142
6143
ErrorContextCallback errcontext ;
6144
+ TimestampTz xtime ;
6143
6145
6144
6146
InRedo = true;
6145
6147
@@ -6210,7 +6212,6 @@ StartupXLOG(void)
6210
6212
*/
6211
6213
SpinLockAcquire (& xlogctl -> info_lck );
6212
6214
xlogctl -> replayEndRecPtr = EndRecPtr ;
6213
- xlogctl -> recoveryLastXTime = recoveryLastXTime ;
6214
6215
SpinLockRelease (& xlogctl -> info_lck );
6215
6216
6216
6217
/* If we are attempting to enter Hot Standby mode, process XIDs we see */
@@ -6243,10 +6244,11 @@ StartupXLOG(void)
6243
6244
ereport (LOG ,
6244
6245
(errmsg ("redo done at %X/%X" ,
6245
6246
ReadRecPtr .xlogid , ReadRecPtr .xrecoff )));
6246
- if (recoveryLastXTime )
6247
+ xtime = GetLatestXTime ();
6248
+ if (xtime )
6247
6249
ereport (LOG ,
6248
6250
(errmsg ("last completed transaction was at log time %s" ,
6249
- timestamptz_to_str (recoveryLastXTime ))));
6251
+ timestamptz_to_str (xtime ))));
6250
6252
InRedo = false;
6251
6253
}
6252
6254
else
@@ -7553,6 +7555,7 @@ CreateRestartPoint(int flags)
7553
7555
CheckPoint lastCheckPoint ;
7554
7556
uint32 _logId ;
7555
7557
uint32 _logSeg ;
7558
+ TimestampTz xtime ;
7556
7559
7557
7560
/* use volatile pointer to prevent code rearrangement */
7558
7561
volatile XLogCtlData * xlogctl = XLogCtl ;
@@ -7705,10 +7708,12 @@ CreateRestartPoint(int flags)
7705
7708
if (log_checkpoints )
7706
7709
LogCheckpointEnd (true);
7707
7710
7711
+ xtime = GetLatestXTime ();
7708
7712
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 ));
7712
7717
7713
7718
LWLockRelease (CheckpointLock );
7714
7719
0 commit comments