*** a/src/backend/access/common/reloptions.c --- b/src/backend/access/common/reloptions.c *************** *** 85,90 **** static relopt_bool boolRelOpts[] = --- 85,98 ---- }, false }, + { + { + "buffer_cache", + "Enables buffer_cache option Table/Index.", + RELOPT_KIND_HEAP | RELOPT_KIND_BTREE + }, + false + }, /* list terminator */ {{NULL}} }; *************** *** 1230,1236 **** default_reloptions(Datum reloptions, bool validate, relopt_kind kind) {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL, offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, analyze_scale_factor)}, {"user_catalog_table", RELOPT_TYPE_BOOL, ! offsetof(StdRdOptions, user_catalog_table)} }; options = parseRelOptions(reloptions, validate, kind, &numoptions); --- 1238,1246 ---- {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL, offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, analyze_scale_factor)}, {"user_catalog_table", RELOPT_TYPE_BOOL, ! offsetof(StdRdOptions, user_catalog_table)}, ! {"buffer_cache", RELOPT_TYPE_BOOL, ! offsetof(StdRdOptions, buffer_cache) } }; options = parseRelOptions(reloptions, validate, kind, &numoptions); *** a/src/backend/storage/buffer/buf_init.c --- b/src/backend/storage/buffer/buf_init.c *************** *** 18,23 **** --- 18,24 ---- #include "storage/buf_internals.h" + BufferPoolHeader *BufferPool; BufferDescPadded *BufferDescriptors; char *BufferBlocks; *************** *** 65,71 **** void InitBufferPool(void) { bool foundBufs, ! foundDescs; /* Align descriptors to a cacheline boundary. */ BufferDescriptors = (BufferDescPadded *) CACHELINEALIGN( --- 66,78 ---- InitBufferPool(void) { bool foundBufs, ! foundDescs, ! foundPoolHeader; ! ! /* Initialize the Buffer Pool Header data */ ! BufferPool = (BufferPoolHeader *) ! ShmemInitStruct("Buffer pool", ! sizeof(BufferPoolHeader), &foundPoolHeader); /* Align descriptors to a cacheline boundary. */ BufferDescriptors = (BufferDescPadded *) CACHELINEALIGN( *************** *** 116,121 **** InitBufferPool(void) --- 123,131 ---- /* Correct last entry of linked list */ GetBufferDescriptor(NBuffers - 1)->freeNext = FREENEXT_END_OF_LIST; + + pg_atomic_init_u32(&BufferPool->current_buffer_cache_pages, 0); + pg_atomic_init_u32(&BufferPool->max_buffer_cache_pages,((NBuffers * buffer_cache_ratio) / 100)); } /* Init other shared buffer-management stuff */ *************** *** 133,138 **** BufferShmemSize(void) --- 143,151 ---- { Size size = 0; + /* size of buffer Pool Header */ + size = add_size(size, sizeof(BufferPoolHeader)); + /* size of buffer descriptors */ size = add_size(size, mul_size(NBuffers, sizeof(BufferDescPadded))); /* to allow aligning buffer descriptors */ *** a/src/backend/storage/buffer/bufmgr.c --- b/src/backend/storage/buffer/bufmgr.c *************** *** 1171,1182 **** BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, * 1 so that the buffer can survive one clock-sweep pass.) */ buf->tag = newTag; ! buf->flags &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_CHECKPOINT_NEEDED | BM_IO_ERROR | BM_PERMANENT); if (relpersistence == RELPERSISTENCE_PERMANENT) buf->flags |= BM_TAG_VALID | BM_PERMANENT; else buf->flags |= BM_TAG_VALID; buf->usage_count = 1; UnlockBufHdr(buf); --- 1171,1196 ---- * 1 so that the buffer can survive one clock-sweep pass.) */ buf->tag = newTag; ! buf->flags &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_CHECKPOINT_NEEDED | BM_IO_ERROR | BM_PERMANENT | BM_BUFFER_CACHE_PAGE); if (relpersistence == RELPERSISTENCE_PERMANENT) buf->flags |= BM_TAG_VALID | BM_PERMANENT; else buf->flags |= BM_TAG_VALID; buf->usage_count = 1; + + if ((oldFlags & BM_BUFFER_CACHE_PAGE) && (smgr->is_a_buffer_cache_rel)) + { + buf->flags |= BM_BUFFER_CACHE_PAGE; + } + else if (smgr->is_a_buffer_cache_rel) + { + buf->flags |= BM_BUFFER_CACHE_PAGE; + increment_buffer_cache_pages_counter(); + } + else if (oldFlags & BM_BUFFER_CACHE_PAGE) + { + decrement_buffer_cache_pages_counter(); + } UnlockBufHdr(buf); *************** *** 1288,1293 **** retry: --- 1302,1310 ---- buf->flags = 0; buf->usage_count = 0; + if (oldFlags & BM_BUFFER_CACHE_PAGE) + decrement_buffer_cache_pages_counter(); + UnlockBufHdr(buf); /* *** a/src/backend/storage/buffer/freelist.c --- b/src/backend/storage/buffer/freelist.c *************** *** 101,106 **** typedef struct BufferAccessStrategyData --- 101,129 ---- static volatile BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy); static void AddBufferToRing(BufferAccessStrategy strategy, volatile BufferDesc *buf); + static bool is_buffer_cache_ratio_reached(void); + + void + decrement_buffer_cache_pages_counter() + { + pg_atomic_fetch_sub_u32(&BufferPool->current_buffer_cache_pages, 1); + } + + void + increment_buffer_cache_pages_counter() + { + pg_atomic_fetch_add_u32(&BufferPool->current_buffer_cache_pages, 1); + } + + static bool + is_buffer_cache_ratio_reached() + { + uint32 current_pages = pg_atomic_read_u32(&BufferPool->current_buffer_cache_pages); + uint32 max_pages = pg_atomic_read_u32(&BufferPool->max_buffer_cache_pages); + + return (current_pages < max_pages) ? false : true; + } + /* * ClockSweepTick - Helper routine for StrategyGetBuffer() *************** *** 305,313 **** StrategyGetBuffer(BufferAccessStrategy strategy) LockBufHdr(buf); if (buf->refcount == 0) { ! if (buf->usage_count > 0) { buf->usage_count--; trycounter = NBuffers; } else --- 328,341 ---- LockBufHdr(buf); if (buf->refcount == 0) { ! if ((buf->flags & BM_BUFFER_CACHE_PAGE) && !is_buffer_cache_ratio_reached()) ! { ! trycounter = NBuffers; ! } ! else if (buf->usage_count > 0) { buf->usage_count--; + trycounter = NBuffers; } else *** a/src/backend/utils/init/globals.c --- b/src/backend/utils/init/globals.c *************** *** 116,121 **** int maintenance_work_mem = 16384; --- 116,122 ---- * register background workers. */ int NBuffers = 1000; + int buffer_cache_ratio = 0; 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 *************** *** 1811,1816 **** static struct config_int ConfigureNamesInt[] = --- 1811,1826 ---- }, { + { "buffer_cache_ratio", PGC_POSTMASTER, RESOURCES_MEM, + gettext_noop("Sets the number of buffer cache ratio can be used for buffer cache relations from shared memory."), + NULL + }, + &buffer_cache_ratio, + 0, 0, 75, + 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,122 ---- #shared_buffers = 32MB # min 128kB # (change requires restart) + #buffer_cache_ratio = 0; #specifies the ratio of shared buffers + #used for buffer cache relations + #(change requires restart) #huge_pages = try # on, off, or try # (change requires restart) #temp_buffers = 8MB # min 800kB *** a/src/bin/pgbench/pgbench.c --- b/src/bin/pgbench/pgbench.c *************** *** 1930,1938 **** init(bool is_no_vacuum) } }; static const char *const DDLINDEXes[] = { ! "alter table pgbench_branches add primary key (bid)", ! "alter table pgbench_tellers add primary key (tid)", ! "alter table pgbench_accounts add primary key (aid)" }; static const char *const DDLKEYs[] = { "alter table pgbench_tellers add foreign key (bid) references pgbench_branches", --- 1930,1938 ---- } }; static const char *const DDLINDEXes[] = { ! "alter table pgbench_branches add primary key (bid) with (buffer_cache=true)", ! "alter table pgbench_tellers add primary key (tid) with (buffer_cache=true)", ! "alter table pgbench_accounts add primary key (aid) with (buffer_cache=true)" }; static const char *const DDLKEYs[] = { "alter table pgbench_tellers add foreign key (bid) references pgbench_branches", *************** *** 1973,1979 **** init(bool is_no_vacuum) opts[0] = '\0'; if (ddl->declare_fillfactor) snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts), ! " with (fillfactor=%d)", fillfactor); if (tablespace != NULL) { char *escape_tablespace; --- 1973,1983 ---- opts[0] = '\0'; if (ddl->declare_fillfactor) snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts), ! " with (fillfactor=%d", fillfactor); ! ! snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts), ! "%s buffer_cache=true)", ddl->declare_fillfactor ? ",":" with ("); ! if (tablespace != NULL) { char *escape_tablespace; *** a/src/include/storage/buf_internals.h --- b/src/include/storage/buf_internals.h *************** *** 40,45 **** --- 40,46 ---- #define BM_CHECKPOINT_NEEDED (1 << 7) /* must write for checkpoint */ #define BM_PERMANENT (1 << 8) /* permanent relation (not * unlogged) */ + #define BM_BUFFER_CACHE_PAGE (1 << 9) /* Buffer used by a buffer cache rel */ typedef bits16 BufFlags; *************** *** 227,232 **** extern void StrategyNotifyBgWriter(int bgwprocno); --- 228,236 ---- extern Size StrategyShmemSize(void); extern void StrategyInitialize(bool init); + extern void decrement_buffer_cache_pages_counter(void); + extern void increment_buffer_cache_pages_counter(void); + /* buf_table.c */ extern Size BufTableShmemSize(int size); extern void InitBufTable(int size); *** a/src/include/storage/bufmgr.h --- b/src/include/storage/bufmgr.h *************** *** 14,19 **** --- 14,20 ---- #ifndef BUFMGR_H #define BUFMGR_H + #include "port/atomics.h" #include "storage/block.h" #include "storage/buf.h" #include "storage/bufpage.h" *************** *** 45,52 **** typedef enum --- 46,61 ---- * replay; otherwise same as RBM_NORMAL */ } ReadBufferMode; + typedef struct BufferPoolHeader + { + pg_atomic_uint32 max_buffer_cache_pages; + pg_atomic_uint32 current_buffer_cache_pages; + } BufferPoolHeader; + /* in globals.c ... this duplicates miscadmin.h */ extern PGDLLIMPORT int NBuffers; + extern int buffer_cache_ratio; + extern BufferPoolHeader *BufferPool; /* in bufmgr.c */ extern bool zero_damaged_pages; *** a/src/include/storage/smgr.h --- b/src/include/storage/smgr.h *************** *** 56,61 **** typedef struct SMgrRelationData --- 56,63 ---- BlockNumber smgr_fsm_nblocks; /* last known size of fsm fork */ BlockNumber smgr_vm_nblocks; /* last known size of vm fork */ + bool is_a_buffer_cache_rel; /* Flag to indicate the relation buffer_cache */ + /* additional public fields may someday exist here */ /* *** a/src/include/utils/rel.h --- b/src/include/utils/rel.h *************** *** 220,225 **** typedef struct StdRdOptions --- 220,227 ---- AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog * relation */ + bool buffer_cache; /* Use buffer cache for relation + * if available */ } StdRdOptions; #define HEAP_MIN_FILLFACTOR 10 *************** *** 256,261 **** typedef struct StdRdOptions --- 258,270 ---- ((relation)->rd_options ? \ ((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false) + /* + * RelationUsesBufferCache + * Returns the relation's buffer_cache option. + */ + #define RelationUsesBufferCache(relation) \ + ((relation)->rd_options ? \ + ((StdRdOptions *) (relation)->rd_options)->buffer_cache : false) /* * ViewOptions *************** *** 390,395 **** typedef struct ViewOptions --- 399,405 ---- do { \ if ((relation)->rd_smgr == NULL) \ smgrsetowner(&((relation)->rd_smgr), smgropen((relation)->rd_node, (relation)->rd_backend)); \ + (relation)->rd_smgr->is_a_buffer_cache_rel = RelationUsesBufferCache(relation); \ } while (0) /*