<!-- $Id: locking.sgml,v 1.2 2005/05/03 21:32:26 cbbrowne Exp $ --> 
<sect1 id="locking"> <title>Locking Issues</title>

<indexterm><primary>locking issues</primary></indexterm>

<para> One of the usual merits the use, by &postgres;, of
Multi-Version Concurrency Control (<acronym>MVCC</acronym>) is that
this eliminates a whole host of reasons to need to lock database
objects.  On some other database systems, you need to acquire a table
lock in order to insert data into the table; that can
<emphasis>severely</emphasis> hinder performance.  On other systems,
read locks can impede writes; with <acronym>MVCC</acronym>, &postgres;
eliminates that whole class of locks in that <quote>old reads</quote>
can access <quote>old tuples.</quote> Most of the time, this allows
the gentle user of &postgres; to not need to worry very much about
locks. </para>

<para> Unfortunately, there are several sorts of &slony1; events that
do require exclusive locks on &postgres; tables, with the result that
modifying &slony1; configuration can bring back some of those
<quote>locking irritations.</quote>  In particular:</para>

<itemizedlist>

<listitem><para><link linkend="stmtsetaddtable"> <command>set add
table</command> </link></para>

<para> A momentary table lock must be acquired on the
<quote>origin</quote> node in order to add the trigger that collects
updates for that table.</para>
</listitem>

<listitem><para><link linkend="stmtmoveset"> <command> move
set</command> </link></para>

<para> When a set origin is shifted from one node to another, locks
must be acquired on the tables on both the old origin and the new
origin in order to change the triggers on the tables.
</para></listitem>

<listitem><para><link linkend="stmtlockset"> <command> lock set
</command> </link> </para>

<para> This operation expressly requests locks on the tables in a
given replication set on the origin node.</para>
</listitem>

<listitem><para><link linkend="stmtddlscript"> <command>execute
script</command> </link> </para>

<para> This operation runs a set of SQL queries; in order for it to
work, the &slony1; triggers must be removed, followed by the query
(which potentially updates the data) running, followed by triggers
being restored.  The operation therefore must acquire table locks on
all replicated tables on each node. </para>
</listitem>

<listitem><para> During the <command>COPY_SET</command> event on a new
subscriber </para>

<para> In a sense, this is the least provocative scenario, since,
before the replication set has been populated, it is pretty reasonable
to say that the node is <quote>unusable</quote> and that &slony1;
could reasonably expect exclusive access to the node. </para>
</listitem>

</itemizedlist>

<para> Each of these actions requires, at some point, modifying each
of the tables in the affected replication set, which requires
acquiring an exclusive lock on the table.  Some users that have tried
running these operations on &slony1; nodes that were actively
servicing applications have experienced difficulties with deadlocks
and/or with the operations hanging up. </para>

<para> The obvious question: <quote>What to do about such
deadlocks?</quote> </para>

<para> Several possibilities admit themselves: </para>

<itemizedlist>

<listitem><para> Announce an application outage to avoid deadlocks
</para>

<para> If you can temporarily block applications from using the
database, that will provide a window of time during which there is
nothing running against the database other than administrative
processes under your control. </para> </listitem>

<listitem><para> Try the operation, hoping for things to work </para> 

<para> Since nothing prevents applications from leaving access locks
in your way, you may find yourself deadlocked.  But if the number of
remaining locks are small, you may be able to negotiate with users to
<quote>get in edgewise.</quote> </para>
</listitem>

<listitem><para> Use pgpool </para> 

<para> If you can use this or some similar <quote>connection
broker</quote>, you may be able to tell the connection manager to stop
using the database for a little while, thereby letting it
<quote>block</quote> the applications for you.  What would be ideal
would be for the connection manager to hold up user queries for a
little while so that the brief database outage looks, to them, like a
period where things were running slowly.  </para></listitem>

<listitem><para> Rapid Outage Management </para> 

<para> The following procedure may minimize the period of the outage:

<itemizedlist>

<listitem><para> Modify <filename>pg_hba.conf</filename> so that only
the <link linkend="slonyuser"> <command>slony</command> user </link>
will have access to the database. </para> </listitem>

<listitem><para> Issue a <command>kill -SIGHUP</command> to the &postgres;  postmaster.</para> 

<para> This will not kill off existing possibly-long-running queries,
but will prevent new ones from coming in.  There is an application
impact in that incoming queries will be rejected until the end of the
process.
</para>
</listitem>

<listitem><para> If <quote>all looks good,</quote> then it should be
safe to proceed with the &slony1; operation. </para> </listitem>

<listitem><para> If some old query is lingering around, you may need
to <command>kill -SIGQUIT</command> one of the &postgres; processes.
This will restart the backend and kill off any lingering queries.  You
probably need to restart the <xref linkend="slon"> processes that
attach to the node. </para> 

<para> At that point, it will be safe to proceed with the &slony1;
operation.</para></listitem>

<listitem><para> Reset <filename>pg_hba.conf</filename> to allow other
users in, and <command>kill -SIGHUP</command> the postmaster to make
it reload the security configuration. </para> </listitem>
</itemizedlist>

</para>
</listitem>

<listitem><para> The section on <link linkend="ddlchanges"> DDL
Changes </link> suggests some additional techniques that may be
useful, such as moving tables between replication sets in such a way
that you minimize the set of tables that need to be
locked. </para></listitem>

</itemizedlist>

<para> Regrettably, there is no perfect answer to this.  If it is
<emphasis>necessary</emphasis> to submit a <xref
linkend="stmtmoveset"> request, then it is presumably
<emphasis>necessary</emphasis> to accept the brief application outage.
As &slony1;/<link linkend="pgpool"> pgpool </link> linkages improve,
that may become a better way to handle this.</para>

</sect1>
<!-- Keep this comment at the end of the file
Local variables:
mode:sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:"book.sgml"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->

