Commit c63172d6 authored by Kevin Grittner's avatar Kevin Grittner

Add GUCs for predicate lock promotion thresholds.

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
parent 9c7f5229
...@@ -7337,7 +7337,43 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' ...@@ -7337,7 +7337,43 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
tables in a single serializable transaction. This parameter can tables in a single serializable transaction. This parameter can
only be set at server start. only be set at server start.
</para> </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> </listitem>
</varlistentry> </varlistentry>
......
...@@ -765,7 +765,9 @@ ERROR: could not serialize access due to read/write dependencies among transact ...@@ -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 locks into a single relation-level predicate lock because the predicate
lock table is short of memory, an increase in the rate of serialization lock table is short of memory, an increase in the rate of serialization
failures may occur. You can avoid this by increasing 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> </para>
</listitem> </listitem>
<listitem> <listitem>
......
...@@ -352,8 +352,15 @@ static OldSerXidControl oldSerXidControl; ...@@ -352,8 +352,15 @@ static OldSerXidControl oldSerXidControl;
static SERIALIZABLEXACT *OldCommittedSxact; 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_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 * This provides a list of objects in order to track transactions
...@@ -437,7 +444,7 @@ static void RestoreScratchTarget(bool lockheld); ...@@ -437,7 +444,7 @@ static void RestoreScratchTarget(bool lockheld);
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target,
uint32 targettaghash); uint32 targettaghash);
static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag); 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 bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag);
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag); static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag);
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag,
...@@ -2118,28 +2125,35 @@ DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag) ...@@ -2118,28 +2125,35 @@ DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
} }
/* /*
* Returns the promotion threshold for a given predicate lock * Returns the promotion limit for a given predicate lock target. This is the
* target. This is the number of descendant locks required to promote * max number of descendant locks allowed before promoting to the specified
* to the specified tag. Note that the threshold includes non-direct * tag. Note that the limit includes non-direct descendants (e.g., both tuples
* descendants, e.g. both tuples and pages for a relation lock. * 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 * TODO SSI: We should probably add additional GUCs to allow a maximum ratio
* thresholds are, either making it proportional to the number of * of page and tuple locks based on the pages in a relation, and the maximum
* tuples in a page & pages in a relation, or at least making it a * ratio of tuple locks to tuples in a page. This would provide more
* GUC. Currently the threshold is 3 for a page lock, and * generally "balanced" allocation of locks to where they are most useful,
* max_pred_locks_per_transaction/2 for a relation lock, chosen * while still allowing the absolute numbers to prevent one relation from
* entirely arbitrarily (and without benchmarking). * tying up all predicate lock resources.
*/ */
static int static int
PredicateLockPromotionThreshold(const PREDICATELOCKTARGETTAG *tag) MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
{ {
switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag)) switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
{ {
case PREDLOCKTAG_RELATION: 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: case PREDLOCKTAG_PAGE:
return 3; return max_predicate_locks_per_page;
case PREDLOCKTAG_TUPLE: case PREDLOCKTAG_TUPLE:
...@@ -2194,8 +2208,8 @@ CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag) ...@@ -2194,8 +2208,8 @@ CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
else else
parentlock->childLocks++; parentlock->childLocks++;
if (parentlock->childLocks >= if (parentlock->childLocks >
PredicateLockPromotionThreshold(&targettag)) MaxPredicateChildLocks(&targettag))
{ {
/* /*
* We should promote to this parent lock. Continue to check its * We should promote to this parent lock. Continue to check its
......
...@@ -2199,6 +2199,28 @@ static struct config_int ConfigureNamesInt[] = ...@@ -2199,6 +2199,28 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL 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, {"authentication_timeout", PGC_SIGHUP, CONN_AUTH_SECURITY,
gettext_noop("Sets the maximum allowed time to complete client authentication."), gettext_noop("Sets the maximum allowed time to complete client authentication."),
......
...@@ -593,6 +593,10 @@ ...@@ -593,6 +593,10 @@
# (change requires restart) # (change requires restart)
#max_pred_locks_per_transaction = 64 # min 10 #max_pred_locks_per_transaction = 64 # min 10
# (change requires restart) # (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
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
* GUC variables * GUC variables
*/ */
extern int max_predicate_locks_per_xact; 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 */ /* Number of SLRU buffers to use for predicate locking */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment