]> granicus.if.org Git - postgresql/commitdiff
Add GUC and storage parameter to set the maximum size of GIN pending list.
authorFujii Masao <fujii@postgresql.org>
Tue, 11 Nov 2014 12:08:21 +0000 (21:08 +0900)
committerFujii Masao <fujii@postgresql.org>
Tue, 11 Nov 2014 12:08:21 +0000 (21:08 +0900)
Previously the maximum size of GIN pending list was controlled only by
work_mem. But the reasonable value of work_mem and the reasonable size
of the list are basically not the same, so it was not appropriate to
control both of them by only one GUC, i.e., work_mem. This commit
separates new GUC, pending_list_cleanup_size, from work_mem to allow
users to control only the size of the list.

Also this commit adds pending_list_cleanup_size as new storage parameter
to allow users to specify the size of the list per index. This is useful,
for example, when users want to increase the size of the list only for
the GIN index which can be updated heavily, and decrease it otherwise.

Reviewed by Etsuro Fujita.

16 files changed:
doc/src/sgml/config.sgml
doc/src/sgml/gin.sgml
doc/src/sgml/gist.sgml
doc/src/sgml/ref/cluster.sgml
doc/src/sgml/ref/create_index.sgml
src/backend/access/common/reloptions.c
src/backend/access/gin/ginfast.c
src/backend/access/gin/ginutil.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/bin/psql/tab-complete.c
src/include/access/gin.h
src/include/access/gin_private.h
src/include/utils/guc.h
src/test/regress/expected/create_index.out
src/test/regress/sql/create_index.sql

index 47b11922455efb599bf3a528692add0715c2dcdb..6bfb7bbc112b2c6fbe30b867e272492b284e1323 100644 (file)
@@ -5911,6 +5911,27 @@ SET XML OPTION { DOCUMENT | CONTENT };
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-pending-list-cleanup-size" xreflabel="pending_list_cleanup_size">
+      <term><varname>pending_list_cleanup_size</varname> (<type>integer</type>)
+      <indexterm>
+       <primary><varname>pending_list_cleanup_size</> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Sets the maximum size of the GIN pending list which is used
+        when <literal>fastupdate</> is enabled. If the list grows
+        larger than this maximum size, it is cleaned up by moving
+        the entries in it to the main GIN data structure in bulk.
+        The default is four megabytes (<literal>4MB</>). This setting
+        can be overridden for individual GIN indexes by changing
+        storage parameters.
+         See <xref linkend="gin-fast-update"> and <xref linkend="gin-tips">
+         for more information.
+       </para>
+      </listitem>
+     </varlistentry>
+
      </variablelist>
     </sect2>
      <sect2 id="runtime-config-client-format">
index 8443c01f6f73958181594b2d64157b6057d73919..94d2d5c19d95b9d8054963d52fe0d37a072e089e 100644 (file)
    from the indexed item). As of <productname>PostgreSQL</productname> 8.4,
    <acronym>GIN</> is capable of postponing much of this work by inserting
    new tuples into a temporary, unsorted list of pending entries.
-   When the table is vacuumed, or if the pending list becomes too large
-   (larger than <xref linkend="guc-work-mem">), the entries are moved to the
+   When the table is vacuumed, or if the pending list becomes larger than
+   <xref linkend="guc-pending-list-cleanup-size">, the entries are moved to the
    main <acronym>GIN</acronym> data structure using the same bulk insert
    techniques used during initial index creation.  This greatly improves
    <acronym>GIN</acronym> index update speed, even counting the additional
   <para>
    If consistent response time is more important than update speed,
    use of pending entries can be disabled by turning off the
-   <literal>FASTUPDATE</literal> storage parameter for a
+   <literal>fastupdate</literal> storage parameter for a
    <acronym>GIN</acronym> index.  See <xref linkend="sql-createindex">
    for details.
   </para>
   </varlistentry>
 
   <varlistentry>
-   <term><xref linkend="guc-work-mem"></term>
+   <term><xref linkend="guc-pending-list-cleanup-size"></term>
    <listitem>
     <para>
      During a series of insertions into an existing <acronym>GIN</acronym>
-     index that has <literal>FASTUPDATE</> enabled, the system will clean up
+     index that has <literal>fastupdate</> enabled, the system will clean up
      the pending-entry list whenever the list grows larger than
-     <varname>work_mem</>.  To avoid fluctuations in observed response time,
-     it's desirable to have pending-list cleanup occur in the background
-     (i.e., via autovacuum).  Foreground cleanup operations can be avoided by
-     increasing <varname>work_mem</> or making autovacuum more aggressive.
-     However, enlarging <varname>work_mem</> means that if a foreground
-     cleanup does occur, it will take even longer.
+     <varname>pending_list_cleanup_size</>. To avoid fluctuations in observed
+     response time, it's desirable to have pending-list cleanup occur in the
+     background (i.e., via autovacuum).  Foreground cleanup operations
+     can be avoided by increasing <varname>pending_list_cleanup_size</>
+     or making autovacuum more aggressive.
+     However, enlarging the threshold of the cleanup operation means that
+     if a foreground cleanup does occur, it will take even longer.
+    </para>
+    <para>
+     <varname>pending_list_cleanup_size</> can be overridden for individual
+     GIN indexes by changing storage parameters, and which allows each
+     GIN index to have its own cleanup threshold.
+     For example, it's possible to increase the threshold only for the GIN
+     index which can be updated heavily, and decrease it otherwise.
     </para>
    </listitem>
   </varlistentry>
index 0158b1759e84b07354c212c818601c425a1103b5..5de282b29485aa50a4b57ff2e9cf154994bb4c1c 100644 (file)
@@ -861,7 +861,7 @@ my_distance(PG_FUNCTION_ARGS)
   <para>
    By default, a GiST index build switches to the buffering method when the
    index size reaches <xref linkend="guc-effective-cache-size">. It can
-   be manually turned on or off by the <literal>BUFFERING</literal> parameter
+   be manually turned on or off by the <literal>buffering</literal> parameter
    to the CREATE INDEX command. The default behavior is good for most cases,
    but turning buffering off might speed up the build somewhat if the input
    data is ordered.
index 2ab090d03e51be58c1bcc593d29a30f1d9667fe5..e6a77095ec3fb315c3bc08ea7d2120f73ad181ba 100644 (file)
@@ -46,7 +46,7 @@ CLUSTER [VERBOSE]
    not clustered.  That is, no attempt is made to store new or
    updated rows according to their index order.  (If one wishes, one can
    periodically recluster by issuing the command again.  Also, setting
-   the table's <literal>FILLFACTOR</literal> storage parameter to less than
+   the table's <literal>fillfactor</literal> storage parameter to less than
    100% can aid in preserving cluster ordering during updates, since updated
    rows are kept on the same page if enough space is available there.)
   </para>
index 18bd0d33704d94f5edb44ae29cfd0a5e0bff5fa1..21f7604ac088a0d757756582773a4420755d5bac 100644 (file)
@@ -300,7 +300,7 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class=
 
    <variablelist>
    <varlistentry>
-    <term><literal>FILLFACTOR</></term>
+    <term><literal>fillfactor</></term>
     <listitem>
      <para>
       The fillfactor for an index is a percentage that determines how full
@@ -327,7 +327,7 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class=
 
    <variablelist>
    <varlistentry>
-    <term><literal>BUFFERING</></term>
+    <term><literal>buffering</></term>
     <listitem>
     <para>
      Determines whether the buffering build technique described in
@@ -341,12 +341,12 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class=
    </variablelist>
 
    <para>
-    GIN indexes accept a different parameter:
+    GIN indexes accept different parameters:
    </para>
 
    <variablelist>
    <varlistentry>
-    <term><literal>FASTUPDATE</></term>
+    <term><literal>fastupdate</></term>
     <listitem>
     <para>
      This setting controls usage of the fast update technique described in
@@ -359,7 +359,7 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class=
 
     <note>
      <para>
-      Turning <literal>FASTUPDATE</> off via <command>ALTER INDEX</> prevents
+      Turning <literal>fastupdate</> off via <command>ALTER INDEX</> prevents
       future insertions from going into the list of pending index entries,
       but does not in itself flush previous entries.  You might want to
       <command>VACUUM</> the table afterward to ensure the pending list is
@@ -369,6 +369,17 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class=
     </listitem>
    </varlistentry>
    </variablelist>
+   <variablelist>
+   <varlistentry>
+    <term><literal>pending_list_cleanup_size</></term>
+    <listitem>
+    <para>
+     Custom <xref linkend="guc-pending-list-cleanup-size"> parameter.
+     This value is specified in kilobytes.
+    </para>
+    </listitem>
+   </varlistentry>
+   </variablelist>
   </refsect2>
 
   <refsect2 id="SQL-CREATEINDEX-CONCURRENTLY">
index c55a7758273cab58a0f97e336b7f562d4d21617b..86d918fafb4237c558a8120a066a2ec79243accb 100644 (file)
@@ -216,6 +216,14 @@ static relopt_int intRelOpts[] =
                        RELOPT_KIND_BRIN
                }, 128, 1, 131072
        },
+       {
+               {
+                       "pending_list_cleanup_size",
+                       "Maximum size of the pending list for this GIN index, in kilobytes.",
+                       RELOPT_KIND_GIN
+               },
+               -1, 64, MAX_KILOBYTES
+       },
 
        /* list terminator */
        {{NULL}}
index ed581977f54079e19e85ad51a7765ac09f073c6c..96255104ac1d442861075e7ee901a43f042b78e5 100644 (file)
@@ -25,6 +25,8 @@
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
+/* GUC parameter */
+int                    pending_list_cleanup_size = 0;
 
 #define GIN_PAGE_FREESIZE \
        ( BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(GinPageOpaqueData)) )
@@ -228,6 +230,7 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
        ginxlogUpdateMeta data;
        bool            separateList = false;
        bool            needCleanup = false;
+       int                     cleanupSize;
 
        if (collector->ntuples == 0)
                return;
@@ -422,11 +425,13 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
         * ginInsertCleanup could take significant amount of time, so we prefer to
         * call it when it can do all the work in a single collection cycle. In
         * non-vacuum mode, it shouldn't require maintenance_work_mem, so fire it
-        * while pending list is still small enough to fit into work_mem.
+        * while pending list is still small enough to fit into
+        * pending_list_cleanup_size.
         *
         * ginInsertCleanup() should not be called inside our CRIT_SECTION.
         */
-       if (metadata->nPendingPages * GIN_PAGE_FREESIZE > work_mem * 1024L)
+       cleanupSize = GinGetPendingListCleanupSize(index);
+       if (metadata->nPendingPages * GIN_PAGE_FREESIZE > cleanupSize * 1024L)
                needCleanup = true;
 
        UnlockReleaseBuffer(metabuffer);
index 1f8db9de6d94bb7cfaf0de4d5faa4da010d5468c..ff1dd7ee519750823d9c8eca420dba187e03a634 100644 (file)
@@ -525,7 +525,9 @@ ginoptions(PG_FUNCTION_ARGS)
        GinOptions *rdopts;
        int                     numoptions;
        static const relopt_parse_elt tab[] = {
-               {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)}
+               {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
+               {"pending_list_cleanup_size", RELOPT_TYPE_INT, offsetof(GinOptions,
+                                                                                                                               pendingListCleanupSize)}
        };
 
        options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIN,
index aca42436d34cb225c6f4c2188a86c2308fe0986b..6547dfab69e3ed6899d0de5d19a285478369017b 100644 (file)
 #define CONFIG_EXEC_PARAMS_NEW "global/config_exec_params.new"
 #endif
 
-/* upper limit for GUC variables measured in kilobytes of memory */
-/* note that various places assume the byte size fits in a "long" variable */
-#if SIZEOF_SIZE_T > 4 && SIZEOF_LONG > 4
-#define MAX_KILOBYTES  INT_MAX
-#else
-#define MAX_KILOBYTES  (INT_MAX / 1024)
-#endif
-
 #define KB_PER_MB (1024)
 #define KB_PER_GB (1024*1024)
 #define KB_PER_TB (1024*1024*1024)
@@ -2550,6 +2542,17 @@ static struct config_int ConfigureNamesInt[] =
                NULL, NULL, NULL
        },
 
+       {
+               {"pending_list_cleanup_size", PGC_USERSET, CLIENT_CONN_STATEMENT,
+                       gettext_noop("Sets the maximum size of the pending list for GIN index."),
+                        NULL,
+                       GUC_UNIT_KB
+               },
+               &pending_list_cleanup_size,
+               4096, 64, MAX_KILOBYTES,
+               NULL, NULL, NULL
+       },
+
        /* End-of-list marker */
        {
                {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
index dac67769f1447fc45ed46c42498bd39a5777f318..6e8ea1e481c721cf6701adbba708a8e9b422238e 100644 (file)
 #bytea_output = 'hex'                  # hex, escape
 #xmlbinary = 'base64'
 #xmloption = 'content'
+#pending_list_cleanup_size = 4MB
 
 # - Locale and Formatting -
 
index 56dc688fcb7fba7f2354c5c7e490eb68829c3182..be6ad7ea6431643c1634df342b6ab8278cc9d34c 100644 (file)
@@ -1172,7 +1172,7 @@ psql_completion(const char *text, int start, int end)
                         pg_strcasecmp(prev_wd, "(") == 0)
        {
                static const char *const list_INDEXOPTIONS[] =
-               {"fillfactor", "fastupdate", NULL};
+               {"fillfactor", "fastupdate", "pending_list_cleanup_size", NULL};
 
                COMPLETE_WITH_LIST(list_INDEXOPTIONS);
        }
index 80826b843bfe949af3c7f77ef8aa5a6b4e6f101e..a0d4da84b084107e06a134ca7b04be1fab8bccd5 100644 (file)
@@ -65,8 +65,9 @@ typedef char GinTernaryValue;
 #define GinTernaryValueGetDatum(X) ((Datum)(X))
 #define PG_RETURN_GIN_TERNARY_VALUE(x) return GinTernaryValueGetDatum(x)
 
-/* GUC parameter */
+/* GUC parameters */
 extern PGDLLIMPORT int GinFuzzySearchLimit;
+extern int pending_list_cleanup_size;
 
 /* ginutil.c */
 extern void ginGetStats(Relation index, GinStatsData *stats);
index 6a09dc990e4338eb2e2f8a88d4c07ff3bd546cce..4a8db5a5003495fe4f938cc2bd23a0516dfc302c 100644 (file)
@@ -315,12 +315,18 @@ typedef struct GinOptions
 {
        int32           vl_len_;                /* varlena header (do not touch directly!) */
        bool            useFastUpdate;  /* use fast updates? */
+       int                     pendingListCleanupSize; /* maximum size of pending list */
 } GinOptions;
 
 #define GIN_DEFAULT_USE_FASTUPDATE     true
 #define GinGetUseFastUpdate(relation) \
        ((relation)->rd_options ? \
         ((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
+#define GinGetPendingListCleanupSize(relation) \
+       ((relation)->rd_options && \
+        ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \
+        ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \
+        pending_list_cleanup_size)
 
 
 /* Macros for buffer lock/unlock operations */
index 66b5cd36c59b417596afadc772670e9df03cdd04..2b2aaf4ac26f6316f6b7685127bc3b0c93f8add3 100644 (file)
 #include "utils/array.h"
 
 
+/* upper limit for GUC variables measured in kilobytes of memory */
+/* note that various places assume the byte size fits in a "long" variable */
+#if SIZEOF_SIZE_T > 4 && SIZEOF_LONG > 4
+#define MAX_KILOBYTES  INT_MAX
+#else
+#define MAX_KILOBYTES  (INT_MAX / 1024)
+#endif
+
 /*
  * Certain options can only be set at certain times. The rules are
  * like this:
index 26d883c447eb0326bdd5ba992b4ab69bbfc09527..45689d9950f0c1dcb248d60276456437ffdee6e4 100644 (file)
@@ -2240,6 +2240,19 @@ SELECT COUNT(*) FROM array_gin_test WHERE a @> '{2}';
 (1 row)
 
 DROP TABLE array_gin_test;
+--
+-- Test GIN index's reloptions
+--
+CREATE INDEX gin_relopts_test ON array_index_op_test USING gin (i)
+  WITH (FASTUPDATE=on, PENDING_LIST_CLEANUP_SIZE=128);
+\d+ gin_relopts_test
+     Index "public.gin_relopts_test"
+ Column |  Type   | Definition | Storage 
+--------+---------+------------+---------
+ i      | integer | i          | plain
+gin, for table "public.array_index_op_test"
+Options: fastupdate=on, pending_list_cleanup_size=128
+
 --
 -- HASH
 --
index e08f35ebcf13ddd570763d6478cab0aa70b49db3..619558551e5308c1146c7b7e470083da7feb7bfa 100644 (file)
@@ -654,6 +654,13 @@ SELECT COUNT(*) FROM array_gin_test WHERE a @> '{2}';
 
 DROP TABLE array_gin_test;
 
+--
+-- Test GIN index's reloptions
+--
+CREATE INDEX gin_relopts_test ON array_index_op_test USING gin (i)
+  WITH (FASTUPDATE=on, PENDING_LIST_CLEANUP_SIZE=128);
+\d+ gin_relopts_test
+
 --
 -- HASH
 --