Skip to content

Commit 541cf53

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 0c267d4 commit 541cf53

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5404,6 +5404,18 @@ ConditionalLockBufferForCleanup(Buffer buffer)
54045404
Assert(refcount > 0);
54055405
if (refcount != 1)
54065406
return false;
5407+
5408+
/*
5409+
* Check that the AIO subsystem doesn't have a pin. Likely not
5410+
* possible today, but better safe than sorry.
5411+
*/
5412+
bufHdr = GetLocalBufferDescriptor(-buffer - 1);
5413+
buf_state = pg_atomic_read_u32(&bufHdr->state);
5414+
refcount = BUF_STATE_GET_REFCOUNT(buf_state);
5415+
Assert(refcount > 0);
5416+
if (refcount != 1)
5417+
return false;
5418+
54075419
/* Nobody else to wait for */
54085420
return true;
54095421
}
@@ -5457,6 +5469,16 @@ IsBufferCleanupOK(Buffer buffer)
54575469
/* There should be exactly one pin */
54585470
if (LocalRefCount[-buffer - 1] != 1)
54595471
return false;
5472+
5473+
/*
5474+
* Check that the AIO subsystem doesn't have a pin. Likely not
5475+
* possible today, but better safe than sorry.
5476+
*/
5477+
bufHdr = GetLocalBufferDescriptor(-buffer - 1);
5478+
buf_state = pg_atomic_read_u32(&bufHdr->state);
5479+
if (BUF_STATE_GET_REFCOUNT(buf_state) != 1)
5480+
return false;
5481+
54605482
/* Nobody else to wait for */
54615483
return true;
54625484
}

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)