Chris Browne cbbrowne at lists.slony.info
Thu Jan 3 14:42:49 PST 2008
Update of /home/cvsd/slony1/slony1-engine/doc/adminguide
In directory main.slony.info:/tmp/cvs-serv23112

Modified Files:
      Tag: REL_1_2_STABLE
	schemadoc.xml 
Log Message:
Bring schemadoc.xml up to date, and address bug #29
http://www.slony.info/bugzilla/show_bug.cgi?id=29


Index: schemadoc.xml
===================================================================
RCS file: /home/cvsd/slony1/slony1-engine/doc/adminguide/schemadoc.xml,v
retrieving revision 1.7.2.1
retrieving revision 1.7.2.2
diff -C2 -d -r1.7.2.1 -r1.7.2.2
*** schemadoc.xml	28 Aug 2007 19:18:12 -0000	1.7.2.1
--- schemadoc.xml	3 Jan 2008 22:42:46 -0000	1.7.2.2
***************
*** 3034,3037 ****
--- 3034,3126 ----
  
  
+ <!-- Function add_empty_table_to_replication( integer, integer, text, text, text, text ) -->
+     <section id="function.add-empty-table-to-replication-integer-integer-text-text-text-text"
+              xreflabel="schemadocadd_empty_table_to_replication( integer, integer, text, text, text, text )">
+       <title id="function.add-empty-table-to-replication-integer-integer-text-text-text-text-title">
+        add_empty_table_to_replication( integer, integer, text, text, text, text )
+       </title>
+       <titleabbrev id="function.add-empty-table-to-replication-integer-integer-text-text-text-text-titleabbrev">
+        add_empty_table_to_replication( integer, integer, text, text, text, text )
+       </titleabbrev>
+ 
+       <para>
+        <segmentedlist>
+         <title>Function Properties</title>
+         <?dbhtml list-presentation="list"?>
+         <segtitle>Language</segtitle>
+         <segtitle>Return Type</segtitle>
+         <seglistitem>
+          <seg>PLPGSQL</seg>
+          <seg>bigint</seg>
+         </seglistitem>
+        </segmentedlist>
+  
+        Verify that a table is empty, and add it to replication.  
+ tab_idxname is optional - if NULL, then we use the primary key.
+         <programlisting>
+ declare
+   p_set_id alias for $1;
+   p_tab_id alias for $2;
+   p_nspname alias for $3;
+   p_tabname alias for $4;
+   p_idxname alias for $5;
+   p_comment alias for $6;
+ 
+   prec record;
+   v_origin int4;
+   v_isorigin boolean;
+   v_fqname text;
+   v_query text;
+   v_rows integer;
+   v_idxname text;
+ 
+ begin
+ -- Need to validate that the set exists; the set will tell us if this is the origin
+   select set_origin into v_origin from sl_set where set_id = p_set_id;
+   if not found then
+ 	raise exception &#39;add_empty_table_to_replication: set % not found!&#39;, p_set_id;
+   end if;
+ 
+ -- Need to be aware of whether or not this node is origin for the set
+    v_isorigin := ( v_origin = getLocalNodeId(&#39;_schemadoc&#39;) );
+ 
+    v_fqname := &#39;&quot;&#39; || p_nspname || &#39;&quot;.&quot;&#39; || p_tabname || &#39;&quot;&#39;;
+ -- Take out a lock on the table
+    v_query := &#39;lock &#39; || v_fqname || &#39;;&#39;;
+    execute v_query;
+ 
+    if v_isorigin then
+ 	-- On the origin, verify that the table is empty, failing if it has any tuples
+         v_query := &#39;select 1 as tuple from &#39; || v_fqname || &#39; limit 1;&#39;;
+ 	execute v_query into prec;
+         GET DIAGNOSTICS v_rows = ROW_COUNT;
+ 	if v_rows = 0 then
+ 		raise notice &#39;add_empty_table_to_replication: table % empty on origin - OK&#39;, v_fqname;
+ 	else
+ 		raise exception &#39;add_empty_table_to_replication: table % contained tuples on origin node %&#39;, v_fqname, v_origin;
+ 	end if;
+    else
+ 	-- On other nodes, TRUNCATE the table
+         v_query := &#39;truncate &#39; || v_fqname || &#39;;&#39;;
+ 	execute v_query;
+    end if;
+ -- If p_idxname is NULL, then look up the PK index, and RAISE EXCEPTION if one does not exist
+    if p_idxname is NULL then
+ 	select c2.relname into prec from pg_catalog.pg_index i, pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_namespace n where i.indrelid = c1.oid and i.indexrelid = c2.oid and c1.relname = p_tabname and i.indisprimary and n.nspname = p_nspname and n.oid = c1.relnamespace;
+ 	if not found then
+ 		raise exception &#39;add_empty_table_to_replication: table % has no primary key and no candidate specified!&#39;, v_fqname;
+ 	else
+ 		v_idxname := prec.relname;
+ 	end if;
+    else
+ 	v_idxname := p_idxname;
+    end if;
+    perform setAddTable_int(p_set_id, p_tab_id, v_fqname, v_idxname, p_comment);
+    return alterTableRestore(p_tab_id);
+ end
+ </programlisting>
+       </para>
+     </section>
+ 
  <!-- Function add_missing_table_field( text, text, text, text ) -->
      <section id="function.add-missing-table-field-text-text-text-text"
***************
*** 6677,6681 ****
  <!-- Function logtrigger(  ) -->
      <section id="function.logtrigger"
!              xreflabel="schemadoclogtrigger(  )">
        <title id="function.logtrigger-title">
         logtrigger(  )
--- 6766,6770 ----
  <!-- Function logtrigger(  ) -->
      <section id="function.logtrigger"
!              xreflabel="schemadoc.logtrigger(  )">
        <title id="function.logtrigger-title">
         logtrigger(  )
***************
*** 7286,7321 ****
          <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 ;
  
--- 7375,7461 ----
          <programlisting>
  declare
! 	v_row	record;
! 	skip    boolean;
  begin
  	-- First remove the entire configuration
  	delete from sl_listen;
  
! 	-- Second populate the sl_listen configuration with a full
! 	-- network of all possible paths.
! 	insert into sl_listen
! 				(li_origin, li_provider, li_receiver)
! 			select pa_server, pa_server, pa_client from sl_path;
! 	while true loop
! 		insert into sl_listen
! 					(li_origin, li_provider, li_receiver)
! 			select distinct li_origin, pa_server, pa_client
! 				from sl_listen, sl_path
! 				where li_receiver = pa_server
! 				  and li_origin &lt;&gt; pa_client
! 			except
! 			select li_origin, li_provider, li_receiver
! 				from sl_listen;
  
! 		if not found then
! 			exit;
! 		end if;
! 	end loop;
  
! 	-- We now replace specific event-origin,receiver combinations
! 	-- with a configuration that tries to avoid events arriving at
! 	-- a node before the data provider actually has the data ready.
  
+ 	-- Loop over every possible pair of receiver and event origin
+ 	for v_row in select N1.no_id as receiver, N2.no_id as origin
+ 			from sl_node as N1, sl_node as N2
+ 			where N1.no_id &lt;&gt; N2.no_id
+ 	loop
+ 		skip := &#39;f&#39;;
+ 		-- 1st choice:
+ 		-- If we use the event origin as a data provider for any
+ 		-- set that originates on that very node, we are a direct
+ 		-- subscriber to that origin and listen there only.
+ 		if exists (select true from sl_set, sl_subscribe
+ 				where set_origin = v_row.origin
+ 				  and sub_set = set_id
+ 				  and sub_provider = v_row.origin
+ 				  and sub_receiver = v_row.receiver
+ 				  and sub_active)
+ 		then
+ 			delete from sl_listen
+ 				where li_origin = v_row.origin
+ 				  and li_receiver = v_row.receiver;
+ 			insert into sl_listen (li_origin, li_provider, li_receiver)
+ 				values (v_row.origin, v_row.origin, v_row.receiver);
+ 			skip := &#39;t&#39;;
+ 		end if;
  
! 		if skip then
! 			skip := &#39;f&#39;;
! 		else
! 		-- 2nd choice:
! 		-- If we are subscribed to any set originating on this
! 		-- event origin, we want to listen on all data providers
! 		-- we use for this origin. We are a cascaded subscriber
! 		-- for sets from this node.
! 			if exists (select true from sl_set, sl_subscribe
! 						where set_origin = v_row.origin
! 						  and sub_set = set_id
! 						  and sub_receiver = v_row.receiver
! 						  and sub_active)
! 			then
! 				delete from sl_listen
! 					where li_origin = v_row.origin
! 					  and li_receiver = v_row.receiver;
! 				insert into sl_listen (li_origin, li_provider, li_receiver)
! 					select distinct set_origin, sub_provider, v_row.receiver
! 						from sl_set, sl_subscribe
! 						where set_origin = v_row.origin
! 						  and sub_set = set_id
! 						  and sub_receiver = v_row.receiver
! 						  and sub_active;
! 			end if;
! 		end if;
  
  	end loop ;
  
***************
*** 7661,7664 ****
--- 7801,7863 ----
      </section>
  
+ <!-- Function replicate_partition( integer, text, text, text, text ) -->
+     <section id="function.replicate-partition-integer-text-text-text-text"
+              xreflabel="schemadocreplicate_partition( integer, text, text, text, text )">
+       <title id="function.replicate-partition-integer-text-text-text-text-title">
+        replicate_partition( integer, text, text, text, text )
+       </title>
+       <titleabbrev id="function.replicate-partition-integer-text-text-text-text-titleabbrev">
+        replicate_partition( integer, text, text, text, text )
+       </titleabbrev>
+ 
+       <para>
+        <segmentedlist>
+         <title>Function Properties</title>
+         <?dbhtml list-presentation="list"?>
+         <segtitle>Language</segtitle>
+         <segtitle>Return Type</segtitle>
+         <seglistitem>
+          <seg>PLPGSQL</seg>
+          <seg>bigint</seg>
+         </seglistitem>
+        </segmentedlist>
+  
+        Add a partition table to replication.
+ tab_idxname is optional - if NULL, then we use the primary key.
+ This function looks up replication configuration via the parent table.
+         <programlisting>
+ declare
+   p_tab_id alias for $1;
+   p_nspname alias for $2;
+   p_tabname alias for $3;
+   p_idxname alias for $4;
+   p_comment alias for $5;
+ 
+   prec record;
+   prec2 record;
+   v_set_id int4;
+ 
+ begin
+ -- Look up the parent table; fail if it does not exist
+    select c1.oid into prec from pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_inherits i, pg_catalog.pg_namespace n where c1.oid = i.inhparent  and c2.oid = i.inhrelid and n.oid = c2.relnamespace and n.nspname = p_nspname and c2.relname = p_tabname;
+    if not found then
+ 	raise exception &#39;replicate_partition: No parent table found for %.%!&#39;, p_nspname, p_tabname;
+    end if;
+ 
+ -- The parent table tells us what replication set to use
+    select tab_set into prec2 from sl_table where tab_reloid = prec.oid;
+    if not found then
+ 	raise exception &#39;replicate_partition: Parent table % for new partition %.% is not replicated!&#39;, prec.oid, p_nspname, p_tabname;
+    end if;
+ 
+    v_set_id := prec2.tab_set;
+ 
+ -- Now, we have all the parameters necessary to run add_empty_table_to_replication...
+    return add_empty_table_to_replication(v_set_id, p_tab_id, p_nspname, p_tabname, p_idxname, p_comment);
+ end
+ </programlisting>
+       </para>
+     </section>
+ 
  <!-- Function sequencelastvalue( text ) -->
      <section id="function.sequencelastvalue-text"
***************
*** 9092,9096 ****
          <programlisting>
  begin
! 	return 11;
  end;
  </programlisting>
--- 9291,9295 ----
          <programlisting>
  begin
! 	return 12;
  end;
  </programlisting>



More information about the Slony1-commit mailing list