Skip to content

Commit d6d8054

Browse files
committed
localbuf: Track pincount in BufferDesc as well
For AIO on temporary table buffers the AIO subsystem needs to be able to ensure a pin on a buffer while AIO is going on, even if the IO issuing query errors out. Tracking the buffer in LocalRefCount does not work, as it would cause CheckForLocalBufferLeaks() to assert out. Instead, also track the refcount in BufferDesc.state, not just LocalRefCount. This also makes local buffers behave a bit more akin to shared buffers. Note that we still don't need locking, AIO completion callbacks for local buffers are executed in the issuing session (i.e. nobody else has access to the BufferDesc). Reviewed-by: Noah Misch <noah@leadboat.com> Discussion: https://postgr.es/m/uvrtrknj4kdytuboidbhwclo4gxhswwcpgadptsjvjqcluzmah%40brqs62irg4dt
1 parent 08ccd56 commit d6d8054

File tree

1 file changed

+26
-2
lines changed

1 file changed

+26
-2
lines changed

src/backend/storage/buffer/localbuf.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,13 @@ GetLocalVictimBuffer(void)
249249
pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
250250
trycounter = NLocBuffer;
251251
}
252+
else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0)
253+
{
254+
/*
255+
* This can be reached if the backend initiated AIO for this
256+
* buffer and then errored out.
257+
*/
258+
}
252259
else
253260
{
254261
/* Found a usable buffer */
@@ -570,7 +577,13 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced)
570577

571578
buf_state = pg_atomic_read_u32(&bufHdr->state);
572579

573-
if (check_unreferenced && LocalRefCount[bufid] != 0)
580+
/*
581+
* We need to test not just LocalRefCount[bufid] but also the BufferDesc
582+
* itself, as the latter is used to represent a pin by the AIO subsystem.
583+
* This can happen if AIO is initiated and then the query errors out.
584+
*/
585+
if (check_unreferenced &&
586+
(LocalRefCount[bufid] != 0 || BUF_STATE_GET_REFCOUNT(buf_state) != 0))
574587
elog(ERROR, "block %u of %s is still referenced (local %u)",
575588
bufHdr->tag.blockNum,
576589
relpathbackend(BufTagGetRelFileLocator(&bufHdr->tag),
@@ -744,12 +757,13 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount)
744757
if (LocalRefCount[bufid] == 0)
745758
{
746759
NLocalPinnedBuffers++;
760+
buf_state += BUF_REFCOUNT_ONE;
747761
if (adjust_usagecount &&
748762
BUF_STATE_GET_USAGECOUNT(buf_state) < BM_MAX_USAGE_COUNT)
749763
{
750764
buf_state += BUF_USAGECOUNT_ONE;
751-
pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state);
752765
}
766+
pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state);
753767
}
754768
LocalRefCount[bufid]++;
755769
ResourceOwnerRememberBuffer(CurrentResourceOwner,
@@ -775,7 +789,17 @@ UnpinLocalBufferNoOwner(Buffer buffer)
775789
Assert(NLocalPinnedBuffers > 0);
776790

777791
if (--LocalRefCount[buffid] == 0)
792+
{
793+
BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid);
794+
uint32 buf_state;
795+
778796
NLocalPinnedBuffers--;
797+
798+
buf_state = pg_atomic_read_u32(&buf_hdr->state);
799+
Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0);
800+
buf_state -= BUF_REFCOUNT_ONE;
801+
pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state);
802+
}
779803
}
780804

781805
/*

0 commit comments

Comments
 (0)