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

Commit e8d029a

Browse files
committed
Do unlocked prechecks in bufmgr.c loops that scan the whole buffer pool.
DropRelFileNodeBuffers, DropDatabaseBuffers, FlushRelationBuffers, and FlushDatabaseBuffers have to scan the whole shared_buffers pool because we have no index structure that would find the target buffers any more efficiently than that. This gets expensive with large NBuffers. We can shave some cycles from these loops by prechecking to see if the current buffer is interesting before we acquire the buffer header lock. Ordinarily such a test would be unsafe, but in these cases it should be safe because we are already assuming that the caller holds a lock that prevents any new target pages from being loaded into the buffer pool concurrently. Therefore, no buffer tag should be changing to a value of interest, only away from a value of interest. So a false negative match is impossible, while a false positive is safe because we'll recheck after acquiring the buffer lock. Initial testing says that this speeds these loops by a factor of 2X to 3X on common Intel hardware. Patch for DropRelFileNodeBuffers by Jeff Janes (based on an idea of Heikki's); extended to the remaining sequential scans by Tom Lane
1 parent 2c8a4e9 commit e8d029a

File tree

1 file changed

+45
-2
lines changed

1 file changed

+45
-2
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,6 +2048,7 @@ DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum,
20482048
{
20492049
int i;
20502050

2051+
/* If it's a local relation, it's localbuf.c's problem. */
20512052
if (rnode.backend != InvalidBackendId)
20522053
{
20532054
if (rnode.backend == MyBackendId)
@@ -2059,6 +2060,25 @@ DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum,
20592060
{
20602061
volatile BufferDesc *bufHdr = &BufferDescriptors[i];
20612062

2063+
/*
2064+
* We can make this a tad faster by prechecking the buffer tag before
2065+
* we attempt to lock the buffer; this saves a lot of lock
2066+
* acquisitions in typical cases. It should be safe because the
2067+
* caller must have AccessExclusiveLock on the relation, or some other
2068+
* reason to be certain that no one is loading new pages of the rel
2069+
* into the buffer pool. (Otherwise we might well miss such pages
2070+
* entirely.) Therefore, while the tag might be changing while we
2071+
* look at it, it can't be changing *to* a value we care about, only
2072+
* *away* from such a value. So false negatives are impossible, and
2073+
* false positives are safe because we'll recheck after getting the
2074+
* buffer lock.
2075+
*
2076+
* We could check forkNum and blockNum as well as the rnode, but the
2077+
* incremental win from doing so seems small.
2078+
*/
2079+
if (!RelFileNodeEquals(bufHdr->tag.rnode, rnode.node))
2080+
continue;
2081+
20622082
LockBufHdr(bufHdr);
20632083
if (RelFileNodeEquals(bufHdr->tag.rnode, rnode.node) &&
20642084
bufHdr->tag.forkNum == forkNum &&
@@ -2084,7 +2104,6 @@ void
20842104
DropDatabaseBuffers(Oid dbid)
20852105
{
20862106
int i;
2087-
volatile BufferDesc *bufHdr;
20882107

20892108
/*
20902109
* We needn't consider local buffers, since by assumption the target
@@ -2093,7 +2112,15 @@ DropDatabaseBuffers(Oid dbid)
20932112

20942113
for (i = 0; i < NBuffers; i++)
20952114
{
2096-
bufHdr = &BufferDescriptors[i];
2115+
volatile BufferDesc *bufHdr = &BufferDescriptors[i];
2116+
2117+
/*
2118+
* As in DropRelFileNodeBuffers, an unlocked precheck should be safe
2119+
* and saves some cycles.
2120+
*/
2121+
if (bufHdr->tag.rnode.dbNode != dbid)
2122+
continue;
2123+
20972124
LockBufHdr(bufHdr);
20982125
if (bufHdr->tag.rnode.dbNode == dbid)
20992126
InvalidateBuffer(bufHdr); /* releases spinlock */
@@ -2220,6 +2247,14 @@ FlushRelationBuffers(Relation rel)
22202247
for (i = 0; i < NBuffers; i++)
22212248
{
22222249
bufHdr = &BufferDescriptors[i];
2250+
2251+
/*
2252+
* As in DropRelFileNodeBuffers, an unlocked precheck should be safe
2253+
* and saves some cycles.
2254+
*/
2255+
if (!RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node))
2256+
continue;
2257+
22232258
LockBufHdr(bufHdr);
22242259
if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) &&
22252260
(bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))
@@ -2262,6 +2297,14 @@ FlushDatabaseBuffers(Oid dbid)
22622297
for (i = 0; i < NBuffers; i++)
22632298
{
22642299
bufHdr = &BufferDescriptors[i];
2300+
2301+
/*
2302+
* As in DropRelFileNodeBuffers, an unlocked precheck should be safe
2303+
* and saves some cycles.
2304+
*/
2305+
if (bufHdr->tag.rnode.dbNode != dbid)
2306+
continue;
2307+
22652308
LockBufHdr(bufHdr);
22662309
if (bufHdr->tag.rnode.dbNode == dbid &&
22672310
(bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))

0 commit comments

Comments
 (0)