<!--  --> 
<sect1 id="locking"> <title>Locking Issues</title>

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

<para> One of the usual merits of 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.  &slony1; configuration events normally grab locks on an
internal table, <envar>sl_config_lock</envar>, which should not be
visible to applications unless they are performing actions on &slony1;
components.  </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 exclusive table lock must be acquired on the
<quote>origin</quote> node in order to add the trigger that collects
updates for that table.  It only needs to be acquired long enough to
establish the new trigger.</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,
exclusive locks must be acquired on each replicated table 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 each of the tables in a
given replication set on the origin node.</para>
</listitem>


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

<para> <emphasis>all</emphasis> tables in the replication set will be locked
via an exclusive lock for the entire duration of the process of
subscription.  By locking the tables early, this means that the
subscription cannot fail after copying some of the data due to some
other process having held on to a table. </para>

<para> In any case, note that this one began with the wording
<quote>on a new subscriber.</quote> The locks are applied <emphasis>on
the new subscriber.</emphasis> They are <emphasis>not</emphasis>
applied on the provider or on the origin. </para>

</listitem>

<listitem>
<para> Each time an event is generated (including SYNC events) &slony1;
obtains an exclusive lock on the sl_event table long enough to insert
the event into sl_event.  This is not normally an issue as &slony1; 
should be the only program using sl_event.   However this means that
any non-slony transactions that read from sl_event can cause replication
to pause.   If you pg_dump your database  avoid dumping 
your Slony schemas or else pg_dump's locking will compete with Slony's own
locking which could stop Slony replication for the duration of the
pg_dump.  Exclude the Slony schemas from pg_dump with
--exclude-schema=schemaname to specifically exclude your Slony schema.

</para>

</itemizedlist>

<para>
When &slony1; locks a table that a running application later tries
to access the application will be blocked waiting for the lock.  It is
also possible for a running application to create a deadlock situation
with &slony1; when they each have obtained locks that the other is 
waiting for.
</para>

<para> Several possible solutions to this are: </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  <command>slony</command> user 
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; there will be no competing processes.</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>

</itemizedlist>

</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:"slony.sgml"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->
