Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)