Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0174769

Browse files
committed
Repair two problems with WAL logging of sequence nextvalI() ops, as
per recent pghackers discussion: force a new WAL record at first nextvalafter a checkpoint, and ensure that xlog is flushed to disk if a nextvalrecord is the only thing emitted by a transaction.
1 parent0b73fe1 commit0174769

File tree

6 files changed

+147
-68
lines changed

6 files changed

+147
-68
lines changed

‎src/backend/access/transam/xact.c

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.117 2002/03/06 06:09:21 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.118 2002/03/15 19:20:29 tgl Exp $
1212
*
1313
* NOTES
1414
*Transaction aborts can now occur two ways:
@@ -546,32 +546,48 @@ RecordTransactionCommit(void)
546546
xid=GetCurrentTransactionId();
547547

548548
/*
549-
* We needn't write anything in xlog or clog if the transaction was
550-
* read-only, which we check by testing if it made any xlog entries.
549+
* We only need to log the commit in xlog and clog if the transaction made
550+
* any transaction-controlled XLOG entries. (Otherwise, its XID appears
551+
* nowhere in permanent storage, so no one will ever care if it
552+
* committed.) However, we must flush XLOG to disk if we made any XLOG
553+
* entries, whether in or out of transaction control. For example, if we
554+
* reported a nextval() result to the client, this ensures that any XLOG
555+
* record generated by nextval will hit the disk before we report the
556+
* transaction committed.
551557
*/
552-
if (MyLastRecPtr.xrecoff!=0)
558+
if (MyXactMadeXLogEntry)
553559
{
554-
XLogRecDatardata;
555-
xl_xact_commitxlrec;
556560
XLogRecPtrrecptr;
557561

558562
BufmgrCommit();
559563

560-
xlrec.xtime=time(NULL);
561-
rdata.buffer=InvalidBuffer;
562-
rdata.data= (char*) (&xlrec);
563-
rdata.len=SizeOfXactCommit;
564-
rdata.next=NULL;
565-
566564
START_CRIT_SECTION();
567565

568-
/*
569-
* SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
570-
*/
571-
recptr=XLogInsert(RM_XACT_ID,XLOG_XACT_COMMIT,&rdata);
566+
if (MyLastRecPtr.xrecoff!=0)
567+
{
568+
/* Need to emit a commit record */
569+
XLogRecDatardata;
570+
xl_xact_commitxlrec;
571+
572+
xlrec.xtime=time(NULL);
573+
rdata.buffer=InvalidBuffer;
574+
rdata.data= (char*) (&xlrec);
575+
rdata.len=SizeOfXactCommit;
576+
rdata.next=NULL;
577+
578+
/*
579+
* XXX SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
580+
*/
581+
recptr=XLogInsert(RM_XACT_ID,XLOG_XACT_COMMIT,&rdata);
582+
}
583+
else
584+
{
585+
/* Just flush through last record written by me */
586+
recptr=ProcLastRecEnd;
587+
}
572588

573589
/*
574-
* Sleep beforecommit! So we can flush more than one commit
590+
* Sleep beforeflush! So we can flush more than one commit
575591
* records per single fsync. (The idea is some other backend may
576592
* do the XLogFlush while we're sleeping. This needs work still,
577593
* because on most Unixen, the minimum select() delay is 10msec or
@@ -593,15 +609,17 @@ RecordTransactionCommit(void)
593609

594610
XLogFlush(recptr);
595611

596-
/* Break the chain of back-links in the XLOG records I output */
597-
MyLastRecPtr.xrecoff=0;
598-
599-
/* Mark the transaction committed in clog */
600-
TransactionIdCommit(xid);
612+
/* Mark the transaction committed in clog, if needed */
613+
if (MyLastRecPtr.xrecoff!=0)
614+
TransactionIdCommit(xid);
601615

602616
END_CRIT_SECTION();
603617
}
604618

619+
/* Break the chain of back-links in the XLOG records I output */
620+
MyLastRecPtr.xrecoff=0;
621+
MyXactMadeXLogEntry= false;
622+
605623
/* Show myself as out of the transaction in PROC array */
606624
MyProc->logRec.xrecoff=0;
607625

@@ -689,8 +707,11 @@ RecordTransactionAbort(void)
689707
TransactionIdxid=GetCurrentTransactionId();
690708

691709
/*
692-
* We needn't write anything in xlog or clog if the transaction was
693-
* read-only, which we check by testing if it made any xlog entries.
710+
* We only need to log the abort in xlog and clog if the transaction made
711+
* any transaction-controlled XLOG entries. (Otherwise, its XID appears
712+
* nowhere in permanent storage, so no one will ever care if it
713+
* committed.) We do not flush XLOG to disk in any case, since the
714+
* default assumption after a crash would be that we aborted, anyway.
694715
*
695716
* Extra check here is to catch case that we aborted partway through
696717
* RecordTransactionCommit ...
@@ -714,11 +735,6 @@ RecordTransactionAbort(void)
714735
*/
715736
recptr=XLogInsert(RM_XACT_ID,XLOG_XACT_ABORT,&rdata);
716737

717-
/*
718-
* There's no need for XLogFlush here, since the default
719-
* assumption would be that we aborted, anyway.
720-
*/
721-
722738
/* Mark the transaction aborted in clog */
723739
TransactionIdAbort(xid);
724740

@@ -727,6 +743,8 @@ RecordTransactionAbort(void)
727743

728744
/* Break the chain of back-links in the XLOG records I output */
729745
MyLastRecPtr.xrecoff=0;
746+
MyXactMadeXLogEntry= false;
747+
730748
/* Show myself as out of the transaction in PROC array */
731749
MyProc->logRec.xrecoff=0;
732750

‎src/backend/access/transam/xlog.c

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.89 2002/03/06 06:09:22 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.90 2002/03/15 19:20:30 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -131,27 +131,36 @@ boolInRecovery = false;
131131

132132
/*
133133
* MyLastRecPtr points to the start of the last XLOG record inserted by the
134-
* current transaction. If MyLastRecPtr.xrecoff == 0, thenwe are not in
135-
*a transaction or the transaction has notyetmade anyloggable changes.
134+
* current transaction. If MyLastRecPtr.xrecoff == 0, thenthe current
135+
*xact hasn'tyetinserted anytransaction-controlled XLOG records.
136136
*
137137
* Note that XLOG records inserted outside transaction control are not
138-
* reflected into MyLastRecPtr.
138+
* reflected into MyLastRecPtr. They do, however, cause MyXactMadeXLogEntry
139+
* to be set true. The latter can be used to test whether the current xact
140+
* made any loggable changes (including out-of-xact changes, such as
141+
* sequence updates).
139142
*/
140143
XLogRecPtrMyLastRecPtr= {0,0};
141144

145+
boolMyXactMadeXLogEntry= false;
146+
142147
/*
143148
* ProcLastRecPtr points to the start of the last XLOG record inserted by the
144149
* current backend. It is updated for all inserts, transaction-controlled
145-
* or not.
150+
* or not. ProcLastRecEnd is similar but points to end+1 of last record.
146151
*/
147152
staticXLogRecPtrProcLastRecPtr= {0,0};
148153

154+
XLogRecPtrProcLastRecEnd= {0,0};
155+
149156
/*
150157
* RedoRecPtr is this backend's local copy of the REDO record pointer
151158
* (which is almost but not quite the same as a pointer to the most recent
152159
* CHECKPOINT record).We update this from the shared-memory copy,
153160
* XLogCtl->Insert.RedoRecPtr, whenever we can safely do so (ie, when we
154-
* hold the Insert lock). See XLogInsert for details.
161+
* hold the Insert lock). See XLogInsert for details. We are also allowed
162+
* to update from XLogCtl->Insert.RedoRecPtr if we hold the info_lck;
163+
* see GetRedoRecPtr.
155164
*/
156165
staticXLogRecPtrRedoRecPtr;
157166

@@ -272,7 +281,8 @@ typedef struct XLogCtlData
272281
StartUpIDThisStartUpID;
273282

274283
/* This value is not protected by *any* lock... */
275-
XLogRecPtrRedoRecPtr;/* see SetRedoRecPtr/GetRedoRecPtr */
284+
/* see SetSavedRedoRecPtr/GetSavedRedoRecPtr */
285+
XLogRecPtrSavedRedoRecPtr;
276286

277287
slock_tinfo_lck;/* locks shared LogwrtRqst/LogwrtResult */
278288
}XLogCtlData;
@@ -777,6 +787,7 @@ begin:;
777787
MyLastRecPtr=RecPtr;
778788
ProcLastRecPtr=RecPtr;
779789
Insert->PrevRecord=RecPtr;
790+
MyXactMadeXLogEntry= true;
780791

781792
Insert->currpos+=SizeOfXLogRecord;
782793
freespace-=SizeOfXLogRecord;
@@ -855,6 +866,8 @@ begin:;
855866
SpinLockRelease_NoHoldoff(&xlogctl->info_lck);
856867
}
857868

869+
ProcLastRecEnd=RecPtr;
870+
858871
END_CRIT_SECTION();
859872

860873
return (RecPtr);
@@ -2538,7 +2551,7 @@ StartupXLOG(void)
25382551

25392552
ThisStartUpID=checkPoint.ThisStartUpID;
25402553
RedoRecPtr=XLogCtl->Insert.RedoRecPtr=
2541-
XLogCtl->RedoRecPtr=checkPoint.redo;
2554+
XLogCtl->SavedRedoRecPtr=checkPoint.redo;
25422555

25432556
if (XLByteLT(RecPtr,checkPoint.redo))
25442557
elog(PANIC,"invalid redo in checkpoint record");
@@ -2824,32 +2837,47 @@ void
28242837
SetThisStartUpID(void)
28252838
{
28262839
ThisStartUpID=XLogCtl->ThisStartUpID;
2827-
RedoRecPtr=XLogCtl->RedoRecPtr;
2840+
RedoRecPtr=XLogCtl->SavedRedoRecPtr;
28282841
}
28292842

28302843
/*
28312844
* CheckPoint process called by postmaster saves copy of new RedoRecPtr
2832-
* in shmem (using SetRedoRecPtr).When checkpointer completes, postmaster
2833-
* calls GetRedoRecPtr to update its own copy of RedoRecPtr, so that
2834-
* subsequently-spawned backends will start out with a reasonably up-to-date
2835-
* local RedoRecPtr. Since these operations are not protected by any lock
2836-
* and copying an XLogRecPtr isn't atomic, it's unsafe to use either of these
2837-
* routines at other times!
2838-
*
2839-
* Note: once spawned, a backend must update its local RedoRecPtr from
2840-
* XLogCtl->Insert.RedoRecPtr while holding the insert lock. This is
2841-
* done in XLogInsert().
2845+
* in shmem (using SetSavedRedoRecPtr). When checkpointer completes,
2846+
* postmaster calls GetSavedRedoRecPtr to update its own copy of RedoRecPtr,
2847+
* so that subsequently-spawned backends will start out with a reasonably
2848+
* up-to-date local RedoRecPtr. Since these operations are not protected by
2849+
* any lock and copying an XLogRecPtr isn't atomic, it's unsafe to use either
2850+
* of these routines at other times!
28422851
*/
28432852
void
2844-
SetRedoRecPtr(void)
2853+
SetSavedRedoRecPtr(void)
28452854
{
2846-
XLogCtl->RedoRecPtr=RedoRecPtr;
2855+
XLogCtl->SavedRedoRecPtr=RedoRecPtr;
28472856
}
28482857

28492858
void
2859+
GetSavedRedoRecPtr(void)
2860+
{
2861+
RedoRecPtr=XLogCtl->SavedRedoRecPtr;
2862+
}
2863+
2864+
/*
2865+
* Once spawned, a backend may update its local RedoRecPtr from
2866+
* XLogCtl->Insert.RedoRecPtr; it must hold the insert lock or info_lck
2867+
* to do so. This is done in XLogInsert() or GetRedoRecPtr().
2868+
*/
2869+
XLogRecPtr
28502870
GetRedoRecPtr(void)
28512871
{
2852-
RedoRecPtr=XLogCtl->RedoRecPtr;
2872+
/* use volatile pointer to prevent code rearrangement */
2873+
volatileXLogCtlData*xlogctl=XLogCtl;
2874+
2875+
SpinLockAcquire_NoHoldoff(&xlogctl->info_lck);
2876+
Assert(XLByteLE(RedoRecPtr,xlogctl->Insert.RedoRecPtr));
2877+
RedoRecPtr=xlogctl->Insert.RedoRecPtr;
2878+
SpinLockRelease_NoHoldoff(&xlogctl->info_lck);
2879+
2880+
returnRedoRecPtr;
28532881
}
28542882

28552883
/*
@@ -2862,6 +2890,7 @@ ShutdownXLOG(void)
28622890

28632891
/* suppress in-transaction check in CreateCheckPoint */
28642892
MyLastRecPtr.xrecoff=0;
2893+
MyXactMadeXLogEntry= false;
28652894

28662895
CritSectionCount++;
28672896
CreateDummyCaches();
@@ -2886,7 +2915,7 @@ CreateCheckPoint(bool shutdown)
28862915
uint32_logId;
28872916
uint32_logSeg;
28882917

2889-
if (MyLastRecPtr.xrecoff!=0)
2918+
if (MyXactMadeXLogEntry)
28902919
elog(ERROR,"CreateCheckPoint: cannot be called inside transaction block");
28912920

28922921
/*
@@ -2972,9 +3001,16 @@ CreateCheckPoint(bool shutdown)
29723001

29733002
/*
29743003
* Here we update the shared RedoRecPtr for future XLogInsert calls;
2975-
* this must be done while holding the insert lock.
3004+
* this must be done while holding the insert lock AND the info_lck.
29763005
*/
2977-
RedoRecPtr=XLogCtl->Insert.RedoRecPtr=checkPoint.redo;
3006+
{
3007+
/* use volatile pointer to prevent code rearrangement */
3008+
volatileXLogCtlData*xlogctl=XLogCtl;
3009+
3010+
SpinLockAcquire_NoHoldoff(&xlogctl->info_lck);
3011+
RedoRecPtr=xlogctl->Insert.RedoRecPtr=checkPoint.redo;
3012+
SpinLockRelease_NoHoldoff(&xlogctl->info_lck);
3013+
}
29783014

29793015
/*
29803016
* Get UNDO record ptr - this is oldest of PROC->logRec values. We do

‎src/backend/bootstrap/bootstrap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.123 2002/03/08 00:42:09 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.124 2002/03/15 19:20:34 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -386,7 +386,7 @@ BootstrapMain(int argc, char *argv[])
386386
InitDummyProcess();/* needed to get LWLocks */
387387
CreateDummyCaches();
388388
CreateCheckPoint(false);
389-
SetRedoRecPtr();
389+
SetSavedRedoRecPtr();/* pass redo ptr back to postmaster */
390390
proc_exit(0);/* done */
391391

392392
caseBS_XLOG_STARTUP:

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp