From: Melanie Plageman Date: Tue, 21 Apr 2026 15:01:57 +0000 (-0400) Subject: Make local buffers pin limit more conservative X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=HEAD;p=thirdparty%2Fpostgresql.git Make local buffers pin limit more conservative GetLocalPinLimit() and GetAdditionalLocalPinLimit(), currently in use only by the read stream, previously allowed a backend to pin all num_temp_buffers local buffers. This meant that the read stream could use every available local buffer for read-ahead, leaving none for other concurrent pin-holders like other read streams and related buffers like the visibility map buffer needed during on-access pruning. This became more noticeable since b46e1e54d07, which allows on-access pruning to set the visibility map, which meant that some scans also needed to pin a page of the VM. It caused a test in src/test/regress/sql/temp.sql to fail in some cases. Cap the local pin limit to num_temp_buffers / 4, providing some headroom. This doesn't guarantee that all needed pins will be available — for example, a backend can still open more cursors than there are buffers — but it makes it less likely that read-ahead will exhaust the pool. Note that these functions are not limited by definition to use in the read stream; however, this cap should be appropriate in other contexts. Reported-by: Alexander Lakhin Author: Melanie Plageman Reviewed-by: Andres Freund Discussion: https://postgr.es/m/97529f5a-ec10-46b1-ab50-4653126c6889%40gmail.com --- diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 396da84b25c..4870c8e13d0 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -307,16 +307,24 @@ GetLocalVictimBuffer(void) uint32 GetLocalPinLimit(void) { - /* Every backend has its own temporary buffers, and can pin them all. */ - return num_temp_buffers; + /* + * Every backend has its own temporary buffers, but we leave headroom for + * concurrent pin-holders -- like multiple scans in the same query. + */ + return num_temp_buffers / 4; } /* see GetAdditionalPinLimit() */ uint32 GetAdditionalLocalPinLimit(void) { + uint32 total = GetLocalPinLimit(); + Assert(NLocalPinnedBuffers <= num_temp_buffers); - return num_temp_buffers - NLocalPinnedBuffers; + + if (NLocalPinnedBuffers >= total) + return 0; + return total - NLocalPinnedBuffers; } /* see LimitAdditionalPins() */