Skip to content

Commit 2f27f8c

Browse files
committed
Provide ReadRecentBuffer() to re-pin buffers by ID.
If you know the ID of a buffer that recently held a block that you would like to pin, this function can be used check if it's still there. It can be used to avoid a second lookup in the buffer mapping table after PrefetchBuffer() reports a cache hit. Reviewed-by: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/CA+hUKGJ4VJN8ttxScUFM8dOKX0BrBiboo5uz1cq=AovOddfHpA@mail.gmail.com
1 parent 0827e8a commit 2f27f8c

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,84 @@ PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
610610
}
611611
}
612612

613+
/*
614+
* ReadRecentBuffer -- try to pin a block in a recently observed buffer
615+
*
616+
* Compared to ReadBuffer(), this avoids a buffer mapping lookup when it's
617+
* successful. Return true if the buffer is valid and still has the expected
618+
* tag. In that case, the buffer is pinned and the usage count is bumped.
619+
*/
620+
bool
621+
ReadRecentBuffer(RelFileNode rnode, ForkNumber forkNum, BlockNumber blockNum,
622+
Buffer recent_buffer)
623+
{
624+
BufferDesc *bufHdr;
625+
BufferTag tag;
626+
uint32 buf_state;
627+
bool have_private_ref;
628+
629+
Assert(BufferIsValid(recent_buffer));
630+
631+
ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
632+
ReservePrivateRefCountEntry();
633+
INIT_BUFFERTAG(tag, rnode, forkNum, blockNum);
634+
635+
if (BufferIsLocal(recent_buffer))
636+
{
637+
bufHdr = GetBufferDescriptor(-recent_buffer - 1);
638+
buf_state = pg_atomic_read_u32(&bufHdr->state);
639+
640+
/* Is it still valid and holding the right tag? */
641+
if ((buf_state & BM_VALID) && BUFFERTAGS_EQUAL(tag, bufHdr->tag))
642+
{
643+
/* Bump local buffer's ref and usage counts. */
644+
ResourceOwnerRememberBuffer(CurrentResourceOwner, recent_buffer);
645+
LocalRefCount[-recent_buffer - 1]++;
646+
if (BUF_STATE_GET_USAGECOUNT(buf_state) < BM_MAX_USAGE_COUNT)
647+
pg_atomic_write_u32(&bufHdr->state,
648+
buf_state + BUF_USAGECOUNT_ONE);
649+
650+
return true;
651+
}
652+
}
653+
else
654+
{
655+
bufHdr = GetBufferDescriptor(recent_buffer - 1);
656+
have_private_ref = GetPrivateRefCount(recent_buffer) > 0;
657+
658+
/*
659+
* Do we already have this buffer pinned with a private reference? If
660+
* so, it must be valid and it is safe to check the tag without
661+
* locking. If not, we have to lock the header first and then check.
662+
*/
663+
if (have_private_ref)
664+
buf_state = pg_atomic_read_u32(&bufHdr->state);
665+
else
666+
buf_state = LockBufHdr(bufHdr);
667+
668+
if ((buf_state & BM_VALID) && BUFFERTAGS_EQUAL(tag, bufHdr->tag))
669+
{
670+
/*
671+
* It's now safe to pin the buffer. We can't pin first and ask
672+
* questions later, because because it might confuse code paths
673+
* like InvalidateBuffer() if we pinned a random non-matching
674+
* buffer.
675+
*/
676+
if (have_private_ref)
677+
PinBuffer(bufHdr, NULL); /* bump pin count */
678+
else
679+
PinBuffer_Locked(bufHdr); /* pin for first time */
680+
681+
return true;
682+
}
683+
684+
/* If we locked the header above, now unlock. */
685+
if (!have_private_ref)
686+
UnlockBufHdr(bufHdr, buf_state);
687+
}
688+
689+
return false;
690+
}
613691

614692
/*
615693
* ReadBuffer -- a shorthand for ReadBufferExtended, for reading from main

src/include/storage/bufmgr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ extern PrefetchBufferResult PrefetchSharedBuffer(struct SMgrRelationData *smgr_r
176176
BlockNumber blockNum);
177177
extern PrefetchBufferResult PrefetchBuffer(Relation reln, ForkNumber forkNum,
178178
BlockNumber blockNum);
179+
extern bool ReadRecentBuffer(RelFileNode rnode, ForkNumber forkNum,
180+
BlockNumber blockNum, Buffer recent_buffer);
179181
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
180182
extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum,
181183
BlockNumber blockNum, ReadBufferMode mode,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy