]> granicus.if.org Git - postgresql/commitdiff
Add GUCs for predicate lock promotion thresholds.
authorKevin Grittner <kgrittn@postgresql.org>
Sat, 8 Apr 2017 02:38:05 +0000 (21:38 -0500)
committerKevin Grittner <kgrittn@postgresql.org>
Sat, 8 Apr 2017 02:38:05 +0000 (21:38 -0500)
Defaults match the fixed behavior of prior releases, but now DBAs
have better options to tune serializable workloads.

It might be nice to be able to set this per relation, but that part
will need to wait for another release.

Author: Dagfinn Ilmari MannsÃ¥ker

doc/src/sgml/config.sgml
doc/src/sgml/mvcc.sgml
src/backend/storage/lmgr/predicate.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/storage/predicate.h

index ac339fb56666e7d594f28a9e3c939932ff482f85..744c5e8f37ac942d368c20353b97be62af2fee8d 100644 (file)
@@ -7337,7 +7337,43 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
         tables in a single serializable transaction. This parameter can
         only be set at server start.
        </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-max-pred-locks-per-relation" xreflabel="max_pred_locks_per_relation">
+      <term><varname>max_pred_locks_per_relation</varname> (<type>integer</type>)
+      <indexterm>
+       <primary><varname>max_pred_locks_per_relation</> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        This controls how many pages or tuples of a single relation can be
+        predicate-locked before the lock is promoted to covering the whole
+        relation.  Values greater than or equal to zero mean an absolute
+        limit, while negative values
+        mean <xref linkend="guc-max-pred-locks-per-transaction"> divided by
+        the absolute value of this setting.  The default is -2, which keeps
+        the behaviour from previous versions of <productname>PostgreSQL</>.
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line.
+       </para>
+      </listitem>
+     </varlistentry>
 
+     <varlistentry id="guc-max-pred-locks-per-page" xreflabel="max_pred_locks_per_page">
+      <term><varname>max_pred_locks_per_page</varname> (<type>integer</type>)
+      <indexterm>
+       <primary><varname>max_pred_locks_per_page</> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        This controls how many rows on a single page can be predicate-locked
+        before the lock is promoted to covering the whole page.  The default
+        is 2.  This parameter can only be set in
+        the <filename>postgresql.conf</> file or on the server command line.
+       </para>
       </listitem>
      </varlistentry>
 
index 7aa32932fab129639f81578d9decfd9907a18ab4..dda01708864852bb0ac3c8a2913e639b10c529fe 100644 (file)
@@ -765,7 +765,9 @@ ERROR:  could not serialize access due to read/write dependencies among transact
        locks into a single relation-level predicate lock because the predicate
        lock table is short of memory, an increase in the rate of serialization
        failures may occur.  You can avoid this by increasing
-       <xref linkend="guc-max-pred-locks-per-transaction">.
+       <xref linkend="guc-max-pred-locks-per-transaction">,
+       <xref linkend="guc-max-pred-locks-per-relation">, and/or
+       <xref linkend="guc-max-pred-locks-per-page">.
       </para>
      </listitem>
      <listitem>
index 7aa719d6123554dcc7393bb1230a0107989b2244..10bac71e94b4fb6541a445be3bfcd3457ad63dc4 100644 (file)
@@ -352,8 +352,15 @@ static OldSerXidControl oldSerXidControl;
 static SERIALIZABLEXACT *OldCommittedSxact;
 
 
-/* This configuration variable is used to set the predicate lock table size */
+/*
+ * These configuration variables are used to set the predicate lock table size
+ * and to control promotion of predicate locks to coarser granularity in an
+ * attempt to degrade performance (mostly as false positive serialization
+ * failure) gracefully in the face of memory pressurel
+ */
 int                    max_predicate_locks_per_xact;           /* set by guc.c */
+int                    max_predicate_locks_per_relation;       /* set by guc.c */
+int                    max_predicate_locks_per_page;           /* set by guc.c */
 
 /*
  * This provides a list of objects in order to track transactions
@@ -437,7 +444,7 @@ static void RestoreScratchTarget(bool lockheld);
 static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target,
                                                   uint32 targettaghash);
 static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag);
-static int     PredicateLockPromotionThreshold(const PREDICATELOCKTARGETTAG *tag);
+static int     MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag);
 static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag);
 static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag);
 static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag,
@@ -2118,28 +2125,35 @@ DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
 }
 
 /*
- * Returns the promotion threshold for a given predicate lock
- * target. This is the number of descendant locks required to promote
- * to the specified tag. Note that the threshold includes non-direct
- * descendants, e.g. both tuples and pages for a relation lock.
+ * Returns the promotion limit for a given predicate lock target.  This is the
+ * max number of descendant locks allowed before promoting to the specified
+ * tag. Note that the limit includes non-direct descendants (e.g., both tuples
+ * and pages for a relation lock).
+ *
+ * Currently the default limit is 2 for a page lock, and half of the value of
+ * max_pred_locks_per_transaction - 1 for a relation lock, to match behavior
+ * of earlier releases when upgrading.
  *
- * TODO SSI: We should do something more intelligent about what the
- * thresholds are, either making it proportional to the number of
- * tuples in a page & pages in a relation, or at least making it a
- * GUC. Currently the threshold is 3 for a page lock, and
- * max_pred_locks_per_transaction/2 for a relation lock, chosen
- * entirely arbitrarily (and without benchmarking).
+ * TODO SSI: We should probably add additional GUCs to allow a maximum ratio
+ * of page and tuple locks based on the pages in a relation, and the maximum
+ * ratio of tuple locks to tuples in a page.  This would provide more
+ * generally "balanced" allocation of locks to where they are most useful,
+ * while still allowing the absolute numbers to prevent one relation from
+ * tying up all predicate lock resources.
  */
 static int
-PredicateLockPromotionThreshold(const PREDICATELOCKTARGETTAG *tag)
+MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
 {
        switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
        {
                case PREDLOCKTAG_RELATION:
-                       return max_predicate_locks_per_xact / 2;
+                       return max_predicate_locks_per_relation < 0
+                               ? (max_predicate_locks_per_xact
+                                  / (-max_predicate_locks_per_relation)) - 1
+                               : max_predicate_locks_per_relation;
 
                case PREDLOCKTAG_PAGE:
-                       return 3;
+                       return max_predicate_locks_per_page;
 
                case PREDLOCKTAG_TUPLE:
 
@@ -2194,8 +2208,8 @@ CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
                else
                        parentlock->childLocks++;
 
-               if (parentlock->childLocks >=
-                       PredicateLockPromotionThreshold(&targettag))
+               if (parentlock->childLocks >
+                       MaxPredicateChildLocks(&targettag))
                {
                        /*
                         * We should promote to this parent lock. Continue to check its
index a57b175b2d3267cecdc3a756bc9e87a447e38adb..19d258d03362103aad1b2282e7c7b4039489a993 100644 (file)
@@ -2199,6 +2199,28 @@ static struct config_int ConfigureNamesInt[] =
                NULL, NULL, NULL
        },
 
+       {
+               {"max_pred_locks_per_relation", PGC_SIGHUP, LOCK_MANAGEMENT,
+                       gettext_noop("Sets the maximum number of predicate-locked pages and tuples per relation."),
+                       gettext_noop("If more than this total of pages and tuples in the same relation are locked "
+                                                "by a connection, those locks are replaced by a relation level lock.")
+               },
+               &max_predicate_locks_per_relation,
+               -2, INT_MIN, INT_MAX,
+               NULL, NULL, NULL
+       },
+
+       {
+               {"max_pred_locks_per_page", PGC_SIGHUP, LOCK_MANAGEMENT,
+                       gettext_noop("Sets the maximum number of predicate-locked tuples per page."),
+                       gettext_noop("If more than this number of tuples on the same page are locked "
+                                                "by a connection, those locks are replaced by a page level lock.")
+               },
+               &max_predicate_locks_per_page,
+               2, 0, INT_MAX,
+               NULL, NULL, NULL
+       },
+
        {
                {"authentication_timeout", PGC_SIGHUP, CONN_AUTH_SECURITY,
                        gettext_noop("Sets the maximum allowed time to complete client authentication."),
index 8a93bdcb3f0ae483cf528ba7e4da57bb3e7d5356..512be0a92ed9a64e9e5daf949ad4412349fbd17a 100644 (file)
                                        # (change requires restart)
 #max_pred_locks_per_transaction = 64   # min 10
                                        # (change requires restart)
+#max_pred_locks_per_relation = -2      # negative values mean
+                                       # (max_pred_locks_per_transaction
+                                       #  / -max_pred_locks_per_relation) - 1
+#max_pred_locks_per_page = 2            # min 0
 
 
 #------------------------------------------------------------------------------
index f996d8e8181934fff5f38c6d70a7e9c6dcf7a9d3..8f9ea29917b04ecccff82b4fe18fba1510a08861 100644 (file)
@@ -22,6 +22,8 @@
  * GUC variables
  */
 extern int     max_predicate_locks_per_xact;
+extern int     max_predicate_locks_per_relation;
+extern int     max_predicate_locks_per_page;
 
 
 /* Number of SLRU buffers to use for predicate locking */