Mon Jul 31 11:56:24 PDT 2006
- Previous message: [Slony1-commit] By cbbrowne: Fix tagging errors
- Next message: [Slony1-commit] By darcyb: Fix spelling mistakes, and Add a note about
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Log Message:
-----------
Schema documentation - per autodoc - for 1.2 RC
Modified Files:
--------------
slony1-engine/doc/adminguide:
schemadoc.xml (r1.6 -> r1.7)
-------------- next part --------------
Index: schemadoc.xml
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/doc/adminguide/schemadoc.xml,v
retrieving revision 1.6
retrieving revision 1.7
diff -Ldoc/adminguide/schemadoc.xml -Ldoc/adminguide/schemadoc.xml -u -w -r1.6 -r1.7
--- doc/adminguide/schemadoc.xml
+++ doc/adminguide/schemadoc.xml
@@ -385,6 +385,7 @@
STORE_TRIGGER =
DROP_TRIGGER =
MOVE_SET =
+ ACCEPT_SET =
SET_DROP_TABLE =
SET_DROP_SEQUENCE =
SET_MOVE_TABLE =
@@ -1127,6 +1128,10 @@
</para>
+ <para>
+ Is the node being used for log shipping?
+ </para>
+
</listitem>
</varlistentry>
@@ -1183,6 +1188,119 @@
</para>
</section>
+ <section id="table.sl-nodelock"
+ xreflabel="sl_nodelock">
+ <title id="table.sl-nodelock-title">
+ Table:
+
+ <structname>sl_nodelock</structname>
+ </title>
+
+
+ <para>
+ Used to prevent multiple slon instances and to identify the backends to kill in terminateNodeConnections().
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_nodelock</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>nl_nodeid</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Clients node_id
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>nl_conncnt</structfield></term>
+ <listitem><para>
+ <type>serial</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Clients connection number
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>nl_backendpid</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ PID of database backend owning this lock
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
<section id="table.sl-path"
xreflabel="sl_path">
<title id="table.sl-path-title">
@@ -1357,6 +1475,130 @@
</para>
</section>
+ <section id="table.sl-registry"
+ xreflabel="sl_registry">
+ <title id="table.sl-registry-title">
+ Table:
+
+ <structname>sl_registry</structname>
+ </title>
+
+
+ <para>
+ Stores miscellaneous runtime data
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_registry</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>reg_key</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Unique key of the runtime option
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>reg_int4</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Option value if type int4
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>reg_text</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Option value if type text
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>reg_timestamp</structfield></term>
+ <listitem><para>
+ <type>timestamp without time zone</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Option value if type timestamp
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
<section id="view.sl-seqlastvalue"
xreflabel="sl_seqlastvalue">
<title id="view.sl-seqlastvalue-title">
@@ -2342,7 +2584,7 @@
</para>
<para>
- Has this subscription been activated? This is not set until the subscriber has received COPY data from the provider
+ Has this subscription been activated? This is not set on the subscriber until AFTER the subscriber has received COPY data from the provider
</para>
</listitem>
@@ -2761,6 +3003,84 @@
</para>
</section>
+<!-- Function addpartiallogindices( ) -->
+ <section id="function.addpartiallogindices"
+ xreflabel="schemadocaddpartiallogindices( )">
+ <title id="function.addpartiallogindices-title">
+ addpartiallogindices( )
+ </title>
+ <titleabbrev id="function.addpartiallogindices-titleabbrev">
+ addpartiallogindices( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Add partial indexes, if possible, to the unused sl_log_? table for
+all origin nodes, and drop any that are no longer needed.
+
+This function presently gets run any time set origins are manipulated
+(FAILOVER, STORE SET, MOVE SET, DROP SET), as well as each time the
+system switches between sl_log_1 and sl_log_2.
+ <programlisting>
+DECLARE
+ v_current_status int4;
+ v_log int4;
+ v_dummy record;
+ idef text;
+ v_count int4;
+BEGIN
+ v_count := 0;
+ select last_value into v_current_status from sl_log_status;
+
+ -- If status is 2 or 3 --> in process of cleanup --> unsafe to create indices
+ if v_current_status in (2, 3) then
+ return 0;
+ end if;
+
+ if v_current_status = 0 then -- Which log should get indices?
+ v_log := 2;
+ else
+ v_log := 1;
+ end if;
+
+ -- Add missing indices...
+ for v_dummy in select distinct set_origin from sl_set
+ where not exists
+ (select * from pg_catalog.pg_indexes where schemaname = 'schemadoc'
+ and tablename = 'sl_log_' || v_log and
+ indexname = 'PartInd_schemadoc_sl_log_' || v_log || '-node-' || set_origin) loop
+ idef := 'create index "PartInd_schemadoc_sl_log_' || v_log || '-node-' || v_dummy.set_origin ||
+ '" on sl_log_' || v_log || ' USING btree(log_xid xxid_ops) where (log_origin = ' || v_dummy.set_origin || ');';
+ execute idef;
+ v_count := v_count + 1;
+ end loop;
+
+ -- Remove unneeded indices...
+ for v_dummy in select indexname from pg_catalog.pg_indexes i where i.schemaname = '@NAMESPACE'
+ and i.tablename = 'sl_log_' || v_log and
+ not exists (select 1 from sl_set where
+ i.indexname = 'PartInd_schemadoc_sl_log_' || v_log || '-node-' || set_origin)
+ loop
+ idef := 'drop index "schemadoc"."' || v_dummy.indexname || '";';
+ execute idef;
+ v_count := v_count - 1;
+ end loop;
+ return v_count;
+END
+</programlisting>
+ </para>
+ </section>
+
<!-- Function altertableforreplication( integer ) -->
<section id="function.altertableforreplication-integer"
xreflabel="schemadocaltertableforreplication( integer )">
@@ -2799,6 +3119,8 @@
v_tab_fqname text;
v_tab_attkind text;
v_n int4;
+ v_trec record;
+ v_tgbad boolean;
begin
-- ----
-- Grab the central configuration lock
@@ -2831,11 +3153,11 @@
and PGXC.relname = T.tab_idxname
for update;
if not found then
- raise exception 'Slony-I: Table with id % not found', p_tab_id;
+ raise exception 'Slony-I: alterTableForReplication(): Table with id % not found', p_tab_id;
end if;
v_tab_fqname = v_tab_row.tab_fqname;
if v_tab_row.tab_altered then
- raise exception 'Slony-I: Table % is already in altered state',
+ raise exception 'Slony-I: alterTableForReplication(): Table % is already in altered state',
v_tab_fqname;
end if;
@@ -2865,6 +3187,32 @@
-- ----
+ -- Check to see if there are any trigger conflicts...
+ -- ----
+ v_tgbad := 'false';
+ for v_trec in
+ select pc.relname, tg1.tgname from
+ "pg_catalog".pg_trigger tg1,
+ "pg_catalog".pg_trigger tg2,
+ "pg_catalog".pg_class pc,
+ "pg_catalog".pg_index pi,
+ sl_table tab
+ where
+ tg1.tgname = tg2.tgname and -- Trigger names match
+ tg1.tgrelid = tab.tab_reloid and -- trigger 1 is on the table
+ pi.indexrelid = tg2.tgrelid and -- trigger 2 is on the index
+ pi.indrelid = tab.tab_reloid and -- indexes table is this table
+ pc.oid = tab.tab_reloid
+ loop
+ raise notice 'Slony-I: alterTableForReplication(): multiple instances of trigger % on table %',
+ v_trec.tgname, v_trec.relname;
+ v_tgbad := 'true';
+ end loop;
+ if v_tgbad then
+ raise exception 'Slony-I: Unable to disable triggers';
+ end if;
+
+ -- ----
-- Disable all existing triggers
-- ----
update "pg_catalog".pg_trigger
@@ -2987,11 +3335,11 @@
and PGXC.relname = T.tab_idxname
for update;
if not found then
- raise exception 'Slony-I: Table with id % not found', p_tab_id;
+ raise exception 'Slony-I: alterTableRestore(): Table with id % not found', p_tab_id;
end if;
v_tab_fqname = v_tab_row.tab_fqname;
if not v_tab_row.tab_altered then
- raise exception 'Slony-I: Table % is not in altered state',
+ raise exception 'Slony-I: alterTableRestore(): Table % is not in altered state',
v_tab_fqname;
end if;
@@ -3053,10 +3401,49 @@
</para>
</section>
-<!-- Function cleanupevent( ) -->
- <section id="function.cleanupevent"
- xreflabel="schemadoccleanupevent( )">
- <title id="function.cleanupevent-title">
+<!-- Function checkmoduleversion( ) -->
+ <section id="function.checkmoduleversion"
+ xreflabel="schemadoccheckmoduleversion( )">
+ <title id="function.checkmoduleversion-title">
+ checkmoduleversion( )
+ </title>
+ <titleabbrev id="function.checkmoduleversion-titleabbrev">
+ checkmoduleversion( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Inline test function that verifies that slonik request for STORE
+NODE/INIT CLUSTER is being run against a conformant set of
+schema/functions.
+ <programlisting>
+declare
+ moduleversion text;
+begin
+ select into moduleversion getModuleVersion();
+ if moduleversion <> '@MODULEVERSION@' then
+ raise exception 'Slonik version: @MODULEVERSION@ != Slony-I version in PG build %',
+ moduleversion;
+ end if;
+ return null;
+end;</programlisting>
+ </para>
+ </section>
+
+<!-- Function cleanupevent( ) -->
+ <section id="function.cleanupevent"
+ xreflabel="schemadoccleanupevent( )">
+ <title id="function.cleanupevent-title">
cleanupevent( )
</title>
<titleabbrev id="function.cleanupevent-titleabbrev">
@@ -3130,20 +3517,45 @@
end if;
end loop;
+ -- ----
+ -- If cluster has only one node, then remove all events up to
+ -- the last SYNC - Bug #1538
+ -- http://gborg.postgresql.org/project/slony1/bugs/bugupdate.php?1538
+ -- ----
+
+ select * into v_min_row from sl_node where
+ no_id <> getLocalNodeId('_schemadoc') limit 1;
+ if not found then
+ select ev_origin, ev_seqno into v_min_row from sl_event
+ where ev_origin = getLocalNodeId('_schemadoc')
+ order by ev_origin desc, ev_seqno desc limit 1;
+ raise notice 'Slony-I: cleanupEvent(): Single node - deleting events < %', v_min_row.ev_seqno;
+ delete from sl_event
+ where
+ ev_origin = v_min_row.ev_origin and
+ ev_seqno < v_min_row.ev_seqno;
+
+ end if;
+
+ -- ----
+ -- Also remove stale entries from the nodelock table.
+ -- ----
+ perform cleanupNodelock();
+
return 0;
end;
</programlisting>
</para>
</section>
-<!-- Function cleanuplistener( ) -->
- <section id="function.cleanuplistener"
- xreflabel="schemadoccleanuplistener( )">
- <title id="function.cleanuplistener-title">
- cleanuplistener( )
+<!-- Function cleanupnodelock( ) -->
+ <section id="function.cleanupnodelock"
+ xreflabel="schemadoccleanupnodelock( )">
+ <title id="function.cleanupnodelock-title">
+ cleanupnodelock( )
</title>
- <titleabbrev id="function.cleanuplistener-titleabbrev">
- cleanuplistener( )
+ <titleabbrev id="function.cleanupnodelock-titleabbrev">
+ cleanupnodelock( )
</titleabbrev>
<para>
@@ -3153,13 +3565,79 @@
<segtitle>Language</segtitle>
<segtitle>Return Type</segtitle>
<seglistitem>
- <seg>C</seg>
+ <seg>PLPGSQL</seg>
<seg>integer</seg>
</seglistitem>
</segmentedlist>
- look for stale pg_listener entries and submit Async_Unlisten() to them
- <programlisting>_Slony_I_cleanupListener</programlisting>
+ Clean up stale entries when restarting slon
+ <programlisting>
+declare
+ v_row record;
+begin
+ for v_row in select nl_nodeid, nl_conncnt, nl_backendpid
+ from sl_nodelock
+ for update
+ loop
+ if killBackend(v_row.nl_backendpid, 'NULL') < 0 then
+ raise notice 'Slony-I: cleanup stale sl_nodelock entry for pid=%',
+ v_row.nl_backendpid;
+ delete from sl_nodelock where
+ nl_nodeid = v_row.nl_nodeid and
+ nl_conncnt = v_row.nl_conncnt;
+ end if;
+ end loop;
+
+ return 0;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function copyfields( integer ) -->
+ <section id="function.copyfields-integer"
+ xreflabel="schemadoccopyfields( integer )">
+ <title id="function.copyfields-integer-title">
+ copyfields( integer )
+ </title>
+ <titleabbrev id="function.copyfields-integer-titleabbrev">
+ copyfields( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Return a string consisting of what should be appended to a COPY statement
+to specify fields for the passed-in tab_id.
+
+In PG versions > 7.3, this looks like (field1,field2,...fieldn)
+ <programlisting>
+declare
+ result text;
+ prefix text;
+ prec record;
+begin
+ result := '';
+ prefix := '('; -- Initially, prefix is the opening paren
+
+ for prec in select slon_quote_input(a.attname) as column from sl_table t, pg_catalog.pg_attribute a where t.tab_id = $1 and t.tab_reloid = a.attrelid and a.attnum > 0 and a.attisdropped = false order by attnum
+ loop
+ result := result || prefix || prec.column;
+ prefix := ','; -- Subsequently, prepend columns with commas
+ end loop;
+ result := result || ')';
+ return result;
+end;
+</programlisting>
</para>
</section>
@@ -3424,14 +3902,14 @@
</para>
</section>
-<!-- Function ddlscript( integer, text, integer ) -->
- <section id="function.ddlscript-integer-text-integer"
- xreflabel="schemadocddlscript( integer, text, integer )">
- <title id="function.ddlscript-integer-text-integer-title">
- ddlscript( integer, text, integer )
+<!-- Function ddlscript_complete( integer, text, integer ) -->
+ <section id="function.ddlscript-complete-integer-text-integer"
+ xreflabel="schemadocddlscript_complete( integer, text, integer )">
+ <title id="function.ddlscript-complete-integer-text-integer-title">
+ ddlscript_complete( integer, text, integer )
</title>
- <titleabbrev id="function.ddlscript-integer-text-integer-titleabbrev">
- ddlscript( integer, text, integer )
+ <titleabbrev id="function.ddlscript-complete-integer-text-integer-titleabbrev">
+ ddlscript_complete( integer, text, integer )
</titleabbrev>
<para>
@@ -3442,15 +3920,15 @@
<segtitle>Return Type</segtitle>
<seglistitem>
<seg>PLPGSQL</seg>
- <seg>bigint</seg>
+ <seg>integer</seg>
</seglistitem>
</segmentedlist>
- ddlScript(set_id, script, only_on_node)
+ ddlScript_complete(set_id, script, only_on_node)
-Generates a SYNC event, runs the script on the origin, and then
-generates a DDL_SCRIPT event to request it to be run on replicated
-slaves.
+After script has run on origin, this fixes up relnames, restores
+triggers, and generates a DDL_SCRIPT event to request it to be run on
+replicated slaves.
<programlisting>
declare
p_set_id alias for $1;
@@ -3458,6 +3936,89 @@
p_only_on_node alias for $3;
v_set_origin int4;
begin
+ perform updateRelname(p_set_id, p_only_on_node);
+ return createEvent('_schemadoc', 'DDL_SCRIPT',
+ p_set_id, p_script, p_only_on_node);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function ddlscript_complete_int( integer, integer ) -->
+ <section id="function.ddlscript-complete-int-integer-integer"
+ xreflabel="schemadocddlscript_complete_int( integer, integer )">
+ <title id="function.ddlscript-complete-int-integer-integer-title">
+ ddlscript_complete_int( integer, integer )
+ </title>
+ <titleabbrev id="function.ddlscript-complete-int-integer-integer-titleabbrev">
+ ddlscript_complete_int( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ ddlScript_complete_int(set_id, script, only_on_node)
+
+Complete processing the DDL_SCRIPT event. This puts tables back into
+replicated mode.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_only_on_node alias for $2;
+ v_row record;
+begin
+ -- ----
+ -- Put all tables back into replicated mode
+ -- ----
+ for v_row in select * from sl_table
+ loop
+ perform alterTableForReplication(v_row.tab_id);
+ end loop;
+
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function ddlscript_prepare( integer, integer ) -->
+ <section id="function.ddlscript-prepare-integer-integer"
+ xreflabel="schemadocddlscript_prepare( integer, integer )">
+ <title id="function.ddlscript-prepare-integer-integer-title">
+ ddlscript_prepare( integer, integer )
+ </title>
+ <titleabbrev id="function.ddlscript-prepare-integer-integer-titleabbrev">
+ ddlscript_prepare( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Prepare for DDL script execution on origin
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_only_on_node alias for $2;
+ v_set_origin int4;
+begin
-- ----
-- Grab the central configuration lock
-- ----
@@ -3482,23 +4043,20 @@
-- Create a SYNC event, run the script and generate the DDL_SCRIPT event
-- ----
perform createEvent('_schemadoc', 'SYNC', NULL);
- perform ddlScript_int(p_set_id, p_script, p_only_on_node);
- perform updateRelname(p_set_id, p_only_on_node);
- return createEvent('_schemadoc', 'DDL_SCRIPT',
- p_set_id, p_script, p_only_on_node);
+ return 1;
end;
</programlisting>
</para>
</section>
-<!-- Function ddlscript_int( integer, text, integer ) -->
- <section id="function.ddlscript-int-integer-text-integer"
- xreflabel="schemadocddlscript_int( integer, text, integer )">
- <title id="function.ddlscript-int-integer-text-integer-title">
- ddlscript_int( integer, text, integer )
+<!-- Function ddlscript_prepare_int( integer, integer ) -->
+ <section id="function.ddlscript-prepare-int-integer-integer"
+ xreflabel="schemadocddlscript_prepare_int( integer, integer )">
+ <title id="function.ddlscript-prepare-int-integer-integer-title">
+ ddlscript_prepare_int( integer, integer )
</title>
- <titleabbrev id="function.ddlscript-int-integer-text-integer-titleabbrev">
- ddlscript_int( integer, text, integer )
+ <titleabbrev id="function.ddlscript-prepare-int-integer-integer-titleabbrev">
+ ddlscript_prepare_int( integer, integer )
</titleabbrev>
<para>
@@ -3513,16 +4071,14 @@
</seglistitem>
</segmentedlist>
- ddlScript_int(set_id, script, only_on_node)
+ ddlScript_prepare_int (set_id, only_on_node)
-Processes the DDL_SCRIPT event. On slave nodes, this restores
-original triggers/rules, runs the script, and then puts tables back
-into replicated mode.
+Do preparatory work for a DDL script, restoring
+triggers/rules to original state.
<programlisting>
declare
p_set_id alias for $1;
- p_script alias for $2;
- p_only_on_node alias for $3;
+ p_only_on_node alias for $2;
v_set_origin int4;
v_no_id int4;
v_row record;
@@ -3561,28 +4117,12 @@
end if;
-- ----
- -- Restore all original triggers and rules
+ -- Restore all original triggers and rules of all sets
-- ----
for v_row in select * from sl_table
- where tab_set = p_set_id
loop
perform alterTableRestore(v_row.tab_id);
end loop;
-
- -- ----
- -- Run the script
- -- ----
- execute p_script;
-
- -- ----
- -- Put all tables back into replicated mode
- -- ----
- for v_row in select * from sl_table
- where tab_set = p_set_id
- loop
- perform alterTableForReplication(v_row.tab_id);
- end loop;
-
return p_set_id;
end;
</programlisting>
@@ -3941,7 +4481,7 @@
where slon_quote_brute(PGN.nspname) || '.' ||
slon_quote_brute(PGC.relname) = v_tab_fqname_quoted
and PGN.oid = PGC.relnamespace) is null then
- raise exception 'Slony-I: table % not found', v_tab_fqname_quoted;
+ raise exception 'Slony-I: determineIdxnameUnique(): table % not found', v_tab_fqname_quoted;
end if;
--
@@ -4094,8 +4634,6 @@
p_li_provider alias for $2;
p_li_receiver alias for $3;
begin
- return -1;
-
perform dropListen_int(p_li_origin,
p_li_provider, p_li_receiver);
@@ -4138,8 +4676,6 @@
p_li_provider alias for $2;
p_li_receiver alias for $3;
begin
- return -1;
-
-- ----
-- Grab the central configuration lock
-- ----
@@ -4212,7 +4748,7 @@
if exists (select true from sl_subscribe
where sub_provider = p_no_id)
then
- raise exception 'Slony-I: Node % is still configured as data provider',
+ raise exception 'Slony-I: Node % is still configured as a data provider',
p_no_id;
end if;
@@ -4570,6 +5106,9 @@
-- Regenerate sl_listen since we revised the subscriptions
perform RebuildListenEntries();
+ -- Run addPartialLogIndices() to try to add indices to unused sl_log_? table
+ perform addPartialLogIndices();
+
return p_set_id;
end;
</programlisting>
@@ -5009,7 +5548,7 @@
-- ----
-- All consistency checks first
- -- Check that every system that has a path to the failed node
+ -- Check that every node that has a path to the failed node
-- also has a path to the backup node.
-- ----
for v_row in select P.pa_client
@@ -5033,7 +5572,7 @@
loop
-- ----
-- Check that the backup node is subscribed to all sets
- -- that origin on the failed node
+ -- that originate on the failed node
-- ----
select into v_row2 sub_forward, sub_active
from sl_subscribe
@@ -5069,46 +5608,7 @@
-- ----
-- Terminate all connections of the failed node the hard way
-- ----
- perform terminateNodeConnections(
- '_schemadoc_Node_' || p_failed_node);
-
--- Note that the following code should all become obsolete in the wake
--- of the availability of RebuildListenEntries()...
-
-if false then
- -- ----
- -- Let every node that listens for something on the failed node
- -- listen for that on the backup node instead.
- -- ----
- for v_row in select * from sl_listen
- where li_provider = p_failed_node
- and li_receiver <> p_backup_node
- loop
- perform storeListen_int(v_row.li_origin,
- p_backup_node, v_row.li_receiver);
- end loop;
-
- -- ----
- -- Let the backup node listen for all events where the
- -- failed node did listen for it.
- -- ----
- for v_row in select li_origin, li_provider
- from sl_listen
- where li_receiver = p_failed_node
- and li_provider <> p_backup_node
- loop
- perform storeListen_int(v_row.li_origin,
- v_row.li_provider, p_backup_node);
- end loop;
-
- -- ----
- -- Remove all sl_listen entries that receive anything from the
- -- failed node.
- -- ----
- delete from sl_listen
- where li_provider = p_failed_node
- or li_receiver = p_failed_node;
-end if;
+ perform terminateNodeConnections(p_failed_node);
-- ----
-- Move the sets
@@ -5141,12 +5641,10 @@
loop
perform alterTableRestore(v_row2.tab_id);
end loop;
- end if;
update sl_set set set_origin = p_backup_node
where set_id = v_row.set_id;
- if p_backup_node = getLocalNodeId('_schemadoc') then
delete from sl_setsync
where ssy_setid = v_row.set_id;
@@ -5192,6 +5690,9 @@
-- Rewrite sl_listen table
perform RebuildListenEntries();
+ -- Run addPartialLogIndices() to try to add indices to unused sl_log_? table
+ perform addPartialLogIndices();
+
-- ----
-- Make sure the node daemon will restart
-- ----
@@ -5231,7 +5732,7 @@
FUNCTION failedNode2 (failed_node, backup_node, set_id, ev_seqno, ev_seqfake)
On the node that has the highest sequence number of the failed node,
-fake the FAILED_NODE event.
+fake the FAILOVER_SET event.
<programlisting>
declare
p_failed_node alias for $1;
@@ -5346,6 +5847,15 @@
loop
perform alterTableForReplication(v_row.tab_id);
end loop;
+ insert into sl_event
+ (ev_origin, ev_seqno, ev_timestamp,
+ ev_minxid, ev_maxxid, ev_xip,
+ ev_type, ev_data1, ev_data2, ev_data3)
+ values
+ (p_backup_node, "pg_catalog".nextval('sl_event_seq'), CURRENT_TIMESTAMP,
+ '0', '0', '',
+ 'ACCEPT_SET', p_set_id::text,
+ p_failed_node::text, p_backup_node::text);
else
delete from sl_subscribe
where sub_set = p_set_id
@@ -5475,7 +5985,7 @@
</seglistitem>
</segmentedlist>
- Generate a sync event if there has not been one in 30 seconds.
+ Generate a sync event if there has not been one in the requested interval.
<programlisting>
declare
p_interval alias for $1;
@@ -5640,6 +6150,33 @@
</para>
</section>
+<!-- Function killbackend( integer, text ) -->
+ <section id="function.killbackend-integer-text"
+ xreflabel="schemadockillbackend( integer, text )">
+ <title id="function.killbackend-integer-text-title">
+ killbackend( integer, text )
+ </title>
+ <titleabbrev id="function.killbackend-integer-text-titleabbrev">
+ killbackend( integer, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Send a signal to a postgres process. Requires superuser rights
+ <programlisting>_Slony_I_killBackend</programlisting>
+ </para>
+ </section>
+
<!-- Function lockedset( ) -->
<section id="function.lockedset"
xreflabel="schemadoclockedset( )">
@@ -5757,6 +6294,268 @@
</para>
</section>
+<!-- Function logswitch_finish( ) -->
+ <section id="function.logswitch-finish"
+ xreflabel="schemadoclogswitch_finish( )">
+ <title id="function.logswitch-finish-title">
+ logswitch_finish( )
+ </title>
+ <titleabbrev id="function.logswitch-finish-titleabbrev">
+ logswitch_finish( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ logswitch_finish()
+
+Attempt to finalize a log table switch in progress
+ <programlisting>
+DECLARE
+ v_current_status int4;
+ v_dummy record;
+BEGIN
+ -- ----
+ -- Grab the central configuration lock to prevent race conditions
+ -- while changing the sl_log_status sequence value.
+ -- ----
+ lock table sl_config_lock;
+
+ -- ----
+ -- Get the current log status.
+ -- ----
+ select last_value into v_current_status from sl_log_status;
+
+ -- ----
+ -- status value 0 or 1 means that there is no log switch in progress
+ -- ----
+ if v_current_status = 0 or v_current_status = 1 then
+ return 0;
+ end if;
+
+ -- ----
+ -- status = 2: sl_log_1 active, cleanup sl_log_2
+ -- ----
+ if v_current_status = 2 then
+ -- ----
+ -- The cleanup thread calls us after it did the delete and
+ -- vacuum of both log tables. If sl_log_2 is empty now, we
+ -- can truncate it and the log switch is done.
+ -- ----
+ for v_dummy in select 1 from sl_log_2 loop
+ -- ----
+ -- Found a row ... log switch is still in progress.
+ -- ----
+ raise notice 'Slony-I: log switch to sl_log_1 still in progress - sl_log_2 not truncated';
+ return -1;
+ end loop;
+
+ raise notice 'Slony-I: log switch to sl_log_1 complete - truncate sl_log_2';
+ truncate sl_log_2;
+ perform "pg_catalog".setval('sl_log_status', 0);
+ -- Run addPartialLogIndices() to try to add indices to unused sl_log_? table
+ perform addPartialLogIndices();
+
+ return 1;
+ end if;
+
+ -- ----
+ -- status = 3: sl_log_2 active, cleanup sl_log_1
+ -- ----
+ if v_current_status = 3 then
+ -- ----
+ -- The cleanup thread calls us after it did the delete and
+ -- vacuum of both log tables. If sl_log_2 is empty now, we
+ -- can truncate it and the log switch is done.
+ -- ----
+ for v_dummy in select 1 from sl_log_1 loop
+ -- ----
+ -- Found a row ... log switch is still in progress.
+ -- ----
+ raise notice 'Slony-I: log switch to sl_log_2 still in progress - sl_log_1 not truncated';
+ return -1;
+ end loop;
+
+ raise notice 'Slony-I: log switch to sl_log_2 complete - truncate sl_log_1';
+ truncate sl_log_1;
+ perform "pg_catalog".setval('sl_log_status', 1);
+ -- Run addPartialLogIndices() to try to add indices to unused sl_log_? table
+ perform addPartialLogIndices();
+ return 2;
+ end if;
+END;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function logswitch_start( ) -->
+ <section id="function.logswitch-start"
+ xreflabel="schemadoclogswitch_start( )">
+ <title id="function.logswitch-start-title">
+ logswitch_start( )
+ </title>
+ <titleabbrev id="function.logswitch-start-titleabbrev">
+ logswitch_start( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ logswitch_start()
+
+Initiate a log table switch if none is in progress
+ <programlisting>
+DECLARE
+ v_current_status int4;
+BEGIN
+ -- ----
+ -- Grab the central configuration lock to prevent race conditions
+ -- while changing the sl_log_status sequence value.
+ -- ----
+ lock table sl_config_lock;
+
+ -- ----
+ -- Get the current log status.
+ -- ----
+ select last_value into v_current_status from sl_log_status;
+
+ -- ----
+ -- status = 0: sl_log_1 active, sl_log_2 clean
+ -- Initiate a switch to sl_log_2.
+ -- ----
+ if v_current_status = 0 then
+ perform "pg_catalog".setval('sl_log_status', 3);
+ perform registry_set_timestamp(
+ 'logswitch.laststart', now()::timestamp);
+ raise notice 'Slony-I: Logswitch to sl_log_2 initiated';
+ return 2;
+ end if;
+
+ -- ----
+ -- status = 1: sl_log_2 active, sl_log_1 clean
+ -- Initiate a switch to sl_log_1.
+ -- ----
+ if v_current_status = 1 then
+ perform "pg_catalog".setval('sl_log_status', 2);
+ perform registry_set_timestamp(
+ 'logswitch.laststart', now()::timestamp);
+ raise notice 'Slony-I: Logswitch to sl_log_1 initiated';
+ return 1;
+ end if;
+
+ raise exception 'Previous logswitch still in progress';
+END;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function logswitch_weekly( ) -->
+ <section id="function.logswitch-weekly"
+ xreflabel="schemadoclogswitch_weekly( )">
+ <title id="function.logswitch-weekly-title">
+ logswitch_weekly( )
+ </title>
+ <titleabbrev id="function.logswitch-weekly-titleabbrev">
+ logswitch_weekly( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ logswitch_weekly()
+
+Ensure a logswitch is done at least weekly
+ <programlisting>
+DECLARE
+ v_now timestamp;
+ v_now_dow int4;
+ v_auto_dow int4;
+ v_auto_time time;
+ v_auto_ts timestamp;
+ v_lastrun timestamp;
+ v_laststart timestamp;
+ v_days_since int4;
+BEGIN
+ -- ----
+ -- Check that today is the day to run at all
+ -- ----
+ v_auto_dow := registry_get_int4(
+ 'logswitch_weekly.dow', 0);
+ v_now := "pg_catalog".now();
+ v_now_dow := extract (DOW from v_now);
+ if v_now_dow <> v_auto_dow then
+ perform registry_set_timestamp(
+ 'logswitch_weekly.lastrun', v_now);
+ return 0;
+ end if;
+
+ -- ----
+ -- Check that the last run of this procedure was before and now is
+ -- after the time we should automatically switch logs.
+ -- ----
+ v_auto_time := registry_get_text(
+ 'logswitch_weekly.time', '02:00');
+ v_auto_ts := current_date + v_auto_time;
+ v_lastrun := registry_get_timestamp(
+ 'logswitch_weekly.lastrun', 'epoch');
+ if v_lastrun >= v_auto_ts or v_now < v_auto_ts then
+ perform registry_set_timestamp(
+ 'logswitch_weekly.lastrun', v_now);
+ return 0;
+ end if;
+
+ -- ----
+ -- This is the moment configured in dow+time. Check that the
+ -- last logswitch was done more than 2 days ago.
+ -- ----
+ v_laststart := registry_get_timestamp(
+ 'logswitch.laststart', 'epoch');
+ v_days_since := extract (days from (v_now - v_laststart));
+ if v_days_since < 2 then
+ perform registry_set_timestamp(
+ 'logswitch_weekly.lastrun', v_now);
+ return 0;
+ end if;
+
+ -- ----
+ -- Fire off an automatic logswitch
+ -- ----
+ perform logswitch_start();
+ perform registry_set_timestamp(
+ 'logswitch_weekly.lastrun', v_now);
+ return 1;
+END;
+</programlisting>
+ </para>
+ </section>
+
<!-- Function logtrigger( ) -->
<section id="function.logtrigger"
xreflabel="schemadoclogtrigger( )">
@@ -6113,17 +6912,9 @@
-- On the new origin, raise an event - ACCEPT_SET
if v_local_node_id = p_new_origin then
- -- Find the event number from the origin
- select max(ev_seqno) as seqno into v_sub_row
- from sl_event
- where ev_type = 'MOVE_SET' and
- ev_data1 = p_set_id and
- ev_data2 = p_old_origin and
- ev_data3 = p_new_origin and
- ev_origin = p_old_origin;
perform createEvent('_schemadoc', 'ACCEPT_SET',
- p_set_id, p_old_origin, p_new_origin, v_sub_row.seqno);
+ p_set_id, p_old_origin, p_new_origin);
end if;
-- ----
@@ -6239,40 +7030,308 @@
end if;
end if;
end if;
- delete from sl_subscribe
- where sub_set = p_set_id
- and sub_receiver = p_new_origin;
+ delete from sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = p_new_origin;
+
+ -- Regenerate sl_listen since we revised the subscriptions
+ perform RebuildListenEntries();
+
+ -- Run addPartialLogIndices() to try to add indices to unused sl_log_? table
+ perform addPartialLogIndices();
+
+ -- ----
+ -- If we are the new or old origin, we have to
+ -- put all the tables into altered state again.
+ -- ----
+ if v_local_node_id = p_old_origin or v_local_node_id = p_new_origin then
+ for v_tab_row in select tab_id from sl_table
+ where tab_set = p_set_id
+ order by tab_id
+ loop
+ perform alterTableForReplication(v_tab_row.tab_id);
+ end loop;
+ end if;
+
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function reachablefromnode( integer, integer[] ) -->
+ <section id="function.reachablefromnode-integer-integerARRAY"
+ xreflabel="schemadocreachablefromnode( integer, integer[] )">
+ <title id="function.reachablefromnode-integer-integerARRAY-title">
+ reachablefromnode( integer, integer[] )
+ </title>
+ <titleabbrev id="function.reachablefromnode-integer-integerARRAY-titleabbrev">
+ reachablefromnode( integer, integer[] )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>SET OF integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ ReachableFromNode(receiver, blacklist)
+
+Find all nodes that <receiver> can receive events from without
+using nodes in <blacklist> as a relay.
+ <programlisting>
+declare
+ v_node alias for $1 ;
+ v_blacklist alias for $2 ;
+ v_ignore int4[] ;
+ v_reachable_edge_last int4[] ;
+ v_reachable_edge_new int4[] default '{}' ;
+ v_server record ;
+begin
+ v_reachable_edge_last := array[v_node] ;
+ v_ignore := v_blacklist || array[v_node] ;
+ return next v_node ;
+ while v_reachable_edge_last != '{}' loop
+ v_reachable_edge_new := '{}' ;
+ for v_server in select pa_server as no_id
+ from sl_path
+ where pa_client = ANY(v_reachable_edge_last) and pa_server != ALL(v_ignore)
+ loop
+ if v_server.no_id != ALL(v_ignore) then
+ v_ignore := v_ignore || array[v_server.no_id] ;
+ v_reachable_edge_new := v_reachable_edge_new || array[v_server.no_id] ;
+ return next v_server.no_id ;
+ end if ;
+ end loop ;
+ v_reachable_edge_last := v_reachable_edge_new ;
+ end loop ;
+ return ;
+end ;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function rebuildlistenentries( ) -->
+ <section id="function.rebuildlistenentries"
+ xreflabel="schemadocrebuildlistenentries( )">
+ <title id="function.rebuildlistenentries-title">
+ rebuildlistenentries( )
+ </title>
+ <titleabbrev id="function.rebuildlistenentries-titleabbrev">
+ rebuildlistenentries( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ RebuildListenEntries()
+
+Invoked by various subscription and path modifying functions, this
+rewrites the sl_listen entries, adding in all the ones required to
+allow communications between nodes in the Slony-I cluster.
+ <programlisting>
+declare
+ v_receiver record ;
+ v_provider record ;
+ v_origin record ;
+ v_reachable int4[] ;
+begin
+ -- First remove the entire configuration
+ delete from sl_listen;
+
+ -- Loop over every possible pair of receiver and provider
+ for v_receiver in select no_id from sl_node loop
+ for v_provider in select pa_server as no_id from sl_path where pa_client = v_receiver.no_id loop
+
+ -- Find all nodes that v_provider.no_id can receiver events from without using v_receiver.no_id
+ for v_origin in select * from ReachableFromNode(v_provider.no_id, array[v_receiver.no_id]) as r(no_id) loop
+
+ -- If v_receiver.no_id subscribes a set from v_provider.no_id, events have to travel the same
+ -- path as the data. Ignore possible sl_listen that would break that rule.
+ perform 1 from sl_subscribe
+ join sl_set on sl_set.set_id = sl_subscribe.sub_set
+ where
+ sub_receiver = v_receiver.no_id and
+ sub_provider != v_provider.no_id and
+ set_origin = v_origin.no_id ;
+ if not found then
+ insert into sl_listen (li_receiver, li_provider, li_origin)
+ values (v_receiver.no_id, v_provider.no_id, v_origin.no_id) ;
+ end if ;
+
+
+ end loop ;
+
+ end loop ;
+ end loop ;
+
+ return null ;
+end ;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function registernodeconnection( integer ) -->
+ <section id="function.registernodeconnection-integer"
+ xreflabel="schemadocregisternodeconnection( integer )">
+ <title id="function.registernodeconnection-integer-title">
+ registernodeconnection( integer )
+ </title>
+ <titleabbrev id="function.registernodeconnection-integer-titleabbrev">
+ registernodeconnection( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Register (uniquely) the node connection so that only one slon can service the node
+ <programlisting>
+declare
+ p_nodeid alias for $1;
+begin
+ insert into sl_nodelock
+ (nl_nodeid, nl_backendpid)
+ values
+ (p_nodeid, pg_backend_pid());
+
+ return 0;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function registry_get_int4( text, integer ) -->
+ <section id="function.registry-get-int4-text-integer"
+ xreflabel="schemadocregistry_get_int4( text, integer )">
+ <title id="function.registry-get-int4-text-integer-title">
+ registry_get_int4( text, integer )
+ </title>
+ <titleabbrev id="function.registry-get-int4-text-integer-titleabbrev">
+ registry_get_int4( text, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ registry_get_int4(key, value)
+
+Get a registry value. If not present, set and return the default.
+ <programlisting>
+DECLARE
+ p_key alias for $1;
+ p_default alias for $2;
+ v_value int4;
+BEGIN
+ select reg_int4 into v_value from sl_registry
+ where reg_key = p_key;
+ if not found then
+ v_value = p_default;
+ if p_default notnull then
+ perform registry_set_int4(p_key, p_default);
+ end if;
+ else
+ if v_value is null then
+ raise exception 'Slony-I: registry key % is not an int4 value',
+ p_key;
+ end if;
+ end if;
+ return v_value;
+END;
+</programlisting>
+ </para>
+ </section>
- -- Regenerate sl_listen since we revised the subscriptions
- perform RebuildListenEntries();
+<!-- Function registry_get_text( text, text ) -->
+ <section id="function.registry-get-text-text-text"
+ xreflabel="schemadocregistry_get_text( text, text )">
+ <title id="function.registry-get-text-text-text-title">
+ registry_get_text( text, text )
+ </title>
+ <titleabbrev id="function.registry-get-text-text-text-titleabbrev">
+ registry_get_text( text, text )
+ </titleabbrev>
- -- ----
- -- If we are the new or old origin, we have to
- -- put all the tables into altered state again.
- -- ----
- if v_local_node_id = p_old_origin or v_local_node_id = p_new_origin then
- for v_tab_row in select tab_id from sl_table
- where tab_set = p_set_id
- order by tab_id
- loop
- perform alterTableForReplication(v_tab_row.tab_id);
- end loop;
- end if;
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
- return p_set_id;
-end;
+ registry_get_text(key, value)
+
+Get a registry value. If not present, set and return the default.
+ <programlisting>
+DECLARE
+ p_key alias for $1;
+ p_default alias for $2;
+ v_value text;
+BEGIN
+ select reg_text into v_value from sl_registry
+ where reg_key = p_key;
+ if not found then
+ v_value = p_default;
+ if p_default notnull then
+ perform registry_set_text(p_key, p_default);
+ end if;
+ else
+ if v_value is null then
+ raise exception 'Slony-I: registry key % is not a text value',
+ p_key;
+ end if;
+ end if;
+ return v_value;
+END;
</programlisting>
</para>
</section>
-<!-- Function rebuildlistenentries( ) -->
- <section id="function.rebuildlistenentries"
- xreflabel="schemadocrebuildlistenentries( )">
- <title id="function.rebuildlistenentries-title">
- rebuildlistenentries( )
+<!-- Function registry_get_timestamp( text, timestamp without time zone ) -->
+ <section id="function.registry-get-timestamp-text-timestamp-without-time-zone"
+ xreflabel="schemadocregistry_get_timestamp( text, timestamp without time zone )">
+ <title id="function.registry-get-timestamp-text-timestamp-without-time-zone-title">
+ registry_get_timestamp( text, timestamp without time zone )
</title>
- <titleabbrev id="function.rebuildlistenentries-titleabbrev">
- rebuildlistenentries( )
+ <titleabbrev id="function.registry-get-timestamp-text-timestamp-without-time-zone-titleabbrev">
+ registry_get_timestamp( text, timestamp without time zone )
</titleabbrev>
<para>
@@ -6283,44 +7342,46 @@
<segtitle>Return Type</segtitle>
<seglistitem>
<seg>PLPGSQL</seg>
- <seg>integer</seg>
+ <seg>timestamp without time zone</seg>
</seglistitem>
</segmentedlist>
- RebuildListenEntries(p_provider, p_receiver)
+ registry_get_timestamp(key, value)
-Invoked by various subscription and path modifying functions, this
-rewrites the sl_listen entries, adding in all the ones required to
-allow communications between nodes in the Slony-I cluster.
+Get a registry value. If not present, set and return the default.
<programlisting>
-declare
- v_row record;
-begin
- -- First remove the entire configuration
- delete from sl_listen;
-
- -- The loop over every possible pair of origin, receiver
- for v_row in select N1.no_id as origin, N2.no_id as receiver
- from sl_node N1, sl_node N2
- where N1.no_id <> N2.no_id
- loop
- perform RebuildListenEntriesOne(v_row.origin, v_row.receiver);
- end loop;
-
- return 0;
-end;
+DECLARE
+ p_key alias for $1;
+ p_default alias for $2;
+ v_value timestamp;
+BEGIN
+ select reg_timestamp into v_value from sl_registry
+ where reg_key = p_key;
+ if not found then
+ v_value = p_default;
+ if p_default notnull then
+ perform registry_set_timestamp(p_key, p_default);
+ end if;
+ else
+ if v_value is null then
+ raise exception 'Slony-I: registry key % is not an timestamp value',
+ p_key;
+ end if;
+ end if;
+ return v_value;
+END;
</programlisting>
</para>
</section>
-<!-- Function rebuildlistenentriesone( integer, integer ) -->
- <section id="function.rebuildlistenentriesone-integer-integer"
- xreflabel="schemadocrebuildlistenentriesone( integer, integer )">
- <title id="function.rebuildlistenentriesone-integer-integer-title">
- rebuildlistenentriesone( integer, integer )
+<!-- Function registry_set_int4( text, integer ) -->
+ <section id="function.registry-set-int4-text-integer"
+ xreflabel="schemadocregistry_set_int4( text, integer )">
+ <title id="function.registry-set-int4-text-integer-title">
+ registry_set_int4( text, integer )
</title>
- <titleabbrev id="function.rebuildlistenentriesone-integer-integer-titleabbrev">
- rebuildlistenentriesone( integer, integer )
+ <titleabbrev id="function.registry-set-int4-text-integer-titleabbrev">
+ registry_set_int4( text, integer )
</titleabbrev>
<para>
@@ -6335,85 +7396,127 @@
</seglistitem>
</segmentedlist>
- RebuildListenEntriesOne(p_origin, p_receiver)
+ registry_set_int4(key, value)
-Rebuilding of sl_listen entries for one origin, receiver pair.
+Set or delete a registry value
<programlisting>
-declare
- p_origin alias for $1;
- p_receiver alias for $2;
- v_row record;
-begin
- -- 1. If the receiver is subscribed to any set from the origin,
- -- listen on the same provider(s).
- for v_row in select distinct sub_provider
- from sl_subscribe, sl_set,
- sl_path
- where sub_set = set_id
- and set_origin = p_origin
- and sub_receiver = p_receiver
- and sub_provider = pa_server
- and sub_receiver = pa_client
- loop
- perform storeListen_int(p_origin,
- v_row.sub_provider, p_receiver);
- end loop;
- if found then
- return 1;
+DECLARE
+ p_key alias for $1;
+ p_value alias for $2;
+BEGIN
+ if p_value is null then
+ delete from sl_registry
+ where reg_key = p_key;
+ else
+ lock table sl_registry;
+ update sl_registry
+ set reg_int4 = p_value
+ where reg_key = p_key;
+ if not found then
+ insert into sl_registry (reg_key, reg_int4)
+ values (p_key, p_value);
end if;
-
- -- 2. If the receiver has a direct path to the provider,
- -- use that.
- if exists (select true
- from sl_path
- where pa_server = p_origin
- and pa_client = p_receiver)
- then
- perform storeListen_int(p_origin, p_origin, p_receiver);
- return 1;
end if;
+ return p_value;
+END;
+</programlisting>
+ </para>
+ </section>
- -- 3. Listen on every node that is either provider for the
- -- receiver or is using the receiver as provider (follow the
- -- normal subscription routes).
- for v_row in select distinct provider from (
- select sub_provider as provider
- from sl_subscribe
- where sub_receiver = p_receiver
- union
- select sub_receiver as provider
- from sl_subscribe
- where sub_provider = p_receiver
- and exists (select true from sl_path
- where pa_server = sub_receiver
- and pa_client = sub_provider)
- ) as S
- loop
- perform storeListen_int(p_origin,
- v_row.provider, p_receiver);
- end loop;
- if found then
- return 1;
- end if;
+<!-- Function registry_set_text( text, text ) -->
+ <section id="function.registry-set-text-text-text"
+ xreflabel="schemadocregistry_set_text( text, text )">
+ <title id="function.registry-set-text-text-text-title">
+ registry_set_text( text, text )
+ </title>
+ <titleabbrev id="function.registry-set-text-text-text-titleabbrev">
+ registry_set_text( text, text )
+ </titleabbrev>
- -- 4. If all else fails - meaning there are no subscriptions to
- -- guide us to the right path - use every node we have a path
- -- to as provider. This normally only happens when the cluster
- -- is built or a new node added. This brute force fallback
- -- ensures that events will propagate if possible at all.
- for v_row in select pa_server as provider
- from sl_path
- where pa_client = p_receiver
- loop
- perform storeListen_int(p_origin,
- v_row.provider, p_receiver);
- end loop;
- if found then
- return 1;
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ registry_set_text(key, value)
+
+Set or delete a registry value
+ <programlisting>
+DECLARE
+ p_key alias for $1;
+ p_value alias for $2;
+BEGIN
+ if p_value is null then
+ delete from sl_registry
+ where reg_key = p_key;
+ else
+ lock table sl_registry;
+ update sl_registry
+ set reg_text = p_value
+ where reg_key = p_key;
+ if not found then
+ insert into sl_registry (reg_key, reg_text)
+ values (p_key, p_value);
+ end if;
end if;
+ return p_value;
+END;
+</programlisting>
+ </para>
+ </section>
- return 0;
-end;
+<!-- Function registry_set_timestamp( text, timestamp without time zone ) -->
+ <section id="function.registry-set-timestamp-text-timestamp-without-time-zone"
+ xreflabel="schemadocregistry_set_timestamp( text, timestamp without time zone )">
+ <title id="function.registry-set-timestamp-text-timestamp-without-time-zone-title">
+ registry_set_timestamp( text, timestamp without time zone )
+ </title>
+ <titleabbrev id="function.registry-set-timestamp-text-timestamp-without-time-zone-titleabbrev">
+ registry_set_timestamp( text, timestamp without time zone )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>timestamp without time zone</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ registry_set_timestamp(key, value)
+
+Set or delete a registry value
+ <programlisting>
+DECLARE
+ p_key alias for $1;
+ p_value alias for $2;
+BEGIN
+ if p_value is null then
+ delete from sl_registry
+ where reg_key = p_key;
+ else
+ lock table sl_registry;
+ update sl_registry
+ set reg_timestamp = p_value
+ where reg_key = p_key;
+ if not found then
+ insert into sl_registry (reg_key, reg_timestamp)
+ values (p_key, p_value);
+ end if;
+ end if;
+ return p_value;
+END;
</programlisting>
</para>
</section>
@@ -6440,13 +7543,16 @@
</seglistitem>
</segmentedlist>
+ sequenceLastValue(p_seqname)
+Utility function used in sl_seqlastvalue view to compactly get the
+last value from the requested sequence.
<programlisting>
declare
p_seqname alias for $1;
v_seq_row record;
begin
- for v_seq_row in execute 'select last_value from ' || p_seqname
+ for v_seq_row in execute 'select last_value from ' || slon_quote_input(p_seqname)
loop
return v_seq_row.last_value;
end loop;
@@ -6501,7 +7607,7 @@
and SQ.seq_reloid = PGC.oid
and PGC.relnamespace = PGN.oid;
if not found then
- raise exception 'Slony-I: sequence % not found', p_seq_id;
+ raise exception 'Slony-I: sequenceSetValue(): sequence % not found', p_seq_id;
end if;
-- ----
@@ -6570,7 +7676,7 @@
raise exception 'Slony-I: setAddSequence(): set % not found', p_set_id;
end if;
if v_set_origin != getLocalNodeId('_schemadoc') then
- raise exception 'Slony-I: setAddSequence(): set % has remote origin', p_set_id;
+ raise exception 'Slony-I: setAddSequence(): set % has remote origin - submit to origin node', p_set_id;
end if;
if exists (select true from sl_subscribe
@@ -6679,6 +7785,13 @@
p_fqname;
end if;
+ select 1 into v_sync_row from sl_sequence where seq_id = p_seq_id;
+ if not found then
+ v_relkind := 'o'; -- all is OK
+ else
+ raise exception 'Slony-I: setAddSequence_int(): sequence ID % has already been assigned', p_seq_id;
+ end if;
+
-- ----
-- Add the sequence to sl_sequence
-- ----
@@ -6827,6 +7940,8 @@
v_sub_provider int4;
v_relkind char;
v_tab_reloid oid;
+ v_pkcand_nn boolean;
+ v_prec record;
begin
-- ----
-- Grab the central configuration lock
@@ -6865,11 +7980,11 @@
and slon_quote_input(p_fqname) = slon_quote_brute(PGN.nspname) ||
'.' || slon_quote_brute(PGC.relname);
if not found then
- raise exception 'Slony-I: setAddTable(): table % not found',
+ raise exception 'Slony-I: setAddTable_int(): table % not found',
p_fqname;
end if;
if v_relkind != 'r' then
- raise exception 'Slony-I: setAddTable(): % is not a regular table',
+ raise exception 'Slony-I: setAddTable_int(): % is not a regular table',
p_fqname;
end if;
@@ -6879,11 +7994,38 @@
and PGX.indexrelid = PGC.oid
and PGC.relname = p_tab_idxname)
then
- raise exception 'Slony-I: setAddTable(): table % has no index %',
+ raise exception 'Slony-I: setAddTable_int(): table % has no index %',
p_fqname, p_tab_idxname;
end if;
-- ----
+ -- Verify that the columns in the PK (or candidate) are not NULLABLE
+ -- ----
+
+ v_pkcand_nn := 'f';
+ for v_prec in select attname from "pg_catalog".pg_attribute where attrelid =
+ (select oid from "pg_catalog".pg_class where oid = v_tab_reloid)
+ and attname in (select attname from "pg_catalog".pg_attribute where
+ attrelid = (select oid from "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_index PGX where
+ PGC.relname = p_tab_idxname and PGX.indexrelid=PGC.oid and
+ PGX.indrelid = v_tab_reloid)) and attnotnull <> 't'
+ loop
+ raise notice 'Slony-I: setAddTable_int: table % PK column % nullable', p_fqname, v_prec.attname;
+ v_pkcand_nn := 't';
+ end loop;
+ if v_pkcand_nn then
+ raise exception 'Slony-I: setAddTable_int: table % not replicable!', p_fqname;
+ end if;
+
+ select * into v_prec from sl_table where tab_id = p_tab_id;
+ if not found then
+ v_pkcand_nn := 't'; -- No-op -- All is well
+ else
+ raise exception 'Slony-I: setAddTable_int: table id % has already been assigned!', p_tab_id;
+ end if;
+
+ -- ----
-- Add the table to sl_table and create the trigger on it.
-- ----
insert into sl_table
@@ -6961,7 +8103,7 @@
raise exception 'Slony-I: setDropSequence(): set % not found', v_set_id;
end if;
if v_set_origin != getLocalNodeId('_schemadoc') then
- raise exception 'Slony-I: setDropSequence(): set % has remote origin', v_set_id;
+ raise exception 'Slony-I: setDropSequence(): set % has origin at another node - submit this to that node', v_set_id;
end if;
-- ----
@@ -7247,7 +8389,9 @@
</seglistitem>
</segmentedlist>
-
+ setMoveSequence(p_seq_id, p_new_set_id) - This generates the
+SET_MOVE_SEQUENCE event, after validation, notably that both sets
+exist, are distinct, and have exactly the same subscription lists
<programlisting>
declare
p_seq_id alias for $1;
@@ -7266,22 +8410,22 @@
select seq_set into v_old_set_id from sl_sequence
where seq_id = p_seq_id;
if not found then
- raise exception 'Slony-I: sequence %d not found', p_seq_id;
+ raise exception 'Slony-I: setMoveSequence(): sequence %d not found', p_seq_id;
end if;
-- ----
-- Check that both sets exist and originate here
-- ----
if p_new_set_id = v_old_set_id then
- raise exception 'Slony-I: set ids cannot be identical';
+ raise exception 'Slony-I: setMoveSequence(): set ids cannot be identical';
end if;
select set_origin into v_origin from sl_set
where set_id = p_new_set_id;
if not found then
- raise exception 'Slony-I: set % not found', p_new_set_id;
+ raise exception 'Slony-I: setMoveSequence(): set % not found', p_new_set_id;
end if;
if v_origin != getLocalNodeId('_schemadoc') then
- raise exception 'Slony-I: set % does not originate on local node',
+ raise exception 'Slony-I: setMoveSequence(): set % does not originate on local node',
p_new_set_id;
end if;
@@ -7351,7 +8495,9 @@
</seglistitem>
</segmentedlist>
-
+ setMoveSequence_int(p_seq_id, p_new_set_id) - processes the
+SET_MOVE_SEQUENCE event, moving a sequence to another replication
+set.
<programlisting>
declare
p_seq_id alias for $1;
@@ -7549,7 +8695,11 @@
</seglistitem>
</segmentedlist>
- not yet documented
+ setSessionRole(username, role) - set role for session.
+
+role can be "normal" or "slon"; setting the latter is necessary, on
+subscriber nodes, in order to override the denyaccess() trigger
+attached to subscribing tables.
<programlisting>_Slony_I_setSessionRole</programlisting>
</para>
</section>
@@ -7582,7 +8732,7 @@
p_tab_fqname alias for $1;
v_fqname text default '';
begin
- v_fqname := '"' || replace(p_tab_fqname,'"','\\"') || '"';
+ v_fqname := '"' || replace(p_tab_fqname,'"','""') || '"';
return v_fqname;
end;
</programlisting>
@@ -7615,48 +8765,68 @@
<programlisting>
declare
p_tab_fqname alias for $1;
- v_temp_fqname text default '';
- v_pre_quoted text[] default '{}';
- v_pre_quote_counter smallint default 0;
- v_count_fqname smallint default 0;
- v_fqname_split text[];
- v_quoted_fqname text default '';
-begin
- v_temp_fqname := p_tab_fqname;
-
- LOOP
- v_pre_quote_counter := v_pre_quote_counter + 1;
- v_pre_quoted[v_pre_quote_counter] :=
- substring(v_temp_fqname from '%#""%"#"%' for '#');
- IF v_pre_quoted[v_pre_quote_counter] <> '' THEN
- v_temp_fqname := replace(v_temp_fqname,
- v_pre_quoted[v_pre_quote_counter], '@' ||
- v_pre_quote_counter);
- ELSE
- EXIT;
- END IF;
- END LOOP;
-
- v_fqname_split := string_to_array(v_temp_fqname , '.');
- v_count_fqname := array_upper (v_fqname_split, 1);
-
- FOR i in 1..v_count_fqname LOOP
- IF substring(v_fqname_split[i],1,1) = '@' THEN
- v_quoted_fqname := v_quoted_fqname ||
- v_pre_quoted[substring (v_fqname_split[i] from 2)::int];
- ELSE
- v_quoted_fqname := v_quoted_fqname || '"' ||
- v_fqname_split[i] || '"';
- END IF;
-
- IF i < v_count_fqname THEN
- v_quoted_fqname := v_quoted_fqname || '.' ;
- END IF;
- END LOOP;
+ v_nsp_name text;
+ v_tab_name text;
+ v_i integer;
+ v_l integer;
+ v_pq2 integer;
+begin
+ v_l := length(p_tab_fqname);
- return v_quoted_fqname;
-end;
-</programlisting>
+ -- Let us search for the dot
+ if p_tab_fqname like '"%' then
+ -- if the first part of the ident starts with a double quote, search
+ -- for the closing double quote, skipping over double double quotes.
+ v_i := 2;
+ while v_i <= v_l loop
+ if substr(p_tab_fqname, v_i, 1) != '"' then
+ v_i := v_i + 1;
+ else
+ v_i := v_i + 1;
+ if substr(p_tab_fqname, v_i, 1) != '"' then
+ exit;
+ end if;
+ v_i := v_i + 1;
+ end if;
+ end loop;
+ else
+ -- first part of ident is not quoted, search for the dot directly
+ v_i := 1;
+ while v_i <= v_l loop
+ if substr(p_tab_fqname, v_i, 1) = '.' then
+ exit;
+ end if;
+ v_i := v_i + 1;
+ end loop;
+ end if;
+
+ -- v_i now points at the dot or behind the string.
+
+ if substr(p_tab_fqname, v_i, 1) = '.' then
+ -- There is a dot now, so split the ident into its namespace
+ -- and objname parts and make sure each is quoted
+ v_nsp_name := substr(p_tab_fqname, 1, v_i - 1);
+ v_tab_name := substr(p_tab_fqname, v_i + 1);
+ if v_nsp_name not like '"%' then
+ v_nsp_name := '"' || replace(v_nsp_name, '"', '""') ||
+ '"';
+ end if;
+ if v_tab_name not like '"%' then
+ v_tab_name := '"' || replace(v_tab_name, '"', '""') ||
+ '"';
+ end if;
+
+ return v_nsp_name || '.' || v_tab_name;
+ else
+ -- No dot ... must be just an ident without schema
+ if p_tab_fqname like '"%' then
+ return p_tab_fqname;
+ else
+ return '"' || replace(p_tab_fqname, '"', '""') || '"';
+ end if;
+ end if;
+
+end;</programlisting>
</para>
</section>
@@ -7749,7 +8919,7 @@
Returns the minor version number of the slony schema
<programlisting>
begin
- return 1;
+ return 2;
end;
</programlisting>
</para>
@@ -7819,8 +8989,6 @@
p_provider alias for $2;
p_receiver alias for $3;
begin
- return -1;
-
perform storeListen_int (p_origin, p_provider, p_receiver);
return createEvent ('_schemadoc', 'STORE_LISTEN',
p_origin, p_provider, p_receiver);
@@ -8250,6 +9418,9 @@
(p_set_id, p_set_origin, p_set_comment);
end if;
+ -- Run addPartialLogIndices() to try to add indices to unused sl_log_? table
+ perform addPartialLogIndices();
+
return p_set_id;
end;
</programlisting>
@@ -8411,6 +9582,7 @@
p_sub_forward alias for $4;
v_set_origin int4;
v_ev_seqno int8;
+ v_rec record;
begin
-- ----
-- Grab the central configuration lock
@@ -8418,7 +9590,7 @@
lock table sl_config_lock;
-- ----
- -- Check that this is called on the receiver node
+ -- Check that this is called on the provider node
-- ----
if p_sub_provider != getLocalNodeId('_schemadoc') then
raise exception 'Slony-I: subscribeSet() must be called on provider';
@@ -8431,26 +9603,28 @@
from sl_set
where set_id = p_sub_set;
if not found then
- raise exception 'Slony-I: set % not found', p_sub_set;
+ raise exception 'Slony-I: subscribeSet(): set % not found', p_sub_set;
end if;
if v_set_origin = p_sub_receiver then
raise exception
- 'Slony-I: set origin and receiver cannot be identical';
+ 'Slony-I: subscribeSet(): set origin and receiver cannot be identical';
end if;
if p_sub_receiver = p_sub_provider then
raise exception
- 'Slony-I: set provider and receiver cannot be identical';
+ 'Slony-I: subscribeSet(): set provider and receiver cannot be identical';
end if;
-
-- ---
- -- Check to see if the set contains any tables - gripe if not - bug #1226
+ -- Verify that the provider is either the origin or an active subscriber
+ -- Bug report #1362
-- ---
- if not exists (select true
- from sl_table
- where tab_set = p_sub_set) then
- raise notice 'subscribeSet:: set % has no tables - risk of problems - see bug 1226', p_sub_set;
- raise notice 'http://gborg.postgresql.org/project/slony1/bugs/bugupdate.php?1226';
+ if v_set_origin <> p_sub_provider then
+ if not exists (select 1 from sl_subscribe
+ where sub_set = p_sub_set and
+ sub_receiver = p_sub_provider and
+ sub_forward and sub_active) then
+ raise exception 'Slony-I: subscribeSet(): provider % is not an active forwarding node for replication set %', p_sub_provider, p_sub_set;
+ end if;
end if;
-- ----
@@ -8466,11 +9640,6 @@
perform subscribeSet_int(p_sub_set, p_sub_provider,
p_sub_receiver, p_sub_forward);
- -- ----
- -- Submit listen management events
- -- ----
- perform RebuildListenEntries();
-
return v_ev_seqno;
end;
</programlisting>
@@ -8526,7 +9695,7 @@
and sub_receiver = p_sub_receiver;
if found then
if not v_sub_row.sub_active then
- raise exception 'Slony-I: set % is not active, cannot change provider',
+ raise exception 'Slony-I: subscribeSet_int(): set % is not active, cannot change provider',
p_sub_set;
end if;
end if;
@@ -8541,6 +9710,11 @@
where sub_set = p_sub_set
and sub_receiver = p_sub_receiver;
if found then
+ -- ----
+ -- Rewrite sl_listen table
+ -- ----
+ perform RebuildListenEntries();
+
return p_sub_set;
end if;
@@ -8569,7 +9743,7 @@
from sl_set
where set_id = p_sub_set;
if not found then
- raise exception 'Slony-I: set % not found', p_sub_set;
+ raise exception 'Slony-I: subscribeSet_int(): set % not found', p_sub_set;
end if;
if v_set_origin = getLocalNodeId('_schemadoc') then
@@ -8580,7 +9754,9 @@
p_sub_provider, p_sub_receiver);
end if;
+ -- ----
-- Rewrite sl_listen table
+ -- ----
perform RebuildListenEntries();
return p_sub_set;
@@ -8653,7 +9829,7 @@
-- anything means the table does not exist.
--
if not found then
- raise exception 'Slony-I: table % not found', v_tab_fqname_quoted;
+ raise exception 'Slony-I: tableAddKey(): table % not found', v_tab_fqname_quoted;
end if;
--
@@ -8734,7 +9910,7 @@
and T.tab_reloid = PGC.oid
and PGC.relnamespace = PGN.oid;
if not found then
- raise exception 'Slony-I: table with ID % not found', p_tab_id;
+ raise exception 'Slony-I: tableDropKey(): table with ID % not found', p_tab_id;
end if;
-- ----
@@ -8805,14 +9981,14 @@
</para>
</section>
-<!-- Function terminatenodeconnections( name ) -->
- <section id="function.terminatenodeconnections-name"
- xreflabel="schemadocterminatenodeconnections( name )">
- <title id="function.terminatenodeconnections-name-title">
- terminatenodeconnections( name )
+<!-- Function terminatenodeconnections( integer ) -->
+ <section id="function.terminatenodeconnections-integer"
+ xreflabel="schemadocterminatenodeconnections( integer )">
+ <title id="function.terminatenodeconnections-integer-title">
+ terminatenodeconnections( integer )
</title>
- <titleabbrev id="function.terminatenodeconnections-name-titleabbrev">
- terminatenodeconnections( name )
+ <titleabbrev id="function.terminatenodeconnections-integer-titleabbrev">
+ terminatenodeconnections( integer )
</titleabbrev>
<para>
@@ -8822,13 +9998,30 @@
<segtitle>Language</segtitle>
<segtitle>Return Type</segtitle>
<seglistitem>
- <seg>C</seg>
+ <seg>PLPGSQL</seg>
<seg>integer</seg>
</seglistitem>
</segmentedlist>
- terminates connections to the node and terminates the process
- <programlisting>_Slony_I_terminateNodeConnections</programlisting>
+ terminates all backends that have registered to be from the given node
+ <programlisting>
+declare
+ p_failed_node alias for $1;
+ v_row record;
+begin
+ for v_row in select nl_nodeid, nl_conncnt,
+ nl_backendpid from sl_nodelock
+ where nl_nodeid = p_failed_node for update
+ loop
+ perform killBackend(v_row.nl_backendpid, 'TERM');
+ delete from sl_nodelock
+ where nl_nodeid = v_row.nl_nodeid
+ and nl_conncnt = v_row.nl_conncnt;
+ end loop;
+
+ return 0;
+end;
+</programlisting>
</para>
</section>
@@ -9020,7 +10213,7 @@
where sub_set = p_sub_set
and sub_provider = p_sub_receiver)
then
- raise exception 'Slony-I: Cannot unsubscibe set % while being provider',
+ raise exception 'Slony-I: Cannot unsubscribe set % while being provider',
p_sub_set;
end if;
@@ -9319,7 +10512,7 @@
p_old alias for $1;
begin
-- upgrade sl_table
- if p_old = '1.0.2' or p_old = '1.0.5' then
+ if p_old IN ('1.0.2', '1.0.5', '1.0.6') then
-- Add new column(s) sl_table.tab_relname, sl_table.tab_nspname
execute 'alter table sl_table add column tab_relname name';
execute 'alter table sl_table add column tab_nspname name';
@@ -9338,7 +10531,7 @@
end if;
-- upgrade sl_sequence
- if p_old = '1.0.2' or p_old = '1.0.5' then
+ if p_old IN ('1.0.2', '1.0.5', '1.0.6') then
-- Add new column(s) sl_sequence.seq_relname, sl_sequence.seq_nspname
execute 'alter table sl_sequence add column seq_relname name';
execute 'alter table sl_sequence add column seq_nspname name';
@@ -9358,11 +10551,60 @@
-- ----
-- Changes from 1.0.x to 1.1.0
-- ----
- if p_old = '1.0.2' or p_old = '1.0.5' then
+ if p_old IN ('1.0.2', '1.0.5', '1.0.6') then
-- Add new column sl_node.no_spool for virtual spool nodes
execute 'alter table sl_node add column no_spool boolean';
update sl_node set no_spool = false;
end if;
+
+ -- ----
+ -- Changes for 1.1.3
+ -- ----
+ if p_old IN ('1.0.2', '1.0.5', '1.0.6', '1.1.0', '1.1.1', '1.1.2') then
+ -- Add new table sl_nodelock
+ execute 'create table sl_nodelock (
+ nl_nodeid int4,
+ nl_conncnt serial,
+ nl_backendpid int4,
+
+ CONSTRAINT "sl_nodelock-pkey"
+ PRIMARY KEY (nl_nodeid, nl_conncnt)
+ )';
+ -- Drop obsolete functions
+ execute 'drop function terminateNodeConnections(name)';
+ execute 'drop function cleanupListener()';
+ execute 'drop function truncateTable(text)';
+ end if;
+
+ -- ----
+ -- Changes for 1.2
+ -- ----
+ if p_old IN ('1.0.2', '1.0.5', '1.0.6', '1.1.0', '1.1.1', '1.1.2', '1.1.3') then
+ -- Add new table sl_registry
+ execute 'create table sl_registry (
+ reg_key text primary key,
+ reg_int4 int4,
+ reg_text text,
+ reg_timestamp timestamp
+ ) without oids';
+ execute 'alter table sl_config_lock set without oids;';
+ execute 'alter table sl_confirm set without oids;';
+ execute 'alter table sl_event set without oids;';
+ execute 'alter table sl_listen set without oids;';
+ execute 'alter table sl_log_1 set without oids;';
+ execute 'alter table sl_log_2 set without oids;';
+ execute 'alter table sl_node set without oids;';
+ execute 'alter table sl_nodelock set without oids;';
+ execute 'alter table sl_path set without oids;';
+ execute 'alter table sl_seqlog set without oids;';
+ execute 'alter table sl_sequence set without oids;';
+ execute 'alter table sl_set set without oids;';
+ execute 'alter table sl_setsync set without oids;';
+ execute 'alter table sl_subscribe set without oids;';
+ execute 'alter table sl_table set without oids;';
+ execute 'alter table sl_trigger set without oids;';
+ end if;
+
return p_old;
end;
</programlisting>
- Previous message: [Slony1-commit] By cbbrowne: Fix tagging errors
- Next message: [Slony1-commit] By darcyb: Fix spelling mistakes, and Add a note about
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Slony1-commit mailing list