Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
3542 lines (3088 sloc) 135 KB
<?xml version="1.0" encoding="UTF-8"?>
<!-- Dernière modifications
le $Date$
par $Author$
révision $Revision$ -->
<qandaset>
<indexterm><primary>Foire aux questions de &slony1;</primary></indexterm>
<qandadiv id="faqcompiling">
<title>FAQ de &slony1;&nbsp;: compiler et installer &slony1;</title>
<qandaentry>
<question>
<para>
J'utilise <productname>Frotznik Freenix 4.5</productname> avec son
système de gestion de paquetages <acronym>FFPM</acronym> (Frotznik
Freenix Package Manager). Il existe des paquets <acronym>FFPM</acronym>
pour &postgres; 7.4.7, que j'utilise actuellement comme base de données,
mais il n'y a pas encore de paquetages &slony1;. Comment puis-je rajouter
&slony1; à cette distribution&nbsp;?
</para>
</question>
<answer>
<para>
<productname>Frotznik Freenix</productname> est nouveau pour moi, alors
il est un peu dangereux de donner une réponse définitive, concise et
rapide.
</para>
<para>
Les réponses différent légèrement selon les diverses combinaisons de
versions entre &postgres; et &slony1; Il est légèrement plus facile,
avec les versions récentes, de faire face à ce genre de questions
qu'avec des versions plus anciennes. En général, vous devez presque
certainement recompiler &slony1; depuis les sources. Selon les versions
des deux composants &slony1; et &postgres;, vous
<emphasis>devez</emphasis> également recompiler &postgres; à partir de
zéro. (Savoir si vous devez <emphasis>utiliser</emphasis> la version
compilée de &postgres; est un autre problème mais en général ce n'est
pas le cas...)
</para>
<itemizedlist>
<listitem>
<para>
Les versions 1.0.5 et ultérieures de &slony1; nécessitent d'avoir
une version complètement configurée des sources de &postgres; afin de
recompiler &slony1;.
</para>
<para>
<emphasis>Heureusement</emphasis>, vous pouvez adapter la configuration
pour qu'elle corresponde à la configuration utilisée nativement par le
paquet d'origine, en vérifiant la version de &postgres; avec la
commande <command>pg_config --configure</command>.
</para>
</listitem>
<listitem>
<para>
La version 1.1 de &slony1; simplifie considérablement les choses&nbsp;;
dans la mesure où vous êtes dispensé d'avoir la version complète des
sources de &postgres;, au lieu de cela, elle se réfère aux emplacements
des bibliothèques, des binaires, de la configuration et des
<command>fichiers #include</command>.
</para>
</listitem>
<listitem>
<para>
&postgres; 8.0 et supérieur est généralement plus facile car
l'<quote>installation par défaut</quote> contient la totalité des
fichiers d'inclusion <command>#include</command>.
</para>
<para>
Si vous utilisez une version antérieure de &postgres;, il est
préférable d'utiliser une version installée à partir des sources, en
particulier si la version packagée ne contient pas les <quote>fichiers
d'inclusions <command>#include</command></quote> du serveur. Ces
fichiers peuvent être installés par la commande <command>make
install-all-headers</command>.
</para>
</listitem>
</itemizedlist>
<para>
En pratique, la <quote>pire situation</quote> est un scénario où vous
utilisez une version de &slony1; antérieure à 1.1 avec une
<quote>vieille</quote> version de &postgres;. Dans ce cas, vous devez
compiler &postgres; à partir de zéro afin d'avoir tous les pré-requis
de compilation de &slony1; même si vous utilisez une version
<quote>packagée</quote> de &postgres;.
</para>
<para>
Si vous utilisez une version récente de &postgres; et une version récente
de &slony1;, alors les dépendences peuvent être assez faibles, et vous
n'avez pas besoin de fichiers sources complémentaires.Ces améliorations
devraient soulager la mise en production des paquets de &slony1; de sorte
que vous pourriez même pouvoir espérer éviter la compilation de &slony1;.
</para>
</answer>
<answer>
<para></para>
</answer>
</qandaentry>
<qandaentry id="missingheaders">
<question>
<para>
J'essaie d'installer &slony1; 1.1 et j'obtiens le message d'erreur suivant&nbsp;:
<screen>configure: error: Headers for libpqserver are not found in the includeserverdir.
This is the path to postgres.h. Please specify the includeserverdir with
--with-pgincludeserverdir=&lt;dir&gt;</screen>
</para>
</question>
<answer>
<para>
Vous exécutez certainement une version 7.4 de &postgres; ou une version
antérieure. Une version où les en-têtes de serveur ne sont pas installés
par défaut. Dans ce cas, il vous suffit de lancer la commande
<command>make install</command> de &postgres;.
</para>
<para>
Vous devez installer les en-têtes du serveur lors d'installation de
&postgres; via la commande <command>make install-all-headers</command>.
</para>
</answer>
</qandaentry>
<qandaentry id="threadsafety">
<question>
<para>
&slony1; semble se compiler correctement&nbsp;; maintenant, lorsque
j'exécute un &lslon;, certains évènements se déclenchent, mais la
réplication ne se met pas route.
</para>
<para>
Les journaux applicatifs de Slony ressemblent à ça&nbsp;:
<screen>DEBUG1 remoteListenThread_1: connected to 'host=host004 dbname=pgbenchrep user=postgres port=5432'
ERROR remoteListenThread_1: "select ev_origin, ev_seqno, ev_timestamp,
ev_minxid, ev_maxxid, ev_xip,
ev_type,
ev_data1, ev_data2,
ev_data3, ev_data4,
ev_data5, ev_data6,
ev_data7, ev_data8 from "_pgbenchtest".sl_event e
where (e.ev_origin = '1' and e.ev_seqno > '1') order by e.ev_origin, e.ev_seqno" - could not receive data from server: Operation now in progress</screen>
</para>
<para>
Parfois, ils contiennent les lignes suivantes...
<screen>ERROR remoteListenThread_2: "select ev_origin, ev_seqno, ev_timestamp,
ev_minxid, ev_maxxid, ev_xip, ev_type, ev_data1, ev_data2,
ev_data3, ev_data4, ev_data5, ev_data6, ev_data7, ev_data8
from "_sl_p2t2".sl_event e where (e.ev_origin = '2' and e.ev_seqno >
'0') order by e.ev_origin, e.ev_seqno" - could not receive data from
server: Error 0</screen>
</para>
</question>
<answer>
<para>
Sur AIX et Solaris (et probablement sur d'autres OS), &slony1;
<emphasis>et &postgres;</emphasis> doivent être compilés avec l'option
<option>--enable-thread-safety</option>. Le message ci-dessus arrive
lorsque la compilation de &postgres; n'a pas fait appel à cette option.
</para>
<para>
Le disfonctionnement ici vient du fait que la bibliothèque C (indépendante
des threads) et la bibliothèque de &postgres;, libpq, (basée sur les
threads) utilisent des emplacements de mémoire différents pour les codes
d'erreur. Cela fait échouer les requêtes.
</para>
<para>
Des problèmes de ce genre surviennent avec des régularités surprenantes
sur AIX et sur Solaris. Il sera probablement nécessaire de réaliser un
<quote>audit du code objet</quote> pour s'assurer que
<emphasis>tous</emphasis> les composants nécessaires ont été compilés
et liés avec l'option <option>--enable-thread-safety</option>.
</para>
<para>
Par exemple, on peut rencontrer un problème sur Solaris lorsque
<envar>LD_LIBRARY_PATH</envar> est défini et pointe sur les bibliothèques
depuis une ancienne version compilée de &postgres;. Cela signifie que
même si la base de donnée <emphasis>avait été</emphasis> compilée avec
l'option <option>--enable-thread-safety</option>, et même si
<application>slon</application> a été recompilé pour cette version,
lors de l'édition de liens dynamique, <application>slon</application>
pointait sur une <quote>ancienne et mauvaise version compilée sans l'option
thread-safe,</quote>, slon ne fonctionne pas. On ne peut s'apercevoir de
cela qu'en exécutant <command>ldd</command> sur
<application>slon</application>.
</para>
</answer>
<answer>
<para>
À noter que la version 7.4.2 de libpq sur Solaris nécessite <link
linkend="threadpatch">un patch supplémentaire pour les threads</link>.
Ce pré-requis est également demandé pour &postgres; version 8.0.
</para>
</answer>
</qandaentry>
<qandaentry id="pg81funs">
<question>
<para>
Je suis en train de migrer sur une nouvelle version de &slony1; et je me
débat avec un problème sur <xref linkend="stmtupdatefunctions"/>. Lors
de l'exécution de <xref linkend="stmtupdatefunctions"/>, mon
<application>postmaster</application> s'arrête brutalement avec le signal
11. Le journal applicatif ne contient aucune erreur, exceptées celles
relatives à &postgres;. Les journaux applicatifs indiquent simplement que
le postmaster est bel bien arrêté.
</para>
<para>
En scrutant le fichier core avec un déboggueur, on constate que l'incident
survient lors de la validation d'une transaction.
</para>
<para>
Pour infos je suis sur &postgres; 8.1.[0-3].
</para>
</question>
<answer>
<para>
Malheureusement, les anciennes versions de &postgres; 8.1 avaient un
problème lors de la re-définition d'une fonction (par exemple
<function>upgradeSchema(text)</function>), lorsque la fonction est
appellée juste après, au sein de la même transaction, le
<application>postmaster</application> plante et la transaction est
annulée.
</para>
<para>
La commande &lslonik; <xref linkend="stmtupdatefunctions"/> fonctionne de
cette manière&nbsp;; dans une même transaction, elle effectue ceci&nbsp;:
<itemizedlist>
<listitem>
<para>
Charger les nouvelles fonctions (depuis
<filename>slony1_funcs.sql</filename>), notamment comprenant
<function>upgradeSchema(text)</function>.
</para>
</listitem>
<listitem>
<para>
Lancer <function>upgradeSchema(text)</function> pour effectuer la
migration nécessaire des schémas de la base.
</para>
</listitem>
<listitem>
<para>
Avertir les processus &lslon; du changement de configuration.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Malheureusement, avec &postgres; 8.1.0, 8.1.1, 8.1.2, et 8.1.3, ceci est
conflictuel avec un bogue où l'utilisation et la modification d'une
fonction plpgsql au sein de la même transaction provoque un arrêt brutal.
</para>
<para>
Plusieurs contournements sont envisageables.
</para>
</answer>
<answer>
<para>
La meilleure solution consiste à migrer &postgres; vers une version 8.1.4
ou supérieure. Les changements entre deux versions mineures ne nécessitent
pas la reconstruction de la base, il suffit simplement d'installer la
nouvelle version, puis de redémarrer le <application>postmaster</application>
avec cette nouvelle version.
</para>
</answer>
<answer>
<para>
Si cette solution ne convient pas, il est possible d'effectuer la mise à
jour via une série de transactions <quote>à la main</quote>, qui
correspondent à ce que &lslonik; aurait fait pour cette migration.
</para>
<itemizedlist>
<listitem>
<para>
Prendre <filename>slony1_funcs.sql</filename> et faire trois
remplacements dans ce fichier&nbsp;:
</para>
<itemizedlist>
<listitem>
<para>
Remplacer <quote>@CLUSTERNAME@</quote> avec le nom du cluster.
</para>
</listitem>
<listitem>
<para>
Remplacer <quote>@MODULEVERSION@</quote> avec la version de
&slony1;&nbsp;; par exemple <quote>1.2.10</quote>
</para>
</listitem>
<listitem>
<para>
Remplacer <quote>@NAMESPACE@</quote> avec le nom du namespace
du cluster <quote>entre guillemets doubles</quote>, par exemple
"_monCluster"
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
Recharger dans la base cet ensemble de fonctions <quote>mises à
jour</quote>.
</para>
</listitem>
<listitem>
<para>
Exécuter la procédure stockée via <command>select
<function>upgradeSchema('1.2.7')</function>;</command>, en supposant
que la précédente version de &slony1; en cours était la 1.2.7.
</para>
</listitem>
<listitem>
<para>
Le redémarrage de tous les processus &lslon; est probablement une
sage décision après ce genre de <quote>chirurgie.</quote>
</para>
</listitem>
</itemizedlist>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Problème d'installation sur Fedora/x86-64</para>
<para>
Lorsqu'on essaie de configurer &slony1; sur un système Fedora x86-64,
où <application>yum</application> a été utilisé pour une installation
du paquetage <filename>postgresql-libs.x86_64</filename>, le message
suivant se manifeste&nbsp;:
<screen>configure: error: Your version of libpq doesn't have PQunescapeBytea
this means that your version of PostgreSQL is lower than 7.3
and thus not supported by Slony-I.</screen></para>
<para>
Ceci arrive avec &postgres; 8.2.5, qui est nettement plus récent que la
version 7.3.
</para>
</question>
<answer>
<para>
La fonction <application>configure</application> est à la recherche du
symbole PQunescapeBytea. Elle compile un petit programme qu'il exécute
et vérifie que la compilation se passe bien. Dans la ligne de commande
<command>gcc</command>, elle utilise <command>-lpq</command> pour
ajouter la bibliothèque.
</para>
<para>
Malheureusement, ce paquetage n'a pas de lien symbolique, reliant
<filename>/usr/lib64/libpq.so</filename> à
<filename>libpq.so.5.0</filename>&nbsp;; c'est pourquoi la fonction
configure n'arrive pas à trouver libpq. Le <emphasis>vrai</emphasis>
problème, c'est que le compilateur n'arrive pas à trouver une
bibliothèque pour l'édition des liens, et non pas que libpq ait manqué
à l'appel.
</para>
<para>
Au final, ces informations doivent être envoyée vers ceux qui gèrent
le paquet <filename>postgresql-libs.x86_64</filename>.
</para>
</answer>
<answer>
<para>
Notez que ce même symptôme peut être révélateur d'autres problèmes de
ce genre au niveau de la configuration système. Les mauvais liens
symboliques, les mauvais droits, le mauvais comportement de la part de
votre compilateur C, tous peuvent potentiellement mener à ce même
message d'erreur.
</para>
<para>
Ainsi, si vous rencontrez cette erreur, vous aurez besoin de regarder
le fichier de traces nommé <filename>config.log</filename>. Cherchez à
partir du bas, et regardez quel souci est <emphasis>réellement</emphasis>
rencontré. Ceci sera utile pour trouver la vraie racine de cet épineux
problème.
</para>
</answer>
</qandaentry>
</qandadiv>
<qandadiv id="faqhowto"> <title> &slony1; FAQ: How Do I? </title>
<qandaentry>
<question>
<para>
I need to dump a database <emphasis>without</emphasis> getting
&slony1; configuration (<emphasis>e.g.</emphasis> - triggers, functions,
and such).
</para>
</question>
<answer>
<para>
Up to version 1.2, this is fairly nontrivial, requiring careful choice
of nodes, and some moderately heavy <quote>procedure</quote>. One
methodology is as follows:
</para>
<itemizedlist>
<listitem>
<para>
First, dump the schema from the node that has the
<quote>master</quote> role. That is the only place, pre-2.0, where
you can readily dump the schema using
<application>pg_dump</application> and have a consistent schema.
You may use the &slony1; tool <xref linkend="extractschema"/> to do
this.
</para>
</listitem>
<listitem>
<para>
Take the resulting schema, which will <emphasis>not</emphasis>
include the &slony1;-specific bits, and split it into two pieces:
</para>
<itemizedlist>
<listitem>
<para>
Firstly, the portion comprising all of the creations of tables
in the schema.
</para>
</listitem>
<listitem>
<para>
Secondly, the portion consisting of creations of indices, constraints, and triggers.
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
Pull a data dump, using <command>pg_dump --data-only</command>, of
some node of your choice. It doesn't need to be for the
<quote>master</quote> node. This dump will include the contents of
the &slony1;-specific tables; you can discard that, or ignore it.
Since the schema dump didn't contain table definitions for the
&slony1; tables, they won't be loaded.
</para>
</listitem>
<listitem>
<para>
Finally, load the three components in proper order:
</para>
<itemizedlist>
<listitem><para>Schema (tables)</para></listitem>
<listitem><para>Data dump</para></listitem>
<listitem><para>Remainder of the schema</para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</answer>
<answer>
<para>
In &slony1; 2.0, the answer becomes simpler: Just take a
<command>pg_dump --exclude-schema=_Cluster</command> against
<emphasis>any</emphasis> node. In 2.0, the schemas are no longer
<quote>clobbered</quote> on subscribers, so a straight
<application>pg_dump</application> will do what you want.
</para>
</answer>
</qandaentry>
<qandaentry id="cannotrenumbernodes">
<question>
<para>
I'd like to renumber the node numbers in my cluster. How can I renumber
nodes?
</para>
</question>
<answer>
<para>
The first answer is <quote>you can't do that</quote> - &slony1; node
numbers are quite <quote>immutable.</quote> Node numbers are deeply
woven into the fibres of the schema, by virtue of being written into
virtually every table in the system, but much more importantly by
virtue of being used as the basis for event propagation. The only time
that it might be <quote>OK</quote> to modify a node number is at some
time where we know that it is not in use, and we would need to do
updates against each node in the cluster in an organized fashion.
</para>
<para>
To do this in an automated fashion seems like a
<emphasis>huge</emphasis> challenge, as it changes the structure of the
very event propagation system that already needs to be working in order
for such a change to propagate.
</para>
</answer>
<answer>
<para>
If it is <emphasis>enormously necessary</emphasis> to renumber nodes,
this might be accomplished by dropping and re-adding nodes to get rid
of the node formerly using the node ID that needs to be held by another
node.
</para>
</answer>
</qandaentry>
</qandadiv>
<qandadiv id="faqimpossibilities">
<title>&slony1; FAQ: Impossible Things People Try</title>
<qandaentry>
<question>
<para>
Can I use &slony1; to replicate changes back and forth on my database
between my two offices?
</para>
</question>
<answer>
<para>
At one level, it is <emphasis>theoretically possible</emphasis> to do
something like that, if you design your application so that each office
has its own distinct set of tables, and you then have some system for
consolidating the data to give them some common view. However, this
requires a great deal of design work to create an application that
performs this consolidation.
</para>
</answer>
<answer>
<para>
In practice, the term for that is <quote>multimaster replication,</quote>
and &slony1; does not support <quote>multimaster replication.</quote>.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
I want to replicate all of the databases for a shared-database system
I am managing. There are multiple databases, being used by my
customers.
</para>
</question>
<answer>
<para>
For this purpose, something like &postgres; PITR (Point In Time
Recovery) is likely to be much more suitable. &slony1; requires a slon
process (and multiple connections) for each identifiable database, and
if you have a &postgres; cluster hosting 50 or 100 databases, this will
require hundreds of database connections. Typically, in <quote>shared
hosting</quote> situations, DML is being managed by customers, who can
change anything they like whenever <emphasis>they</emphasis> want.
&slony1; does not work out well when not used in a disciplined manner.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
I want to be able to make DDL changes, and have them replicated
automatically.
</para>
</question>
<answer>
<para>
&slony1; requires that <xref linkend="ddlchanges"/> be planned for
explicitly and carefully. &slony1; captures changes using triggers,
and &postgres; does not provide a way to use triggers to capture DDL
changes.
</para>
<note>
<para>
There has been quite a bit of discussion, off and on, about how
&postgres; might capture DDL changes in a way that would make triggers
useful; nothing concrete has emerged after several years of
discussion.
</para>
</note>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
I want to split my cluster into disjoint partitions that are not aware
of one another. &slony1; keeps generating <xref
linkend="listenpaths"/> that link those partitions together.
</para>
</question>
<answer>
<para>
The notion that all nodes are aware of one another is deeply imbedded
in the design of &slony1;. For instance, its handling of cleanup of
obsolete data depends on being aware of whether any of the nodes are
behind, and thus might still depend on older data.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
I want to change some of my node numbers. How do I
<quote>rename</quote> a node to have a different node number?
</para>
</question>
<answer>
<para>
You don't. The node number is used to coordinate inter-node
communications, and changing the node ID number <quote>on the fly</quote>
would make it essentially impossible to keep node configuration
coordinated.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
My application uses OID attributes; is it possible to replicate tables
like this?
</para>
</question>
<answer>
<para>
It is worth noting that oids, as a regular table attribute, have been
deprecated since &postgres; version 8.1, back in 2005. &slony1; has
<emphasis>never</emphasis> collected oids to replicate them, and, with
that functionality being deprecated, the developers do not intend to
add this functionality.
</para>
<para>
&postgres; implemented oids as a way to link its internal system tables
together; to use them with application tables is considered
<emphasis>poor practice</emphasis>, and it is recommended that you use
sequences to populate your own ID column on application tables.
</para>
</answer>
<answer>
<para>
Of course, nothing prevents you from creating a table
<emphasis>without</emphasis> oids, and then add in your own application
column called <envar>oid</envar>, preferably with type information
<command>SERIAL NOT NULL UNIQUE</command>, which
<emphasis>can</emphasis> be replicated, and which is likely to be
suitable as a candidate primary key for the table.
</para>
</answer>
</qandaentry>
</qandadiv>
<qandadiv id="faqconnections">
<title> &slony1; FAQ: Problèmes relatifs aux connections</title>
<qandaentry>
<question>
<para>
Je cherche le namespace <envar>_clustername</envar>, mais il est
introuvable.
</para>
</question>
<answer>
<para>
Si les DNS sont erronés, alors l'instance &lslon; ne pourra pas se
connecter aux n&oelig;uds.
</para>
<para>
Ceci mène au fait que les n&oelig;uds seront introuvables.
</para>
<para>
Vérifier de nouveau la configuration des connexions. D'ailleurs,
puisque <xref linkend="slon"/> est lié à libpq, vous pouvez stocker le
mot de passe dans <filename>$HOME/.pgpass</filename>, le problème vient
peut-être d'une erreur dans ce fichier.
</para>
</answer>
</qandaentry>
<qandaentry id="morethansuper">
<question>
<para>
J'ai créé un compte <quote>super-utilisateur</quote>,
<command>slony</command>, pour exécuter les activités de réplication.
Comme suggéré, je l'ai configuré comme super-utilisateur, avec la
requête suivante&nbsp;:
<command>UPDATE pg_shadow SET usesuper = 't'
WHERE usename IN ('slony', 'molly', 'dumpy');</command>
(Cette même commande permet d'autoriser autres utilisateurs à exécuter
VACUUM et sauvegardes).
</para>
<para>
Malheureusement, j'ai eu une erreur à chaque fois où je voulais
souscrire à un nouveau ensemble.
</para>
<programlisting>DEBUG1 copy_set 28661
DEBUG1 remoteWorkerThread_1: connected to provider DB
DEBUG2 remoteWorkerThread_78: forward confirm 1,594436 received by 78
DEBUG2 remoteWorkerThread_1: copy table public.billing_discount
ERROR remoteWorkerThread_1: "select "_mycluster".setAddTable_int(28661, 51, 'public.billing_discount', 'billing_discount_pkey', 'Table public.billing_discount with candidate primary key billing_discount_pkey'); " PGRES_FATAL_ERROR ERROR: permission denied for relation pg_class
CONTEXT: PL/pgSQL function "altertableforreplication" line 23 at select into variables
PL/pgSQL function "setaddtable_int" line 76 at perform
WARN remoteWorkerThread_1: data copy for set 28661 failed - sleep 60 seconds</programlisting>
<para>
Cela continue de s'arrêter avec une erreur, encore et toujours, jusqu'à
ce que je redémarre <application>slon</application> pour qu'il se
connecte avec le compte <command>postgres</command>.
</para>
</question>
<answer>
<para>
Le problème est assez évident en soi&nbsp;; le droit sur la table
système <envar>pg_class</envar> est ignoré.
</para>
</answer>
<answer>
<para>
La <quote>solution</quote> est la suivante&nbsp;:
</para>
<programlisting>UPDATE pg_shadow SET usesuper = 't', usecatupd='t'
WHERE usename = 'slony';</programlisting>
</answer>
<answer>
<para>
En version 8.1 et supérieure, vous avez aussi besoin de&nbsp;:
</para>
<programlisting>UPDATE pg_authid SET rolcatupdate = 't', rolsuper='t'
WHERE rolname = 'slony';</programlisting>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Au moment d'enregistrer un esclave, j'obtiens le message suivant dans
les journaux applicatifs&nbsp;:
<screen>DEBUG1 copy_set 1
DEBUG1 remoteWorkerThread_1: connected to provider DB
WARN remoteWorkerThread_1: transactions earlier than XID 127314958 are still in progress
WARN remoteWorkerThread_1: data copy for set 1 failed - sleep 60 seconds</screen>
</para>
</question>
<answer>
<para>
Il y a évidemment un certain nombre de vieilles transactions qui
empêchent &slony1; de traiter des synchronisations. Vous devriez
jeter un coup d'&oelig;il à pg_locks pour voir ce qu'il en est&nbsp;:
</para>
<screen>sampledb=# select * from pg_locks where transaction is not null order by transaction;
relation | database | transaction | pid | mode | granted
----------+----------+-------------+---------+---------------+---------
| | 127314921 | 2605100 | ExclusiveLock | t
| | 127326504 | 5660904 | ExclusiveLock | t
(2 rows)</screen>
<para>
Vous voyez&nbsp;? la transaction 127314921 est en effet plus vieille
que la transaction 127314958, et elle est toujours en cours d'exécution.
</para>
<para>
Un long traitement de publi-postage, une requête
<application>RT3</application> qui s'emballe, un
<application>pg_dump</application>, toutes ces opérations ouvrent des
transactions pour une période importante. Jusqu'à ce qu'elles soient
complétées ou bien interrompues, on verra alors le message d'erreur
suivant&nbsp;:
<quote>data copy
for set 1 failed - sleep 60 seconds </quote>
</para>
<para>
Quoiqu'il en soit, s'il y a plus d'une base de données sur le cluster
&postgres; et que la charge se situe sur une autre base, vous verrez
apparaître des <quote>transactions en cours avec un XID
antérieur</quote> à celle de &slony1;. Le fait que la transaction se
déroule sur une base de donnée dissociée ne change rien&nbsp;; &slony1;
attendra jusqu'à ce que ces vieilles transactions se terminent.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Même question que précèdemment. J'ai oublié de mentionner que
j'essayais d'ajouter <emphasis>DEUX</emphasis> abonnés simultanément.
</para>
</question>
<answer>
<para>
Cela ne peut pas fonctionner&nbsp;: &slony1; ne peut employer pas la
commande <command>COPY</command> de manière concurrente. Voir la
fonction <function>copy_set()</function> dans le fichier
<filename>src/slon/remote_worker.c</filename>.
</para>
<screen>$ ps -aef | egrep '[2]605100'
postgres 2605100 205018 0 18:53:43 pts/3 3:13 postgres: postgres sampledb localhost COPY</screen>
<para>
Une transaction <command>COPY</command> essaie d'installer l'abonnement
pour un des n&oelig;uds. Tout a l'air bien&nbsp;; le système s'occupe
de configurer le premier abonné&nbsp;; il ne va pas démarrer sur le
second tant que le premier n'a pas fini son enregistrement. Cela
représente une cause possible.
</para>
<para>
Ceci a comme (fâcheuse) conséquence que vous ne pouvez pas peupler deux
esclaves simultanément à partir d'un même fournisseur. Vous devez
souscrire un et un seul abonné à la fois. Une fois qu'il a accompli
l'abonnement (en copiant le contenu des table, etc.), on peut s'occuper
de débuter l'enregistrement du deuxième.
</para>
</answer>
</qandaentry>
<qandaentry id="missingoids">
<question>
<para>
Nous avons rencontré un message inattendu en désinstallant entièrement
un cluster de réplication slony sur le maître et l'esclave.
</para>
<warning>
<para>
<emphasis>MAKE SURE YOU STOP YOUR APPLICATION RUNNING AGAINST YOUR
MASTER DATABASE WHEN REMOVING THE WHOLE SLONY CLUSTER</emphasis>,
or at least re-cycle all your open connections after the event!
</para>
</warning>
<para>
The connections <quote>remember</quote> or refer to OIDs which are
removed by the uninstall node script. And you will get lots of errors
as a result...
</para>
</question>
<answer>
<para>
Il y a deux mécanismes de &postgres; qui mettent en cache les plans
d'interrogation et les OIDs&nbsp;:
</para>
<itemizedlist>
<listitem>
<para>les requêtes préparées («&nbsp;prepared statements&nbsp;»)&nbsp;;</para>
</listitem>
<listitem>
<para>les fonctions PL/pgsql.</para>
</listitem>
</itemizedlist>
<para>
Ce problème n'est pas particulier à &slony1;; il se produit à chaque
fois que des modifications importantes sont apportées aux schémas de
la base de données. Cela n'entraîne pas de perte des données mais cela
provoque des vagues d'erreurs relatives aux OID.
</para>
</answer>
<answer>
<para>
Le problème survient lorsque vous utilisez une sorte de <quote>pool de
connexion</quote> qui recycle les vieilles connexions. Si vous relancez
l'application après ceci, les nouvelles connexions vont produire de
<emphasis>nouveaux</emphasis> plans d'exécution et les erreurs
disparaîtront. Si votre pool de connexion tue les sessions et en
recrée de nouvelles, alors ces nouvelles sessions auront de
<emphasis>nouveaux</emphasis> plans d'exécution et les erreurs disparaîtront.
</para>
</answer>
<answer>
<para>
Dans notre code, nous éliminons toutes connexions ayant des erreurs
inattendues dans le contexte. Ainsi, toutes les connexions devraient
être renouvelées dès l'apparition d'une erreur inattendue.
Naturellement, si l'erreur remonte une violation de contrainte, qui est
une condition reconnue, cela va provoquer un renouvellement de connexion.
Si le problème persiste, les connexions sont recyclées en permanence,
ce qui annulera l'effet du pool. Dans ce cas, le pooler de connexion
proposera probablement à l'administrateur de jeter un coup d'&oelig;il
à la situation.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai migré mon &slony1; en version 1.2. J'ai maintenant cet
avertissement dans les journaux applicatifs&nbsp;:
</para>
<screen>NOTICE: Slony-I: log switch to sl_log_2 still in progress - sl_log_1 not truncated</screen>
<para>
Les tables <envar>sl_log_1</envar> et <envar>sl_log_2</envar>
continuent de prendre du volume, et <envar>sl_log_1</envar> n'est
jamais vidée. Quel est le souci&nbsp;?
</para>
</question>
<answer>
<para>
Ceci est un cas symptomatique du problème précèdent, relatif à la
suppression de la réplication&nbsp;: s'il y a des vieilles connexions
établies, qui continuent à utiliser des plan d'exécutions basés sur
des vieilles procédures stockées, cela provoque des écritures dans
<envar>sl_log_1</envar>.
</para>
<para>
La fermeture des vieilles connexions et l'ouverture de nouvelles
connexions résoudra ce problème.
</para>
</answer>
<answer>
<para>
À plus long terme, un élément de la liste des choses à faire pour
&postgres; est l'implantation d'une vérification des dépendances, qui
pourra supprimer un plan d'exécution caché lorsqu'un objet lié à ce
plan est modifié.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai pointé un n&oelig;ud abonné vers un n&oelig;ud fournisseur différent,
et il a cessé la réplication.
</para>
</question>
<answer>
<para>
Nous avons constaté que ceci arrive lorsque on réinitialise un
n&oelig;ud dans la configuration suivante&nbsp;:
<itemizedlist>
<listitem>
<para>N&oelig;ud 1 - fournisseur</para>
</listitem>
<listitem>
<para>
N&oelig;ud 2 - abonné au n&oelig;ud 1 - le n&oelig;ud que l'on
réinitialise
</para>
</listitem>
<listitem>
<para>
N&oelig;ud 3 - abonné au n&oelig;ud 3 - le n&oelig;ud qui doit
continuer à répliquer
</para>
</listitem>
</itemizedlist>
</para>
<para>
L'abonnement du n&oelig;ud 3 est changé pour que le n&oelig;ud 1 soit
son fournisseur et on exécute <xref linkend="stmtdropset"/> / <xref
linkend="stmtsubscribeset"/> sur le n&oelig;ud 2 pour qu'il soit
repeuplé.
</para>
<para>
Malheureusement, la réplication s'arrête soudainement sur le n&oelig;ud
3.
</para>
<para>
Le problème vient du fait qu'il n'y a pas d'ensemble approprié de
<quote>voies d'écoute</quote> dans la table <xref
linkend="table.sl-listen"/> pour propager les évènements depuis le
n&oelig;ud 1 vers le n&oelig;ud 3. Les événements sont transportés vers
le n&oelig;ud 2 et sont bloqués par l'événement <xref
linkend="stmtsubscribeset"/> que le n&oelig;ud 2 est en train de
traiter.
</para>
<para>
Le script suivant supprime les voies d'écoute qui font transiter les
événements par le n&oelig;ud 2 et ajoute une voie d'écoute directe
entre les n&oelig;uds 1 et 3.
<programlisting>cluster name = oxrslive;
node 1 admin conninfo='host=32.85.68.220 dbname=oxrslive user=postgres port=5432';
node 2 admin conninfo='host=32.85.68.216 dbname=oxrslive user=postgres port=5432';
node 3 admin conninfo='host=32.85.68.244 dbname=oxrslive user=postgres port=5432';
node 4 admin conninfo='host=10.28.103.132 dbname=oxrslive user=postgres port=5432';
try {
store listen (origin = 1, receiver = 3, provider = 1);
store listen (origin = 3, receiver = 1, provider = 3);
drop listen (origin = 1, receiver = 3, provider = 2);
drop listen (origin = 3, receiver = 1, provider = 2);
}</programlisting></para>
<para>
Juste après l'exécution de ce script, les événements
<command>SYNC</command> se propagent à nouveau vers le n&oelig;ud 3.
Ceci souligne deux principes&nbsp;:
<itemizedlist>
<listitem>
<para>
Si vous avez plusieurs n&oelig;uds et des abonnés en cascade,
vous devez faire attention en repeuplant les entrées <xref
linkend="stmtstorelisten"/> et en les modifiant si la structure
de l'<quote>arbre</quote> de réplication a changé.
</para>
</listitem>
<listitem>
<para>
La version 1.1 fourni des meilleurs outils pour gérer ce cas.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Les problèmes relatifs aux <quote>voies d'écoute</quote> sont discutés
avec plus de précisions dans la section <xref linkend="listenpaths"/>.
</para>
</answer>
</qandaentry>
<qandaentry id="multipleslonconnections">
<question>
<para>
En redémarrant &lslon;, j'obtiens les messages <quote>FATAL</quote>
suivants dans les journaux applicatifs. Que se passe-t-il&nbsp;?
</para>
<screen>2006-03-29 16:01:34 UTC CONFIG main: slon version 1.2.0 starting up
2006-03-29 16:01:34 UTC DEBUG2 slon: watchdog process started
2006-03-29 16:01:34 UTC DEBUG2 slon: watchdog ready - pid = 28326
2006-03-29 16:01:34 UTC DEBUG2 slon: worker process created - pid = 28327
2006-03-29 16:01:34 UTC CONFIG main: local node id = 1
2006-03-29 16:01:34 UTC DEBUG2 main: main process started
2006-03-29 16:01:34 UTC CONFIG main: launching sched_start_mainloop
2006-03-29 16:01:34 UTC CONFIG main: loading current cluster configuration
2006-03-29 16:01:34 UTC CONFIG storeSet: set_id=1 set_origin=1 set_comment='test set'
2006-03-29 16:01:34 UTC DEBUG2 sched_wakeup_node(): no_id=1 (0 threads + worker signaled)
2006-03-29 16:01:34 UTC DEBUG2 main: last local event sequence = 7
2006-03-29 16:01:34 UTC CONFIG main: configuration complete - starting threads
2006-03-29 16:01:34 UTC DEBUG1 localListenThread: thread starts
2006-03-29 16:01:34 UTC FATAL localListenThread: "select "_test1538".cleanupNodelock(); insert into "_test1538".sl_nodelock values ( 1, 0, "pg_catalog".pg_backend_pid()); " - ERROR: duplicate key violates unique constraint "sl_nodelock-pkey"
2006-03-29 16:01:34 UTC FATAL Do you already have a slon running against this node?
2006-03-29 16:01:34 UTC FATAL Or perhaps a residual idle backend connection from a dead slon?</screen>
</question>
<answer>
<para>
La table <envar>sl_nodelock</envar> est utilisée comme un <quote>verrou
partagé</quote> pour empêcher que deux processus &lslon; essaient de
prendre le controle du même n&oelig;ud en même temps. Le &lslon; essaie
d'insérer un enregistrement dans la table&nbsp;; il ne peut réussir que
s'il est le seul à gérer le n&oelig;ud.
</para>
</answer>
<answer>
<para>
Ce message d'erreur est typiquement un signe que vous avez démarrez un
second processus &lslon; pour un n&oelig;ud donné. Le &lslon; pose la
question évidente suivante&nbsp;: <quote>avez-vous déjà un slon démarré
pour gérer ce n&oelig;ud&nbsp;?</quote>
</para>
</answer>
<answer>
<para>
En supposant que vous subissez une panne réseau, les connections entre
&lslon; et la base de données peuvent échouer et &lslon; peut s'en
apercevoir bien avant l'instance de &postgres; sur laquelle il est
connecté. La conséquence en est qu'un certain nombre de connexions
pré-établies vont rester ouvertes sur la base de données jusqu'à ce
que le timeout TCP/IP arrive à échéance, chose qui normalement arrive
au bout de deux heures. Durant cette période de deux heures, le &lslon;
va essayer de se reconnecter, encore et encore, et fait que vous
obtenez le message d'erreur ci-dessous, encore et encore.
</para>
<para>
Un administrateur peut mettre fin à cette situation en se connectant sur
le serveur et en lançant <command>kill -2</command> pour terminer les
connexions bloquantes. Malheureusement, puisque le problème a eu lieu
au niveau de la couche réseau, &postgres; et &slony1; n'ont aucun
moyen direct de détecter ceci.
</para>
<para>
Vous pouvez éviter ceci dans la <emphasis>plupart</emphasis> des cas
en vous assurant que le processus &lslon; est hébergé à proximité des
serveurs qu'il gère. Si le &lslon; est hébergé sur le même serveur que
la base de donnée qu'il gère, alors toute <quote>panne réseau</quote>
qui peut interrompre les connexions serait susceptible d'être assez
sérieus pour menacer le serveur entier.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Quand puis-je arrêter les processus &lslon;&nbsp;?
</para>
</question>
<answer>
<para>
Généralement, il n'y a aucun risque à arrêter un processus &lslon;.
Chacun d'eux est <quote>simplement</quote> un client de &postgres;,
gérant un n&oelig;ud, qui déploie des threads pour gérer et recevoir
des évènements depuis d'autres n&oelig;uds.
</para>
<para>
Les threads des <quote>évènements d'écoute</quote> ne sont pas très
importants&nbsp;; ils ne font que vérifier de temps en temps les
n&oelig;uds distants pour déterminer s'il y a des taches à faire sur
le n&oelig;ud local. Si vous tuez le processus &lslon; ces threads de
surveillance seront fermés, ce qui aura peu ou pas du tout d'impact.
Les événements produits pendant que &lslon; est arrêté seront récupérés
lors de son redémarrage.
</para>
<para>
Le thread de <quote>gestion des n&oelig;uds</quote> est un peu plus
intéressant&nbsp;; la plupart du temps, sur un abonné, on peut
s'attendre à ce que le thread traite des événements
<command>SYNC</command>. Si vous arrêtez le &lslon; durant un évènement,
la transaction va échouer et s'annuler. Lorsque &lslon; redémarre, il
reprendra l'évènement pour l'exécuter.
</para>
<para>
L'unique situation où cela peut provoquer des problèmes
<emphasis>particulièrs</emphasis> est lorsque l'évènement en cours est
un traitement de longue durée comme un <command>COPY_SET</command> pour
un large ensemble de réplication.
</para>
<para>
L'autre chose qui <emphasis>pourrait</emphasis> poser problème
est s'il est relativement distant du n&oelig;ud auxquel il est
connecté&nbsp;; vous pouvez découvrir que les connexions de la base
de données sont laissées <command>disponibles en transaction</command>
&nbsp;idle in transaction&nbsp;»). Ceci peut survenir si les
connexions réseaux sont supprimées sans que ni &lslon; ni la base en
aient pris connaissance. Dans ce cas, vous pouvez découvrir que des
connexions <quote>zombies</quote> traînent encore durant deux longues
heures si vous n'allez pas tuer à la main les processus &postgres;.
</para>
<para>
Il y existe un autre cas qui peut poser problème&nbsp;: quand le
processus &lslon; qui administre le n&oelig;ud origine ne fonctionne
pas, aucun évènement <command>SYNC</command> ne s'exécute sur ce
n&oelig;ud. Si le &lslon; reste arrêté pendant une longue durée et
qu'aucun processus de type <xref linkend="gensync"/> n'est en cours,
alors vous pouvez vous retrouver avec <emphasis>un énorme
<command>SYNC</command></emphasis> à effectuer lorsque le processus
&lslon; du n&oelig;ud origine sera relancé. Toutefois, ceci est vrai
seulement si &lslon; est en arrêt pendant une période assez
longue&nbsp;; un arrêt de quelques secondes ne génère pas de problèmes.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Y a-t-il des risques lorsqu'on arrête &lslon;&nbsp;? Quels sont les
avantages&nbsp;?
</para>
</question>
<answer>
<para>
En bref, si un <command>COPY_SET</command> qui dure 18h n'est pas en
cours d'exécution, alors ce n'est pas un grand sacrifice d'arrêter un
&lslon; pendant quelques instants, ni même de relancer
<emphasis>tous</emphasis> les &lslon;.
</para>
</answer>
</qandaentry>
</qandadiv>
<qandadiv id="faqconfiguration">
<title>FAQ &slony1;&nbsp;: Problèmes de configuration</title>
<qandaentry>
<question>
<para>
Slonik échoue lors du chargement des bibliothèques &postgres;&nbsp;:
<command>PGRES_FATAL_ERROR load '$libdir/xxid';</command>
</para>
<para>
Lorsque j'exécute un simple script de configuration, j'obtiens un
message similaire à&nbsp;:
<command>stdin:64: PGRES_FATAL_ERROR load '$libdir/xxid'; - ERROR: LOAD:
could not open file '$libdir/xxid': No such file or directory</command>
</para>
</question>
<answer>
<para>
Évidemment, vous n'avez pas accès à la bibliothèque
<filename>xxid.so</filename> dans le répertoire <envar>$libdir</envar>
que l'instance &postgres; utilise. Notez que les composants &slony1;
doivent être installés avec le noyau &postgres; sur <emphasis>chacun
des n&oelig;uds</emphasis> et pas seulement sur le n&oelig;ud d'origine.
</para>
<para>
Cela peut également venir du fait d'une disparité entre les binaires
du noyau &postgres; et celui du noyau de &slony1;. Si vous avez
manuellement compilé &slony1; par vous-même, sur une machine où il y
a plusieurs versions de &postgres;, il est possible que les binaires
slon ou slonik demande de charger une bibliothèque qui n'est pas
accessible dans les répertoires des bibliothèques de la version de
&postgres; utilisée.
</para>
<para>
En deux mots&nbsp;: ceci indique que vous devez <quote>auditer</quote>
l'installation des instances &postgres; et &slony1; qui sont en place
sur la machine. Malheureusement, n'importe quelle incompatibilité peut
faire remonter ce genre d'erreur. Voir aussi la <link
linkend="threadsafety">sécurité des threads</link> à propos de la
gestion des threads sur Solaris.
</para>
<para>
La situation est plus simple si vous avez une seule version de
&postgres; installée par serveur&nbsp;; dans ce cas, il n'y aura pas
d'<quote>incompatibilité de chemins</quote> là où les composants de
&slony1; sont installés. Si vous avez une installation multiple, vous
devrez vous assurer que la bonne version de &slony1; est associée à la
bonne version du noyau de &postgres;.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'essaie de créer un cluster dont le nom contient un tiret. Cela ne
fonctionne pas.
</para>
</question>
<answer>
<para>
&slony1; utilise les mêmes règles de nommage que &postgres;, donc vous
ne devriez pas utiliser un tiret dans les identifiants.
</para>
<para>
Vous pouvez tenter de mettre des simples <quote>guillemets</quote> pour
l'identifiant, mais vous allez vous exposer à des soucis qui pourront
surgir à tout moment.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
La commande ps affiche le mot de passe en clair.
</para>
<para>
Avec la commande <command>ps</command>, tout le monde peut voir le mot
de passe qui a été fourni sur la ligne de commande.
</para>
</question>
<answer>
<para>
Conservez le mot de passe en dehors de la configuration Slony, en les
mettant dans le fichier <filename>$(HOME)/.pgpass.</filename>.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Les index dont le nom contient le namespace
<programlisting>set add table (set id = 1, origin = 1, id = 27,
full qualified name = 'nspace.ma_table',
key = 'clef_sur_une_colonne',
comment = 'une table ma_table dans le namespace nspace avec une clef primaire');</programlisting>
</para>
</question>
<answer>
<para>
Si vous avez <command> key = 'nspace.clef_sur_une_colonne'</command>,
la requête <emphasis>échouera</emphasis>.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
La réplication est retardée, et il semble que les requêtes sur les
tables &sllog1;/&sllog2; prennent beaucoup de temps alors qu'il n'y a
que quelques événements <command>SYNC</command>.
</para>
</question>
<answer>
<para>
Jusqu'à la version 1.1.1, les tables &sllog1;/&sllog2; possédaient
seulement un index, et lorsqu'il y avait plusieurs ensembles de
réplication, quelques colonnes dans l'index n'étaient pas assez
discriminantes. Si l'index ne contient pas la colonne
<function>log_xid</function>, il est conseillé de l'ajouter. Voir le
script <filename>slony1_base.sql</filename> pour regarder la manière
de créer cet index.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai besoin de renommer une colonne qui figure dans la clef primaire
pour l'une de mes tables répliquées. L'opération est un peu dangereuse,
n'est-ce pas&nbsp;? Je dois retirer la table de la réplication puis la
replacer, c'est bien ça&nbsp;?
</para>
</question>
<answer>
<para>
En fait, cette opération fonctionne proprement. &slony1; fait un usage
intensif des clefs primaires mais, en pratique, ce type d'opération
peut se faire de manière transparente.
</para>
<para>
Supposons que vous souhaitez renommer une colonne, avec la commande DDL
suivante <command>ALTER TABLE accounts ALTER COLUMN aid RENAME TO
cid;</command>. Ceci permet de renommer la colonne dans la table&nbsp;;
elle permet de mettre à jour <emphasis>simultanément</emphasis> l'index
de la clef primaire. Le résultat est que ce genre de changement
s'effectue simultanément sur un n&oelig;ud donné.
</para>
<para>
Dans l'<emphasis>ideal</emphasis> et pour bien faire les choses, il
aurait fallu utiliser <xref linkend="stmtddlscript"/> pour déployer
la modification au bon moment sur chaque n&oelig;ud.
</para>
<para>
Toutefois, ce n'est pas forcément nécessaire. Tant que la modification
est appliquée sur le n&oelig;ud origine avant d'être effectuée sur les
abonnés, il n'y aura pas de cassure irrémédiable. Certains évènements
<command>SYNC</command> qui n'incluent pas la table sur laquelle il y
a la modification, pourront fonctionner sans problème... Par contre,
lorsqu'une mise à jour de la table est effectuée sur un abonné, alors
les événements <command>SYNC</command> vont échouer puisque le
fournisseur indiquera une <quote>nouvelle</quote> colonne alors que
l'abonné connait toujours les <quote>anciennes</quote>. Dès que l'on
appliquera la modification de la clef chez l'abonné, les événements
<command>SYNC</command> seront traités de nouveau et le
<quote>nouveau</quote> nom de colonne sera présent. Tout fonctionnera
sans problème.
</para>
</answer>
</qandaentry>
<qandaentry id="v72upgrade">
<question>
<para>
J'ai un &postgres; version 7.2 et je souhaite
<emphasis>vraiment</emphasis> utiliser &slony1; pour le migrer en
version 8.0. Que faut-il faire pour que &slony1; fonctionne&nbsp;?
</para>
</question>
<answer>
<para>
Voici Rod Taylor écrit sur le sujet...
</para>
<para>
Voici approximativement ce dont vous avez besoin&nbsp;:
</para>
<itemizedlist>
<listitem>
<para>
Prendre les templates 7.3 et les copier en 7.2 -- ou bien écrire
en dur la version de vos templates
</para>
</listitem>
<listitem>
<para>
Supprimer toute trace de schémas dans le code SQL de vos templates.
Concrètement, j'ai remplacé les points par des tirets.
</para>
</listitem>
<listitem>
<para>
Pas mal de travaux sur les types et fonctions XID. Par exemple,
Slony crée des conversions pour la conversion xid vers xxid et
vice versa -- mais la 7.2 ne peut pas créer de nouvelles conversions
et dans ce cas vous êtes obligé de le modifier à la main. Je me
rappelle avoir créé une classe d'opérateur et modifié certaines
fonctions.
</para>
</listitem>
<listitem>
<para>
sl_log_1 aura de graves problèmes de performance quelque soit le
volume des données. Ceci exige qu'un certain nombre d'index soient
positionnés pour optimiser les interrogations en 7.2, 7.3 et
supérieur.
</para>
</listitem>
<listitem>
<para>
Ne pas s'embêter à essayer de faire fonctionner les séquences.
Faites-les à la main en utilisant pg_dump et grep.
</para>
</listitem>
</itemizedlist>
<para>
Bien sûr, une fois ces pre-requis terminés, on n'est pas encore
compatible avec le Slony standard. Ainsi soit vous devez au moins
modifier la version 7.2 de manière moins artisanale soit vous devez
modifier slony pour qu'il fonctionne sans les schémas avec les
nouvelles versions de &postgres; afin qu'ils puissent dialoguer.
</para>
<para>
Juste après le déroulement de la procédure de migration de 7.2 vers
7.4, on peut désinstaller la version bidouillée de Slony (à la main
encore pour la majeure partie), et démarrer la migration de 7.2 à
7.4 sur les différentes machines en utilisant un Slony standard.
Ceci afin de s'assurer qu'on ne conserve pas les catalogues systèmes
qui ont subi des changements manuels.
</para>
<para>
Ceci étant dit, nous avons migré quelques centaines de Go de données,
de 7.2 à 7.4 avec une coupure de service de 30 minutes (contre 48
heures de sauvegarde/restauration) et sans pertes de données.
</para>
</answer>
<answer>
<para>
Ceci vous dresse un éventail assez laid des <quote>bidouilles</quote>
qu'il faut faire entrer dans le périmètre de production. Si quelqu'un
est intéressé pour <quote>industrialiser</quote> cette tache, il vaut
mieux s'appuyer sur &slony1; en version 1.0, avec un maître mot de ne
<emphasis>pas</emphasis> essayer de le rendre pérenne, étant donnée sa
durée de vie limitée.
</para>
<para>
Vous devriez seulement adapter cette solution que si vous êtes à l'aise
avec &postgres; et &slony1; et si mettre la main dans le code ne vous
fait pas peur.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai subit une <quote>avarie réseau</quote> qui m'a obligé à utiliser
<xref linkend="stmtfailover"/> pour basculer sur un n&oelig;ud
secondaire. Le plantage n'était pas causé par un problème de corruption
de données venant du disque. Pourquoi serais-je obligé de reconstruire
le n&oelig;ud qui s'est arrêté brutalement&nbsp;?
</para>
</question>
<answer>
<para>
Le rôle de <xref linkend="stmtfailover"/> est
d'<emphasis>abandonner</emphasis> le n&oelig;ud arrêté brutalement et,
par conséquence il n'a plus de charge générée par l'activité de
&slony1;. Plus le temps passe plus, le serveur arrêté brutalement se
désynchronise.
</para>
</answer>
<answer>
<para>
L'<emphasis>énorme</emphasis> problème pour restaurer le serveur planté
est qu'il peut contenir des mises à jours qui n'ont pas eu le temps de
se propager en dehors. Vous ne pouvez pas non plus les rejouer car
elles vont être conflictuelles, car à moitié en place. En tout cas,
vous avez une sorte de corruption <quote>logique</quote> de données,
qui n'est jamais causée par une erreur disque dite
<quote>physique</quote>.
</para>
</answer>
<answer>
<para>
Comme cela a été abordé dans la section <xref linkend="failover"/>, <xref
linkend="stmtfailover"/> doit être utilisé en <emphasis>dernier
recourt</emphasis> car cela implique d'abandonner le n&oelig;ud
d'origine pour cette corruption.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Après notification d'un abonnement sur un <emphasis>autre</emphasis>
n&oelig;ud, la réplication échoue sur l'un des abonnés avec le message
d'erreur suivant&nbsp;:
</para>
<screen>ERROR remoteWorkerThread_1: "begin transaction; set transaction isolation level serializable; lock table "_livesystem".sl_config_lock; select "_livesystem".enableSubscription(25506, 1, 501); notify "_livesystem_Event"; notify "_livesystem_Confirm"; insert into "_livesystem".sl_event (ev_origin, ev_seqno, ev_timestamp, ev_minxid, ev_maxxid, ev_xip, ev_type , ev_data1, ev_data2, ev_data3, ev_data4 ) values ('1', '4896546', '2005-01-23 16:08:55.037395', '1745281261', '1745281262', '', 'ENABLE_SUBSCRIPTION', '25506', '1', '501', 't'); insert into "_livesystem".sl_confirm (con_origin, con_received, con_seqno, con_timestamp) values (1, 4, '4896546', CURRENT_TIMESTAMP); commit transaction;" PGRES_FATAL_ERROR ERROR: insert or update on table "sl_subscribe" violates foreign key constraint "sl_subscribe-sl_path-ref"
DETAIL: Key (sub_provider,sub_receiver)=(1,501) is not present in table "sl_path".</screen>
<para>
Par la suite, l'erreur est suivie par un ensemble de SYNC en échec
tandis que <xref linkend="slon"/> s'arrête&nbsp;:
</para>
<screen>DEBUG2 remoteListenThread_1: queue event 1,4897517 SYNC
DEBUG2 remoteListenThread_1: queue event 1,4897518 SYNC
DEBUG2 remoteListenThread_1: queue event 1,4897519 SYNC
DEBUG2 remoteListenThread_1: queue event 1,4897520 SYNC
DEBUG2 remoteWorker_event: ignore new events due to shutdown
DEBUG2 remoteListenThread_1: queue event 1,4897521 SYNC
DEBUG2 remoteWorker_event: ignore new events due to shutdown
DEBUG2 remoteListenThread_1: queue event 1,4897522 SYNC
DEBUG2 remoteWorker_event: ignore new events due to shutdown
DEBUG2 remoteListenThread_1: queue event 1,4897523 SYNC</screen>
</question>
<answer>
<para>
Si vous constatez qu'un &lslon; s'arrête et que le jounal des traces
indique que des événements ont été ignorés, vous devez remonter dans le
journal <emphasis>avant</emphasis> que ces erreurs n'apparaissent, pour
trouver des indications sur l'origine du problème.
</para>
</answer>
<answer>
<para>
Dans ce cas particulier, l'erreur est due à la commande <xref
linkend="stmtstorepath"/> qui n'est pas encore répercutée sur le
n&oelig;ud 4 en attendant la propagation de la commande <xref
linkend="stmtsubscribeset"/>.
</para>
<para>
Cet exemple démontre à nouveau qu'il ne faut pas se précipiter&nbsp;;
vous devez vous assurer que tout fonctionne correctement
<emphasis>avant</emphasis> de poursuivre les changements de configuration.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai juste utilisé <xref linkend="stmtmoveset"/> afin de déporter le
n&oelig;ud d'origine sur un nouveau serveur. Malheureusement, certains
abonnés sont toujours attachés à l'ancien n&oelig;ud que je viens de
migrer or je ne peux les mettre hors service tant qu'ils n'ont pas reçu
le signalement de ce changement. Que puis-je faire&nbsp;?
</para>
</question>
<answer>
<para>
Vous avez besoin d'utiliser <xref linkend="stmtsubscribeset"/> afin de
modifier les abonnements de ces serveurs abonnés et les réorienter vers
un fournisseur qui <emphasis>sera</emphasis> disponible durant la
période de maintenance.
</para>
<warning>
<para>
Il <emphasis>ne faut pas</emphasis> faire <xref
linkend="stmtunsubscribeset"/> car vous seriez obligé de recharger
toutes les données à partir de zéro.
</para>
</warning>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Après la notification d'un abonnement auprès <emphasis>d'un
autre</emphasis> serveur fournisseur, la réplication tombe en panne, et
affiche des messages d'erreurs du type&nbsp;:
</para>
<screen>ERROR remoteWorkerThread_1: "begin transaction; set transaction isolation level serializable; lock table "_livesystem".sl_config_lock; select "_livesystem".enableSubscription(25506, 1, 501); notify "_livesystem_Event"; notify "_livesystem_Confirm"; insert into "_livesystem".sl_event (ev_origin, ev_seqno, ev_timestamp, ev_minxid, ev_maxxid, ev_xip, ev_type , ev_data1, ev_data2, ev_data3, ev_data4 ) values ('1', '4896546', '2005-01-23 16:08:55.037395', '1745281261', '1745281262', '', 'ENABLE_SUBSCRIPTION', '25506', '1', '501', 't'); insert into "_livesystem".sl_confirm (con_origin, con_received, con_seqno, con_timestamp) values (1, 4, '4896546', CURRENT_TIMESTAMP); commit transaction;" PGRES_FATAL_ERROR ERROR: insert or update on table "sl_subscribe" violates foreign key constraint "sl_subscribe-sl_path-ref"
DETAIL: Key (sub_provider,sub_receiver)=(1,501) is not present in table "sl_path".</screen>
<para>
Ceci est suivi plus tard par une série d'erreur de syncs tandis que le
démon <xref linkend="slon"/> s'arrête&nbsp;:
<screen>DEBUG2 remoteListenThread_1: queue event 1,4897517 SYNC
DEBUG2 remoteListenThread_1: queue event 1,4897518 SYNC
DEBUG2 remoteListenThread_1: queue event 1,4897519 SYNC
DEBUG2 remoteListenThread_1: queue event 1,4897520 SYNC
DEBUG2 remoteWorker_event: ignore new events due to shutdown
DEBUG2 remoteListenThread_1: queue event 1,4897521 SYNC
DEBUG2 remoteWorker_event: ignore new events due to shutdown
DEBUG2 remoteListenThread_1: queue event 1,4897522 SYNC
DEBUG2 remoteWorker_event: ignore new events due to shutdown
DEBUG2 remoteListenThread_1: queue event 1,4897523 SYNC</screen>
</para>
</question>
<answer>
<para>
Si vous constatez qu'un démon &lslon; s'arrête et que le jounal des
traces indique que des événements ont été ignorés, vous devez remonter
dans le journal <emphasis>avant</emphasis> que ces erreurs
n'apparaissent, pour trouver des indications sur l'origine du problème.
</para>
</answer>
<answer>
<para>
Dans ce cas particulier, le problème était que certaines commandes <xref
linkend="stmtstorepath"/> n'ont pas été transmises aux n&oelig;ud 4
avant que la commande <xref linkend="stmtsubscribeset"/> ne soit
propagée.
</para>
<para>
C'est encore un exemple où il ne faut pas hâtivement modifier les
choses&nbsp;; vous devez être sûr que tout fonctionne bien
<emphasis>avant</emphasis> de faire de nouveaux changements de
configuration.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Est-ce que l'ordre est important dans un ensemble de réplication&nbsp;?
</para>
</question>
<answer>
<para>
La plupart de temps, il ne l'est pas. On pourrait imaginer qu'il faille
déclarer les tables <quote>mères</quote> avant leur <quote>filles</quote>
en fonction des relations de clefs étrangères qui les relient&nbsp;;
mais ce n'est <emphasis>pas nécessaire</emphasis> si, sur le n&oelig;ud
abonné, on a pris le soin de désactiver les déclencheurs.
</para>
</answer>
<answer>
<para>
(Commentaires de Jan Wieck) L'ordre des identifiants des tables a une
importance uniquement lors d'une opération de <xref
linkend="stmtlockset"/> en préparation de basculement. Si l'ordre est
différent de celui selon lequel les applications obtiennent des verrous,
ces derniers peuvent se transformer en verrous interbloqués
&nbsp;deadlock&nbsp;») et par conséquent faire tomber l'application ou
bien <application>slon</application>.
</para>
</answer>
<answer>
<para>
(David Parker) J'ai renconté un autre cas où l'ordre des tables avait
une importance&nbsp;: avec l'héritage. Si une table fille se présente
avant la table mère, alors l'abonnement initial provoquera la suppression
du contenu de la table, alors qu'elle aura probablement reçue des
données. En effet, la logique de la commande <command>copy_set</command>
effectue un <command>delete</command>, et non pas un <command>delete
only</command>, ce qui implique que la suppression des données de la
table maître provoquera la suppression de celle de la table fille.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Si votre script <xref linkend="slonik"/> ressemble à quelque chose comme
celui ci-dessous, il peut tomber en erreur et ne jamais se terminer car
on ne peut pas utiliser <command>wait for event</command> à l'intérieur
d'un bloc <command>try</command>. Un bloc <command>try</command> est
exécuté comme une seule et même transaction, et l'évènement pour lequel
vous êtes en attente peut ne jamais avoir lieu dans le courant de la
transaction.
</para>
<programlisting>try {
echo 'Moving set 1 to node 3';
lock set (id=1, origin=1);
echo 'Set locked';
wait for event (origin = 1, confirmed = 3);
echo 'Moving set';
move set (id=1, old origin=1, new origin=3);
echo 'Set moved - waiting for event to be confirmed by node 3';
wait for event (origin = 1, confirmed = 3);
echo 'Confirmed';
} on error {
echo 'Could not move set for cluster foo';
unlock set (id=1, origin=1);
exit -1;
}</programlisting>
</question>
<answer>
<para>
Vous ne devez pas invoquer <xref linkend="stmtwaitevent"/> à l'intérieur
d'un bloc <quote>try</quote>.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Slony-I: cannot add table to currently subscribed set 1</para>
<para>
J'ai essayé de rajouter une table à un jeu d'ensemble et j'ai le message
d'erreur suivant&nbsp;:
<screen>Slony-I: cannot add table to currently subscribed set 1</screen>
</para>
</question>
<answer>
<para>
Vous ne pouvez pas rajouter des tables à un ensemble pour lequel il y a
des abonnées.
</para>
<para>
Le contournement est de créer un <emphasis>AUTRE</emphasis> ensemble de
réplication, d'y rajouter les tables souhaitées, de brancher les
serveurs abonnés à l'ensemble de réplication 1 sur le nouveau qu'on vient
de créer, et enfin de fusionner les deux ensembles.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>ERROR: duplicate key violates unique constraint "sl_table-pkey"</para>
<para>
En essayant de monter un deuxième ensemble de réplication, j'ai ce
message&nbsp;:
<screen>stdin:9: Could not create subscription set 2 for oxrslive!
stdin:11: PGRES_FATAL_ERROR select "_oxrslive".setAddTable(2, 1, 'public.replic_test', 'replic_test__Slony-I_oxrslive_rowID_key', 'Table public.replic_test without primary key'); - ERROR: duplicate key violates unique constraint "sl_table-pkey"
CONTEXT: PL/pgSQL function "setaddtable_int" line 71 at SQL statement</screen>
</para>
</question>
<answer>
<para>
Les identifiants des tables utilisées dans <xref
linkend="stmtsetaddtable"/> doivent être uniques <emphasis>À TRAVERS
TOUS LES ENSEMBLES DE REPLICATION</emphasis>. En conséquence, vous ne
pouvez pas reprendre la numérotation à zéro à l'intérieur d'un deuxième
ensemble de réplication&nbsp;; si vous les numérotez de manière
consécutive, le prochain ensemble de réplication doit commencer avec un
identifiant supérieur à ceux de l'ensemble précédent.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
L'un de mes n&oelig;udss est tombé (&lslon; ou le postmaster était
arrêté) et personne ne s'en est aperçu pendant plusieurs jours.
Maintenant, lorsque &lslon; démarre sur ce n&oelig;ud, il tourne durant
cinq minutes, puis s'arrête avec l'erreur suivante&nbsp;:
<command>ERROR: remoteListenThread_%d: timeout for event selection</command>
Quel est le problème&nbsp;? Que faire pour le résoudre&nbsp;?
</para>
</question>
<answer>
<para>
Le problème est que le port d'écoute de ce processus
(dans <filename>src/slon/remote_listener.c</filename>) arrive à une
expiration de temps lorsqu'il tente de déterminer quel le prochain
évènement à reprendre sur ce n&oelig;ud. Par défaut, le délai
d'expiration de cette interrogation est de cinq minutes&nbsp;; si la
reprise contient les évènements pour une durée de plusieurs jours,
cela prendra beaucoup plus de temps.
</para>
</answer>
<answer>
<para>
La réponse à cette question, pour les versions de &slony1; antérieures
aux versions 1.1.7, 1.2.7, et à 1.3, serait d'augmenter le délai
d'expiration dans <filename>src/slon/remote_listener.c</filename>, de
recompiler &lslon; et enfin de ré-essayer.
</para>
</answer>
<answer>
<para>
Une autre réponse serait de conseiller de reconstruire entièrement le
n&oelig;ud ayant échoué, à l'aide de la commande &lslonik;
<xref linkend="stmtdropnode"/> en le supprimant d'abord et en le
recréant après. Si les mises à jours sont volumineuses côté base de
données, il vaut mieux reconstruire plutôt que d'essayer de rattraper.
</para>
</answer>
<answer>
<para>
Dans les version récentes de &slony1;, il existe un nouveau paramètre
appelé <xref linkend="slon-config-remote-listen-timeout"/> qui permet
de modifier le délai d'expiration et de relancer les mises à jour. Bien
sûr, comme cela a été mentionné ci-dessus, il est plus efficace dans ce
cas de supprimer et de recréer le n&oelig;ud, que d'essayer de rattraper
les mises à jours.
</para>
</answer>
</qandaentry>
</qandadiv>
<qandadiv id="faqperformance">
<title>FAQ &slony1;&nbsp;: problèmes de performances</title>
<qandaentry id="longtxnsareevil">
<question>
<para>
La réplication ralentit. Je vois des requêtes <command>FETCH 100 FROM
LOG</command> très longues, la table &sllog1;/&sllog2; grossit et les
performances se dégradent de manière continue.
</para>
</question>
<answer>
<para>
Il y a beaucoup de causes possibles pour ce genre de choses. Il s'agit
du même genre de pathologies qui entrainent l'augmentation du volume
dans <link linkend="pglistenerfull">&pglistener; lorsque la purge via
vacuum n'est pas exécutée</link>.
</para>
<para>
Par rapprochement, <quote>on peut avancer</quote> que cette augmentation
de volume est due à une session existante sur le serveur qui est en
<command>IDLE IN TRANSACTION</command> pour une durée très longue.
</para>
<para>
Cette transaction ouverte peut avoir de multiples effets négatifs,
chacun entrainant une dégradation de performances.
</para>
<itemizedlist>
<listitem>
<para>
Le fait de lancer un VACUUM sur la totalité des tables, &pglistener;
y compris, ne va pas nettoyer les lignes mortes après après le début
de la transaction en attente.
</para>
</listitem>
<listitem>
<para>
Le processus de nettoyage ne pourra pas se supprimer les entrées
dans &sllog1;, &sllog2; et &slseqlog;, ce qui entraîne par
conséquence une croissance de volume tant que la transaction
persiste.
</para>
</listitem>
</itemizedlist>
</answer>
<answer>
<para>
Vous pouvez surveiller cette situation uniquement si, dans le fichier
de configuration de &postgres; <filename> postgresql.conf</filename>,
le paramètre <envar>stats_command_string</envar> est positionné à vrai.
Dans ce cas, vous pouvez lancer une interrogation SQL comme suit&nbsp;:
<command>SELECT * FROM pg_stat_activity WHERE current_query LIKE
'%IDLE% in transaction';</command> dont le résultat vous donne les
transactions en activités.
</para>
</answer>
<answer>
<para>
Vous pouvez également rechercher les <quote>idle in transaction</quote>
dans la table des processus pour trouver ceux qui détiennent encore des
transactions anciennes.
</para>
</answer>
<answer>
<para>
Il est aussi possible (quoique plus rare) que le problème soit causé
par une transaction qui, pour d'autres raisons, est conservée comme
ouverte et ceci pour une longue durée. La valeur
<envar>query_start</envar> dans la table <envar>pg_stat_activity</envar>
vous présentera les longues requêtes qui s'exécutent depuis longtemps.
</para>
</answer>
<answer>
<para>
Il est prévu que &postgres; ait un paramètre d'expiration de délai,
<envar>open_idle_transaction_timeout</envar>, qui permettrait de venir
à bout des transactions après une certaine période. Les pools de
connexions peuvent engendrer ce genre de situation d'erreurs. Il est
prévu des amélioration où <productname><link
linkend="pgpool">pgpool</link></productname> devrait présenter des
meilleures alternatives afin de mieux gérer les connexions partagées.
Il existe des pools de connexions plus ou moins bogués dans les
applications Java ou PHP&nbsp;;si un nombre restreint de
<emphasis>vraies</emphasis> connexions sont conservées dans
<productname>pgpool</productname>, ceci va faire croire à la base qu'en
réalité les connexions de l'application restent dans un statut
disponible et en activité pendant des heures.
</para>
</answer>
</qandaentry>
<qandaentry id="faq17">
<question>
<para>
Après une suppression de n&oelig;ud, les tables &sllog1;/&sllog2; ne
sont plus purgées.
</para>
</question>
<answer>
<para>
Ceci est un scénario commun dans les versions d'avant 1.0.5. En effet,
le <quote>nettoyage</quote> du n&oelig;ud oublie les vieilles entrées
de la table <xref linkend="table.sl-confirm"/> pour le serveur qui
vient de disparaître.
</para>
<para>
Le n&oelig;ud n'est plus présent et n'envoie plus les confirmations
annonçant les synchronisations qui viennent de s'effectuer sur ce
serveur, et le processus de nettoyage estime qu'il ne peut supprimer
sans risque les entrées plus récentes que la dernière entrée de la
<xref linkend="table.sl-confirm"/> , ce qui limite nettement la
capacité de purge des anciens journaux.
</para>
<para>
Diagnostiques&nbsp;: Exécuter les requêtes suivantes pour voir s'il y a
un résidus d'entrées en état <quote>fantôme/obsolète/bloqué</quote> dans
la table <xref linkend="table.sl-confirm"/>:
<screen>oxrsbar=# SELECT * FROM _oxrsbar.sl_confirm
oxrsbar-# WHERE con_origin NOT IN (SELECT no_id FROM _oxrsbar.sl_node)
oxrsbar-# OR con_received NOT IN (SELECT no_id FROM _oxrsbar.sl_node);
con_origin | con_received | con_seqno | con_timestamp
------------+--------------+-----------+----------------------------
4 | 501 | 83999 | 2004-11-09 19:57:08.195969
1 | 2 | 3345790 | 2004-11-14 10:33:43.850265
2 | 501 | 102718 | 2004-11-14 10:33:47.702086
501 | 2 | 6577 | 2004-11-14 10:34:45.717003
4 | 5 | 83999 | 2004-11-14 21:11:11.111686
4 | 3 | 83999 | 2004-11-24 16:32:39.020194
(6 rows)</screen>
</para>
<para>
Dans la version 1.0.5, la fonction <xref linkend="stmtdropnode"/> purge
les données dans <xref linkend="table.sl-confirm"/> pour le n&oelig;ud
qui quitte la configuration. Dans les versions plus anciennes, il faut
faire cela à la main. Supposons que l'identifiant du n&oelig;ud soit 3,
alors la requête serait la suivante&nbsp;:
<screen>DELETE FROM _namespace.sl_confirm WHERE con_origin = 3 OR con_received = 3;</screen>
</para>
<para>
Sinon, pour chasser <quote>tous les fantômes</quote>, vous pouvez utiliser&nbsp;:
<screen>oxrsbar=# DELETE FROM _oxrsbar.sl_confirm
oxrsbar-# WHERE con_origin NOT IN (SELECT no_id FROM _oxrsbar.sl_node)
oxrsbar-# OR con_received NOT IN (SELECT no_id FROM _oxrsbar.sl_node);
DELETE 6</screen>
</para>
<para>
Une <quote>raisonnable diligence</quote> dicterait de commencer par
<command>BEGIN</command> et vérifier le contenu des
<command>SYNC</command> dans la table <xref linkend="table.sl-confirm"/>
avant de les purger, puis de valider l'opération par un
<command>COMMIT</command>. Si vous supprimez par erreur les données
d'un autre n&oelig;ud, votre journée est perdue le temps de rattraper
l'erreur commise.
</para>
<para>
Vous aurez besoin d'exécuter cette opération sur chaque n&oelig;ud
qui reste...
</para>
<para>
À noter qu'à partir de la version 1.0.5, ce n'est plus un problème car
il purge les entrées inutiles de <xref linkend="table.sl-confirm"/> à
deux instants&nbsp;:
<itemizedlist>
<listitem>
<para>
lorsqu'un n&oelig;ud est supprimé&nbsp;;
</para>
</listitem>
<listitem>
<para>
au démarrage de chaque fonction <function>cleanupEvent</function>,
qui est l'évènement qui purge les vieilles données de
&sllog1;/&sllog2; et de &slseqlog;.
</para>
</listitem>
</itemizedlist>
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Le démon <application>slon</application> était éteint ce week-end.
Désormais, il lui faut énormément de temps pour exécuter un sync.
</para>
</question>
<answer>
<para>
Jetez un coup d'&oelig;il sur les tables &sllog1;/&sllog2; pour voir
brièvement s'il y a une énorme transaction en cours d'exécution. Jusqu'à
la version 1.0.2, il faut qu'il y ait un &lslon; connecté au n&oelig;ud
origine pour que les événements <command>SYNC</command> soient générés.
</para>
<note>
<para>
À partir de la version 1.0.2, la fonction
<function>generate_sync_event()</function> fournit une alternative à
la sauvegarde...
</para>
</note>
<para>
Si aucun évènement n'est généré, alors toute les mises à jour jusqu'au
prochain évènement seront aggrégées dans une énorme transaction
&slony1;.
</para>
<para>
Conclusion&nbsp;: même s'il n'y a pas d'abonné dans votre réplication,
vous devez <emphasis>vraiment</emphasis> mettre en place un démon
<application>slon</application> pour qu'il se connecte au
n&oelig;ud origine.
</para>
<para>
&slony1; 1.1 fournit une procédure stockée qui permet aux SYNC d'être
mis à jour par le planificateur <application>cron</application> même si
<xref linkend="slon"/> ne tourne pas en tâche de fond.
</para>
</answer>
</qandaentry>
<qandaentry id="pglistenerfull">
<question>
<para>
Quelques n&oelig;uds commencent à se ralentir constamment.
</para>
<para>
J'avais lancé, depuis un moment, &slony1; sur un n&oelig;ud, et je vois
que la machine est à genoux.
</para>
<para>
Je vois des instructions en cours comme&nbsp;:
<screen>FETCH 100 FROM LOG;</screen>
</para>
</question>
<answer>
<para>
Typiquement, ceci peut se produire lorsque &pglistener; (la table qui
contient les données de <command>NOTIFY</command>) est remplie de lignes
mortes. Ce qui fait que les évènements <command>NOTIFY</command>
prennent du temps, et causent le ralentissement de plus en plus fort du
n&oelig;ud affecté.
</para>
<para>
Vous avez probablement besoin d'effectuer un <command>VACUUM
FULL</command> sur &pglistener; pour le nettoyer vigoureusement, puis
d'effectuer un VACUUM simple sur &pglistener; vraiment fréquemment. Une
planification tous les cinq minutes fera l'affaire.
</para>
<para>
Les démons Slon font déjà un VACUUM sur beaucoup de tables et
<filename>cleanup_thread.c</filename> contient une liste de tables à
nettoyer fréquemment de manière automatique. Dans &slony1; 1.0.2,
&pglistener; n'est pas inclus. Dans la version 1.0.5 et supérieure, il
est purgé régulièrement. Du coup, ce problème n'a plus lieu d'être.
Dans la version 1.2, &pglistener; est seulement utilisé quand le
n&oelig;ud reçoit périodiquement l'évènement, ce qui signifie que ce
problème la plupart du temps disparaît même en présence de transactions
longues et lentes...
</para>
<para>
Il y a, cependant, toujours un scénario où ceci peut
<quote>surgir</quote>. Pour respecter le MVCC, les VACUUM ne peuvent pas
supprimer des lignes qui sont rendues <quote>obsolètes</quote> à
n'importe quel moment après le démarrage de la transaction la plus
ancienne qui reste encore ouverte. Les transactions longues devront être
évitées, car elles sont sources de soucis, même sur les n&oelig;uds
abonnés.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai soumis une requête <xref linkend="stmtmoveset"/> / <xref
linkend="stmtddlscript"/>, et elle semble être coincée sur mon serveur.
Les journaux de &slony1; ne montrent aucun avertissement et aucune
erreur.
</para>
</question>
<answer>
<para>
Peut-être que <application>pg_autovacuum</application> est en cours
d'exécution, et qu'il a posé des verrous sur des tables dans l'ensemble
de réplication&nbsp;? Ceci entraine de manière silencieuse le blocage
de &slony1; en l'empêchant d'effectuer les opérations qui exigent
l'acquisition des <link linkend="locking">verrous exclusifs</link>.
</para>
<para>
Vous pourriez vérifier la présence de ce genre de verrous à l'aide de
cette requête&nbsp;:
<command>SELECT l.*, c.relname FROM pg_locks l, pg_class c
WHERE c.oid = l.relation;</command>
Un verrou <envar>ShareUpdateExclusiveLock</envar> peut bloquer les
opérations de &slony1; qui nécessitent leurs propres verrous exclusifs,
et les mettre en attente et marquées comme non-validées.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Je remarque que, dans les journaux, un démon &lslon; change d'état
fréquemment&nbsp;: <quote>LISTEN - switch from polling mode to use
LISTEN</quote> et <quote>UNLISTEN - switch into polling mode</quote>.
</para>
</question>
<answer>
<para>
Les seuils pour commuter entre ces modes sont commandés par les
paramètres de configuration <xref linkend="slon-config-sync-interval"/>
et <xref linkend="slon-config-sync-interval-timeout"/>&nbsp;; si la
valeur du temps d'expiration (par défaut étant à 10000, impliquant 10s)
est maintenu bas, cela encourage le démon &lslon; à retourner dans
l'état <quote>d'écoute</quote>. Vous devriez augmenter cette valeur
d'expiration de temps.
</para>
</answer>
</qandaentry>
</qandadiv>
<qandadiv id="faqbugs">
<title>FAQ &slony1;&nbsp;: Bugs dans les versions anciennes</title>
<qandaentry>
<question>
<para>
Les processus &lslon; gérant mes abonnés deviennent énormes, mettant en
danger la ressource du système en terme de swap ainsi que le risque
d'atteindre la taille limite de 2&nbsp;Go par processus.
</para>
<para>
D'ailleurs, les données que je suis en train de répliquer ont une
taille assez grande. Il y a des enregistrements dont la taille dépasse
des dizaine de mégaoctets. Peut-être que c'est lié&nbsp;?
</para>
</question>
<answer>
<para>
Oui, ces enregistrements volumineux sont à la racine du problème. Le
problème vient du fait que &lslon; procède normalement par paquet de
cent enregistrements à la fois, lorsqu'un abonné charge des données
depuis le fournisseur. Ainsi, si la taille moyenne des enregistrements
est de 10&nbsp;Mo, cela entraîne des paquets de données atteignant
1000&nbsp;Mo qui sont ensuite transformés en <command>INSERT</command>
ou en <command>UPDATE</command> dans la mémoire du processus &lslon;.
</para>
<para>
Cela mène évidemment &lslon; à des tailles gigantesques.
</para>
<para>
Le nombre d'enregistrements regroupés est contrôlé par la valeur
<envar>SLON_DTA_FETCH_SIZE</envar>, définie dans le fichier
<filename>src/slon/slon.h</filename>. Voici un extrait de ce fichier
contenant ce paramètre&nbsp;:
</para>
<programlisting>#ifdef SLON_CHECK_CMDTUPLES
#define SLON_COMMANDS_PER_LINE 1
#define SLON_DATA_FETCH_SIZE 100
#define SLON_WORKLINES_PER_HELPER (SLON_DATA_FETCH_SIZE * 4)
#else
#define SLON_COMMANDS_PER_LINE 10
#define SLON_DATA_FETCH_SIZE 10
#define SLON_WORKLINES_PER_HELPER (SLON_DATA_FETCH_SIZE * 50)
#endif</programlisting>
<para>
Si vous rencontrez ce problème, vous devriez définir
<envar>SLON_DATA_FETCH_SIZE</envar>, peut-être le réduire par un facteur
de 10, et recompiler ensuite &lslon;. L'activation de
<envar>SLON_CHECK_CMDTUPLES</envar> permet de faire une surveillance
supplémentaire pour s'assurer que les abonnés ne sont pas désynchronisés
par rapport au fournisseur. Par défaut, cette option est désactivée,
donc la modification par défaut consiste réduire la seconde définition
de <envar>SLON_DATA_FETCH_SIZE</envar> en remplaçant 10 par 1.
</para>
</answer>
<answer>
<para>
Dans la version 1.2, la configuration des valeurs de <xref
linkend="slon-config-max-rowsize"/> et de <xref
linkend="slon-config-max-largemem"/> est associée avec un nouvel
algorithme qui change la logique des choses. Plutôt que de restituer
cent enregistrements à la fois&nbsp;:
</para>
<itemizedlist>
<listitem>
<para>
La lecture de <command>FETCH FROM LOG</command> se fera par paquet
de 500 enregistrements à la fois, tant que la taille n'excède pas
<xref linkend="slon-config-max-rowsize"/>. Avec les valeurs par
défaut, ceci limitera ce phénomène de consommation de mémoire à un
plafond de 8&nbsp;Mo.
</para>
</listitem>
<listitem>
<para>
Les lignes sont lus jusqu'à ce que la taille n'excède pas le
paramètre <xref linkend="slon-config-max-largemem"/>. Par défaut,
cette restriction ne consommera pas plus de 5&nbsp;Mo. Cette valeur
n'est pas un seuil de limitation stricte&nbsp;; si vous avez des
lignes dont la taille est de 50&nbsp;Mo, elles
<emphasis>seront</emphasis> forcément chargées en mémoire. Il n'est
pas possible d'éviter cela. Mais &lslon;, au moins, n'essayera pas
de charger à la fois cent enregistrements coûte que coûte, dépassant
les 10&nbsp;Mo de mémoire consommée à cet effet.
</para>
</listitem>
</itemizedlist>
<para>
Ceci devrait alléger des problèmes que les gens avaient éprouvé, quand
ils ont chargés sporadiquement des séries de lignes très volumineuses.
</para>
</answer>
</qandaentry>
<qandaentry id="faqunicode">
<question>
<para>
Je suis en train de répliquer les données de type <envar>UNICODE</envar>
depuis la version 8.0 de &postgres; à la version 8.1, et je rencontre
des problèmes.
</para>
</question>
<answer>
<para>
&postgres; 8.1 est un peu plus strict dans l'usage des codes caractères
UTF-8 et Unicode, comparé à la version 8.0.
</para>
<para>
Si vous êtes amené à utiliser &slony1; pour migrer depuis une plus
vieille version vers la version 8.1 et que vous avez des valeurs UTF-8
invalides, vous aurez une surprise déplaisante.
</para>
<para>
Supposons que votre version de base est la version 8.0, avec l'encodage
en UTF-8. La base va accepter des séquences <command>'\060\242'</command>
comme une valeur UTF-8 conforme, même si ce n'est pas le cas.
</para>
<para>
Si vous répliquez ceci dans des instances de &postgres; en version 8.1,
il va se plaindre, soit lors de l'enregistrement d'un abonné car
&slony1; va râler à propos des codes caractères invalides qu'il vient
de rencontrer durant la COPY des données, ce qui empêchera que
l'enregistrement se fasse, soit lors de l'ajout de données, plus tard,
ce qui brisera irrémédiablement la réplication. (Vous pouvez tricher
sur le contenu de sl_log_1, mais rapidement cela deviendra
<emphasis>vraiment</emphasis> intéressant...)
</para>
<para>
Il y a déjà eu des discussions sur ce sujet pour savoir ce qu'il faudra
faire. Pour le moment, une stratégie attractive ne se dégage pas sur le
sujet.
</para>
<para>
Si vous utilisez Unicode avec la version 8.0 de &postgres;, vous courrez
un risque considérable de corrompre vos données.
</para>
<para>
Si votre réplication a pour but de convertir une fois pour toutes vos
données, il y a le risque évoqué ci-dessus&nbsp;; si cela vous arrive,
il vaudra mieux convertir vos données de la version 8.0 d'abord et de
re-essayer après.
</para>
<para>
Au regard des risques encourus, exécuter la réplication en mettant en
jeu des versions différentes semble être non pérenne à maintenir.
</para>
<para>
Pour plus d'information, voir la <ulink
url="http://archives.postgresql.org/pgsql-hackers/2005-12/msg00181.php">
discussion sur le groupe de discussion postgresql-hackers</ulink>.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'utilise &slony1; 1.1 avec plus de 4 n&oelig;uds et deux ensembles
de réplication, 1 et 2, qui ne partagent aucun n&oelig;uds. Je découvre
que les confirmations pour l'ensemble 1 n'arrivent jamais aux
n&oelig;uds souscrivant à l'ensemble 2, et inversement (celles de
l'ensemble 2 n'arrivent pas non plus aux n&oelig;uds souscrivant à
l'ensemble 1). En conséquence, &sllog1;/&sllog2; grossissent et ne sont
jamais purgées. Ceci est mentionné dans le <ulink
url="http://gborg.postgresql.org/project/slony1/bugs/bugupdate.php?1485">bug 1485</ulink>.
</para>
</question>
<answer>
<para>
Apparemment, le code de la fonction
<function>RebuildListenEntries()</function> ne suffit pas pour résoudre
ce cas.
</para>
<para>
La fonction <function>RebuildListenEntries()</function> sera rectifié
dans &slony1; version 1.2 avec un algorithme couvrant ce cas.
</para>
<para>
Dans l'intérim, vous devrez ajouter manuellement quelques entrées dans
<xref linkend="table.sl-listen"/> en utilisant <xref
linkend="stmtstorelisten"/> ou <function>storeListen()</function>, basé
sur les principes décrits dans <xref linkend="listenpaths"/>
(apparemment pas aussi désuet que nous avons pensé).
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Je trouve que quelques colonnes de multibyte (Unicode, Big5) sont
tronqués un peu, il leur manque les derniers caractères. Pourquoi&nbsp;?
</para>
</question>
<answer>
<para>
C'était un bug présent jusqu'à la version 1.1.0 de &slony1;&nbsp;;
les colonnes étaient capturées par la fonction
<function>logtrigger()</function>, qui coupait les derniers octets d'une
colonne représentée dans un format de multibyte. que votre version de
<filename>src/backend/slony1_funcs.c</filename> est bien la 1.34 ou
supérieur&nbsp;; le patch a été intégré dans la version CVS 1.34 de ce
fichier.
</para>
</answer>
</qandaentry>
<qandaentry id="sequenceset">
<question>
<para>
Le <ulink
url="http://gborg.postgresql.org/project/slony1/bugs/bugupdate.php?1226">bug
#1226</ulink> indique une condition d'erreur qui peut survenir si vous
faites placer une réplication composée seulement de séquences.
</para>
</question>
<answer>
<para>
Une réponse courte consiste à dire qu'une réplication composée seulement
de séquences n'est pas une <link linkend="bestpractices">bonne
pratique</link>.
</para>
</answer>
<answer>
<para>
Le problème avec un ensemble de réplication contenant uniquement des
séquences, ce sont les cas où les seuls abonnements actifs sont composés
uniquement de séquences. Si un n&oelig;ud entre dans cet état, la
réplication échouera puisque la requête qui collecte les données dans
&sllog1;/&sllog2; ne trouveront aucune table et par conséquent la
requête sera malformée et échouera. Si un ensemble de réplication
<emphasis>contenant</emphasis> des tables ré-apparaît, tout va
fonctionner correctement&nbsp;; cela <emphasis>paraît</emphasis>
effrayant.
</para>
<para>
Ce problème devrait être résolu après &slony1; 1.1.0.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Je dois supprimer une table d'un ensemble de réplication.
</para>
</question>
<answer>
<para>
Ceci peut être accompli de plusieurs manières, pas toutes également
souhaitables ;-).
<itemizedlist>
<listitem>
<para>
Vous pourriez supprimer tout le jeu de réplication, et les recréer
avec juste les tables dont vous avez besoin. Hélas, cela signifie
reproduire un tas de données, et interrompt la réplication des
autres éléments de l'ensemble pendant toute la durée de l'opération.
</para>
</listitem>
<listitem>
<para>
Si vous êtes en version 1.0.5 ou supérieur, il y a une commande
SET DROP TABLE, qui le fera très bien.
</para>
</listitem>
<listitem>
<para>
Si vous utilisez toujours une version 1.0.1 ou 1.0.2, <emphasis>la
fonctionnalité essentielle de <xref linkend="stmtsetdroptable"/>
se trouve dans la fonction <function>droptable_int()</function>.
Vous pouvez l'utiliser à la main en trouvant l'identifiant de la
table à supprimer, qui se trouve dans la table <xref
linkend="table.sl-table"/>, puis lancer les trois requêtes
suivantes sur chaque n&oelig;ud&nbsp;:
</emphasis>
<programlisting>SELECT _slonyschema.alterTableRestore(40);
SELECT _slonyschema.tableDropKey(40);
DELETE FROM _slonyschema.sl_table where tab_id = 40;</programlisting></para>
<para>
Évidement, le nom du schéma dépend de la façon dont vous avez
défini le cluster &slony1;. L'identifiant de la table, dans cet
exemple 40, doit être remplacé par celui de la table dont voulez
vous débarrasser.
</para>
<para>
Vous devrez lancer ces trois interrogations sur tous les
n&oelig;uds, de préférence premièrement sur le n&oelig;ud
d'origine, de sorte que la suppression se propage correctement.
On peut également implémenter ceci à travers une commande <xref
linkend="slonik"/> et un nouvel évenement &slony1;. Soumettre les
trois requêtes en utilisant <xref linkend="stmtddlscript"/>
permet de le faire. Il est égalementt possible de se connecter à
chaque base de données et de lancer les requêtes à la main.
</para>
</listitem>
</itemizedlist>
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Je dois supprimer une séquence dans une séquence pour un ensemble de
réplication.
</para>
</question>
<answer>
<para>
Si vous êtes en version 1.0.5 ou supérieure, il existe une commande
<xref linkend="stmtsetdropsequence"/> dans Slonik vous permettant de
le faire en parallèle <xref linkend="stmtsetdroptable"/>.
</para>
<para>
Si vous êtes en version 1.0.2 ou antérieure, l'opération sera un peu
plus manuelle.
</para>
<para>
À supposer que je veux me débarrasser des deux séquences suivante&nbsp;:
<envar>whois_cachemgmt_seq</envar> et <envar>epp_whoi_cach_seq_</envar>.
Tout d'abord, il nous faut les valeurs de <envar>seq_id</envar>&nbsp;:
<screen>oxrsorg=# SELECT * FROM _oxrsorg.sl_sequence WHERE seq_id IN (93,59);
seq_id | seq_reloid | seq_set | seq_comment
--------+------------+---------+-------------------------------------
93 | 107451516 | 1 | Sequence public.whois_cachemgmt_seq
59 | 107451860 | 1 | Sequence public.epp_whoi_cach_seq_
(2 rows)</screen>
</para>
<para>
Les données à supprimer pour empêcher Slony de continuer la réplication
sont&nbsp;:
<programlisting>DELETE FROM _oxrsorg.sl_seqlog WHERE seql_seqid IN (93, 59);
DELETE FROM _oxrsorg.sl_sequence WHERE seq_id IN (93,59);</programlisting>
</para>
<para>
Ces deux interrogations peuvent être soumises à l'ensemble des
n&oelig;uds via la fonction &funddlscript; / <xref
linkend="stmtddlscript"/>, éliminant la séquence partout <quote>en
même temps</quote>. Ou bien on peut les appliquer à la main à chacun
des n&oelig;uds.
</para>
<para>
De la même manière que <xref linkend="stmtsetdroptable"/>, cette
fonction est implémentée dans &slony1; version 1.0.5 sous le nom
<xref linkend="stmtsetdropsequence"/>.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai configuré mon cluster avec pgAdminIII, avec le nom
<quote>MON-CLUSTER</quote>. Le temps a passé et j'ai tenté d'utiliser Slonik
pour effectuer un changement de configuration, et j'obtiens le messages d'erreur
suivant :
</para>
<programlisting>ERROR: syntax error at or near -</programlisting>
</question>
<answer>
<para>
Le problème est que &slony1; s'attend à ce que les noms de cluster soient des
<ulink url="http://www.postgresql.org/docs/8.3/static/sql-syntax-lexical.html">
Identifiants SQL </ulink> valides, et &lslonik; garantit cela. Malheureusement,
<application>pgAdminIII</application> ne vérifie pas cela et autorise
des noms de cluster qui provoquent des <emphasis> problèmes</emphasis>.
</para>
</answer>
<answer>
<para>
Si vous êtes dans cette situation cas, il n'y a pas grand'chose que l'on puisse faire.
</para>
<para>
Il <emphasis>peut-être possible</emphasis> que l'execution de la commande
SQL <command>alter namespace "_My-Bad-Clustername" rename to
"_BetterClusterName";</command> sur chacune des bases fonctionne.
Cela ne devrait pas particulièrement <emphasis>aggraver</emphasis>les choses !
</para>
<para>
D'un autre coté, à chaque fois que ce problème a été rencontré, il a fallu
détruire la réplication et reconstruire le cluster.
</para>
</answer>
<answer>
<para>
Dans la version 2.0.2, une fonction a été ajoutée pour vérifier la
la validité du nom du cluster. Si vous tentez de définir un nom invalide,
la chargement de la fonction échouera, avec un message d'erreur approprié, ce qui
devrait empecher les choses d'empirer, meme si vous utiliser d'autres outils que
&lslonik; pour gérer la configuration du cluster.
</para>
</answer>
</qandaentry>
</qandadiv>
<qandadiv id="faqobsolete">
<title>FAQ &slony1;&nbsp;: problèmes devenus obsolètes</title>
<qandaentry>
<question>
<para>&lslon; ne se remet pas en marche après un incident</para>
<para>
Après un arrêt immédiat de &postgres; (équivalent à un crash du système),
dans la table &pglistener; on trouve une ligne contenant
<command>relname='_${cluster_name}_Restart'</command>. slon ne démarre
pas car il considère qu'un autre processus gère le cluster sur ce
n&oelig;ud. Que puis-je faire&nbsp;? la ligne ne peut pas être supprimée
dans cette relation.
</para>
<para>
Les journaux de traces indiquent qu'<blockquote><para>un autre slon en
tâche de fond gère déjà ce n&oelig;ud.</para></blockquote>.
</para>
</question>
<answer>
<para>
Le problème est que la table système &pglistener;, utilisée par
&postgres; pour gérer les notification d'évènements, contient quelques
entrées pointant vers des processus qui n'existent plus. La nouvelle
instance de <xref linkend="slon"/> se connecte à la base, et elle est
convaincue, à cause de la présence de ces entrées qu'un ancien
<application>slon</application> est toujours en activité pour s'occuper
de ce n&oelig;ud de &slony1;.
</para>
<para>
Les <quote>détritus</quote> dans cette table doivent être nettoyés.
</para>
<para>
Il est utile de maintenir un script manuel pour ce genre de
situation&nbsp;:
<programlisting>twcsds004[/opt/twcsds004/OXRS/slony-scripts]$ cat restart_org.slonik
cluster name = oxrsorg ;
node 1 admin conninfo = 'host=32.85.68.220 dbname=oxrsorg user=postgres port=5532';
node 2 admin conninfo = 'host=32.85.68.216 dbname=oxrsorg user=postgres port=5532';
node 3 admin conninfo = 'host=32.85.68.244 dbname=oxrsorg user=postgres port=5532';
node 4 admin conninfo = 'host=10.28.103.132 dbname=oxrsorg user=postgres port=5532';
restart node 1;
restart node 2;
restart node 3;
restart node 4;</programlisting>
</para>
<para>
<xref linkend="stmtrestartnode"/> nettoie les notifications mortes pour
qu'on puisse ensuite redémarrer le n&oelig;ud.
</para>
<para>
À partir de la version 1.0.5, le processus de démarrage de slon
cherche ce genre de données obsolètes et les nettoie le cas échéant.
</para>
<para>
À partir de la version 8.1 de &postgres;, la fonction manipulant
&pglistener; ne supporte pas cet usage, alors, pour les versions de
&slony1; postérieures à la 1.1.2 (<emphasis>e.g. - </emphasis> 1.1.5),
ce risque d'<quote>inter-blocage</quote> est géré via une nouvelle
table, et le problème disparaît de manière transparente.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai essayé la requête suivante qui ne fonctionne pas&nbsp;:
</para>
<programlisting>sdb=# EXPLAIN SELECT query_start, current_query FROM pg_locks
sdb-# JOIN pg_stat_activity ON pid = procpid
sdb-# WHERE granted = true
sdb-# AND transaction IN (SELECT transaction FROM pg_locks WHERE granted = false);
ERROR: could not find hash function for hash operator 716373</programlisting>
<para>
Il semble que les fonctions <function>xxid</function> de &slony1;
prétendent pouvoir faire du hachage, mais qu'elles n'y arrivent pas.
</para>
<para>
Que se passe-t-il&nbsp;?
</para>
</question>
<answer>
<para>
&slony1; a défini un nouveau type de données et d'opérateurs XXID afin
de permettre la manipulation des identifiants de transaction qui sont
employés pour grouper ensemble les mises à jour qui sont associées
dans une même transaction.
</para>
<para>
Ces opérateurs n'étaient pas disponible pour &postgres; version 7.3 et
inférieure&nbsp;; afin de rendre &slony1; opérationnel avec la version
7.3, des fonctions spécifiques doivent être ajoutées. L'opérateur
<function>=</function> a été marqué comme supportant le hachage, mais
pour que cela fonctionne, l'opérateur de jointure doit apparaître dans
une classe d'opérateurs d'index haché. Cela n'a pas été défini ainsi
et, en conséquence, les requêtes (comme celle ci-dessus) qui décident
d'employer des jointures par hachage échoueront.
</para>
</answer>
<answer>
<para>
Ceci <emphasis>n'a pas</emphasis> été considéré comme bugs
<quote>critiques</quote>, car &slony1; ne produit pas de requêtes
employant des jointures de hachage. Ce problème ne devrait pas perturber
la réplication.
</para>
</answer>
<answer>
<para>
Les versions suivantes de &slony1; (<emphasis>par exemple&nbsp;:</emphasis>
1.0.6, 1.1) omettent l'indicateur <command>HASHES</command>.
</para>
</answer>
<answer>
<para>
Supposons que vous souhaitiez réparer une instance existante, et vous
constatez que vos propres scripts ne fonctionnent pas bien, vous pouvez
suivre la démarche suivante&nbsp;:
</para>
<programlisting>/* cbbrowne@[local]/dba2 slony_test1=*/ \x
Expanded display is on.
/* cbbrowne@[local]/dba2 slony_test1=*/ select * from pg_operator where oprname = '='
and oprnamespace = (select oid from pg_namespace where nspname = 'public');
-[ RECORD 1 ]+-------------
oprname | =
oprnamespace | 2200
oprowner | 1
oprkind | b
oprcanhash | t
oprleft | 82122344
oprright | 82122344
oprresult | 16
oprcom | 82122365
oprnegate | 82122363
oprlsortop | 82122362
oprrsortop | 82122362
oprltcmpop | 82122362
oprgtcmpop | 82122360
oprcode | "_T1".xxideq
oprrest | eqsel
oprjoin | eqjoinsel
/* cbbrowne@[local]/dba2 slony_test1=*/ update pg_operator set oprcanhash = 'f' where
oprname = '=' and oprnamespace = 2200 ;
UPDATE 1</programlisting>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Je peux faire un <command>pg_dump</command> et recharger les données
beaucoup plus rapidement qu'avec <command>SUBSCRIBE SET</command>.
Comment est-ce possible&nbsp;?
</para>
</question>
<answer>
<para>
&slony1; dépend de l'existance d'un index sur la clef primaire et ne
touche pas aux autres index pendant l'opération &postgres;
<command>COPY</command> qui charge les données. Par ailleurs, il peut
y avoir une dégradation de performance, provoquée par l'événement
<command>COPY SET</command> (un événement généré lors d'un abonnement)
dans la mesure où l'opération commence par une suppression des contenus
des tables, ce qui laisse la table remplie de lignes mortes.
</para>
<para>
Lorsque vous utilisez <command>pg_dump</command> pour exporter le
contenu de la base, et que vous les re-importez après, les index ne sont
crées qu'à la fin. Il est <emphasis>beaucoup</emphasis> plus performant
de reconstruire les index sur une table entièrement re-importée, plutôt
que de refaire les index à la volée lorsque les enregistrements sont
rajoutés un à un à la table.
</para>
</answer>
<answer>
<para>
Si vous pouvez supprimer des index inutiles, lorsque
<command>COPY</command> se met en marche, les performances sont
sensiblement améliorée. Encore mieux, si vous pouvez faire un
<command>TRUNCATE</command> sur les tables dont le contenu devra
disparaître, les performances vont augmenter
<emphasis>énormément</emphasis>.
</para>
</answer>
<answer>
<para>
&slony1;, en version 1.1.5 et supérieures, fait cela automatiquement&nbsp;;
il <quote>dégage</quote> les index dans le catalogue de &postgres; afin
de les cacher, de la même façon qu'il cache les triggers, puis il
<quote>répare</quote> les pointeurs d'index et effectue une reindexation
de la table.
</para>
</answer>
</qandaentry>
<qandaentry id="dupkey">
<question>
<para>
La réplication échoue à cause d'une violation de contrainte unique.
</para>
<para>
Alors que la réplication se déroule correctement depuis un bout de
temps, un n&oelig;ud rencontre un <quote>soucis</quote> et les erreurs
suivantes sont envoyées dans le journal&nbsp;:
<screen>DEBUG2 remoteWorkerThread_1: syncing set 2 with 5 table(s) from provider 1
DEBUG2 remoteWorkerThread_1: syncing set 1 with 41 table(s) from provider 1
DEBUG2 remoteWorkerThread_1: syncing set 5 with 1 table(s) from provider 1
DEBUG2 remoteWorkerThread_1: syncing set 3 with 1 table(s) from provider 1
DEBUG2 remoteHelperThread_1_1: 0.135 seconds delay for first row
DEBUG2 remoteHelperThread_1_1: 0.343 seconds until close cursor
ERROR remoteWorkerThread_1: "insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '34', '35090538', 'D', '_rserv_ts=''9275244''');
delete from only public.epp_domain_host where _rserv_ts='9275244';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '34', '35090539', 'D', '_rserv_ts=''9275245''');
delete from only public.epp_domain_host where _rserv_ts='9275245';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '26', '35090540', 'D', '_rserv_ts=''24240590''');
delete from only public.epp_domain_contact where _rserv_ts='24240590';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '26', '35090541', 'D', '_rserv_ts=''24240591''');
delete from only public.epp_domain_contact where _rserv_ts='24240591';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '26', '35090542', 'D', '_rserv_ts=''24240589''');
delete from only public.epp_domain_contact where _rserv_ts='24240589';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '11', '35090543', 'D', '_rserv_ts=''36968002''');
delete from only public.epp_domain_status where _rserv_ts='36968002';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '11', '35090544', 'D', '_rserv_ts=''36968003''');
delete from only public.epp_domain_status where _rserv_ts='36968003';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '24', '35090549', 'I', '(contact_id,status,reason,_rserv_ts) values (''6972897'',''64'','''',''31044208'')');
insert into public.contact_status (contact_id,status,reason,_rserv_ts) values ('6972897','64','','31044208');insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '24', '35090550', 'D', '_rserv_ts=''18139332''');
delete from only public.contact_status where _rserv_ts='18139332';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '24', '35090551', 'D', '_rserv_ts=''18139333''');
delete from only public.contact_status where _rserv_ts='18139333';" ERROR: duplicate key violates unique constraint "contact_status_pkey"
- qualification was:
ERROR remoteWorkerThread_1: SYNC aborted</screen>
</para>
<para>
La transaction s'annule, et &slony1; essaie à nouveau sans cesse. Le
problème est dû à une des <emphasis>dernières</emphasis> requêtes SQL,
celle qui contenait <command>log_cmdtype = 'I'</command>. Ce n'est pas
évident du tout&nbsp;; &slony1; regroupe dix opérations de mise à jour
ensemble, afin de diminuer les allers-retours réseau.
</para>
</question>
<answer>
<para>
Il est difficile de déterminer avec <emphasis>exactitude</emphasis>
l'origine de tout ceci.
</para>
<para>
En même temps, nous notons qu'il y a un problème&nbsp;: les transactions
annulées ont été supprimées dans &sllog1;, et on constate qu'il est
impossible de les récupérer. À ce stade, il parait nécessaire de
supprimer l'ensemble de réplication (ou même le n&oelig;ud), et de
redémarrer la réplication à partir de zéro pour ce n&oelig;ud.
</para>
<para>
Dans &slony1; 1.0.5, l'opération de purge de &sllog1; devient plus
prudente, en refusant de purger des entrées qui n'ont pas encore été
synchronisées, pendant au moins dix minutes sur l'ensemble des
n&oelig;uds. Il n'est pas certain que ceci empêche que le
<quote>problème</quote> ait lieu, mais il paraît plausible que cela
laisse assez de données dans &sllog1; permettant un recouvrement ou
bien de permettre d'au moins de diagnostiquer plus exactement la
situation. Et peut-être que le problème venait du fait que &sllog1;
était brutalement purgée, donc cette solution permet de résoudre
complètement ce genre d'incident.
</para>
<para>
C'est une honte de devoir reconstruire une réplication volumineuse sur
un n&oelig;ud à cause de cela. Si vous découvrez que le problème
persiste, la bonne idée serait de diviser la réplication en plusieurs
ensembles de réplication afin de dimininuer la charge de travail lors
de la reconstruction de la réplication. Si un seul ensemble est cassé,
vous n'auriez qu'à désabonner et supprimer celui-ci.
</para>
<para>
Dans un cas, nous avons trouvé dans le journal de trace deux lignes
<emphasis>identiques</emphasis> concernant l'insertion dans &sllog1;.
Ceci <emphasis>devrait</emphasis> être impossible d'autant plus qu'il
s'agit d'une clef primaire sur &sllog1;. La dernière théorie sur le
sujet laisserait à penser que cette situation viendrait du fait que
l'index de <emphasis>cette</emphasis> clé était peut-être corrompu
(à cause d'un bug de &postgres;), et qu'il serait possible d'éviter ce
problème en exécutant la commande suivante&nbsp;:
</para>
<programlisting># REINDEX TABLE _slonyschema.sl_log_1;</programlisting>
<para>
Au moins dans une occasion cette solution s'est révélée efficace, alors
cela sera dommage de ne pas suivre l'exemple.
</para>
</answer>
<answer>
<para>
Ce problème s'est avéré être un bug dans &postgres; plutôt qu'un bug
dans &slony1;. La version 7.4.8 a intégré deux solutions qui permettent
de résoudre ce cas. Donc, si vous avez un noyau de &postgres; antérieur
à 7.4.8, vous devriez migrer pour éviter l'erreur.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai commencé à faire une sauvegarde via
<application>pg_dump</application>, et Slony s'arrête soudainement.
</para>
</question>
<answer>
<para>
Aïe. Ce qui se passe ici est un conflit entre&nbsp;:
<itemizedlist>
<listitem>
<para>
<application>pg_dump</application>, qui pose un verrou
<command>AccessShareLock</command> sur toutes les tables de la
base, y compris celle de &slony1; et
</para>
</listitem>
<listitem>
<para>
Un événement SYNC de &slony1; qui veut poser un verrou
<command>AccessExclusiveLock</command> sur la table <xref
linkend="table.sl-event"/>.
</para>
</listitem>
</itemizedlist>
</para>
<para>
La requête initiale qui est bloquée est&nbsp;:
<screen>SELECT "_slonyschema".createEvent('_slonyschema, 'SYNC', NULL);</screen>
</para>
<para>
(vous pouvez voir ceci dans la vue <envar>pg_stat_activity</envar>, si
l'affichage des requête est activé dans
<filename>postgresql.conf</filename>)
</para>
<para>
La requête qui demande ce verrou vient de la fonction
<function>Slony_I_ClusterStatus()</function>, que vous trouverez dans
<filename>slony1_funcs.c</filename>, localisé dans un bloc de code qui
est&nbsp;:
<programlisting>LOCK TABLE %s.sl_event;
INSERT INTO %s.sl_event (...stuff...)
SELECT currval('%s.sl_event_seq');</programlisting>
</para>
<para>
La demande de <command>VERROU</command> va donc attendre et durer
jusqu'à ce que <command>pg_dump</command> (ou un autre programme ayant
un verrou d'accès sur <xref linkend="table.sl-event"/>) se termine.
</para>
<para>
Chaque lecture touchant <xref linkend="table.sl-event"/> sera bloqué
derrière les appels à <function>createEvent</function>.
</para>
<para>
Les réponses à cette question sont multiples&nbsp;:
<itemizedlist>
<listitem>
<para>
Indiquer explicitement à <application>pg_dump</application> les
schémas qu'il doit exporter en utilisant l'option
<option>--schema=quoiquecesoit</option>, et ne pas essayer
d'exporter le schéma du cluster.
</para>
</listitem>
<listitem>
<para>
Il sera utile aussi d'avoir une option
<option>--exclude-schema</option> dans
<application>pg_dump</application> afin d'exclure le schéma du
cluster de &slony1;. Pourquoi pas dans la 8.2...
</para>
</listitem>
<listitem>
<para>
Notez que la version 1.0.5 utilise des verrous plus précis et
moins exclusifs qui évitent ce problème.
</para>
</listitem>
</itemizedlist>
</para>
</answer>
</qandaentry>
</qandadiv>
<qandadiv id="faqoddities">
<title>FAQ &slony1;&nbsp;: Bizzareries et modifications dans Slony-I</title>
<qandaentry>
<question>
<para>
Que se produit-il avec les règles et les déclencheurs pour les tables
répliquées par &slony1;&nbsp;?
</para>
</question>
<answer>
<para>
Tout d'abord, regardons comment ceci est géré <emphasis>en
dehors</emphasis> du cas spécifique de la commande Slonik <xref
linkend="stmtstoretrigger"/>.
</para>
<para>
La fonction <xref linkend="function.altertableforreplication-integer"/>
prépare chacune des tables pour la réplication.
</para>
<itemizedlist>
<listitem>
<para>
Sur le n&oelig;ud maître, ceci implique l'ajout sur la table d'un
déclencheur qui utilise la fonction <xref
linkend="function.logtrigger"/>.
</para>
<para>
Le déclencheur a pour action d'enregistrer toutes les mises à jours
dans la table &sllog1; de &slony1;.
</para>
</listitem>
<listitem>
<para>
Sur un n&oelig;ud d'abonné, ceci revient à désactiver les
déclencheurs et les règles, puis, via un déclencheur, de refuser
le droit d'accès en écriture sur celle-ci en utilisant la fonction
<function>denyAccess()</function>.
</para>
<para>
Jusqu'à la version 1.1 (et peut-être après), la
<quote>désactivation</quote> est faite en modifiant la valeur de
<envar>tgrelid</envar> dans les tables <envar>pg_trigger</envar>
ou <envar>pg_rewrite</envar> en pointant l'identifiant OID sur la
<quote>clé primaire</quote> de l'index du catalogue, plutôt que sur
la table elle-même.
</para>
</listitem>
</itemizedlist>
<para>
Un effet secondaire malheureux est que cette gestion des règles et des
déclencheurs a pour effet de les <quote>piétiner</quote>. Les règles
et les déclencheurs sont toujours là, mais ne sont plus correctement
attachés à leurs tables. Si vous faites un <command>pg_dump</command>
sur un <quote>n&oelig;ud abonné</quote>, il ne trouvera ni les règles
ni les déclencheurs, et du coup il ne s'attend pas à les voir associés
à un index.
</para>
</answer>
<answer>
<para>
Maintenant, observez comment <xref linkend="stmtstoretrigger"/> entre
en jeu.
</para>
<para>
Pour simplifier, cette commande permet de restaurer les déclencheurs
avec la fonction <function>alterTableRestore(table id)</function>, qui
restaure l'identifiant OID de la table dans la colonne
<envar>tgrelid</envar> de <envar>pg_trigger</envar> ou
<envar>pg_rewrite</envar> sur le n&oelig;ud affecté.
</para>
</answer>
<answer>
<para>
Ceci implique que le jour où vous souhaitez lancer une sauvegarde
directement sur un abonné, vous devrez reprendre le schéma depuis un
n&oelig;ud d'origine. Clairement, il faudra faire&nbsp;:
</para>
<screen>% pg_dump -h originnode.example.info -p 5432 --schema-only --schema=public ourdb > schema_backup.sql
% pg_dump -h subscribernode.example.info -p 5432 --data-only --schema=public ourdb > data_backup.sql</screen>
</answer>
</qandaentry>
<!-- todo -->
<qandaentry>
<question>
<para>
J'ai essayé les commandes <xref linkend="stmtddlscript"/> ou <xref
linkend="stmtmoveset"/>, et trouvé les messages suivants sur l'un des
abonnés&nbsp;:
</para>
<screen>NOTICE: Slony-I: multiple instances of trigger defrazzle on table frobozz
NOTICE: Slony-I: multiple instances of trigger derez on table tron
ERROR: Slony-I: Unable to disable triggers</screen>
</question>
<answer>
<para>
La difficulté semble venir du fait que vous avez ajouté des
déclencheurs sur des tables dont le nom rentre en conflit, avec les
déclencheurs que &slony1; a caché.
</para>
<para>
&slony1; cache des déclencheurs (sauf ceux marqués comme
<quote>visibles</quote> via <xref linkend="stmtstoretrigger"/>) en les
attachant à la clé primaire de leur table. Dans le cas d'un déclencheur
pour clef étrangère ou d'autres déclencheurs de cohérence des données,
il est complètement inutile de les placer sur un abonnné. Au contraire,
ces déclencheurs doivent être mis en place sur le n&oelig;ud d'origine.
En revanche, les déclencheurs de type <quote>invalidation de cache</quote>
peuvent être placés sur l'abonné.
</para>
<para>
La <emphasis>bonne manière</emphasis> de manipuler ce genre de
déclencheurs est d'utiliser <xref linkend="stmtstoretrigger"/>, qui
indique à &slony1; de ne pas désactiver le déclencheur.
</para>
</answer>
<answer>
<para>
Mais il peut y avoir quelques DBA intrépides qui vont assumer
individuellement ce travail en installant les déclencheurs à la main
sur l'abonné, et cela mène généralement à créer ce genre de situation.
Que faire&nbsp;?
</para>
<para>
La réponse est assez simple&nbsp;: retirez le déclencheur
<quote>spécifique</quote> sur l'abonné avant que slony tente de les
restaurer. Dans le meilleur des cas, si le DBA est intrépide et réactif,
il aurait fait cela <emphasis>avant</emphasis> que le message ait le
temps d'arriver.
</para>
<para>
Si le DBA n'est pas intrépide, il faut se connecter au n&oelig;ud qui
pose problème, et de supprimer la version <quote>visible</quote> du
déclencheur utilisant l'ordre <acronym>SQL</acronym> <command>DROP
TRIGGER</command>. Ceci permet à l'évènement de se dérouler. Si
l'évènement était <xref linkend="stmtddlscript"/>, alors notre
<quote>pas-tellement-intrépide </quote> DBA devra remettre en place
le déclencheur à la main, ou, s'il a plus de sagesse, il les réactivera
avec <xref linkend="stmtstoretrigger"/>.
</para>
</answer>
</qandaentry>
<qandaentry id="neededexecddl">
<question>
<para>
Le comportement&nbsp;: tous les n&oelig;uds abonnés commencent à tomber
et ont le message d'erreur suivant dans le journal.
(lorsque j'ai rencontré ce problème, il y avait une longue requête SQL
devant chaque message)
</para>
<screen>ERROR remoteWorkerThread_1: helper 1 finished with error
ERROR remoteWorkerThread_1: SYNC aborted</screen>
</question>
<answer>
<para>
La cause&nbsp;: vous avez probablement effectué un <command>ALTER
TABLE</command> directement sur la base au lieu de l'utilisation de la
commande slonik <xref linkend="stmtddlscript"/>.
</para>
<para>
La solution consiste à remettre le trigger sur la table affectée, et de
corriger à la main les données afférentes dans &sllog1;/&sllog2;.
</para>
<itemizedlist>
<listitem>
<para>
À partir des journaux de slon ou de &postgres;, vous devrez
identifier la requête SQL exacte qui a causé l'anomalie.
</para>
</listitem>
<listitem>
<para>
Vous avez besoin de réparer les déclencheurs définis par Slony
dans la table en question. Ceci peut se faire à l'aide de la
procédure suivante&nbsp;:
</para>
<screen>BEGIN;
LOCK TABLE table_name;
SELECT _oxrsorg.altertablerestore(tab_id);--tab_id is _slony_schema.sl_table.tab_id
SELECT _oxrsorg.altertableforreplication(tab_id);--tab_id is _slony_schema.sl_table.tab_id
COMMIT;</screen>
<para>
Ensuite, vous devez trouver les enregistrements dans
&sllog1;/&sllog2; qui sont incohérents et les corriger. Il sera
préférable d'arrêter les démons Slon pour l'ensemble des n&oelig;uds
excepté celui du maître&nbsp;; de cette manière, si vous faites une
erreur, elle ne se propagera pas immédiatement sur tous les
n&oelig;uds abonnés.
</para>
<para>
Voici un exemple&nbsp;:
</para>
<screen>BEGIN;
LOCK TABLE customer_account;
SELECT _app1.altertablerestore(31);
SELECT _app1.altertableforreplication(31);
COMMIT;
BEGIN;
LOCK TABLE txn_log;
SELECT _app1.altertablerestore(41);
SELECT _app1.altertableforreplication(41);
COMMIT;
--fixing customer_account, which had an attempt to insert a "" into a timestamp with timezone.
BEGIN;
update _app1.sl_log_1 SET log_cmddata = 'balance=''60684.00'' where pkey=''49''' where log_actionseq = '67796036';
update _app1.sl_log_1 SET log_cmddata = 'balance=''60690.00'' where pkey=''49''' where log_actionseq = '67796194';
update _app1.sl_log_1 SET log_cmddata = 'balance=''60684.00'' where pkey=''49''' where log_actionseq = '67795881';
update _app1.sl_log_1 SET log_cmddata = 'balance=''1852.00'' where pkey=''57''' where log_actionseq = '67796403';
update _app1.sl_log_1 SET log_cmddata = 'balance=''87906.00'' where pkey=''8''' where log_actionseq = '68352967';
update _app1.sl_log_1 SET log_cmddata = 'balance=''125180.00'' where pkey=''60''' where log_actionseq = '68386951';
update _app1.sl_log_1 SET log_cmddata = 'balance=''125198.00'' where pkey=''60''' where log_actionseq = '68387055';
update _app1.sl_log_1 SET log_cmddata = 'balance=''125174.00'' where pkey=''60''' where log_actionseq = '68386682';
update _app1.sl_log_1 SET log_cmddata = 'balance=''125186.00'' where pkey=''60''' where log_actionseq = '68386992';
update _app1.sl_log_1 SET log_cmddata = 'balance=''125192.00'' where pkey=''60''' where log_actionseq = '68387029';</screen>
</listitem>
</itemizedlist>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Le n&oelig;ud numéro 1 a été supprimé via <xref
linkend="stmtdropnode"/>, et le &lslon; d'un autre n&oelig;ud plante
systématiquement avec le message d'erreurs suivant&nbsp;:
</para>
<screen>ERROR remoteWorkerThread_3: "begin transaction; set transaction isolation level
serializable; lock table "_mailermailer".sl_config_lock; select "_mailermailer"
.storeListen_int(2, 1, 3); notify "_mailermailer_Event"; notify "_mailermailer_C
onfirm"; insert into "_mailermailer".sl_event (ev_origin, ev_seqno, ev_times
tamp, ev_minxid, ev_maxxid, ev_xip, ev_type , ev_data1, ev_data2, ev_data3
) values ('3', '2215', '2005-02-18 10:30:42.529048', '3286814', '3286815', ''
, 'STORE_LISTEN', '2', '1', '3'); insert into "_mailermailer".sl_confirm
(con_origin, con_received, con_seqno, con_timestamp) values (3, 2, '2215', CU
RRENT_TIMESTAMP); commit transaction;" PGRES_FATAL_ERROR ERROR: insert or updat
e on table "sl_listen" violates foreign key constraint "sl_listen-sl_path-ref"
DETAIL: Key (li_provider,li_receiver)=(1,3) is not present in table "sl_path".
DEBUG1 syncThread: thread done</screen>
<para>
Il semble évident qu'un appel à <xref linkend="stmtstorelisten"/>
n'avait pas encore été propagé avant que le n&oelig;ud 1 soit éliminé.
</para>
</question>
<answer id="eventsurgery">
<para>
Ceci illustre le cas où vous avez besoin de réaliser une
<quote>opération chirurgicale</quote> sur un ou plusieurs n&oelig;uds.
Un évènement <command>STORE_LISTEN</command> demeure sans réponse alors
qu'il veut ajouter une voie d'écoute qui <emphasis>ne peut pas</emphasis>
être créé car le n&oelig;ud 1 ainsi que toutes les voies vers le
n&oelig;ud 1 ont disparu.
</para>
<para>
Supposons, pour la démonstration, que les n&oelig;uds encore en place
soient le 2 et le 3, ainsi le rapport d'erreur est remonté au
n&oelig;ud 3.
</para>
<para>
Cela implique que l'évènement soit stocké sur le n&oelig;ud 2,
puisqu'il ne peut pas être sur le n&oelig;ud 3, vu qu'il n'a pas été
traité avec succès. La manière la plus facile pour faire face à cette
situation est de supprimer la ligne erronée dans <xref
linkend="table.sl-event"/> sur le n&oelig;ud 2. Vous vous connectez à
la base du n&oelig;ud 2, et vous recherchez l'évènement
<command>STORE_LISTEN</command>&nbsp;:
</para>
<para>
<command>SELECT * FROM sl_event WHERE ev_type='STORE_LISTEN';</command>
</para>
<para>
La requête peut ramener plusieurs lignes, mais ne supprimez que la
partie nécessaire.
</para>
<screen> -# begin; -- Don't straight delete them; open a transaction so you can respond to OOPS
BEGIN;
-# delete from sl_event where ev_type = 'STORE_LISTEN' and
-# (ev_data1 = '1' or ev_data2 = '1' or ev_data3 = '1');
DELETE 3
-# -- Seems OK...
-# commit;
COMMIT</screen>
<para>
La prochaine fois que le démon <application>slon</application> du
n&oelig;ud 3 va démarrer, il ne trouvera plus l'évènement
<command>STORE_LISTEN</command> <quote>erroné</quote>, et la
réplication pourra se poursuivre.
(cependant, vous pourrez ensuite voir surgir un vieil évènement
enregistré qui fait référence à une configuration qui n'existe plus...)
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
J'ai une base qui nous provoque les erreurs suivants dans notre application :
</para>
<screen>permission denied for sequence sl_action_seq</screen>
<para>
Lorsque nous traçons ce message, il est du à la fonction <function>lastval()</function> qui récupère la plus récente mise à jour de la séquence, ce qui revient à attraper la dernière mise à jour d'une séquence interne &slony1;.
</para>
</question>
<answer>
<para>
&slony1; utilise des séquences pour attribuer les valeurs des clefs primaires
des lignes de logs, On pouvait donc s'attendre à ce genre de comportement.
</para>
<para>
Appeler <function>lastval()</function>, pour obtenir <quote>anonymement</quote>
<quote>la valeur de séquence la plus récemment modifiée</quote>, plutot que
d'utiliser la <function>currval('sequence_name')</function> est une pratique
risquée en général, car tout autre application qui utiliser le SGBD pour tracer l'arctivité, archiver ou répliquer peut déclencher une mise à jour de séquence
au moment ou vous vous y attendez le moins.
</para>
<para>
De manière générale, l'utilisation de <function>lastval()</function> n'est pas
très sécurisante, l'utiliser lorsque &slony1; ( ou un système similaire de réplication basé sur les triggers comme <application>Londiste</application> ou
<application>Bucardo</application>) peut vous conduite à des mises à jour de séquence inoppinées.
</para>
</answer>
</qandaentry>
</qandadiv>
</qandaset>