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

Commit fdd13f1

Browse files
committed
Give the ResourceOwner mechanism full responsibility for releasing buffer
pins at end of transaction, and reduce AtEOXact_Buffers to an Assert cross-check that this was done correctly. When not USE_ASSERT_CHECKING, AtEOXact_Buffers is a complete no-op. This gets rid of an O(NBuffers) bottleneck during transaction commit/abort, which recent testing has shown becomes significant above a few tens of thousands of shared buffers.
1 parent 1c2de47 commit fdd13f1

File tree

6 files changed

+95
-72
lines changed

6 files changed

+95
-72
lines changed

src/backend/access/transam/xact.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.191 2004/10/04 21:52:14 tgl Exp $
13+
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.192 2004/10/16 18:57:22 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -1528,6 +1528,9 @@ CommitTransaction(void)
15281528
RESOURCE_RELEASE_BEFORE_LOCKS,
15291529
true, true);
15301530

1531+
/* Check we've released all buffer pins */
1532+
AtEOXact_Buffers(true);
1533+
15311534
/*
15321535
* Make catalog changes visible to all backends. This has to happen
15331536
* after relcache references are dropped (see comments for
@@ -1684,6 +1687,7 @@ AbortTransaction(void)
16841687
ResourceOwnerRelease(TopTransactionResourceOwner,
16851688
RESOURCE_RELEASE_BEFORE_LOCKS,
16861689
false, true);
1690+
AtEOXact_Buffers(false);
16871691
AtEOXact_Inval(false);
16881692
smgrDoPendingDeletes(false);
16891693
ResourceOwnerRelease(TopTransactionResourceOwner,

src/backend/storage/buffer/bufmgr.c

+57-18
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.179 2004/10/16 18:05:06 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.180 2004/10/16 18:57:23 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -851,35 +851,45 @@ ResetBufferUsage(void)
851851
/*
852852
* AtEOXact_Buffers - clean up at end of transaction.
853853
*
854-
* During abort, we need to release any buffer pins we're holding
855-
* (this cleans up in case ereport interrupted a routine that pins a
856-
* buffer). During commit, we shouldn't need to do that, but check
857-
* anyway to see if anyone leaked a buffer reference count.
854+
* As of PostgreSQL 8.0, buffer pins should get released by the
855+
* ResourceOwner mechanism. This routine is just a debugging
856+
* cross-check that no pins remain.
858857
*/
859858
void
860859
AtEOXact_Buffers(bool isCommit)
861860
{
861+
#ifdef USE_ASSERT_CHECKING
862862
int i;
863863

864+
for (i = 0; i < NBuffers; i++)
865+
{
866+
Assert(PrivateRefCount[i] == 0);
867+
}
868+
869+
AtEOXact_LocalBuffers(isCommit);
870+
#endif
871+
}
872+
873+
/*
874+
* Ensure we have released all shared-buffer locks and pins during backend exit
875+
*/
876+
void
877+
AtProcExit_Buffers(void)
878+
{
879+
int i;
880+
881+
AbortBufferIO();
882+
UnlockBuffers();
883+
864884
for (i = 0; i < NBuffers; i++)
865885
{
866886
if (PrivateRefCount[i] != 0)
867887
{
868888
BufferDesc *buf = &(BufferDescriptors[i]);
869889

870-
if (isCommit)
871-
elog(WARNING,
872-
"buffer refcount leak: [%03d] "
873-
"(rel=%u/%u/%u, blockNum=%u, flags=0x%x, refcount=%u %d)",
874-
i,
875-
buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
876-
buf->tag.rnode.relNode,
877-
buf->tag.blockNum, buf->flags,
878-
buf->refcount, PrivateRefCount[i]);
879-
880890
/*
881-
* We don't worry about updating the ResourceOwner structures;
882-
* resowner.c will clear them for itself.
891+
* We don't worry about updating ResourceOwner; if we even got
892+
* here, it suggests that ResourceOwners are messed up.
883893
*/
884894
PrivateRefCount[i] = 1; /* make sure we release shared pin */
885895
LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
@@ -888,8 +898,37 @@ AtEOXact_Buffers(bool isCommit)
888898
Assert(PrivateRefCount[i] == 0);
889899
}
890900
}
901+
}
891902

892-
AtEOXact_LocalBuffers(isCommit);
903+
/*
904+
* Helper routine to issue warnings when a buffer is unexpectedly pinned
905+
*/
906+
void
907+
PrintBufferLeakWarning(Buffer buffer)
908+
{
909+
BufferDesc *buf;
910+
int32 loccount;
911+
912+
Assert(BufferIsValid(buffer));
913+
if (BufferIsLocal(buffer))
914+
{
915+
buf = &LocalBufferDescriptors[-buffer - 1];
916+
loccount = LocalRefCount[-buffer - 1];
917+
}
918+
else
919+
{
920+
buf = &BufferDescriptors[buffer - 1];
921+
loccount = PrivateRefCount[buffer - 1];
922+
}
923+
924+
elog(WARNING,
925+
"buffer refcount leak: [%03d] "
926+
"(rel=%u/%u/%u, blockNum=%u, flags=0x%x, refcount=%u %d)",
927+
buffer,
928+
buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
929+
buf->tag.rnode.relNode,
930+
buf->tag.blockNum, buf->flags,
931+
buf->refcount, loccount);
893932
}
894933

895934
/*

src/backend/storage/buffer/localbuf.c

+4-15
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.59 2004/08/29 05:06:47 momjian Exp $
12+
* $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.60 2004/10/16 18:57:24 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -232,23 +232,12 @@ InitLocalBuffer(void)
232232
void
233233
AtEOXact_LocalBuffers(bool isCommit)
234234
{
235+
#ifdef USE_ASSERT_CHECKING
235236
int i;
236237

237238
for (i = 0; i < NLocBuffer; i++)
238239
{
239-
if (LocalRefCount[i] != 0)
240-
{
241-
BufferDesc *buf = &(LocalBufferDescriptors[i]);
242-
243-
if (isCommit)
244-
elog(WARNING,
245-
"local buffer leak: [%03d] (rel=%u/%u/%u, blockNum=%u, flags=0x%x, refcount=%u %d)",
246-
i,
247-
buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
248-
buf->tag.rnode.relNode, buf->tag.blockNum, buf->flags,
249-
buf->refcount, LocalRefCount[i]);
250-
251-
LocalRefCount[i] = 0;
252-
}
240+
Assert(LocalRefCount[i] == 0);
253241
}
242+
#endif
254243
}

src/backend/storage/lmgr/proc.c

+3-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.154 2004/09/29 15:15:55 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.155 2004/10/16 18:57:24 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -461,9 +461,7 @@ ProcKill(int code, Datum arg)
461461
* shutdown callback registered by the bufmgr ... but we must do this
462462
* *after* LWLockReleaseAll and *before* zapping MyProc.
463463
*/
464-
AbortBufferIO();
465-
UnlockBuffers();
466-
AtEOXact_Buffers(false);
464+
AtProcExit_Buffers();
467465

468466
/* Get off any wait queue I might be on */
469467
LockWaitCancel();
@@ -509,9 +507,7 @@ DummyProcKill(int code, Datum arg)
509507
LWLockReleaseAll();
510508

511509
/* Release buffer locks and pins, too */
512-
AbortBufferIO();
513-
UnlockBuffers();
514-
AtEOXact_Buffers(false);
510+
AtProcExit_Buffers();
515511

516512
/* I can't be on regular lock queues, so needn't check */
517513

src/backend/utils/resowner/resowner.c

+23-30
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
*
1616
* IDENTIFICATION
17-
* $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.7 2004/08/30 02:54:40 momjian Exp $
17+
* $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.8 2004/10/16 18:57:25 tgl Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -191,37 +191,30 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
191191

192192
if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
193193
{
194-
/* Release buffer pins */
195-
if (isTopLevel)
196-
{
197-
/*
198-
* For a top-level xact we are going to release all buffers,
199-
* so just do a single bufmgr call at the top of the
200-
* recursion.
201-
*/
202-
if (owner == TopTransactionResourceOwner)
203-
AtEOXact_Buffers(isCommit);
204-
/* Mark object as owning no buffers, just for sanity */
205-
owner->nbuffers = 0;
206-
}
207-
else
194+
/*
195+
* Release buffer pins. Note that ReleaseBuffer will
196+
* remove the buffer entry from my list, so I just have to
197+
* iterate till there are none.
198+
*
199+
* During a commit, there shouldn't be any remaining pins ---
200+
* that would indicate failure to clean up the executor correctly ---
201+
* so issue warnings. In the abort case, just clean up quietly.
202+
*
203+
* XXX this is fairly inefficient due to multiple BufMgrLock
204+
* grabs if there are lots of buffers to be released, but we
205+
* don't expect many (indeed none in the success case) so it's
206+
* probably not worth optimizing.
207+
*
208+
* We are however careful to release back-to-front, so as to
209+
* avoid O(N^2) behavior in ResourceOwnerForgetBuffer().
210+
*/
211+
while (owner->nbuffers > 0)
208212
{
209-
/*
210-
* Release buffers retail. Note that ReleaseBuffer will
211-
* remove the buffer entry from my list, so I just have to
212-
* iterate till there are none.
213-
*
214-
* XXX this is fairly inefficient due to multiple BufMgrLock
215-
* grabs if there are lots of buffers to be released, but we
216-
* don't expect many (indeed none in the success case) so it's
217-
* probably not worth optimizing.
218-
*
219-
* We are however careful to release back-to-front, so as to
220-
* avoid O(N^2) behavior in ResourceOwnerForgetBuffer().
221-
*/
222-
while (owner->nbuffers > 0)
223-
ReleaseBuffer(owner->buffers[owner->nbuffers - 1]);
213+
if (isCommit)
214+
PrintBufferLeakWarning(owner->buffers[owner->nbuffers - 1]);
215+
ReleaseBuffer(owner->buffers[owner->nbuffers - 1]);
224216
}
217+
225218
/* Release relcache references */
226219
if (isTopLevel)
227220
{

src/include/storage/bufmgr.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.87 2004/10/15 22:40:25 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.88 2004/10/16 18:57:26 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -122,6 +122,8 @@ extern void InitBufferPoolAccess(void);
122122
extern char *ShowBufferUsage(void);
123123
extern void ResetBufferUsage(void);
124124
extern void AtEOXact_Buffers(bool isCommit);
125+
extern void AtProcExit_Buffers(void);
126+
extern void PrintBufferLeakWarning(Buffer buffer);
125127
extern void FlushBufferPool(void);
126128
extern BlockNumber BufferGetBlockNumber(Buffer buffer);
127129
extern BlockNumber RelationGetNumberOfBlocks(Relation relation);

0 commit comments

Comments
 (0)