mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Allow BufferAccessStrategy to limit pin count.
While pinning extra buffers to look ahead, users of strategies are in danger of using too many buffers. 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 how many buffers to pin at once. Reviewed-by: Andres Freund <andres@anarazel.de> Reviewed-by: Melanie Plageman <melanieplageman@gmail.com> Discussion: https://postgr.es/m/CAAKRu_aJXnqsyZt6HwFLnxYEBgE17oypkxbKbT1t1geE_wvH2Q%40mail.gmail.com
This commit is contained in:
		@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -629,6 +629,48 @@ GetAccessStrategyBufferCount(BufferAccessStrategy strategy)
 | 
			
		||||
	return strategy->nbuffers;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user