7
7
* Portions Copyright (c) 1996-2006, 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.248 2006/08/17 23:04:05 tgl Exp $
10
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.249 2006/08/21 16:16:31 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
@@ -312,10 +312,8 @@ static XLogRecPtr RedoRecPtr;
312
312
* new log file.
313
313
*
314
314
* CheckpointLock: must be held to do a checkpoint (ensures only one
315
- * checkpointer at a time; even though the postmaster won't launch
316
- * parallel checkpoint processes, we need this because manual checkpoints
317
- * could be launched simultaneously). XXX now that all checkpoints are
318
- * done by the bgwriter, isn't this lock redundant?
315
+ * checkpointer at a time; currently, with all checkpoints done by the
316
+ * bgwriter, this is just pro forma).
319
317
*
320
318
*----------
321
319
*/
@@ -363,9 +361,13 @@ typedef struct XLogCtlData
363
361
{
364
362
/* Protected by WALInsertLock: */
365
363
XLogCtlInsert Insert ;
364
+
366
365
/* Protected by info_lck: */
367
366
XLogwrtRqst LogwrtRqst ;
368
367
XLogwrtResult LogwrtResult ;
368
+ uint32 ckptXidEpoch ;/* nextXID & epoch of latest checkpoint */
369
+ TransactionId ckptXid ;
370
+
369
371
/* Protected by WALWriteLock: */
370
372
XLogCtlWrite Write ;
371
373
@@ -380,7 +382,7 @@ typedef struct XLogCtlData
380
382
int XLogCacheBlck ;/* highest allocated xlog buffer index */
381
383
TimeLineID ThisTimeLineID ;
382
384
383
- slock_t info_lck ;/* locks sharedLogwrtRqst/LogwrtResult */
385
+ slock_t info_lck ;/* locks sharedvariables shown above */
384
386
}XLogCtlData ;
385
387
386
388
static XLogCtlData * XLogCtl = NULL ;
@@ -4086,6 +4088,7 @@ BootStrapXLOG(void)
4086
4088
checkPoint .redo .xrecoff = SizeOfXLogLongPHD ;
4087
4089
checkPoint .undo = checkPoint .redo ;
4088
4090
checkPoint .ThisTimeLineID = ThisTimeLineID ;
4091
+ checkPoint .nextXidEpoch = 0 ;
4089
4092
checkPoint .nextXid = FirstNormalTransactionId ;
4090
4093
checkPoint .nextOid = FirstBootstrapObjectId ;
4091
4094
checkPoint .nextMulti = FirstMultiXactId ;
@@ -4752,8 +4755,9 @@ StartupXLOG(void)
4752
4755
checkPoint .undo .xlogid ,checkPoint .undo .xrecoff ,
4753
4756
wasShutdown ?"TRUE" :"FALSE" )));
4754
4757
ereport (LOG ,
4755
- (errmsg ("next transaction ID: %u; next OID: %u" ,
4756
- checkPoint .nextXid ,checkPoint .nextOid )));
4758
+ (errmsg ("next transaction ID: %u/%u; next OID: %u" ,
4759
+ checkPoint .nextXidEpoch ,checkPoint .nextXid ,
4760
+ checkPoint .nextOid )));
4757
4761
ereport (LOG ,
4758
4762
(errmsg ("next MultiXactId: %u; next MultiXactOffset: %u" ,
4759
4763
checkPoint .nextMulti ,checkPoint .nextMultiOffset )));
@@ -5135,6 +5139,10 @@ StartupXLOG(void)
5135
5139
/* start the archive_timeout timer running */
5136
5140
XLogCtl -> Write .lastSegSwitchTime = ControlFile -> time ;
5137
5141
5142
+ /* initialize shared-memory copy of latest checkpoint XID/epoch */
5143
+ XLogCtl -> ckptXidEpoch = ControlFile -> checkPointCopy .nextXidEpoch ;
5144
+ XLogCtl -> ckptXid = ControlFile -> checkPointCopy .nextXid ;
5145
+
5138
5146
/* Start up the commit log and related stuff, too */
5139
5147
StartupCLOG ();
5140
5148
StartupSUBTRANS (oldestActiveXID );
@@ -5364,6 +5372,46 @@ GetRecentNextXid(void)
5364
5372
return ControlFile -> checkPointCopy .nextXid ;
5365
5373
}
5366
5374
5375
+ /*
5376
+ * GetNextXidAndEpoch - get the current nextXid value and associated epoch
5377
+ *
5378
+ * This is exported for use by code that would like to have 64-bit XIDs.
5379
+ * We don't really support such things, but all XIDs within the system
5380
+ * can be presumed "close to" the result, and thus the epoch associated
5381
+ * with them can be determined.
5382
+ */
5383
+ void
5384
+ GetNextXidAndEpoch (TransactionId * xid ,uint32 * epoch )
5385
+ {
5386
+ uint32 ckptXidEpoch ;
5387
+ TransactionId ckptXid ;
5388
+ TransactionId nextXid ;
5389
+
5390
+ /* Must read checkpoint info first, else have race condition */
5391
+ {
5392
+ /* use volatile pointer to prevent code rearrangement */
5393
+ volatile XLogCtlData * xlogctl = XLogCtl ;
5394
+
5395
+ SpinLockAcquire (& xlogctl -> info_lck );
5396
+ ckptXidEpoch = xlogctl -> ckptXidEpoch ;
5397
+ ckptXid = xlogctl -> ckptXid ;
5398
+ SpinLockRelease (& xlogctl -> info_lck );
5399
+ }
5400
+
5401
+ /* Now fetch current nextXid */
5402
+ nextXid = ReadNewTransactionId ();
5403
+
5404
+ /*
5405
+ * nextXid is certainly logically later than ckptXid. So if it's
5406
+ * numerically less, it must have wrapped into the next epoch.
5407
+ */
5408
+ if (nextXid < ckptXid )
5409
+ ckptXidEpoch ++ ;
5410
+
5411
+ * xid = nextXid ;
5412
+ * epoch = ckptXidEpoch ;
5413
+ }
5414
+
5367
5415
/*
5368
5416
* This must be called ONCE during postmaster or standalone-backend shutdown
5369
5417
*/
@@ -5531,6 +5579,11 @@ CreateCheckPoint(bool shutdown, bool force)
5531
5579
checkPoint .nextXid = ShmemVariableCache -> nextXid ;
5532
5580
LWLockRelease (XidGenLock );
5533
5581
5582
+ /* Increase XID epoch if we've wrapped around since last checkpoint */
5583
+ checkPoint .nextXidEpoch = ControlFile -> checkPointCopy .nextXidEpoch ;
5584
+ if (checkPoint .nextXid < ControlFile -> checkPointCopy .nextXid )
5585
+ checkPoint .nextXidEpoch ++ ;
5586
+
5534
5587
LWLockAcquire (OidGenLock ,LW_SHARED );
5535
5588
checkPoint .nextOid = ShmemVariableCache -> nextOid ;
5536
5589
if (!shutdown )
@@ -5600,6 +5653,17 @@ CreateCheckPoint(bool shutdown, bool force)
5600
5653
UpdateControlFile ();
5601
5654
LWLockRelease (ControlFileLock );
5602
5655
5656
+ /* Update shared-memory copy of checkpoint XID/epoch */
5657
+ {
5658
+ /* use volatile pointer to prevent code rearrangement */
5659
+ volatile XLogCtlData * xlogctl = XLogCtl ;
5660
+
5661
+ SpinLockAcquire (& xlogctl -> info_lck );
5662
+ xlogctl -> ckptXidEpoch = checkPoint .nextXidEpoch ;
5663
+ xlogctl -> ckptXid = checkPoint .nextXid ;
5664
+ SpinLockRelease (& xlogctl -> info_lck );
5665
+ }
5666
+
5603
5667
/*
5604
5668
* We are now done with critical updates; no need for system panic if we
5605
5669
* have trouble while fooling with offline log segments.
@@ -5803,6 +5867,10 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
5803
5867
MultiXactSetNextMXact (checkPoint .nextMulti ,
5804
5868
checkPoint .nextMultiOffset );
5805
5869
5870
+ /* ControlFile->checkPointCopy always tracks the latest ckpt XID */
5871
+ ControlFile -> checkPointCopy .nextXidEpoch = checkPoint .nextXidEpoch ;
5872
+ ControlFile -> checkPointCopy .nextXid = checkPoint .nextXid ;
5873
+
5806
5874
/*
5807
5875
* TLI may change in a shutdown checkpoint, but it shouldn't decrease
5808
5876
*/
@@ -5836,6 +5904,11 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
5836
5904
}
5837
5905
MultiXactAdvanceNextMXact (checkPoint .nextMulti ,
5838
5906
checkPoint .nextMultiOffset );
5907
+
5908
+ /* ControlFile->checkPointCopy always tracks the latest ckpt XID */
5909
+ ControlFile -> checkPointCopy .nextXidEpoch = checkPoint .nextXidEpoch ;
5910
+ ControlFile -> checkPointCopy .nextXid = checkPoint .nextXid ;
5911
+
5839
5912
/* TLI should not change in an on-line checkpoint */
5840
5913
if (checkPoint .ThisTimeLineID != ThisTimeLineID )
5841
5914
ereport (PANIC ,
@@ -5861,10 +5934,11 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
5861
5934
CheckPoint * checkpoint = (CheckPoint * )rec ;
5862
5935
5863
5936
appendStringInfo (buf ,"checkpoint: redo %X/%X; undo %X/%X; "
5864
- "tli %u; xid %u; oid %u; multi %u; offset %u; %s" ,
5937
+ "tli %u; xid %u/%u ; oid %u; multi %u; offset %u; %s" ,
5865
5938
checkpoint -> redo .xlogid ,checkpoint -> redo .xrecoff ,
5866
5939
checkpoint -> undo .xlogid ,checkpoint -> undo .xrecoff ,
5867
- checkpoint -> ThisTimeLineID ,checkpoint -> nextXid ,
5940
+ checkpoint -> ThisTimeLineID ,
5941
+ checkpoint -> nextXidEpoch ,checkpoint -> nextXid ,
5868
5942
checkpoint -> nextOid ,
5869
5943
checkpoint -> nextMulti ,
5870
5944
checkpoint -> nextMultiOffset ,