mirror of
https://github.com/postgres/postgres.git
synced 2025-05-29 16:21:20 +03:00
Improve buffer manager API for backend pin limits.
Previously the support functions assumed that the caller needed one pin to make progress, and could optionally use some more, allowing enough for every connection to do the same. Add a couple more functions for callers that want to know: * what the maximum possible number could be, irrespective of currently held pins, for space planning purposes * how many additional pins they could acquire right now, without the special case allowing one pin, for callers that already hold pins and could already make progress even if no extra pins are available The pin limit logic began in commit 31966b15. This refactoring is better suited to read_stream.c, which will be adjusted to respect the remaining limit as it changes over time in a follow-up commit. It also computes MaxProportionalPins up front, to avoid performing divisions whenever a caller needs to check the balance. Reviewed-by: Andres Freund <andres@anarazel.de> (earlier versions) Discussion: https://postgr.es/m/CA%2BhUKGK_%3D4CVmMHvsHjOVrK6t4F%3DLBpFzsrr3R%2BaJYN8kcTfWg%40mail.gmail.com
This commit is contained in:
parent
7c99dc587a
commit
01261fb078
@ -211,6 +211,8 @@ static int32 PrivateRefCountOverflowed = 0;
|
||||
static uint32 PrivateRefCountClock = 0;
|
||||
static PrivateRefCountEntry *ReservedRefCountEntry = NULL;
|
||||
|
||||
static uint32 MaxProportionalPins;
|
||||
|
||||
static void ReservePrivateRefCountEntry(void);
|
||||
static PrivateRefCountEntry *NewPrivateRefCountEntry(Buffer buffer);
|
||||
static PrivateRefCountEntry *GetPrivateRefCountEntry(Buffer buffer, bool do_move);
|
||||
@ -2097,43 +2099,62 @@ again:
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the maximum number of buffers that a backend should try to pin once,
|
||||
* to avoid exceeding its fair share. This is the highest value that
|
||||
* GetAdditionalPinLimit() could ever return. Note that it may be zero on a
|
||||
* system with a very small buffer pool relative to max_connections.
|
||||
*/
|
||||
uint32
|
||||
GetPinLimit(void)
|
||||
{
|
||||
return MaxProportionalPins;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the maximum number of additional buffers that this backend should
|
||||
* pin if it wants to stay under the per-backend limit, considering the number
|
||||
* of buffers it has already pinned. Unlike LimitAdditionalPins(), the limit
|
||||
* return by this function can be zero.
|
||||
*/
|
||||
uint32
|
||||
GetAdditionalPinLimit(void)
|
||||
{
|
||||
uint32 estimated_pins_held;
|
||||
|
||||
/*
|
||||
* We get the number of "overflowed" pins for free, but don't know the
|
||||
* number of pins in PrivateRefCountArray. The cost of calculating that
|
||||
* exactly doesn't seem worth it, so just assume the max.
|
||||
*/
|
||||
estimated_pins_held = PrivateRefCountOverflowed + REFCOUNT_ARRAY_ENTRIES;
|
||||
|
||||
/* Is this backend already holding more than its fair share? */
|
||||
if (estimated_pins_held > MaxProportionalPins)
|
||||
return 0;
|
||||
|
||||
return MaxProportionalPins - estimated_pins_held;
|
||||
}
|
||||
|
||||
/*
|
||||
* Limit the number of pins a batch operation may additionally acquire, to
|
||||
* avoid running out of pinnable buffers.
|
||||
*
|
||||
* One additional pin is always allowed, as otherwise the operation likely
|
||||
* cannot be performed at all.
|
||||
*
|
||||
* The number of allowed pins for a backend is computed based on
|
||||
* shared_buffers and the maximum number of connections possible. That's very
|
||||
* pessimistic, but outside of toy-sized shared_buffers it should allow
|
||||
* sufficient pins.
|
||||
* One additional pin is always allowed, on the assumption that the operation
|
||||
* requires at least one to make progress.
|
||||
*/
|
||||
void
|
||||
LimitAdditionalPins(uint32 *additional_pins)
|
||||
{
|
||||
uint32 max_backends;
|
||||
int max_proportional_pins;
|
||||
uint32 limit;
|
||||
|
||||
if (*additional_pins <= 1)
|
||||
return;
|
||||
|
||||
max_backends = MaxBackends + NUM_AUXILIARY_PROCS;
|
||||
max_proportional_pins = NBuffers / max_backends;
|
||||
|
||||
/*
|
||||
* Subtract the approximate number of buffers already pinned by this
|
||||
* backend. We get the number of "overflowed" pins for free, but don't
|
||||
* know the number of pins in PrivateRefCountArray. The cost of
|
||||
* calculating that exactly doesn't seem worth it, so just assume the max.
|
||||
*/
|
||||
max_proportional_pins -= PrivateRefCountOverflowed + REFCOUNT_ARRAY_ENTRIES;
|
||||
|
||||
if (max_proportional_pins <= 0)
|
||||
max_proportional_pins = 1;
|
||||
|
||||
if (*additional_pins > max_proportional_pins)
|
||||
*additional_pins = max_proportional_pins;
|
||||
limit = GetAdditionalPinLimit();
|
||||
limit = Max(limit, 1);
|
||||
if (limit < *additional_pins)
|
||||
*additional_pins = limit;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3575,6 +3596,15 @@ InitBufferManagerAccess(void)
|
||||
{
|
||||
HASHCTL hash_ctl;
|
||||
|
||||
/*
|
||||
* An advisory limit on the number of pins each backend should hold, based
|
||||
* on shared_buffers and the maximum number of connections possible.
|
||||
* That's very pessimistic, but outside toy-sized shared_buffers it should
|
||||
* allow plenty of pins. LimitAdditionalPins() and
|
||||
* GetAdditionalPinLimit() can be used to check the remaining balance.
|
||||
*/
|
||||
MaxProportionalPins = NBuffers / (MaxBackends + NUM_AUXILIARY_PROCS);
|
||||
|
||||
memset(&PrivateRefCountArray, 0, sizeof(PrivateRefCountArray));
|
||||
|
||||
hash_ctl.keysize = sizeof(int32);
|
||||
|
@ -286,6 +286,22 @@ GetLocalVictimBuffer(void)
|
||||
return BufferDescriptorGetBuffer(bufHdr);
|
||||
}
|
||||
|
||||
/* see GetPinLimit() */
|
||||
uint32
|
||||
GetLocalPinLimit(void)
|
||||
{
|
||||
/* Every backend has its own temporary buffers, and can pin them all. */
|
||||
return num_temp_buffers;
|
||||
}
|
||||
|
||||
/* see GetAdditionalPinLimit() */
|
||||
uint32
|
||||
GetAdditionalLocalPinLimit(void)
|
||||
{
|
||||
Assert(NLocalPinnedBuffers <= num_temp_buffers);
|
||||
return num_temp_buffers - NLocalPinnedBuffers;
|
||||
}
|
||||
|
||||
/* see LimitAdditionalPins() */
|
||||
void
|
||||
LimitAdditionalLocalPins(uint32 *additional_pins)
|
||||
|
@ -290,6 +290,10 @@ extern bool HoldingBufferPinThatDelaysRecovery(void);
|
||||
|
||||
extern bool BgBufferSync(struct WritebackContext *wb_context);
|
||||
|
||||
extern uint32 GetPinLimit(void);
|
||||
extern uint32 GetLocalPinLimit(void);
|
||||
extern uint32 GetAdditionalPinLimit(void);
|
||||
extern uint32 GetAdditionalLocalPinLimit(void);
|
||||
extern void LimitAdditionalPins(uint32 *additional_pins);
|
||||
extern void LimitAdditionalLocalPins(uint32 *additional_pins);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user