diff options
-rw-r--r-- | src/backend/storage/aio/read_stream.c | 5 | ||||
-rw-r--r-- | src/backend/storage/buffer/freelist.c | 42 | ||||
-rw-r--r-- | src/include/storage/bufmgr.h | 1 |
3 files changed, 48 insertions, 0 deletions
diff --git a/src/backend/storage/aio/read_stream.c b/src/backend/storage/aio/read_stream.c index b9e11a28312..9a70a81f7ae 100644 --- a/src/backend/storage/aio/read_stream.c +++ b/src/backend/storage/aio/read_stream.c @@ -419,6 +419,7 @@ read_stream_begin_relation(int flags, size_t size; int16 queue_size; int16 max_ios; + int strategy_pin_limit; uint32 max_pinned_buffers; Oid tablespace_id; SMgrRelation smgr; @@ -460,6 +461,10 @@ read_stream_begin_relation(int flags, max_pinned_buffers = Min(max_pinned_buffers, PG_INT16_MAX - io_combine_limit - 1); + /* Give the strategy a chance to limit the number of buffers we pin. */ + strategy_pin_limit = GetAccessStrategyPinLimit(strategy); + max_pinned_buffers = Min(strategy_pin_limit, max_pinned_buffers); + /* Don't allow this backend to pin more than its share of buffers. */ if (SmgrIsTemp(smgr)) LimitAdditionalLocalPins(&max_pinned_buffers); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 3611357fa30..de2ef1dd5e6 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -630,6 +630,48 @@ GetAccessStrategyBufferCount(BufferAccessStrategy strategy) } /* + * GetAccessStrategyPinLimit -- get cap of number of buffers that should be pinned + * + * When pinning extra buffers to look ahead, users of a ring-based strategy are + * in danger of pinning too much of the ring at once while performing look-ahead. + * For some strategies, that means "escaping" from the ring, and in others it + * means forcing dirty data to disk very frequently with associated WAL + * flushing. Since external code has no insight into any of that, allow + * individual strategy types to expose a clamp that should be applied when + * deciding on a maximum number of buffers to pin at once. + * + * Callers should combine this number with other relevant limits and take the + * minimum. + */ +int +GetAccessStrategyPinLimit(BufferAccessStrategy strategy) +{ + if (strategy == NULL) + return NBuffers; + + switch (strategy->btype) + { + case BAS_BULKREAD: + + /* + * Since BAS_BULKREAD uses StrategyRejectBuffer(), dirty buffers + * shouldn't be a problem and the caller is free to pin up to the + * entire ring at once. + */ + return strategy->nbuffers; + + default: + + /* + * Tell caller not to pin more than half the buffers in the ring. + * This is a trade-off between look ahead distance and deferring + * writeback and associated WAL traffic. + */ + return strategy->nbuffers / 2; + } +} + +/* * FreeAccessStrategy -- release a BufferAccessStrategy object * * A simple pfree would do at the moment, but we would prefer that callers diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index f380f9d9a6c..07ba1a60502 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -318,6 +318,7 @@ extern BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype); extern BufferAccessStrategy GetAccessStrategyWithSize(BufferAccessStrategyType btype, int ring_size_kb); extern int GetAccessStrategyBufferCount(BufferAccessStrategy strategy); +extern int GetAccessStrategyPinLimit(BufferAccessStrategy strategy); extern void FreeAccessStrategy(BufferAccessStrategy strategy); |