*** a/doc/src/sgml/config.sgml --- b/doc/src/sgml/config.sgml *************** *** 1162,1167 **** include 'filename' --- 1162,1183 ---- + + gin_fast_limit (integer) + + gin_fast_limit configuration parameter + + + + Specifies the amount of memory to be used by the fastgin cache before writing + to the GIN index itself. The value defaults to 128kB. + The fastgin cache is more effective when it is small. The size of gin_fast_limit + should be kept significantly lower than work_mem. A value of 0 will turn off + the cache entirely. This global can be overridden by the index setting fast_cache_size. + + + + max_stack_depth (integer) *** a/doc/src/sgml/ref/create_index.sgml --- b/doc/src/sgml/ref/create_index.sgml *************** *** 355,360 **** CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ name + + FAST_CACHE_SIZE + + + This setting controls the size of the fast update cache described in + . The parameter describes the size (in kB) + of the fast update cache. A value of -1 indicates that the index will + use the current global size (gin_fast_limit). However, if the + value is above -1, the index-specific value will be used. + The default is -1. + + + *** a/src/backend/access/common/reloptions.c --- b/src/backend/access/common/reloptions.c *************** *** 177,182 **** static relopt_int intRelOpts[] = --- 177,189 ---- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST }, -1, 0, 2000000000 }, + { + { + "fast_cache_size", + "Size of the fast gin cache, in kB", + RELOPT_KIND_GIN + }, -1, 0, INT_MAX + }, /* list terminator */ {{NULL}} }; *** a/src/backend/access/gin/ginfast.c --- b/src/backend/access/gin/ginfast.c *************** *** 28,33 **** --- 28,40 ---- #define GIN_PAGE_FREESIZE \ ( BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(GinPageOpaqueData)) ) + #define GET_RELATION_LIMIT(relation) \ + ((relation)->rd_options ? \ + ((GinOptions *) (relation)->rd_options)->fastCacheSize : (-1)) + + #define HAS_RELATION_LIMIT(relation) \ + (GET_RELATION_LIMIT(relation) > -1) + typedef struct KeyArray { Datum *keys; /* expansible array */ *************** *** 426,433 **** ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector) * * ginInsertCleanup() should not be called inside our CRIT_SECTION. */ ! if (metadata->nPendingPages * GIN_PAGE_FREESIZE > work_mem * 1024L) needCleanup = true; UnlockReleaseBuffer(metabuffer); --- 433,450 ---- * * ginInsertCleanup() should not be called inside our CRIT_SECTION. */ ! ! if (HAS_RELATION_LIMIT(index)) ! { ! if (metadata->nPendingPages * GIN_PAGE_FREESIZE > GET_RELATION_LIMIT(index) * 1024L) ! { ! needCleanup = true; ! } ! } ! else if (metadata->nPendingPages * GIN_PAGE_FREESIZE > gin_fast_limit * 1024L) ! { needCleanup = true; + } UnlockReleaseBuffer(metabuffer); *** a/src/backend/access/gin/gininsert.c --- b/src/backend/access/gin/gininsert.c *************** *** 586,591 **** gininsert(PG_FUNCTION_ARGS) --- 586,592 ---- if (GinGetUseFastUpdate(index)) { + // elog(NOTICE, "using fast update"); GinTupleCollector collector; memset(&collector, 0, sizeof(GinTupleCollector)); *************** *** 600,605 **** gininsert(PG_FUNCTION_ARGS) --- 601,607 ---- } else { + // elog(NOTICE, "not using fast update"); for (i = 0; i < ginstate.origTupdesc->natts; i++) ginHeapTupleInsert(&ginstate, (OffsetNumber) (i + 1), values[i], isnull[i], *** a/src/backend/access/gin/ginutil.c --- b/src/backend/access/gin/ginutil.c *************** *** 501,507 **** ginoptions(PG_FUNCTION_ARGS) GinOptions *rdopts; int numoptions; static const relopt_parse_elt tab[] = { ! {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)} }; options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIN, --- 501,508 ---- GinOptions *rdopts; int numoptions; static const relopt_parse_elt tab[] = { ! {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)}, ! {"fast_cache_size", RELOPT_TYPE_INT, offsetof(GinOptions, fastCacheSize)} }; options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIN, *************** *** 599,601 **** ginUpdateStats(Relation index, const GinStatsData *stats) --- 600,640 ---- END_CRIT_SECTION(); } + + /* + * Used to check if the gin fast cache should be used. + * Use the gin_fast_limit global to turn off the cache entirely. + * The per-index sizes will kick in if the user has set a size and enabled fastCacheSize + */ + bool + GinGetUseFastUpdate(Relation relation) + { + if((relation)->rd_options) + { + if( ((GinOptions *) (relation)->rd_options)->fastCacheSize > 0 + && ((GinOptions *) (relation)->rd_options)->useFastUpdate) + { + return true; + } + else if(!((GinOptions *) (relation)->rd_options)->useFastUpdate) + { + return false; + } + else if(gin_fast_limit > 0) + { + return true; + } + else + { + return false; + } + } + else if(gin_fast_limit > 0) + { + return true; + } + else + { + return false; + } + } *** a/src/backend/utils/init/globals.c --- b/src/backend/utils/init/globals.c *************** *** 99,104 **** int CTimeZone = 0; --- 99,105 ---- bool enableFsync = true; bool allowSystemTableMods = false; int work_mem = 1024; + int gin_fast_limit = 128; int maintenance_work_mem = 16384; /* *** a/src/backend/utils/misc/guc.c --- b/src/backend/utils/misc/guc.c *************** *** 1711,1716 **** static struct config_int ConfigureNamesInt[] = --- 1711,1728 ---- }, { + {"gin_fast_limit", PGC_USERSET, RESOURCES_MEM, + gettext_noop("Sets the maximum memory to be used for fastgin operations."), + gettext_noop("This represents the maximum amount of space stored in " + "the fast gin cache."), + GUC_UNIT_KB + }, + &gin_fast_limit, + 128, 0, MAX_KILOBYTES, + NULL, NULL, NULL + }, + + { {"maintenance_work_mem", PGC_USERSET, RESOURCES_MEM, gettext_noop("Sets the maximum memory to be used for maintenance operations."), gettext_noop("This includes operations such as VACUUM and CREATE INDEX."), *** a/src/backend/utils/misc/postgresql.conf.sample --- b/src/backend/utils/misc/postgresql.conf.sample *************** *** 121,126 **** --- 121,127 ---- # It is not advisable to set max_prepared_transactions nonzero unless you # actively intend to use prepared transactions. #work_mem = 1MB # min 64kB + #gin_fast_limit = 128kB # min 0kB #maintenance_work_mem = 16MB # min 1MB #max_stack_depth = 2MB # min 100kB *** a/src/include/access/gin.h --- b/src/include/access/gin.h *************** *** 46,52 **** typedef struct GinStatsData int32 ginVersion; } GinStatsData; ! /* GUC parameter */ extern PGDLLIMPORT int GinFuzzySearchLimit; /* ginutil.c */ --- 46,52 ---- int32 ginVersion; } GinStatsData; ! /* GUC parameters */ extern PGDLLIMPORT int GinFuzzySearchLimit; /* ginutil.c */ *** a/src/include/access/gin_private.h --- b/src/include/access/gin_private.h *************** *** 262,275 **** typedef struct GinOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ bool useFastUpdate; /* use fast updates? */ } GinOptions; - #define GIN_DEFAULT_USE_FASTUPDATE true - #define GinGetUseFastUpdate(relation) \ - ((relation)->rd_options ? \ - ((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE) - - /* Macros for buffer lock/unlock operations */ #define GIN_UNLOCK BUFFER_LOCK_UNLOCK #define GIN_SHARE BUFFER_LOCK_SHARE --- 262,270 ---- { int32 vl_len_; /* varlena header (do not touch directly!) */ bool useFastUpdate; /* use fast updates? */ + int32 fastCacheSize; /* cachesize - independent of work_mem */ } GinOptions; /* Macros for buffer lock/unlock operations */ #define GIN_UNLOCK BUFFER_LOCK_UNLOCK #define GIN_SHARE BUFFER_LOCK_SHARE *************** *** 443,448 **** extern int ginCompareAttEntries(GinState *ginstate, --- 438,444 ---- extern Datum *ginExtractEntries(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories); + extern bool GinGetUseFastUpdate(Relation relation); extern OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple); extern Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, *** a/src/include/miscadmin.h --- b/src/include/miscadmin.h *************** *** 230,235 **** extern int CTimeZone; --- 230,236 ---- extern bool enableFsync; extern bool allowSystemTableMods; extern PGDLLIMPORT int work_mem; + extern PGDLLIMPORT int gin_fast_limit; extern PGDLLIMPORT int maintenance_work_mem; extern int VacuumCostPageHit;