Add documentation for new in-core advisory lock functions. Merlin Moncure

This commit is contained in:
Tom Lane 2006-09-20 23:43:22 +00:00
parent e56ccad7b0
commit 0efa510bf7
2 changed files with 290 additions and 18 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.338 2006/09/16 00:30:13 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.339 2006/09/20 23:43:21 tgl Exp $ -->
<chapter id="functions">
<title>Functions and Operators</title>
@ -10577,15 +10577,205 @@ postgres=# select * from pg_xlogfile_name_offset(pg_stop_backup());
</indexterm>
<para>
<function>pg_stat_file</> returns a record containing the file
size, last accessed time stamp, last modified time stamp,
last file status change time stamp (Unix platforms only),
file creation timestamp (Windows only), and a <type>boolean</type> indicating
if it is a directory. Typical usages include:
size, last accessed time stamp, last modified time stamp,
last file status change time stamp (Unix platforms only),
file creation timestamp (Windows only), and a <type>boolean</type>
indicating if it is a directory. Typical usages include:
<programlisting>
SELECT * FROM pg_stat_file('filename');
SELECT (pg_stat_file('filename')).modification;
</programlisting>
</para>
<para>
The functions shown in <xref linkend="functions-advisory-locks"> manage
advisory locks. For details about proper usage of these functions, see
<xref linkend="advisory-locks">.
</para>
<table id="functions-advisory-locks">
<title>Advisory Lock Functions</title>
<tgroup cols="3">
<thead>
<row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<literal><function>pg_advisory_lock</function>(<parameter>key</> <type>bigint</>)</literal>
</entry>
<entry><type>void</type></entry>
<entry>Obtain exclusive advisory lock</entry>
</row>
<row>
<entry>
<literal><function>pg_advisory_lock</function>(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</literal>
</entry>
<entry><type>void</type></entry>
<entry>Obtain exclusive advisory lock</entry>
</row>
<row>
<entry>
<literal><function>pg_advisory_lock_shared</function>(<parameter>key</> <type>bigint</>)</literal>
</entry>
<entry><type>void</type></entry>
<entry>Obtain shared advisory lock</entry>
</row>
<row>
<entry>
<literal><function>pg_advisory_lock_shared</function>(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</literal>
</entry>
<entry><type>void</type></entry>
<entry>Obtain shared advisory lock</entry>
</row>
<row>
<entry>
<literal><function>pg_try_advisory_lock</function>(<parameter>key</> <type>bigint</>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>Obtain exclusive advisory lock if available</entry>
</row>
<row>
<entry>
<literal><function>pg_try_advisory_lock</function>(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>Obtain exclusive advisory lock if available</entry>
</row>
<row>
<entry>
<literal><function>pg_try_advisory_lock_shared</function>(<parameter>key</> <type>bigint</>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>Obtain shared advisory lock if available</entry>
</row>
<row>
<entry>
<literal><function>pg_try_advisory_lock_shared</function>(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>Obtain shared advisory lock if available</entry>
</row>
<row>
<entry>
<literal><function>pg_advisory_unlock</function>(<parameter>key</> <type>bigint</>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>Release an exclusive advisory lock</entry>
</row>
<row>
<entry>
<literal><function>pg_advisory_unlock</function>(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>Release an exclusive advisory lock</entry>
</row>
<row>
<entry>
<literal><function>pg_advisory_unlock_shared</function>(<parameter>key</> <type>bigint</>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>Release a shared advisory lock</entry>
</row>
<row>
<entry>
<literal><function>pg_advisory_unlock_shared</function>(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>Release a shared advisory lock</entry>
</row>
<row>
<entry>
<literal><function>pg_advisory_unlock_all</function>()</literal>
</entry>
<entry><type>void</type></entry>
<entry>Release all advisory locks held by the current session</entry>
</row>
</tbody>
</tgroup>
</table>
<indexterm zone="functions-admin">
<primary>pg_advisory_lock</primary>
</indexterm>
<para>
<function>pg_advisory_lock</> locks an application-defined resource,
which may be identified either by a single 64-bit key value or two
32-bit key values (note that these two key spaces do not overlap). If
another session already holds a lock on the same resource, the
function will wait until the resource becomes available. The lock
is exclusive. Multiple lock requests stack, so that if the same resource
is locked three times it must be also unlocked three times to be
released for other sessions' use.
</para>
<indexterm zone="functions-admin">
<primary>pg_advisory_lock_shared</primary>
</indexterm>
<para>
<function>pg_advisory_lock_shared</> works the same as
<function>pg_advisory_lock</>,
except the lock can be shared with other sessions requesting shared locks.
Only would-be exclusive lockers are locked out.
</para>
<indexterm zone="functions-admin">
<primary>pg_try_advisory_lock</primary>
</indexterm>
<para>
<function>pg_try_advisory_lock</> is similar to
<function>pg_advisory_lock</>, except the function will not wait for the
lock to become available. It will either obtain the lock immediately and
return <literal>true</>, or return <literal>false</> if the lock cannot be
acquired now.
</para>
<indexterm zone="functions-admin">
<primary>pg_try_advisory_lock_shared</primary>
</indexterm>
<para>
<function>pg_try_advisory_lock_shared</> works the same as
<function>pg_try_advisory_lock</>, except it attempts to acquire
shared rather than exclusive lock.
</para>
<indexterm zone="functions-admin">
<primary>pg_advisory_unlock</primary>
</indexterm>
<para>
<function>pg_advisory_unlock</> will release a previously-acquired
exclusive advisory lock. It
will return <literal>true</> if the lock is successfully released.
If the lock was in fact not held, it will return <literal>false</>,
and in addition, an SQL warning will be raised by the server.
</para>
<indexterm zone="functions-admin">
<primary>pg_advisory_unlock_shared</primary>
</indexterm>
<para>
<function>pg_advisory_unlock_shared</> works the same as
<function>pg_advisory_unlock</>,
except to release a shared advisory lock.
</para>
<indexterm zone="functions-admin">
<primary>pg_advisory_unlock_all</primary>
</indexterm>
<para>
<function>pg_advisory_unlock_all</> will release all advisory locks
held by the current session. (This function is implicitly invoked
at session end, even if the client disconnects ungracefully.)
</para>
</sect1>
</chapter>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/mvcc.sgml,v 2.62 2006/09/18 12:11:36 teodor Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/mvcc.sgml,v 2.63 2006/09/20 23:43:22 tgl Exp $ -->
<chapter id="mvcc">
<title>Concurrency Control</title>
@ -25,10 +25,10 @@
</indexterm>
<para>
Unlike traditional database systems which use locks for concurrency control,
<productname>PostgreSQL</productname>
maintains data consistency by using a multiversion model
(Multiversion Concurrency Control, <acronym>MVCC</acronym>).
<productname>PostgreSQL</productname> provides a rich set of tools
for developers to manage concurrent access to data. Internally,
data consistency is maintained by using a multiversion
model (Multiversion Concurrency Control, <acronym>MVCC</acronym>).
This means that while querying a database each transaction sees
a snapshot of data (a <firstterm>database version</firstterm>)
as it was some
@ -36,7 +36,10 @@
This protects the transaction from viewing inconsistent data that
could be caused by (other) concurrent transaction updates on the same
data rows, providing <firstterm>transaction isolation</firstterm>
for each database session.
for each database session. <acronym>MVCC</acronym>, by eschewing
explicit locking methodologies of traditional database systems,
minimizes lock contention in order to allow for reasonable
performance in multiuser environments.
</para>
<para>
@ -52,7 +55,9 @@
<productname>PostgreSQL</productname> for applications that cannot
adapt easily to <acronym>MVCC</acronym> behavior. However, proper
use of <acronym>MVCC</acronym> will generally provide better
performance than locks.
performance than locks. In addition, application-defined advisory
locks provide a mechanism for acquiring locks that are not tied
to a single transaction.
</para>
</sect1>
@ -859,6 +864,83 @@ UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;
(e.g., while waiting for user input).
</para>
</sect2>
<sect2 id="advisory-locks">
<title>Advisory Locks</title>
<indexterm zone="advisory-locks">
<primary>lock</primary>
<secondary>advisory</secondary>
</indexterm>
<para>
<productname>PostgreSQL</productname> provides a means for
creating locks that have application-defined meanings. These are
called <firstterm>advisory locks</>, because the system does not
enforce their use &mdash; it is up to the application to use them
correctly. Advisory locks can be useful for locking strategies
that are an awkward fit for the MVCC model. Once acquired, an
advisory lock is held until explicitly released or the session ends.
Unlike standard locks, advisory locks do not
honor transaction semantics. For example, a lock acquired during a
transaction that is later rolled back will still be held following the
rollback. The same lock can be acquired multiple times by its
owning process: for each lock request there must be a corresponding
unlock request before the lock is actually released. (If a session
already holds a given lock, additional requests will always succeed, even
if other sessions are awaiting the lock.) Like all locks in
<productname>PostgreSQL</productname>, a complete list of advisory
locks currently held by any session can be found in the system view
<structname>pg_locks</structname>.
</para>
<para>
Advisory locks are allocated out of a shared memory pool whose size
is defined by the configuration variables
<xref linkend="guc-max-locks-per-transaction"> and
<xref linkend="guc-max-connections">.
Care must be taken not to exhaust this
memory or the server will not be able to grant any locks at all.
This imposes an upper limit on the number of advisory locks
grantable by the server, typically in the tens to hundreds of thousands
depending on how the server is configured.
</para>
<para>
A common use of advisory locks is to emulate pessimistic locking
strategies typical of so called <quote>flat file</> data management
systems.
While a flag stored in a table could be used for the same purpose,
advisory locks are faster, avoid MVCC bloat, and are automatically
cleaned up by the server at the end of the session.
In certain cases using this method, especially in queries
involving explicit ordering and <literal>LIMIT</> clauses, care must be
taken to control the locks acquired because of the order in which SQL
expressions are evaluated. For example:
<screen>
SELECT pg_advisory_lock(id) FROM foo WHERE id = 12345; -- ok
SELECT pg_advisory_lock(id) FROM foo WHERE id &gt; 12345 LIMIT 100; -- danger!
SELECT pg_advisory_lock(q.id) FROM
(
SELECT id FROM foo WHERE id &gt; 12345 LIMIT 100;
) q; -- ok
</screen>
In the above queries, the second form is dangerous because the
<literal>LIMIT</> is not guaranteed to be applied before the locking
function is executed. This might cause some locks to be acquired
that the application was not expecting, and hence would fail to release
(until it ends the session).
From the point of view of the application, such locks
would be dangling, although still viewable in
<structname>pg_locks</structname>.
</para>
<para>
The functions provided to manipulate advisory locks are described in
<xref linkend="functions-advisory-locks">.
</para>
</sect2>
</sect1>
<sect1 id="applevel-consistency">
@ -993,12 +1075,12 @@ UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;
</term>
<listitem>
<para>
Short-term share/exclusive page-level locks are used for
read/write access. Locks are released immediately after each
index row is fetched or inserted. But note that a GIN-indexed
value insertion usually produces several index key insertions
per row, so GIN may do substantial work for a single value's
insertion.
Short-term share/exclusive page-level locks are used for
read/write access. Locks are released immediately after each
index row is fetched or inserted. But note that a GIN-indexed
value insertion usually produces several index key insertions
per row, so GIN may do substantial work for a single value's
insertion.
</para>
</listitem>
</varlistentry>