cache_table_poc_v2.patch

application/octet-stream

Filename: cache_table_poc_v2.patch
Type: application/octet-stream
Part: 0
Message: Re: Priority table or Cache table

Patch

Format: context
Series: patch v2
File+
contrib/pg_buffercache/pg_buffercache_pages.c 3 0
src/backend/access/common/reloptions.c 33 0
src/backend/access/transam/clog.c 1 0
src/backend/access/transam/xlog.c 4 0
src/backend/postmaster/checkpointer.c 3 0
src/backend/storage/buffer/buf_init.c 15 2
src/backend/storage/buffer/bufmgr.c 233 0
src/backend/storage/buffer/buf_table.c 0 0
src/backend/storage/buffer/freelist.c 93 0
src/backend/storage/lmgr/lwlock.c 1 0
src/backend/tcop/postgres.c 1 0
src/backend/utils/init/globals.c 2 0
src/backend/utils/misc/guc.c 11 0
src/backend/utils/misc/postgresql.conf.sample 2 0
src/include/miscadmin.h 1 0
src/include/storage/buf_internals.h 5 0
src/include/storage/bufmgr.h 4 0
src/include/storage/lwlock.h 41 0
src/include/utils/rel.h 12 0
*** a/contrib/pg_buffercache/pg_buffercache_pages.c
--- b/contrib/pg_buffercache/pg_buffercache_pages.c
***************
*** 98,107 **** pg_buffercache_pages(PG_FUNCTION_ARGS)
  		fctx->tupdesc = BlessTupleDesc(tupledesc);
  
  		/* Allocate NBuffers worth of BufferCachePagesRec records. */
! 		fctx->record = (BufferCachePagesRec *) palloc(sizeof(BufferCachePagesRec) * NBuffers);
  
  		/* Set max calls and remember the user function context. */
! 		funcctx->max_calls = NBuffers;
  		funcctx->user_fctx = fctx;
  
  		/* Return to original context when allocating transient memory */
--- 98,107 ----
  		fctx->tupdesc = BlessTupleDesc(tupledesc);
  
  		/* Allocate NBuffers worth of BufferCachePagesRec records. */
! 		fctx->record = (BufferCachePagesRec *) palloc(sizeof(BufferCachePagesRec) * NSharedBuffers);
  
  		/* Set max calls and remember the user function context. */
! 		funcctx->max_calls = NSharedBuffers;
  		funcctx->user_fctx = fctx;
  
  		/* Return to original context when allocating transient memory */
***************
*** 120,126 **** pg_buffercache_pages(PG_FUNCTION_ARGS)
  		 * Scan though all the buffers, saving the relevant fields in the
  		 * fctx->record structure.
  		 */
! 		for (i = 0, bufHdr = BufferDescriptors; i < NBuffers; i++, bufHdr++)
  		{
  			/* Lock each buffer header before inspecting. */
  			LockBufHdr(bufHdr);
--- 120,126 ----
  		 * Scan though all the buffers, saving the relevant fields in the
  		 * fctx->record structure.
  		 */
! 		for (i = 0, bufHdr = BufferDescriptors; i < NSharedBuffers; i++, bufHdr++)
  		{
  			/* Lock each buffer header before inspecting. */
  			LockBufHdr(bufHdr);
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
***************
*** 33,38 ****
--- 33,40 ----
  #include "utils/memutils.h"
  #include "utils/rel.h"
  
+ static void validateBufferPoolOption(char *value);
+ 
  /*
   * Contents of pg_class.reloptions
   *
***************
*** 292,297 **** static relopt_string stringRelOpts[] =
--- 294,310 ----
  		validateWithCheckOption,
  		NULL
  	},
+ 	{
+ 		{
+ 			"buffer_pool",
+ 			"Table with buffer_pool option defined (default or priority).",
+ 			RELOPT_KIND_HEAP | RELOPT_KIND_BTREE
+ 		},
+ 		7,
+ 		false,
+ 		validateBufferPoolOption,
+ 		"default"
+ 	},
  	/* list terminator */
  	{{NULL}}
  };
***************
*** 1174,1179 **** default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
--- 1187,1194 ----
  	int			numoptions;
  	static const relopt_parse_elt tab[] = {
  		{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
+ 		{"buffer_pool", RELOPT_TYPE_STRING,
+ 		offsetof(StdRdOptions, bufferpool_offset)},
  		{"autovacuum_enabled", RELOPT_TYPE_BOOL,
  		offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, enabled)},
  		{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
***************
*** 1356,1358 **** tablespace_reloptions(Datum reloptions, bool validate)
--- 1371,1391 ----
  
  	return (bytea *) tsopts;
  }
+ 
+ /*
+  * Validator for "bufferpool" reloption on Tables and views. The allowed values
+  * are "default" and "priority".
+  */
+ static void
+ validateBufferPoolOption(char *value)
+ {
+ 	if (value == NULL ||
+ 		(pg_strcasecmp(value, "default") != 0 &&
+ 		 pg_strcasecmp(value, "priority") != 0))
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ 				 errmsg("invalid value for \"bufferpool\" option"),
+ 			  errdetail("Valid values are \"default\", and \"priority\".")));
+ 	}
+ }
*** a/src/backend/access/transam/clog.c
--- b/src/backend/access/transam/clog.c
***************
*** 437,443 **** TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
  Size
  CLOGShmemBuffers(void)
  {
! 	return Min(32, Max(4, NBuffers / 512));
  }
  
  /*
--- 437,443 ----
  Size
  CLOGShmemBuffers(void)
  {
! 	return Min(32, Max(4, NSharedBuffers / 512));
  }
  
  /*
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 4702,4708 **** XLOGChooseNumBuffers(void)
  {
  	int			xbuffers;
  
! 	xbuffers = NBuffers / 32;
  	if (xbuffers > XLOG_SEG_SIZE / XLOG_BLCKSZ)
  		xbuffers = XLOG_SEG_SIZE / XLOG_BLCKSZ;
  	if (xbuffers < 8)
--- 4702,4708 ----
  {
  	int			xbuffers;
  
! 	xbuffers = NSharedBuffers / 32;
  	if (xbuffers > XLOG_SEG_SIZE / XLOG_BLCKSZ)
  		xbuffers = XLOG_SEG_SIZE / XLOG_BLCKSZ;
  	if (xbuffers < 8)
***************
*** 7845,7851 **** LogCheckpointEnd(bool restartpoint)
  			 "write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
  			 "sync files=%d, longest=%ld.%03d s, average=%ld.%03d s",
  			 CheckpointStats.ckpt_bufs_written,
! 			 (double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
  			 CheckpointStats.ckpt_segs_added,
  			 CheckpointStats.ckpt_segs_removed,
  			 CheckpointStats.ckpt_segs_recycled,
--- 7845,7851 ----
  			 "write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
  			 "sync files=%d, longest=%ld.%03d s, average=%ld.%03d s",
  			 CheckpointStats.ckpt_bufs_written,
! 			 (double) CheckpointStats.ckpt_bufs_written * 100 / NSharedBuffers,
  			 CheckpointStats.ckpt_segs_added,
  			 CheckpointStats.ckpt_segs_removed,
  			 CheckpointStats.ckpt_segs_recycled,
***************
*** 7861,7867 **** LogCheckpointEnd(bool restartpoint)
  			 "write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
  			 "sync files=%d, longest=%ld.%03d s, average=%ld.%03d s",
  			 CheckpointStats.ckpt_bufs_written,
! 			 (double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
  			 CheckpointStats.ckpt_segs_added,
  			 CheckpointStats.ckpt_segs_removed,
  			 CheckpointStats.ckpt_segs_recycled,
--- 7861,7867 ----
  			 "write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
  			 "sync files=%d, longest=%ld.%03d s, average=%ld.%03d s",
  			 CheckpointStats.ckpt_bufs_written,
! 			 (double) CheckpointStats.ckpt_bufs_written * 100 / NSharedBuffers,
  			 CheckpointStats.ckpt_segs_added,
  			 CheckpointStats.ckpt_segs_removed,
  			 CheckpointStats.ckpt_segs_recycled,
***************
*** 8301,8307 **** CreateCheckPoint(int flags)
  	LogCheckpointEnd(false);
  
  	TRACE_POSTGRESQL_CHECKPOINT_DONE(CheckpointStats.ckpt_bufs_written,
! 									 NBuffers,
  									 CheckpointStats.ckpt_segs_added,
  									 CheckpointStats.ckpt_segs_removed,
  									 CheckpointStats.ckpt_segs_recycled);
--- 8301,8307 ----
  	LogCheckpointEnd(false);
  
  	TRACE_POSTGRESQL_CHECKPOINT_DONE(CheckpointStats.ckpt_bufs_written,
! 									 NSharedBuffers,
  									 CheckpointStats.ckpt_segs_added,
  									 CheckpointStats.ckpt_segs_removed,
  									 CheckpointStats.ckpt_segs_recycled);
*** a/src/backend/postmaster/checkpointer.c
--- b/src/backend/postmaster/checkpointer.c
***************
*** 903,912 **** CheckpointerShmemSize(void)
  
  	/*
  	 * Currently, the size of the requests[] array is arbitrarily set equal to
! 	 * NBuffers.  This may prove too large or small ...
  	 */
  	size = offsetof(CheckpointerShmemStruct, requests);
! 	size = add_size(size, mul_size(NBuffers, sizeof(CheckpointerRequest)));
  
  	return size;
  }
--- 903,912 ----
  
  	/*
  	 * Currently, the size of the requests[] array is arbitrarily set equal to
! 	 * NSharedBuffers.  This may prove too large or small ...
  	 */
  	size = offsetof(CheckpointerShmemStruct, requests);
! 	size = add_size(size, mul_size(NSharedBuffers, sizeof(CheckpointerRequest)));
  
  	return size;
  }
***************
*** 935,941 **** CheckpointerShmemInit(void)
  		 */
  		MemSet(CheckpointerShmem, 0, size);
  		SpinLockInit(&CheckpointerShmem->ckpt_lck);
! 		CheckpointerShmem->max_requests = NBuffers;
  	}
  }
  
--- 935,941 ----
  		 */
  		MemSet(CheckpointerShmem, 0, size);
  		SpinLockInit(&CheckpointerShmem->ckpt_lck);
! 		CheckpointerShmem->max_requests = NSharedBuffers;
  	}
  }
  
*** a/src/backend/storage/buffer/buf_init.c
--- b/src/backend/storage/buffer/buf_init.c
***************
*** 17,25 ****
  #include "storage/bufmgr.h"
  #include "storage/buf_internals.h"
  
- 
  BufferDesc *BufferDescriptors;
! char	   *BufferBlocks;
  int32	   *PrivateRefCount;
  
  
--- 17,24 ----
  #include "storage/bufmgr.h"
  #include "storage/buf_internals.h"
  
  BufferDesc *BufferDescriptors;
! char *BufferBlocks; 
  int32	   *PrivateRefCount;
  
  
***************
*** 77,87 **** InitBufferPool(void)
  
  	BufferDescriptors = (BufferDesc *)
  		ShmemInitStruct("Buffer Descriptors",
! 						NBuffers * sizeof(BufferDesc), &foundDescs);
  
  	BufferBlocks = (char *)
  		ShmemInitStruct("Buffer Blocks",
! 						NBuffers * (Size) BLCKSZ, &foundBufs);
  
  	if (foundDescs || foundBufs)
  	{
--- 76,86 ----
  
  	BufferDescriptors = (BufferDesc *)
  		ShmemInitStruct("Buffer Descriptors",
! 						NSharedBuffers * sizeof(BufferDesc), &foundDescs);
  
  	BufferBlocks = (char *)
  		ShmemInitStruct("Buffer Blocks",
! 						NSharedBuffers * (Size) BLCKSZ, &foundBufs);
  
  	if (foundDescs || foundBufs)
  	{
***************
*** 98,119 **** InitBufferPool(void)
  
  		/*
  		 * Initialize all the buffer headers.
! 		 */
! 		for (i = 0; i < NBuffers; buf++, i++)
  		{
  			CLEAR_BUFFERTAG(buf->tag);
  			buf->flags = 0;
  			buf->usage_count = 0;
  			buf->refcount = 0;
  			buf->wait_backend_pid = 0;
! 
  			SpinLockInit(&buf->buf_hdr_lock);
  
  			buf->buf_id = i;
  
  			/*
  			 * Initially link all the buffers together as unused. Subsequent
! 			 * management of this list is done by freelist.c.
  			 */
  			buf->freeNext = i + 1;
  
--- 97,118 ----
  
  		/*
  		 * Initialize all the buffer headers.
! 		*/
! 		for (i = 0; i < NSharedBuffers; buf++, i++)
  		{
  			CLEAR_BUFFERTAG(buf->tag);
  			buf->flags = 0;
  			buf->usage_count = 0;
  			buf->refcount = 0;
  			buf->wait_backend_pid = 0;
! 			
  			SpinLockInit(&buf->buf_hdr_lock);
  
  			buf->buf_id = i;
  
  			/*
  			 * Initially link all the buffers together as unused. Subsequent
!   			 * management of this list is done by freelist.c.
  			 */
  			buf->freeNext = i + 1;
  
***************
*** 122,134 **** InitBufferPool(void)
  		}
  
  		/* Correct last entry of linked list */
! 		BufferDescriptors[NBuffers - 1].freeNext = FREENEXT_END_OF_LIST;
  	}
  
  	/* Init other shared buffer-management stuff */
  	StrategyInitialize(!foundDescs);
  }
  
  /*
   * Initialize access to shared buffer pool
   *
--- 121,134 ----
  		}
  
  		/* Correct last entry of linked list */
! 		BufferDescriptors[NSharedBuffers - 1].freeNext = FREENEXT_END_OF_LIST;
  	}
  
  	/* Init other shared buffer-management stuff */
  	StrategyInitialize(!foundDescs);
  }
  
+ 
  /*
   * Initialize access to shared buffer pool
   *
***************
*** 147,153 **** InitBufferPoolAccess(void)
  	/*
  	 * Allocate and zero local arrays of per-buffer info.
  	 */
! 	PrivateRefCount = (int32 *) calloc(NBuffers, sizeof(int32));
  	if (!PrivateRefCount)
  		ereport(FATAL,
  				(errcode(ERRCODE_OUT_OF_MEMORY),
--- 147,153 ----
  	/*
  	 * Allocate and zero local arrays of per-buffer info.
  	 */
! 	PrivateRefCount = (int32 *) calloc(NSharedBuffers, sizeof(int32));
  	if (!PrivateRefCount)
  		ereport(FATAL,
  				(errcode(ERRCODE_OUT_OF_MEMORY),
***************
*** 164,178 **** Size
  BufferShmemSize(void)
  {
  	Size		size = 0;
  
  	/* size of buffer descriptors */
! 	size = add_size(size, mul_size(NBuffers, sizeof(BufferDesc)));
  
  	/* size of data pages */
! 	size = add_size(size, mul_size(NBuffers, BLCKSZ));
  
  	/* size of stuff controlled by freelist.c */
  	size = add_size(size, StrategyShmemSize());
! 
  	return size;
  }
--- 164,180 ----
  BufferShmemSize(void)
  {
  	Size		size = 0;
+ 	
+ 	NSharedBuffers = add_size(NBuffers, NPriorityBuffers);
  
  	/* size of buffer descriptors */
! 	size = add_size(size, mul_size(NSharedBuffers, sizeof(BufferDesc)));
  
  	/* size of data pages */
! 	size = add_size(size, mul_size(NSharedBuffers, BLCKSZ));
  
  	/* size of stuff controlled by freelist.c */
  	size = add_size(size, StrategyShmemSize());
! 	
  	return size;
  }
*** a/src/backend/storage/buffer/buf_table.c
--- b/src/backend/storage/buffer/buf_table.c
***************
*** 34,40 **** typedef struct
  
  static HTAB *SharedBufHash;
  
- 
  /*
   * Estimate space needed for mapping hashtable
   *		size is the desired hash table size (possibly more than NBuffers)
--- 34,39 ----
*** a/src/backend/storage/buffer/bufmgr.c
--- b/src/backend/storage/buffer/bufmgr.c
***************
*** 86,92 **** static bool IsForInput;
  static volatile BufferDesc *PinCountWaitBuf = NULL;
  
  
! static Buffer ReadBuffer_common(SMgrRelation reln, char relpersistence,
  				  ForkNumber forkNum, BlockNumber blockNum,
  				  ReadBufferMode mode, BufferAccessStrategy strategy,
  				  bool *hit);
--- 86,92 ----
  static volatile BufferDesc *PinCountWaitBuf = NULL;
  
  
! static Buffer ReadBuffer_common(int poolid, SMgrRelation reln, char relpersistence,
  				  ForkNumber forkNum, BlockNumber blockNum,
  				  ReadBufferMode mode, BufferAccessStrategy strategy,
  				  bool *hit);
***************
*** 101,107 **** static void TerminateBufferIO(volatile BufferDesc *buf, bool clear_dirty,
  				  int set_flag_bits);
  static void shared_buffer_write_error_callback(void *arg);
  static void local_buffer_write_error_callback(void *arg);
! static volatile BufferDesc *BufferAlloc(SMgrRelation smgr,
  			char relpersistence,
  			ForkNumber forkNum,
  			BlockNumber blockNum,
--- 101,107 ----
  				  int set_flag_bits);
  static void shared_buffer_write_error_callback(void *arg);
  static void local_buffer_write_error_callback(void *arg);
! static volatile BufferDesc *BufferAlloc(int poolid, SMgrRelation smgr,
  			char relpersistence,
  			ForkNumber forkNum,
  			BlockNumber blockNum,
***************
*** 231,236 **** ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
--- 231,237 ----
  				   ReadBufferMode mode, BufferAccessStrategy strategy)
  {
  	bool		hit;
+ 	int			poolid;
  	Buffer		buf;
  
  	/* Open it at the smgr level if not already done */
***************
*** 251,257 **** ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
  	 * miss.
  	 */
  	pgstat_count_buffer_read(reln);
! 	buf = ReadBuffer_common(reln->rd_smgr, reln->rd_rel->relpersistence,
  							forkNum, blockNum, mode, strategy, &hit);
  	if (hit)
  		pgstat_count_buffer_hit(reln);
--- 252,260 ----
  	 * miss.
  	 */
  	pgstat_count_buffer_read(reln);
! 	poolid = RelationIsInPriorityBufferPool(reln) ? PRIORITY_BUFFER_POOL : DEFAULT_BUFFER_POOL;
! 
! 	buf = ReadBuffer_common(poolid, reln->rd_smgr, reln->rd_rel->relpersistence,
  							forkNum, blockNum, mode, strategy, &hit);
  	if (hit)
  		pgstat_count_buffer_hit(reln);
***************
*** 278,285 **** ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
  	SMgrRelation smgr = smgropen(rnode, InvalidBackendId);
  
  	Assert(InRecovery);
! 
! 	return ReadBuffer_common(smgr, RELPERSISTENCE_PERMANENT, forkNum, blockNum,
  							 mode, strategy, &hit);
  }
  
--- 281,287 ----
  	SMgrRelation smgr = smgropen(rnode, InvalidBackendId);
  
  	Assert(InRecovery);
! 	return ReadBuffer_common(DEFAULT_BUFFER_POOL, smgr, RELPERSISTENCE_PERMANENT, forkNum, blockNum,
  							 mode, strategy, &hit);
  }
  
***************
*** 290,296 **** ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
   * *hit is set to true if the request was satisfied from shared buffer cache.
   */
  static Buffer
! ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
  				  BlockNumber blockNum, ReadBufferMode mode,
  				  BufferAccessStrategy strategy, bool *hit)
  {
--- 292,298 ----
   * *hit is set to true if the request was satisfied from shared buffer cache.
   */
  static Buffer
! ReadBuffer_common(int poolid, SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
  				  BlockNumber blockNum, ReadBufferMode mode,
  				  BufferAccessStrategy strategy, bool *hit)
  {
***************
*** 332,338 **** ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
  		 * lookup the buffer.  IO_IN_PROGRESS is set if the requested block is
  		 * not currently in memory.
  		 */
! 		bufHdr = BufferAlloc(smgr, relpersistence, forkNum, blockNum,
  							 strategy, &found);
  		if (found)
  			pgBufferUsage.shared_blks_hit++;
--- 334,340 ----
  		 * lookup the buffer.  IO_IN_PROGRESS is set if the requested block is
  		 * not currently in memory.
  		 */
! 		bufHdr = BufferAlloc(poolid, smgr, relpersistence, forkNum, blockNum,
  							 strategy, &found);
  		if (found)
  			pgBufferUsage.shared_blks_hit++;
***************
*** 531,537 **** ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
   * No locks are held either at entry or exit.
   */
  static volatile BufferDesc *
! BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
  			BlockNumber blockNum,
  			BufferAccessStrategy strategy,
  			bool *foundPtr)
--- 533,539 ----
   * No locks are held either at entry or exit.
   */
  static volatile BufferDesc *
! BufferAlloc(int poolid, SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
  			BlockNumber blockNum,
  			BufferAccessStrategy strategy,
  			bool *foundPtr)
***************
*** 612,618 **** BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
  		 * still held, since it would be bad to hold the spinlock while
  		 * possibly waking up other processes.
  		 */
! 		buf = StrategyGetBuffer(strategy, &lock_held);
  
  		Assert(buf->refcount == 0);
  
--- 614,620 ----
  		 * still held, since it would be bad to hold the spinlock while
  		 * possibly waking up other processes.
  		 */
! 		buf = StrategyGetBuffer(poolid, strategy, &lock_held);
  
  		Assert(buf->refcount == 0);
  
***************
*** 624,630 **** BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
  
  		/* Now it's safe to release the freelist lock */
  		if (lock_held)
! 			LWLockRelease(BufFreelistLock);
  
  		/*
  		 * If the buffer was dirty, try to write it out.  There is a race
--- 626,632 ----
  
  		/* Now it's safe to release the freelist lock */
  		if (lock_held)
! 			LWLockRelease(BufFreelistLock(poolid));
  
  		/*
  		 * If the buffer was dirty, try to write it out.  There is a race
***************
*** 1245,1251 **** BufferSync(int flags)
  	 * certainly need to be written for the next checkpoint attempt, too.
  	 */
  	num_to_write = 0;
! 	for (buf_id = 0; buf_id < NBuffers; buf_id++)
  	{
  		volatile BufferDesc *bufHdr = &BufferDescriptors[buf_id];
  
--- 1247,1253 ----
  	 * certainly need to be written for the next checkpoint attempt, too.
  	 */
  	num_to_write = 0;
! 	for (buf_id = 0; buf_id < NSharedBuffers; buf_id++)
  	{
  		volatile BufferDesc *bufHdr = &BufferDescriptors[buf_id];
  
***************
*** 1267,1273 **** BufferSync(int flags)
  	if (num_to_write == 0)
  		return;					/* nothing to do */
  
! 	TRACE_POSTGRESQL_BUFFER_SYNC_START(NBuffers, num_to_write);
  
  	/*
  	 * Loop over all buffers again, and write the ones (still) marked with
--- 1269,1275 ----
  	if (num_to_write == 0)
  		return;					/* nothing to do */
  
! 	TRACE_POSTGRESQL_BUFFER_SYNC_START(NSharedBuffers, num_to_write);
  
  	/*
  	 * Loop over all buffers again, and write the ones (still) marked with
***************
*** 1277,1284 **** BufferSync(int flags)
  	 * Note that we don't read the buffer alloc count here --- that should be
  	 * left untouched till the next BgBufferSync() call.
  	 */
! 	buf_id = StrategySyncStart(NULL, NULL);
! 	num_to_scan = NBuffers;
  	num_written = 0;
  	while (num_to_scan-- > 0)
  	{
--- 1279,1286 ----
  	 * Note that we don't read the buffer alloc count here --- that should be
  	 * left untouched till the next BgBufferSync() call.
  	 */
! 	buf_id = StrategySyncStart(0, NULL, NULL);
! 	num_to_scan = NSharedBuffers;
  	num_written = 0;
  	while (num_to_scan-- > 0)
  	{
***************
*** 1325,1341 **** BufferSync(int flags)
  			}
  		}
  
! 		if (++buf_id >= NBuffers)
  			buf_id = 0;
  	}
- 
  	/*
  	 * Update checkpoint statistics. As noted above, this doesn't include
  	 * buffers written by other backends or bgwriter scan.
  	 */
  	CheckpointStats.ckpt_bufs_written += num_written;
  
! 	TRACE_POSTGRESQL_BUFFER_SYNC_DONE(NBuffers, num_written, num_to_write);
  }
  
  /*
--- 1327,1342 ----
  			}
  		}
  
! 		if (++buf_id >= NSharedBuffers)
  			buf_id = 0;
  	}
  	/*
  	 * Update checkpoint statistics. As noted above, this doesn't include
  	 * buffers written by other backends or bgwriter scan.
  	 */
  	CheckpointStats.ckpt_bufs_written += num_written;
  
! 	TRACE_POSTGRESQL_BUFFER_SYNC_DONE(BufferPool[poolid].num_buffers, num_written, num_to_write);
  }
  
  /*
***************
*** 1388,1634 **** BgBufferSync(void)
  	int			num_to_scan;
  	int			num_written;
  	int			reusable_buffers;
  
  	/* Variables for final smoothed_density update */
  	long		new_strategy_delta;
  	uint32		new_recent_alloc;
  
! 	/*
! 	 * Find out where the freelist clock sweep currently is, and how many
! 	 * buffer allocations have happened since our last call.
! 	 */
! 	strategy_buf_id = StrategySyncStart(&strategy_passes, &recent_alloc);
! 
! 	/* Report buffer alloc counts to pgstat */
! 	BgWriterStats.m_buf_alloc += recent_alloc;
! 
! 	/*
! 	 * If we're not running the LRU scan, just stop after doing the stats
! 	 * stuff.  We mark the saved state invalid so that we can recover sanely
! 	 * if LRU scan is turned back on later.
! 	 */
! 	if (bgwriter_lru_maxpages <= 0)
  	{
! 		saved_info_valid = false;
! 		return true;
! 	}
! 
! 	/*
! 	 * Compute strategy_delta = how many buffers have been scanned by the
! 	 * clock sweep since last time.  If first time through, assume none. Then
! 	 * see if we are still ahead of the clock sweep, and if so, how many
! 	 * buffers we could scan before we'd catch up with it and "lap" it. Note:
! 	 * weird-looking coding of xxx_passes comparisons are to avoid bogus
! 	 * behavior when the passes counts wrap around.
! 	 */
! 	if (saved_info_valid)
! 	{
! 		int32		passes_delta = strategy_passes - prev_strategy_passes;
! 
! 		strategy_delta = strategy_buf_id - prev_strategy_buf_id;
! 		strategy_delta += (long) passes_delta *NBuffers;
  
! 		Assert(strategy_delta >= 0);
  
! 		if ((int32) (next_passes - strategy_passes) > 0)
  		{
! 			/* we're one pass ahead of the strategy point */
! 			bufs_to_lap = strategy_buf_id - next_to_clean;
! #ifdef BGW_DEBUG
! 			elog(DEBUG2, "bgwriter ahead: bgw %u-%u strategy %u-%u delta=%ld lap=%d",
! 				 next_passes, next_to_clean,
! 				 strategy_passes, strategy_buf_id,
! 				 strategy_delta, bufs_to_lap);
! #endif
  		}
! 		else if (next_passes == strategy_passes &&
! 				 next_to_clean >= strategy_buf_id)
  		{
! 			/* on same pass, but ahead or at least not behind */
! 			bufs_to_lap = NBuffers - (next_to_clean - strategy_buf_id);
! #ifdef BGW_DEBUG
! 			elog(DEBUG2, "bgwriter ahead: bgw %u-%u strategy %u-%u delta=%ld lap=%d",
! 				 next_passes, next_to_clean,
! 				 strategy_passes, strategy_buf_id,
! 				 strategy_delta, bufs_to_lap);
! #endif
  		}
  		else
  		{
  			/*
! 			 * We're behind, so skip forward to the strategy point and start
! 			 * cleaning from there.
  			 */
! #ifdef BGW_DEBUG
! 			elog(DEBUG2, "bgwriter behind: bgw %u-%u strategy %u-%u delta=%ld",
! 				 next_passes, next_to_clean,
! 				 strategy_passes, strategy_buf_id,
! 				 strategy_delta);
! #endif
  			next_to_clean = strategy_buf_id;
  			next_passes = strategy_passes;
! 			bufs_to_lap = NBuffers;
  		}
- 	}
- 	else
- 	{
- 		/*
- 		 * Initializing at startup or after LRU scanning had been off. Always
- 		 * start at the strategy point.
- 		 */
- #ifdef BGW_DEBUG
- 		elog(DEBUG2, "bgwriter initializing: strategy %u-%u",
- 			 strategy_passes, strategy_buf_id);
- #endif
- 		strategy_delta = 0;
- 		next_to_clean = strategy_buf_id;
- 		next_passes = strategy_passes;
- 		bufs_to_lap = NBuffers;
- 	}
  
! 	/* Update saved info for next time */
! 	prev_strategy_buf_id = strategy_buf_id;
! 	prev_strategy_passes = strategy_passes;
! 	saved_info_valid = true;
  
! 	/*
! 	 * Compute how many buffers had to be scanned for each new allocation, ie,
! 	 * 1/density of reusable buffers, and track a moving average of that.
! 	 *
! 	 * If the strategy point didn't move, we don't update the density estimate
! 	 */
! 	if (strategy_delta > 0 && recent_alloc > 0)
! 	{
! 		scans_per_alloc = (float) strategy_delta / (float) recent_alloc;
! 		smoothed_density += (scans_per_alloc - smoothed_density) /
! 			smoothing_samples;
! 	}
! 
! 	/*
! 	 * Estimate how many reusable buffers there are between the current
! 	 * strategy point and where we've scanned ahead to, based on the smoothed
! 	 * density estimate.
! 	 */
! 	bufs_ahead = NBuffers - bufs_to_lap;
! 	reusable_buffers_est = (float) bufs_ahead / smoothed_density;
  
! 	/*
! 	 * Track a moving average of recent buffer allocations.  Here, rather than
! 	 * a true average we want a fast-attack, slow-decline behavior: we
! 	 * immediately follow any increase.
! 	 */
! 	if (smoothed_alloc <= (float) recent_alloc)
! 		smoothed_alloc = recent_alloc;
! 	else
! 		smoothed_alloc += ((float) recent_alloc - smoothed_alloc) /
! 			smoothing_samples;
  
! 	/* Scale the estimate by a GUC to allow more aggressive tuning. */
! 	upcoming_alloc_est = (int) (smoothed_alloc * bgwriter_lru_multiplier);
  
! 	/*
! 	 * If recent_alloc remains at zero for many cycles, smoothed_alloc will
! 	 * eventually underflow to zero, and the underflows produce annoying
! 	 * kernel warnings on some platforms.  Once upcoming_alloc_est has gone to
! 	 * zero, there's no point in tracking smaller and smaller values of
! 	 * smoothed_alloc, so just reset it to exactly zero to avoid this
! 	 * syndrome.  It will pop back up as soon as recent_alloc increases.
! 	 */
! 	if (upcoming_alloc_est == 0)
! 		smoothed_alloc = 0;
  
! 	/*
! 	 * Even in cases where there's been little or no buffer allocation
! 	 * activity, we want to make a small amount of progress through the buffer
! 	 * cache so that as many reusable buffers as possible are clean after an
! 	 * idle period.
! 	 *
! 	 * (scan_whole_pool_milliseconds / BgWriterDelay) computes how many times
! 	 * the BGW will be called during the scan_whole_pool time; slice the
! 	 * buffer pool into that many sections.
! 	 */
! 	min_scan_buffers = (int) (NBuffers / (scan_whole_pool_milliseconds / BgWriterDelay));
  
! 	if (upcoming_alloc_est < (min_scan_buffers + reusable_buffers_est))
! 	{
! #ifdef BGW_DEBUG
! 		elog(DEBUG2, "bgwriter: alloc_est=%d too small, using min=%d + reusable_est=%d",
! 			 upcoming_alloc_est, min_scan_buffers, reusable_buffers_est);
! #endif
! 		upcoming_alloc_est = min_scan_buffers + reusable_buffers_est;
! 	}
  
! 	/*
! 	 * Now write out dirty reusable buffers, working forward from the
! 	 * next_to_clean point, until we have lapped the strategy scan, or cleaned
! 	 * enough buffers to match our estimate of the next cycle's allocation
! 	 * requirements, or hit the bgwriter_lru_maxpages limit.
! 	 */
  
! 	/* Make sure we can handle the pin inside SyncOneBuffer */
! 	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
  
! 	num_to_scan = bufs_to_lap;
! 	num_written = 0;
! 	reusable_buffers = reusable_buffers_est;
  
! 	/* Execute the LRU scan */
! 	while (num_to_scan > 0 && reusable_buffers < upcoming_alloc_est)
! 	{
! 		int			buffer_state = SyncOneBuffer(next_to_clean, true);
  
! 		if (++next_to_clean >= NBuffers)
  		{
! 			next_to_clean = 0;
! 			next_passes++;
! 		}
! 		num_to_scan--;
  
! 		if (buffer_state & BUF_WRITTEN)
! 		{
! 			reusable_buffers++;
! 			if (++num_written >= bgwriter_lru_maxpages)
  			{
! 				BgWriterStats.m_maxwritten_clean++;
! 				break;
  			}
  		}
- 		else if (buffer_state & BUF_REUSABLE)
- 			reusable_buffers++;
- 	}
  
! 	BgWriterStats.m_buf_written_clean += num_written;
  
! #ifdef BGW_DEBUG
! 	elog(DEBUG1, "bgwriter: recent_alloc=%u smoothed=%.2f delta=%ld ahead=%d density=%.2f reusable_est=%d upcoming_est=%d scanned=%d wrote=%d reusable=%d",
! 		 recent_alloc, smoothed_alloc, strategy_delta, bufs_ahead,
! 		 smoothed_density, reusable_buffers_est, upcoming_alloc_est,
! 		 bufs_to_lap - num_to_scan,
! 		 num_written,
! 		 reusable_buffers - reusable_buffers_est);
! #endif
  
! 	/*
! 	 * Consider the above scan as being like a new allocation scan.
! 	 * Characterize its density and update the smoothed one based on it. This
! 	 * effectively halves the moving average period in cases where both the
! 	 * strategy and the background writer are doing some useful scanning,
! 	 * which is helpful because a long memory isn't as desirable on the
! 	 * density estimates.
! 	 */
! 	new_strategy_delta = bufs_to_lap - num_to_scan;
! 	new_recent_alloc = reusable_buffers - reusable_buffers_est;
! 	if (new_strategy_delta > 0 && new_recent_alloc > 0)
! 	{
! 		scans_per_alloc = (float) new_strategy_delta / (float) new_recent_alloc;
! 		smoothed_density += (scans_per_alloc - smoothed_density) /
! 			smoothing_samples;
! 
! #ifdef BGW_DEBUG
! 		elog(DEBUG2, "bgwriter: cleaner density alloc=%u scan=%ld density=%.2f new smoothed=%.2f",
! 			 new_recent_alloc, new_strategy_delta,
! 			 scans_per_alloc, smoothed_density);
! #endif
  	}
  
  	/* Return true if OK to hibernate */
--- 1389,1639 ----
  	int			num_to_scan;
  	int			num_written;
  	int			reusable_buffers;
+ 	int			poolid;
  
  	/* Variables for final smoothed_density update */
  	long		new_strategy_delta;
  	uint32		new_recent_alloc;
  
! 	for (poolid = 0; poolid < NUM_MAX_BUFFER_POOLS; poolid++)
  	{
! 		/*
! 		 * Find out where the freelist clock sweep currently is, and how many
! 		 * buffer allocations have happened since our last call.
! 		 */
! 		strategy_buf_id = StrategySyncStart(poolid, &strategy_passes, &recent_alloc);
  
! 		/* Report buffer alloc counts to pgstat */
! 		BgWriterStats.m_buf_alloc += recent_alloc;
  
! 		/*
! 		 * If we're not running the LRU scan, just stop after doing the stats
! 		 * stuff.  We mark the saved state invalid so that we can recover sanely
! 		 * if LRU scan is turned back on later.
! 		 */
! 		if (bgwriter_lru_maxpages <= 0)
  		{
! 			saved_info_valid = false;
! 			return true;
  		}
! 
! 		/*
! 		 * Compute strategy_delta = how many buffers have been scanned by the
! 		 * clock sweep since last time.  If first time through, assume none. Then
! 		 * see if we are still ahead of the clock sweep, and if so, how many
! 		 * buffers we could scan before we'd catch up with it and "lap" it. Note:
! 		 * weird-looking coding of xxx_passes comparisons are to avoid bogus
! 		 * behavior when the passes counts wrap around.
! 		 */
! 		if (saved_info_valid)
  		{
! 			int32		passes_delta = strategy_passes - prev_strategy_passes;
! 
! 			strategy_delta = strategy_buf_id - prev_strategy_buf_id;
! 			strategy_delta += (long) passes_delta * ((poolid == 0) ? NBuffers : NSharedBuffers);
! 
! 			/*Assert(strategy_delta >= 0); Temp fix to avoid the crash*/
! 
! 			if ((int32) (next_passes - strategy_passes) > 0)
! 			{
! 				/* we're one pass ahead of the strategy point */
! 				bufs_to_lap = strategy_buf_id - next_to_clean;
! 	#ifdef BGW_DEBUG
! 				elog(DEBUG2, "bgwriter ahead: bgw %u-%u strategy %u-%u delta=%ld lap=%d",
! 					 next_passes, next_to_clean,
! 					 strategy_passes, strategy_buf_id,
! 					 strategy_delta, bufs_to_lap);
! 	#endif
! 			}
! 			else if (next_passes == strategy_passes &&
! 					 next_to_clean >= strategy_buf_id)
! 			{
! 				/* on same pass, but ahead or at least not behind */
! 				bufs_to_lap = ((poolid == 0) ? NBuffers : NSharedBuffers) - (next_to_clean - strategy_buf_id);
! 	#ifdef BGW_DEBUG
! 				elog(DEBUG2, "bgwriter ahead: bgw %u-%u strategy %u-%u delta=%ld lap=%d",
! 					 next_passes, next_to_clean,
! 					 strategy_passes, strategy_buf_id,
! 					 strategy_delta, bufs_to_lap);
! 	#endif
! 			}
! 			else
! 			{
! 				/*
! 				 * We're behind, so skip forward to the strategy point and start
! 				 * cleaning from there.
! 				 */
! 	#ifdef BGW_DEBUG
! 				elog(DEBUG2, "bgwriter behind: bgw %u-%u strategy %u-%u delta=%ld",
! 					 next_passes, next_to_clean,
! 					 strategy_passes, strategy_buf_id,
! 					 strategy_delta);
! 	#endif
! 				next_to_clean = strategy_buf_id;
! 				next_passes = strategy_passes;
! 				bufs_to_lap = ((poolid == 0) ? NBuffers : NSharedBuffers);
! 			}
  		}
  		else
  		{
  			/*
! 			 * Initializing at startup or after LRU scanning had been off. Always
! 			 * start at the strategy point.
  			 */
! 	#ifdef BGW_DEBUG
! 			elog(DEBUG2, "bgwriter initializing: strategy %u-%u",
! 				 strategy_passes, strategy_buf_id);
! 	#endif
! 			strategy_delta = 0;
  			next_to_clean = strategy_buf_id;
  			next_passes = strategy_passes;
! 			bufs_to_lap = ((poolid == 0) ? NBuffers : NSharedBuffers);
  		}
  
! 		/* Update saved info for next time */
! 		prev_strategy_buf_id = strategy_buf_id;
! 		prev_strategy_passes = strategy_passes;
! 		saved_info_valid = true;
  
! 		/*
! 		 * Compute how many buffers had to be scanned for each new allocation, ie,
! 		 * 1/density of reusable buffers, and track a moving average of that.
! 		 *
! 		 * If the strategy point didn't move, we don't update the density estimate
! 		 */
! 		if (strategy_delta > 0 && recent_alloc > 0)
! 		{
! 			scans_per_alloc = (float) strategy_delta / (float) recent_alloc;
! 			smoothed_density += (scans_per_alloc - smoothed_density) /
! 				smoothing_samples;
! 		}
  
! 		/*
! 		 * Estimate how many reusable buffers there are between the current
! 		 * strategy point and where we've scanned ahead to, based on the smoothed
! 		 * density estimate.
! 		 */
! 		bufs_ahead = ((poolid == 0) ? NBuffers : NSharedBuffers) - bufs_to_lap;
! 		reusable_buffers_est = (float) bufs_ahead / smoothed_density;
  
! 		/*
! 		 * Track a moving average of recent buffer allocations.  Here, rather than
! 		 * a true average we want a fast-attack, slow-decline behavior: we
! 		 * immediately follow any increase.
! 		 */
! 		if (smoothed_alloc <= (float) recent_alloc)
! 			smoothed_alloc = recent_alloc;
! 		else
! 			smoothed_alloc += ((float) recent_alloc - smoothed_alloc) /
! 				smoothing_samples;
  
! 		/* Scale the estimate by a GUC to allow more aggressive tuning. */
! 		upcoming_alloc_est = (int) (smoothed_alloc * bgwriter_lru_multiplier);
  
! 		/*
! 		 * If recent_alloc remains at zero for many cycles, smoothed_alloc will
! 		 * eventually underflow to zero, and the underflows produce annoying
! 		 * kernel warnings on some platforms.  Once upcoming_alloc_est has gone to
! 		 * zero, there's no point in tracking smaller and smaller values of
! 		 * smoothed_alloc, so just reset it to exactly zero to avoid this
! 		 * syndrome.  It will pop back up as soon as recent_alloc increases.
! 		 */
! 		if (upcoming_alloc_est == 0)
! 			smoothed_alloc = 0;
  
! 		/*
! 		 * Even in cases where there's been little or no buffer allocation
! 		 * activity, we want to make a small amount of progress through the buffer
! 		 * cache so that as many reusable buffers as possible are clean after an
! 		 * idle period.
! 		 *
! 		 * (scan_whole_pool_milliseconds / BgWriterDelay) computes how many times
! 		 * the BGW will be called during the scan_whole_pool time; slice the
! 		 * buffer pool into that many sections.
! 		 */
! 		min_scan_buffers = (int) (((poolid == 0) ? NBuffers : NPriorityBuffers) / (scan_whole_pool_milliseconds / BgWriterDelay));
  
! 		if (upcoming_alloc_est < (min_scan_buffers + reusable_buffers_est))
! 		{
! 	#ifdef BGW_DEBUG
! 			elog(DEBUG2, "bgwriter: alloc_est=%d too small, using min=%d + reusable_est=%d",
! 				 upcoming_alloc_est, min_scan_buffers, reusable_buffers_est);
! 	#endif
! 			upcoming_alloc_est = min_scan_buffers + reusable_buffers_est;
! 		}
  
! 		/*
! 		 * Now write out dirty reusable buffers, working forward from the
! 		 * next_to_clean point, until we have lapped the strategy scan, or cleaned
! 		 * enough buffers to match our estimate of the next cycle's allocation
! 		 * requirements, or hit the bgwriter_lru_maxpages limit.
! 		 */
  
! 		/* Make sure we can handle the pin inside SyncOneBuffer */
! 		ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
  
! 		num_to_scan = bufs_to_lap;
! 		num_written = 0;
! 		reusable_buffers = reusable_buffers_est;
  
! 		/* Execute the LRU scan */
! 		while (num_to_scan > 0 && reusable_buffers < upcoming_alloc_est)
  		{
! 			int			buffer_state = SyncOneBuffer(next_to_clean, true);
  
! 			if (++next_to_clean >= ((poolid == 0) ? NBuffers : NSharedBuffers))
! 			{
! 				next_to_clean = (poolid == 0) ? 0 : NBuffers;
! 				next_passes++;
! 			}
! 			num_to_scan--;
! 
! 			if (buffer_state & BUF_WRITTEN)
  			{
! 				reusable_buffers++;
! 				if (++num_written >= bgwriter_lru_maxpages)
! 				{
! 					BgWriterStats.m_maxwritten_clean++;
! 					break;
! 				}
  			}
+ 			else if (buffer_state & BUF_REUSABLE)
+ 				reusable_buffers++;
  		}
  
! 		BgWriterStats.m_buf_written_clean += num_written;
  
! 	#ifdef BGW_DEBUG
! 		elog(DEBUG1, "bgwriter: recent_alloc=%u smoothed=%.2f delta=%ld ahead=%d density=%.2f reusable_est=%d upcoming_est=%d scanned=%d wrote=%d reusable=%d",
! 			 recent_alloc, smoothed_alloc, strategy_delta, bufs_ahead,
! 			 smoothed_density, reusable_buffers_est, upcoming_alloc_est,
! 			 bufs_to_lap - num_to_scan,
! 			 num_written,
! 			 reusable_buffers - reusable_buffers_est);
! 	#endif
  
! 		/*
! 		 * Consider the above scan as being like a new allocation scan.
! 		 * Characterize its density and update the smoothed one based on it. This
! 		 * effectively halves the moving average period in cases where both the
! 		 * strategy and the background writer are doing some useful scanning,
! 		 * which is helpful because a long memory isn't as desirable on the
! 		 * density estimates.
! 		 */
! 		new_strategy_delta = bufs_to_lap - num_to_scan;
! 		new_recent_alloc = reusable_buffers - reusable_buffers_est;
! 		if (new_strategy_delta > 0 && new_recent_alloc > 0)
! 		{
! 			scans_per_alloc = (float) new_strategy_delta / (float) new_recent_alloc;
! 			smoothed_density += (scans_per_alloc - smoothed_density) /
! 				smoothing_samples;
! 
! 	#ifdef BGW_DEBUG
! 			elog(DEBUG2, "bgwriter: cleaner density alloc=%u scan=%ld density=%.2f new smoothed=%.2f",
! 				 new_recent_alloc, new_strategy_delta,
! 				 scans_per_alloc, smoothed_density);
! 	#endif
! 		}
  	}
  
  	/* Return true if OK to hibernate */
***************
*** 1716,1722 **** AtEOXact_Buffers(bool isCommit)
  		int			RefCountErrors = 0;
  		Buffer		b;
  
! 		for (b = 1; b <= NBuffers; b++)
  		{
  			if (PrivateRefCount[b - 1] != 0)
  			{
--- 1721,1727 ----
  		int			RefCountErrors = 0;
  		Buffer		b;
  
! 		for (b = 1; b <= NSharedBuffers; b++)
  		{
  			if (PrivateRefCount[b - 1] != 0)
  			{
***************
*** 1762,1768 **** AtProcExit_Buffers(int code, Datum arg)
  		int			RefCountErrors = 0;
  		Buffer		b;
  
! 		for (b = 1; b <= NBuffers; b++)
  		{
  			if (PrivateRefCount[b - 1] != 0)
  			{
--- 1767,1773 ----
  		int			RefCountErrors = 0;
  		Buffer		b;
  
! 		for (b = 1; b <= NSharedBuffers; b++)
  		{
  			if (PrivateRefCount[b - 1] != 0)
  			{
***************
*** 2143,2149 **** DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum,
  		return;
  	}
  
! 	for (i = 0; i < NBuffers; i++)
  	{
  		volatile BufferDesc *bufHdr = &BufferDescriptors[i];
  
--- 2148,2154 ----
  		return;
  	}
  
! 	for (i = 0; i < NSharedBuffers; i++)
  	{
  		volatile BufferDesc *bufHdr = &BufferDescriptors[i];
  
***************
*** 2232,2238 **** DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes)
  	if (use_bsearch)
  		pg_qsort(nodes, n, sizeof(RelFileNode), rnode_comparator);
  
! 	for (i = 0; i < NBuffers; i++)
  	{
  		RelFileNode *rnode = NULL;
  		volatile BufferDesc *bufHdr = &BufferDescriptors[i];
--- 2237,2243 ----
  	if (use_bsearch)
  		pg_qsort(nodes, n, sizeof(RelFileNode), rnode_comparator);
  
! 	for (i = 0; i < NSharedBuffers; i++)
  	{
  		RelFileNode *rnode = NULL;
  		volatile BufferDesc *bufHdr = &BufferDescriptors[i];
***************
*** 2297,2303 **** DropDatabaseBuffers(Oid dbid)
  	 * database isn't our own.
  	 */
  
! 	for (i = 0; i < NBuffers; i++)
  	{
  		volatile BufferDesc *bufHdr = &BufferDescriptors[i];
  
--- 2302,2308 ----
  	 * database isn't our own.
  	 */
  
! 	for (i = 0; i < NSharedBuffers; i++)
  	{
  		volatile BufferDesc *bufHdr = &BufferDescriptors[i];
  
***************
*** 2330,2336 **** PrintBufferDescs(void)
  	int			i;
  	volatile BufferDesc *buf = BufferDescriptors;
  
! 	for (i = 0; i < NBuffers; ++i, ++buf)
  	{
  		/* theoretically we should lock the bufhdr here */
  		elog(LOG,
--- 2335,2341 ----
  	int			i;
  	volatile BufferDesc *buf = BufferDescriptors;
  
! 	for (i = 0; i < NSharedBuffers; ++i, ++buf)
  	{
  		/* theoretically we should lock the bufhdr here */
  		elog(LOG,
***************
*** 2351,2357 **** PrintPinnedBufs(void)
  	int			i;
  	volatile BufferDesc *buf = BufferDescriptors;
  
! 	for (i = 0; i < NBuffers; ++i, ++buf)
  	{
  		if (PrivateRefCount[i] > 0)
  		{
--- 2356,2362 ----
  	int			i;
  	volatile BufferDesc *buf = BufferDescriptors;
  
! 	for (i = 0; i < NSharedBuffers; ++i, ++buf)
  	{
  		if (PrivateRefCount[i] > 0)
  		{
***************
*** 2436,2442 **** FlushRelationBuffers(Relation rel)
  	/* Make sure we can handle the pin inside the loop */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
  
! 	for (i = 0; i < NBuffers; i++)
  	{
  		bufHdr = &BufferDescriptors[i];
  
--- 2441,2447 ----
  	/* Make sure we can handle the pin inside the loop */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
  
! 	for (i = 0; i < NSharedBuffers; i++)
  	{
  		bufHdr = &BufferDescriptors[i];
  
***************
*** 2486,2492 **** FlushDatabaseBuffers(Oid dbid)
  	/* Make sure we can handle the pin inside the loop */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
  
! 	for (i = 0; i < NBuffers; i++)
  	{
  		bufHdr = &BufferDescriptors[i];
  
--- 2491,2497 ----
  	/* Make sure we can handle the pin inside the loop */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
  
! 	for (i = 0; i < NSharedBuffers; i++)
  	{
  		bufHdr = &BufferDescriptors[i];
  
*** a/src/backend/storage/buffer/freelist.c
--- b/src/backend/storage/buffer/freelist.c
***************
*** 49,55 **** typedef struct
  } BufferStrategyControl;
  
  /* Pointers to shared state */
! static BufferStrategyControl *StrategyControl = NULL;
  
  /*
   * Private (non-shared) state for managing a ring of shared buffers to re-use.
--- 49,66 ----
  } BufferStrategyControl;
  
  /* Pointers to shared state */
! static BufferStrategyControl *StrategyControl[NUM_MAX_BUFFER_POOLS];
! 
! struct bufferAccessStrategyStatus
! {
! 	char name[NAMEDATALEN];
! 	int  num_buffers;
! };
! 
! struct bufferAccessStrategyStatus BufferStrategyStatus[NUM_MAX_BUFFER_POOLS] = {
! 	{"Default Buffer Strategy status", 0},
! 	{"Priority Buffer Strategy status", 0}
! };
  
  /*
   * Private (non-shared) state for managing a ring of shared buffers to re-use.
***************
*** 109,115 **** static void AddBufferToRing(BufferAccessStrategy strategy,
   *	kernel calls while holding the buffer header spinlock.
   */
  volatile BufferDesc *
! StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
  {
  	volatile BufferDesc *buf;
  	Latch	   *bgwriterLatch;
--- 120,126 ----
   *	kernel calls while holding the buffer header spinlock.
   */
  volatile BufferDesc *
! StrategyGetBuffer(int poolid, BufferAccessStrategy strategy, bool *lock_held)
  {
  	volatile BufferDesc *buf;
  	Latch	   *bgwriterLatch;
***************
*** 131,144 **** StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
  
  	/* Nope, so lock the freelist */
  	*lock_held = true;
! 	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
  
  	/*
  	 * We count buffer allocation requests so that the bgwriter can estimate
  	 * the rate of buffer consumption.  Note that buffers recycled by a
  	 * strategy object are intentionally not counted here.
  	 */
! 	StrategyControl->numBufferAllocs++;
  
  	/*
  	 * If bgwriterLatch is set, we need to waken the bgwriter, but we should
--- 142,155 ----
  
  	/* Nope, so lock the freelist */
  	*lock_held = true;
! 	LWLockAcquire(BufFreelistLock(poolid), LW_EXCLUSIVE);
  
  	/*
  	 * We count buffer allocation requests so that the bgwriter can estimate
  	 * the rate of buffer consumption.  Note that buffers recycled by a
  	 * strategy object are intentionally not counted here.
  	 */
! 	StrategyControl[poolid]->numBufferAllocs++;
  
  	/*
  	 * If bgwriterLatch is set, we need to waken the bgwriter, but we should
***************
*** 146,158 **** StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
  	 * is annoyingly tedious, but it happens at most once per bgwriter cycle,
  	 * so the performance hit is minimal.
  	 */
! 	bgwriterLatch = StrategyControl->bgwriterLatch;
  	if (bgwriterLatch)
  	{
! 		StrategyControl->bgwriterLatch = NULL;
! 		LWLockRelease(BufFreelistLock);
  		SetLatch(bgwriterLatch);
! 		LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
  	}
  
  	/*
--- 157,169 ----
  	 * is annoyingly tedious, but it happens at most once per bgwriter cycle,
  	 * so the performance hit is minimal.
  	 */
! 	bgwriterLatch = StrategyControl[poolid]->bgwriterLatch;
  	if (bgwriterLatch)
  	{
! 		StrategyControl[poolid]->bgwriterLatch = NULL;
! 		LWLockRelease(BufFreelistLock(poolid));
  		SetLatch(bgwriterLatch);
! 		LWLockAcquire(BufFreelistLock(poolid), LW_EXCLUSIVE);
  	}
  
  	/*
***************
*** 161,173 **** StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
  	 * individual buffer spinlocks, so it's OK to manipulate them without
  	 * holding the spinlock.
  	 */
! 	while (StrategyControl->firstFreeBuffer >= 0)
  	{
! 		buf = &BufferDescriptors[StrategyControl->firstFreeBuffer];
  		Assert(buf->freeNext != FREENEXT_NOT_IN_LIST);
  
  		/* Unconditionally remove buffer from freelist */
! 		StrategyControl->firstFreeBuffer = buf->freeNext;
  		buf->freeNext = FREENEXT_NOT_IN_LIST;
  
  		/*
--- 172,184 ----
  	 * individual buffer spinlocks, so it's OK to manipulate them without
  	 * holding the spinlock.
  	 */
! 	while (StrategyControl[poolid]->firstFreeBuffer >= 0)
  	{
! 		buf = &BufferDescriptors[StrategyControl[poolid]->firstFreeBuffer];
  		Assert(buf->freeNext != FREENEXT_NOT_IN_LIST);
  
  		/* Unconditionally remove buffer from freelist */
! 		StrategyControl[poolid]->firstFreeBuffer = buf->freeNext;
  		buf->freeNext = FREENEXT_NOT_IN_LIST;
  
  		/*
***************
*** 188,202 **** StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
  	}
  
  	/* Nothing on the freelist, so run the "clock sweep" algorithm */
! 	trycounter = NBuffers;
  	for (;;)
  	{
! 		buf = &BufferDescriptors[StrategyControl->nextVictimBuffer];
  
! 		if (++StrategyControl->nextVictimBuffer >= NBuffers)
  		{
! 			StrategyControl->nextVictimBuffer = 0;
! 			StrategyControl->completePasses++;
  		}
  
  		/*
--- 199,213 ----
  	}
  
  	/* Nothing on the freelist, so run the "clock sweep" algorithm */
! 	trycounter = BufferStrategyStatus[poolid].num_buffers;
  	for (;;)
  	{
! 		buf = &BufferDescriptors[StrategyControl[poolid]->nextVictimBuffer];
  
! 		if (++StrategyControl[poolid]->nextVictimBuffer >= ((poolid == 0) ? BufferStrategyStatus[poolid].num_buffers : NSharedBuffers))
  		{
! 			StrategyControl[poolid]->nextVictimBuffer = (poolid == 0) ? 0 : BufferStrategyStatus[poolid - 1].num_buffers;
! 			StrategyControl[poolid]->completePasses++;
  		}
  
  		/*
***************
*** 209,215 **** StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
  			if (buf->usage_count > 0)
  			{
  				buf->usage_count--;
! 				trycounter = NBuffers;
  			}
  			else
  			{
--- 220,226 ----
  			if (buf->usage_count > 0)
  			{
  				buf->usage_count--;
! 				trycounter = BufferStrategyStatus[poolid].num_buffers;
  			}
  			else
  			{
***************
*** 241,247 **** StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
  void
  StrategyFreeBuffer(volatile BufferDesc *buf)
  {
! 	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
  
  	/*
  	 * It is possible that we are told to put something in the freelist that
--- 252,260 ----
  void
  StrategyFreeBuffer(volatile BufferDesc *buf)
  {
! 	int poolid = buf->buf_id < NBuffers ? DEFAULT_BUFFER_POOL : PRIORITY_BUFFER_POOL;
! 
! 	LWLockAcquire(BufFreelistLock(poolid), LW_EXCLUSIVE);
  
  	/*
  	 * It is possible that we are told to put something in the freelist that
***************
*** 249,261 **** StrategyFreeBuffer(volatile BufferDesc *buf)
  	 */
  	if (buf->freeNext == FREENEXT_NOT_IN_LIST)
  	{
! 		buf->freeNext = StrategyControl->firstFreeBuffer;
  		if (buf->freeNext < 0)
! 			StrategyControl->lastFreeBuffer = buf->buf_id;
! 		StrategyControl->firstFreeBuffer = buf->buf_id;
  	}
  
! 	LWLockRelease(BufFreelistLock);
  }
  
  /*
--- 262,274 ----
  	 */
  	if (buf->freeNext == FREENEXT_NOT_IN_LIST)
  	{
! 		buf->freeNext = StrategyControl[poolid]->firstFreeBuffer;
  		if (buf->freeNext < 0)
! 			StrategyControl[poolid]->lastFreeBuffer = buf->buf_id;
! 		StrategyControl[poolid]->firstFreeBuffer = buf->buf_id;
  	}
  
! 	LWLockRelease(BufFreelistLock(poolid));
  }
  
  /*
***************
*** 270,289 **** StrategyFreeBuffer(volatile BufferDesc *buf)
   * being read.
   */
  int
! StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
  {
  	int			result;
  
! 	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
! 	result = StrategyControl->nextVictimBuffer;
  	if (complete_passes)
! 		*complete_passes = StrategyControl->completePasses;
  	if (num_buf_alloc)
  	{
! 		*num_buf_alloc = StrategyControl->numBufferAllocs;
! 		StrategyControl->numBufferAllocs = 0;
  	}
! 	LWLockRelease(BufFreelistLock);
  	return result;
  }
  
--- 283,302 ----
   * being read.
   */
  int
! StrategySyncStart(int poolid, uint32 *complete_passes, uint32 *num_buf_alloc)
  {
  	int			result;
  
! 	LWLockAcquire(BufFreelistLock(poolid), LW_EXCLUSIVE);
! 	result = StrategyControl[poolid]->nextVictimBuffer;
  	if (complete_passes)
! 		*complete_passes = StrategyControl[poolid]->completePasses;
  	if (num_buf_alloc)
  	{
! 		*num_buf_alloc = StrategyControl[poolid]->numBufferAllocs;
! 		StrategyControl[poolid]->numBufferAllocs = 0;
  	}
! 	LWLockRelease(BufFreelistLock(poolid));
  	return result;
  }
  
***************
*** 298,311 **** StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
  void
  StrategyNotifyBgWriter(Latch *bgwriterLatch)
  {
! 	/*
! 	 * We acquire the BufFreelistLock just to ensure that the store appears
! 	 * atomic to StrategyGetBuffer.  The bgwriter should call this rather
! 	 * infrequently, so there's no performance penalty from being safe.
! 	 */
! 	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
! 	StrategyControl->bgwriterLatch = bgwriterLatch;
! 	LWLockRelease(BufFreelistLock);
  }
  
  
--- 311,329 ----
  void
  StrategyNotifyBgWriter(Latch *bgwriterLatch)
  {
! 	int poolid;
! 
! 	for (poolid = 0; poolid < NUM_MAX_BUFFER_POOLS; poolid++)
! 	{
! 		/*
! 		 * We acquire the BufFreelistLock just to ensure that the store appears
! 		 * atomic to StrategyGetBuffer.  The bgwriter should call this rather
! 		 * infrequently, so there's no performance penalty from being safe.
! 		 */
! 		LWLockAcquire(BufFreelistLock(poolid), LW_EXCLUSIVE);
! 		StrategyControl[poolid]->bgwriterLatch = bgwriterLatch;
! 		LWLockRelease(BufFreelistLock(poolid));
! 	}
  }
  
  
***************
*** 318,329 **** StrategyNotifyBgWriter(Latch *bgwriterLatch)
   * is also determined here.
   */
  Size
! StrategyShmemSize(void)
  {
  	Size		size = 0;
  
  	/* size of lookup hash table ... see comment in StrategyInitialize */
! 	size = add_size(size, BufTableShmemSize(NBuffers + NUM_BUFFER_PARTITIONS));
  
  	/* size of the shared replacement strategy control block */
  	size = add_size(size, MAXALIGN(sizeof(BufferStrategyControl)));
--- 336,347 ----
   * is also determined here.
   */
  Size
! StrategyShmemSize()
  {
  	Size		size = 0;
  
  	/* size of lookup hash table ... see comment in StrategyInitialize */
! 	size = add_size(size, BufTableShmemSize(NSharedBuffers + NUM_BUFFER_PARTITIONS));
  
  	/* size of the shared replacement strategy control block */
  	size = add_size(size, MAXALIGN(sizeof(BufferStrategyControl)));
***************
*** 342,394 **** void
  StrategyInitialize(bool init)
  {
  	bool		found;
  
  	/*
  	 * Initialize the shared buffer lookup hashtable.
  	 *
  	 * Since we can't tolerate running out of lookup table entries, we must be
  	 * sure to specify an adequate table size here.  The maximum steady-state
! 	 * usage is of course NBuffers entries, but BufferAlloc() tries to insert
  	 * a new entry before deleting the old.  In principle this could be
  	 * happening in each partition concurrently, so we could need as many as
! 	 * NBuffers + NUM_BUFFER_PARTITIONS entries.
  	 */
! 	InitBufTable(NBuffers + NUM_BUFFER_PARTITIONS);
  
! 	/*
! 	 * Get or create the shared strategy control block
! 	 */
! 	StrategyControl = (BufferStrategyControl *)
! 		ShmemInitStruct("Buffer Strategy Status",
! 						sizeof(BufferStrategyControl),
! 						&found);
  
! 	if (!found)
  	{
  		/*
! 		 * Only done once, usually in postmaster
  		 */
! 		Assert(init);
  
! 		/*
! 		 * Grab the whole linked list of free buffers for our strategy. We
! 		 * assume it was previously set up by InitBufferPool().
! 		 */
! 		StrategyControl->firstFreeBuffer = 0;
! 		StrategyControl->lastFreeBuffer = NBuffers - 1;
  
! 		/* Initialize the clock sweep pointer */
! 		StrategyControl->nextVictimBuffer = 0;
  
! 		/* Clear statistics */
! 		StrategyControl->completePasses = 0;
! 		StrategyControl->numBufferAllocs = 0;
  
! 		/* No pending notification */
! 		StrategyControl->bgwriterLatch = NULL;
  	}
- 	else
- 		Assert(!init);
  }
  
  
--- 360,419 ----
  StrategyInitialize(bool init)
  {
  	bool		found;
+ 	int			poolid;
  
  	/*
  	 * Initialize the shared buffer lookup hashtable.
  	 *
  	 * Since we can't tolerate running out of lookup table entries, we must be
  	 * sure to specify an adequate table size here.  The maximum steady-state
! 	 * usage is of course NSharedBuffers entries, but BufferAlloc() tries to insert
  	 * a new entry before deleting the old.  In principle this could be
  	 * happening in each partition concurrently, so we could need as many as
! 	 * NSharedBuffers + NUM_BUFFER_PARTITIONS entries.
  	 */
! 	InitBufTable(NSharedBuffers + NUM_BUFFER_PARTITIONS);
  
! 	BufferStrategyStatus[DEFAULT_BUFFER_POOL].num_buffers = NBuffers;
! 	BufferStrategyStatus[PRIORITY_BUFFER_POOL].num_buffers = NPriorityBuffers;
  
! 	for (poolid = 0; poolid < NUM_MAX_BUFFER_POOLS; poolid++)
  	{
  		/*
! 		 * Get or create the shared strategy control block
  		 */
! 		StrategyControl[poolid] = (BufferStrategyControl *)
! 			ShmemInitStruct(BufferStrategyStatus[poolid].name,
! 							sizeof(BufferStrategyControl),
! 							&found);
  
! 		if (!found)
! 		{
! 			/*
! 			 * Only done once, usually in postmaster
! 			 */
! 			Assert(init);
  
! 			/*
! 			 * Grab the whole linked list of free buffers for our strategy. We
! 			 * assume it was previously set up by InitBufferPool().
! 			 */
! 			StrategyControl[poolid]->firstFreeBuffer = (poolid == 0) ? 0 : BufferStrategyStatus[poolid - 1].num_buffers;
! 			StrategyControl[poolid]->lastFreeBuffer = BufferStrategyStatus[poolid].num_buffers - 1;
  
! 			/* Initialize the clock sweep pointer */
! 			StrategyControl[poolid]->nextVictimBuffer = (poolid == 0) ? 0 : BufferStrategyStatus[poolid - 1].num_buffers;;
  
! 			/* Clear statistics */
! 			StrategyControl[poolid]->completePasses = 0;
! 			StrategyControl[poolid]->numBufferAllocs = 0;
! 
! 			/* No pending notification */
! 			StrategyControl[poolid]->bgwriterLatch = NULL;
! 		}
! 		else
! 			Assert(!init);
  	}
  }
  
  
***************
*** 438,444 **** GetAccessStrategy(BufferAccessStrategyType btype)
  	}
  
  	/* Make sure ring isn't an undue fraction of shared buffers */
! 	ring_size = Min(NBuffers / 8, ring_size);
  
  	/* Allocate the object and initialize all elements to zeroes */
  	strategy = (BufferAccessStrategy)
--- 463,469 ----
  	}
  
  	/* Make sure ring isn't an undue fraction of shared buffers */
! 	ring_size = Min(NSharedBuffers / 8, ring_size);
  
  	/* Allocate the object and initialize all elements to zeroes */
  	strategy = (BufferAccessStrategy)
*** a/src/backend/storage/lmgr/lwlock.c
--- b/src/backend/storage/lmgr/lwlock.c
***************
*** 229,235 **** NumLWLocks(void)
  	numLocks = NUM_FIXED_LWLOCKS;
  
  	/* bufmgr.c needs two for each shared buffer */
! 	numLocks += 2 * NBuffers;
  
  	/* proc.c needs one for each backend or auxiliary process */
  	numLocks += MaxBackends + NUM_AUXILIARY_PROCS;
--- 229,235 ----
  	numLocks = NUM_FIXED_LWLOCKS;
  
  	/* bufmgr.c needs two for each shared buffer */
! 	numLocks += 2 * NSharedBuffers;
  
  	/* proc.c needs one for each backend or auxiliary process */
  	numLocks += MaxBackends + NUM_AUXILIARY_PROCS;
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
***************
*** 3538,3544 **** PostgresMain(int argc, char *argv[],
  
  		MyStartTime = time(NULL);
  	}
! 
  	SetProcessingMode(InitProcessing);
  
  	/* Compute paths, if we didn't inherit them from postmaster */
--- 3538,3544 ----
  
  		MyStartTime = time(NULL);
  	}
! 	
  	SetProcessingMode(InitProcessing);
  
  	/* Compute paths, if we didn't inherit them from postmaster */
*** a/src/backend/utils/init/globals.c
--- b/src/backend/utils/init/globals.c
***************
*** 107,112 **** int			maintenance_work_mem = 16384;
--- 107,114 ----
   * register background workers.
   */
  int			NBuffers = 1000;
+ int			NPriorityBuffers = 0;
+ int			NSharedBuffers;
  int			MaxConnections = 90;
  int			max_worker_processes = 8;
  int			MaxBackends = 0;
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 1712,1717 **** static struct config_int ConfigureNamesInt[] =
--- 1712,1728 ----
  	},
  
  	{
+ 		{"priority_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ 			gettext_noop("Sets the number of priority buffers used by the server."),
+ 			NULL,
+ 			GUC_UNIT_BLOCKS
+ 		},
+ 		&NPriorityBuffers,
+ 		1024, 16, INT_MAX / 2,
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
  		{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
  			gettext_noop("Sets the maximum number of temporary buffers used by each session."),
  			NULL,
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 114,119 ****
--- 114,121 ----
  
  #shared_buffers = 32MB			# min 128kB
  					# (change requires restart)
+ #priority_buffers = 32MB		#Buffers used for priority tables
+ 					# (change requires restart)
  #huge_pages = try			# on, off, or try
  					# (change requires restart)
  #temp_buffers = 8MB			# min 800kB
*** a/src/include/miscadmin.h
--- b/src/include/miscadmin.h
***************
*** 126,132 **** do { \
  /*****************************************************************************
   *	  globals.h --															 *
   *****************************************************************************/
- 
  /*
   * from utils/init/globals.c
   */
--- 126,131 ----
***************
*** 140,146 **** extern bool ExitOnAnyError;
  
  extern PGDLLIMPORT char *DataDir;
  
! extern PGDLLIMPORT int NBuffers;
  extern int	MaxBackends;
  extern int	MaxConnections;
  extern int	max_worker_processes;
--- 139,145 ----
  
  extern PGDLLIMPORT char *DataDir;
  
! extern PGDLLIMPORT int NSharedBuffers;
  extern int	MaxBackends;
  extern int	MaxConnections;
  extern int	max_worker_processes;
*** a/src/include/storage/buf_internals.h
--- b/src/include/storage/buf_internals.h
***************
*** 23,28 ****
--- 23,31 ----
  #include "storage/spin.h"
  #include "utils/relcache.h"
  
+ #define NUM_MAX_BUFFER_POOLS 2
+ #define DEFAULT_BUFFER_POOL 0
+ #define PRIORITY_BUFFER_POOL 1
  
  /*
   * Flags for buffer descriptors
***************
*** 185,197 **** extern BufferDesc *LocalBufferDescriptors;
   */
  
  /* freelist.c */
! extern volatile BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy,
  				  bool *lock_held);
  extern void StrategyFreeBuffer(volatile BufferDesc *buf);
  extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
  					 volatile BufferDesc *buf);
  
! extern int	StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc);
  extern void StrategyNotifyBgWriter(Latch *bgwriterLatch);
  
  extern Size StrategyShmemSize(void);
--- 188,200 ----
   */
  
  /* freelist.c */
! extern volatile BufferDesc *StrategyGetBuffer(int poolid, BufferAccessStrategy strategy,
  				  bool *lock_held);
  extern void StrategyFreeBuffer(volatile BufferDesc *buf);
  extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
  					 volatile BufferDesc *buf);
  
! extern int	StrategySyncStart(int poolid, uint32 *complete_passes, uint32 *num_buf_alloc);
  extern void StrategyNotifyBgWriter(Latch *bgwriterLatch);
  
  extern Size StrategyShmemSize(void);
*** a/src/include/storage/bufmgr.h
--- b/src/include/storage/bufmgr.h
***************
*** 16,21 ****
--- 16,22 ----
  
  #include "storage/block.h"
  #include "storage/buf.h"
+ #include "storage/buf_internals.h"
  #include "storage/bufpage.h"
  #include "storage/relfilenode.h"
  #include "utils/relcache.h"
***************
*** 44,50 **** typedef enum
--- 45,53 ----
  } ReadBufferMode;
  
  /* in globals.c ... this duplicates miscadmin.h */
+ extern PGDLLIMPORT int NSharedBuffers;
  extern PGDLLIMPORT int NBuffers;
+ extern PGDLLIMPORT int NPriorityBuffers;
  
  /* in bufmgr.c */
  extern bool zero_damaged_pages;
***************
*** 97,103 **** extern PGDLLIMPORT int32 *LocalRefCount;
   */
  #define BufferIsValid(bufnum) \
  ( \
! 	AssertMacro((bufnum) <= NBuffers && (bufnum) >= -NLocBuffer), \
  	(bufnum) != InvalidBuffer  \
  )
  
--- 100,106 ----
   */
  #define BufferIsValid(bufnum) \
  ( \
! 	AssertMacro((bufnum) <= NSharedBuffers && (bufnum) >= -NLocBuffer), \
  	(bufnum) != InvalidBuffer  \
  )
  
*** a/src/include/storage/lwlock.h
--- b/src/include/storage/lwlock.h
***************
*** 89,133 **** extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
   * if you remove a lock, consider leaving a gap in the numbering sequence for
   * the benefit of DTrace and other external debugging scripts.
   */
! #define BufFreelistLock				(&MainLWLockArray[0].lock)
! #define ShmemIndexLock				(&MainLWLockArray[1].lock)
! #define OidGenLock					(&MainLWLockArray[2].lock)
! #define XidGenLock					(&MainLWLockArray[3].lock)
! #define ProcArrayLock				(&MainLWLockArray[4].lock)
! #define SInvalReadLock				(&MainLWLockArray[5].lock)
! #define SInvalWriteLock				(&MainLWLockArray[6].lock)
! #define WALBufMappingLock			(&MainLWLockArray[7].lock)
! #define WALWriteLock				(&MainLWLockArray[8].lock)
! #define ControlFileLock				(&MainLWLockArray[9].lock)
! #define CheckpointLock				(&MainLWLockArray[10].lock)
! #define CLogControlLock				(&MainLWLockArray[11].lock)
! #define SubtransControlLock			(&MainLWLockArray[12].lock)
! #define MultiXactGenLock			(&MainLWLockArray[13].lock)
! #define MultiXactOffsetControlLock	(&MainLWLockArray[14].lock)
! #define MultiXactMemberControlLock	(&MainLWLockArray[15].lock)
! #define RelCacheInitLock			(&MainLWLockArray[16].lock)
! #define CheckpointerCommLock		(&MainLWLockArray[17].lock)
! #define TwoPhaseStateLock			(&MainLWLockArray[18].lock)
! #define TablespaceCreateLock		(&MainLWLockArray[19].lock)
! #define BtreeVacuumLock				(&MainLWLockArray[20].lock)
! #define AddinShmemInitLock			(&MainLWLockArray[21].lock)
! #define AutovacuumLock				(&MainLWLockArray[22].lock)
! #define AutovacuumScheduleLock		(&MainLWLockArray[23].lock)
! #define SyncScanLock				(&MainLWLockArray[24].lock)
! #define RelationMappingLock			(&MainLWLockArray[25].lock)
! #define AsyncCtlLock				(&MainLWLockArray[26].lock)
! #define AsyncQueueLock				(&MainLWLockArray[27].lock)
! #define SerializableXactHashLock	(&MainLWLockArray[28].lock)
! #define SerializableFinishedListLock		(&MainLWLockArray[29].lock)
! #define SerializablePredicateLockListLock	(&MainLWLockArray[30].lock)
! #define OldSerXidLock				(&MainLWLockArray[31].lock)
! #define SyncRepLock					(&MainLWLockArray[32].lock)
! #define BackgroundWorkerLock		(&MainLWLockArray[33].lock)
! #define DynamicSharedMemoryControlLock		(&MainLWLockArray[34].lock)
! #define AutoFileLock				(&MainLWLockArray[35].lock)
! #define ReplicationSlotAllocationLock	(&MainLWLockArray[36].lock)
! #define ReplicationSlotControlLock		(&MainLWLockArray[37].lock)
! #define NUM_INDIVIDUAL_LWLOCKS		38
  
  /*
   * It's a bit odd to declare NUM_BUFFER_PARTITIONS and NUM_LOCK_PARTITIONS
--- 89,135 ----
   * if you remove a lock, consider leaving a gap in the numbering sequence for
   * the benefit of DTrace and other external debugging scripts.
   */
! #define BufFreelistLock(poolid)				(&MainLWLockArray[poolid].lock)
! #define NUM_FREELIST_LOCKS	2
! 
! #define ShmemIndexLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 1].lock)
! #define OidGenLock					(&MainLWLockArray[NUM_FREELIST_LOCKS + 2].lock)
! #define XidGenLock					(&MainLWLockArray[NUM_FREELIST_LOCKS + 3].lock)
! #define ProcArrayLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 4].lock)
! #define SInvalReadLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 5].lock)
! #define SInvalWriteLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 6].lock)
! #define WALBufMappingLock			(&MainLWLockArray[NUM_FREELIST_LOCKS + 7].lock)
! #define WALWriteLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 8].lock)
! #define ControlFileLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 9].lock)
! #define CheckpointLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 10].lock)
! #define CLogControlLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 11].lock)
! #define SubtransControlLock			(&MainLWLockArray[NUM_FREELIST_LOCKS + 12].lock)
! #define MultiXactGenLock			(&MainLWLockArray[NUM_FREELIST_LOCKS + 13].lock)
! #define MultiXactOffsetControlLock	(&MainLWLockArray[NUM_FREELIST_LOCKS + 14].lock)
! #define MultiXactMemberControlLock	(&MainLWLockArray[NUM_FREELIST_LOCKS + 15].lock)
! #define RelCacheInitLock			(&MainLWLockArray[NUM_FREELIST_LOCKS + 16].lock)
! #define CheckpointerCommLock		(&MainLWLockArray[NUM_FREELIST_LOCKS + 17].lock)
! #define TwoPhaseStateLock			(&MainLWLockArray[NUM_FREELIST_LOCKS + 18].lock)
! #define TablespaceCreateLock		(&MainLWLockArray[NUM_FREELIST_LOCKS + 19].lock)
! #define BtreeVacuumLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 20].lock)
! #define AddinShmemInitLock			(&MainLWLockArray[NUM_FREELIST_LOCKS + 21].lock)
! #define AutovacuumLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 22].lock)
! #define AutovacuumScheduleLock		(&MainLWLockArray[NUM_FREELIST_LOCKS + 23].lock)
! #define SyncScanLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 24].lock)
! #define RelationMappingLock			(&MainLWLockArray[NUM_FREELIST_LOCKS + 25].lock)
! #define AsyncCtlLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 26].lock)
! #define AsyncQueueLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 27].lock)
! #define SerializableXactHashLock	(&MainLWLockArray[NUM_FREELIST_LOCKS + 28].lock)
! #define SerializableFinishedListLock		(&MainLWLockArray[NUM_FREELIST_LOCKS + 29].lock)
! #define SerializablePredicateLockListLock	(&MainLWLockArray[NUM_FREELIST_LOCKS + 30].lock)
! #define OldSerXidLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 31].lock)
! #define SyncRepLock					(&MainLWLockArray[NUM_FREELIST_LOCKS + 32].lock)
! #define BackgroundWorkerLock		(&MainLWLockArray[NUM_FREELIST_LOCKS + 33].lock)
! #define DynamicSharedMemoryControlLock		(&MainLWLockArray[NUM_FREELIST_LOCKS + 34].lock)
! #define AutoFileLock				(&MainLWLockArray[NUM_FREELIST_LOCKS + 35].lock)
! #define ReplicationSlotAllocationLock	(&MainLWLockArray[NUM_FREELIST_LOCKS + 36].lock)
! #define ReplicationSlotControlLock		(&MainLWLockArray[NUM_FREELIST_LOCKS + 37].lock)
! #define NUM_INDIVIDUAL_LWLOCKS		NUM_FREELIST_LOCKS + 37
  
  /*
   * It's a bit odd to declare NUM_BUFFER_PARTITIONS and NUM_LOCK_PARTITIONS
*** a/src/include/utils/rel.h
--- b/src/include/utils/rel.h
***************
*** 215,220 **** typedef struct StdRdOptions
--- 215,221 ----
  {
  	int32		vl_len_;		/* varlena header (do not touch directly!) */
  	int			fillfactor;		/* page fill factor in percent (0..100) */
+ 	int			bufferpool_offset;		/* Buffer Pool option */
  	AutoVacOpts autovacuum;		/* autovacuum-related options */
  	bool		security_barrier;		/* for views */
  	int			check_option_offset;	/* for views */
***************
*** 248,253 **** typedef struct StdRdOptions
--- 249,265 ----
  	(BLCKSZ * (100 - RelationGetFillFactor(relation, defaultff)) / 100)
  
  /*
+  * RelationIsInPriorityBufferPool
+  *		Returns the relation's buffer pool.  
+  */
+ #define RelationIsInPriorityBufferPool(relation) \
+ 	((relation)->rd_options &&												\
+ 	 ((StdRdOptions *) (relation)->rd_options)->bufferpool_offset != 0 ?	\
+ 	 strcmp((char *) (relation)->rd_options +								\
+ 			((StdRdOptions *) (relation)->rd_options)->bufferpool_offset,	\
+ 			"priority") == 0 : false)
+ 
+ /*
   * RelationIsSecurityView
   *		Returns whether the relation is security view, or not
   */