cache_table_poc.patch
application/octet-stream
Filename: cache_table_poc.patch
Type: application/octet-stream
Part: 1
Message:
Re: Priority table or Cache table
Patch
Format: context
| File | + | − |
|---|---|---|
| contrib/pg_buffercache/pg_buffercache_pages.c | 3 | 0 |
| src/backend/access/common/reloptions.c | 34 | 0 |
| src/backend/access/transam/clog.c | 1 | 0 |
| src/backend/access/transam/xlog.c | 4 | 0 |
| src/backend/optimizer/path/costsize.c | 2 | 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
***************
*** 100,109 **** 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 */
--- 100,109 ----
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 */
***************
*** 122,128 **** 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);
--- 122,128 ----
* 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,
***************
*** 1205,1211 **** default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{"check_option", RELOPT_TYPE_STRING,
offsetof(StdRdOptions, check_option_offset)},
{"user_catalog_table", RELOPT_TYPE_BOOL,
! offsetof(StdRdOptions, user_catalog_table)}
};
options = parseRelOptions(reloptions, validate, kind, &numoptions);
--- 1220,1226 ----
{"check_option", RELOPT_TYPE_STRING,
offsetof(StdRdOptions, check_option_offset)},
{"user_catalog_table", RELOPT_TYPE_BOOL,
! offsetof(StdRdOptions, user_catalog_table)}
};
options = parseRelOptions(reloptions, validate, kind, &numoptions);
***************
*** 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
***************
*** 5048,5054 **** XLOGChooseNumBuffers(void)
{
int xbuffers;
! xbuffers = NBuffers / 32;
if (xbuffers > XLOG_SEG_SIZE / XLOG_BLCKSZ)
xbuffers = XLOG_SEG_SIZE / XLOG_BLCKSZ;
if (xbuffers < 8)
--- 5048,5054 ----
{
int xbuffers;
! xbuffers = NSharedBuffers / 32;
if (xbuffers > XLOG_SEG_SIZE / XLOG_BLCKSZ)
xbuffers = XLOG_SEG_SIZE / XLOG_BLCKSZ;
if (xbuffers < 8)
***************
*** 8194,8200 **** 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,
--- 8194,8200 ----
"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,
***************
*** 8210,8216 **** 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,
--- 8210,8216 ----
"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,
***************
*** 8651,8657 **** 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);
--- 8651,8657 ----
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/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
***************
*** 4118,4125 **** check_effective_cache_size(int *newval, void **extra, GucSource source)
/*
* Otherwise, substitute the auto-tune value, being wary of overflow.
*/
! if (NBuffers < INT_MAX / 4)
! *newval = NBuffers * 4;
else
*newval = INT_MAX;
}
--- 4118,4125 ----
/*
* Otherwise, substitute the auto-tune value, being wary of overflow.
*/
! if (NSharedBuffers < INT_MAX / 4)
! *newval = NSharedBuffers * 4;
else
*newval = INT_MAX;
}
*** 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
***************
*** 87,93 **** 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);
--- 87,93 ----
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);
***************
*** 102,108 **** 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,
--- 102,108 ----
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,
***************
*** 232,237 **** ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
--- 232,238 ----
ReadBufferMode mode, BufferAccessStrategy strategy)
{
bool hit;
+ int poolid;
Buffer buf;
/* Open it at the smgr level if not already done */
***************
*** 252,258 **** 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);
--- 253,261 ----
* 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);
***************
*** 279,286 **** ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
SMgrRelation smgr = smgropen(rnode, InvalidBackendId);
Assert(InRecovery);
!
! return ReadBuffer_common(smgr, RELPERSISTENCE_PERMANENT, forkNum, blockNum,
mode, strategy, &hit);
}
--- 282,288 ----
SMgrRelation smgr = smgropen(rnode, InvalidBackendId);
Assert(InRecovery);
! return ReadBuffer_common(DEFAULT_BUFFER_POOL, smgr, RELPERSISTENCE_PERMANENT, forkNum, blockNum,
mode, strategy, &hit);
}
***************
*** 291,297 **** 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)
{
--- 293,299 ----
* *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)
{
***************
*** 333,339 **** 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++;
--- 335,341 ----
* 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++;
***************
*** 532,538 **** 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)
--- 534,540 ----
* 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)
***************
*** 613,619 **** 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);
--- 615,621 ----
* 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);
***************
*** 625,631 **** 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
--- 627,633 ----
/* 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
***************
*** 1246,1252 **** 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];
--- 1248,1254 ----
* 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];
***************
*** 1268,1274 **** 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
--- 1270,1276 ----
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
***************
*** 1278,1285 **** 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)
{
--- 1280,1287 ----
* 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)
{
***************
*** 1326,1342 **** 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);
}
/*
--- 1328,1343 ----
}
}
! 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);
}
/*
***************
*** 1389,1635 **** 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 */
--- 1390,1640 ----
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);
!
! 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 */
***************
*** 1717,1723 **** AtEOXact_Buffers(bool isCommit)
int RefCountErrors = 0;
Buffer b;
! for (b = 1; b <= NBuffers; b++)
{
if (PrivateRefCount[b - 1] != 0)
{
--- 1722,1728 ----
int RefCountErrors = 0;
Buffer b;
! for (b = 1; b <= NSharedBuffers; b++)
{
if (PrivateRefCount[b - 1] != 0)
{
***************
*** 1763,1769 **** AtProcExit_Buffers(int code, Datum arg)
int RefCountErrors = 0;
Buffer b;
! for (b = 1; b <= NBuffers; b++)
{
if (PrivateRefCount[b - 1] != 0)
{
--- 1768,1774 ----
int RefCountErrors = 0;
Buffer b;
! for (b = 1; b <= NSharedBuffers; b++)
{
if (PrivateRefCount[b - 1] != 0)
{
***************
*** 2144,2150 **** DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum,
return;
}
! for (i = 0; i < NBuffers; i++)
{
volatile BufferDesc *bufHdr = &BufferDescriptors[i];
--- 2149,2155 ----
return;
}
! for (i = 0; i < NSharedBuffers; i++)
{
volatile BufferDesc *bufHdr = &BufferDescriptors[i];
***************
*** 2233,2239 **** 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];
--- 2238,2244 ----
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];
***************
*** 2298,2304 **** DropDatabaseBuffers(Oid dbid)
* database isn't our own.
*/
! for (i = 0; i < NBuffers; i++)
{
volatile BufferDesc *bufHdr = &BufferDescriptors[i];
--- 2303,2309 ----
* database isn't our own.
*/
! for (i = 0; i < NSharedBuffers; i++)
{
volatile BufferDesc *bufHdr = &BufferDescriptors[i];
***************
*** 2331,2337 **** PrintBufferDescs(void)
int i;
volatile BufferDesc *buf = BufferDescriptors;
! for (i = 0; i < NBuffers; ++i, ++buf)
{
/* theoretically we should lock the bufhdr here */
elog(LOG,
--- 2336,2342 ----
int i;
volatile BufferDesc *buf = BufferDescriptors;
! for (i = 0; i < NSharedBuffers; ++i, ++buf)
{
/* theoretically we should lock the bufhdr here */
elog(LOG,
***************
*** 2352,2358 **** PrintPinnedBufs(void)
int i;
volatile BufferDesc *buf = BufferDescriptors;
! for (i = 0; i < NBuffers; ++i, ++buf)
{
if (PrivateRefCount[i] > 0)
{
--- 2357,2363 ----
int i;
volatile BufferDesc *buf = BufferDescriptors;
! for (i = 0; i < NSharedBuffers; ++i, ++buf)
{
if (PrivateRefCount[i] > 0)
{
***************
*** 2437,2443 **** FlushRelationBuffers(Relation rel)
/* Make sure we can handle the pin inside the loop */
ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
! for (i = 0; i < NBuffers; i++)
{
bufHdr = &BufferDescriptors[i];
--- 2442,2448 ----
/* Make sure we can handle the pin inside the loop */
ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
! for (i = 0; i < NSharedBuffers; i++)
{
bufHdr = &BufferDescriptors[i];
***************
*** 2487,2493 **** FlushDatabaseBuffers(Oid dbid)
/* Make sure we can handle the pin inside the loop */
ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
! for (i = 0; i < NBuffers; i++)
{
bufHdr = &BufferDescriptors[i];
--- 2492,2498 ----
/* 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
***************
*** 219,225 **** 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;
--- 219,225 ----
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
***************
*** 217,222 **** typedef struct StdRdOptions
--- 217,223 ----
{
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 */
***************
*** 249,254 **** typedef struct StdRdOptions
--- 250,266 ----
(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
*/