Christopher Browne cbbrowne
Wed Nov 3 18:33:05 PST 2004
Below is a CVS HEAD patch "candidate" (I expect it to change before
being applied) that uses a heuristic to generate sl_listen entries
automatically rather than requiring them to be statically generated
(as in the "altperl" script, or by hand).

The approach is thus...

 - Each time we add a node subscription, we calculate two sets of
   'listens':

   1.  There's a direct connection between the new node and its parent
       that should override any other paths between those nodes;

   2.  For every other pair of nodes (a,b), where b<>a and
       it's not the connection from #1, we point (a,b) to go through
       the "parent."

 - When we do a MOVE SET, we run the
   GenerateListensOnSubscribe(provider,receiver) function against each
   of the subscribers in the subscription set to revise _all_ of the
   paths.

I think I've got it placed rightly in subscribeSet(); it may be that
it needs to get put some place else in moveSet().

There's a bit of a difference between what this generates and an
"optimal" set...  Consider the following set of nodes (in "altperl")
form:

  add_node(host => 'h1', dbname=>'oxrslive', port=>5432,
           user=>'postgres', node=>1);

  add_node(host => 'h2', dbname=>'oxrslive', port=>5432,
           user=>'postgres', node=>2, parent => 1);

  add_node(host => 'h3', dbname=>'oxrslive', port=>5432,
           user=>'postgres', node=>3, parent => 1);

  add_node(host => 'h4', dbname=>'oxrslive', port=>5432,
           user=>'postgres', node=>4, parent => 2);

  add_node(host => 'h5', dbname=>'oxrslive', port=>5432,
           user=>'postgres', node=>5, parent => 3);

The "optimal" network that gets generated by init_cluster.pl for this
is the following set of listens:

      store listen (origin = 1, receiver = 2, provider = 1);
      store listen (origin = 1, receiver = 3, provider = 1);
      store listen (origin = 1, receiver = 4, provider = 2);
      store listen (origin = 1, receiver = 5, provider = 3);
      store listen (origin = 2, receiver = 1, provider = 2);
      store listen (origin = 2, receiver = 3, provider = 1);
      store listen (origin = 2, receiver = 4, provider = 2);
      store listen (origin = 2, receiver = 5, provider = 3);
      store listen (origin = 3, receiver = 1, provider = 3);
      store listen (origin = 3, receiver = 2, provider = 1);
      store listen (origin = 3, receiver = 4, provider = 2);
      store listen (origin = 3, receiver = 5, provider = 3);
      store listen (origin = 4, receiver = 1, provider = 2);
      store listen (origin = 4, receiver = 2, provider = 4);
      store listen (origin = 4, receiver = 3, provider = 1);
      store listen (origin = 4, receiver = 5, provider = 3);
      store listen (origin = 5, receiver = 1, provider = 3);
      store listen (origin = 5, receiver = 2, provider = 1);
      store listen (origin = 5, receiver = 3, provider = 5);
      store listen (origin = 5, receiver = 4, provider = 2);

The heuristic provides _nearly_ the same result; there are only three
nodes where the listen paths differ:

      store listen (origin = 5, receiver = 4, provider = 3);  # 2 is 'optimal'
      store listen (origin = 5, receiver = 2, provider = 3);  # 1 is 'optimal'
      store listen (origin = 4, receiver = 3, provider = 2);  # 1 is 'optimal'

I don't _think_ that these slightly different paths present a problem,
as events are propagating to those providers already as a result of
the other paths.  Or am I off base?

Comments welcome...

Index: slony1_funcs.sql
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/backend/slony1_funcs.sql,v
retrieving revision 1.35
diff -c -r1.35 slony1_funcs.sql
*** slony1_funcs.sql	19 Oct 2004 01:16:06 -0000	1.35
--- slony1_funcs.sql	3 Nov 2004 16:48:43 -0000
***************
*** 1755,1760 ****
--- 1755,1767 ----
  	perform @NAMESPACE at .moveSet_int(p_set_id, v_local_node_id,
  			p_new_origin);
  
+ 	for v_sub_row in select sub_provider, sub_receiver 
+ 			from @NAMESPACE at .sl_subscribe
+ 			where sub_set = p_set_id
+ 	loop
+ 		perform @NAMESPACE at .GenerateListensOnSubscribe(v_sub_row.sub_provider, v_sub_row.sub_receiver)
+ 	done;
+ 
  	-- ----
  	-- At this time we hold access exclusive locks for every table
  	-- in the set. But we did move the set to the new origin, so the
***************
*** 3615,3620 ****
--- 3622,3632 ----
  			p_sub_receiver, p_sub_forward);
  
  	-- ----
+ 	-- Submit listen management events
+ 	-- ----
+ 	perform @NAMESPACE at .GenerateListensOnSubscribe(p_sub_provider, p_sub_receiver);
+ 
+ 	-- ----
  	-- Create the SUBSCRIBE_SET event
  	-- ----
  	return  @NAMESPACE at .createEvent(''_ at CLUSTERNAME@'', ''SUBSCRIBE_SET'', 
***************
*** 4436,4441 ****
--- 4448,4519 ----
  the creation of the serial column. The return an attkind according to
  that.';
  
+ 
+ -- ----------------------------------------------------------------------
+ -- FUNCTION GenerateListensOnSubscribe (provider, receiver)
+ --
+ --	Revises sl_listen rules when a new subscription is introduced
+ -- ----------------------------------------------------------------------
+ create or replace function @NAMESPACE at .GenerateListensOnSubscribe(int4,int4)
+ returns int
+ as '
+ declare
+ 	p_provider	alias for $1;
+ 	p_receiver	alias for $2;
+ 	v_row			record;
+ 	v_row2			record;
+ 	v_row3			record;
+ 	v_origin		int4;
+ 	v_receiver		int4;
+ 
+ begin
+ 	-- 1.  Drop out listens between this node and its parent other
+ 	--     than via it...
+ 	for v_row in select li_provider from @NAMESPACE at .sl_listen 
+ 			where li_origin = p_provider and
+ 			      li_receiver = p_provider and
+ 			      li_provider <> p_receiver
+ 	loop
+ 		perform @NAMESPACE at .droplisten(p_receiver, v_row.li_provider, p_receiver);
+ 	end loop;
+ 			
+ 	-- 2.  Add in the listener pointing this node to its parent
+ 	perform @NAMESPACE at .storelisten(p_receiver, p_receiver, p_provider);
+ 
+ 	-- 3.  Replace other listens...
+ 
+ 	for v_row in select no_id from @NAMESPACE at .sl_node
+ 	loop
+ 		v_origin := v_row.no_id;
+ 		for v_row2 in select no_id from @NAMESPACE at .sl_node
+ 			where no_id <> v_origin 
+ 		loop
+ 			v_receiver = v_row2.no_id;
+ 			if ((v_origin <> p_receiver) and (v_receiver <> p_receiver) then
+ 				-- Do nothing; no need to add entries
+ 			else
+ 				for v_row3 in select li_provider from @NAMESPACE at .sl_listen
+ 					where li_origin = v_origin and
+ 					      li_receiver = v_receiver and
+ 					      li_provider <> p_provider
+ 				loop
+ 					perform @NAMESPACE at .droplisten(v_origin,
+ 						v_row3.li_provider, v_receiver); 
+ 				end loop;
+ 				perform @NAMESPACE at .storelisten(v_origin, p_provider, v_receiver);
+ 			end if;
+ 		end loop;
+ 	end loop;
+ end;
+ ' language plpgsql;
+ 
+ comment on function @NAMESPACE at .GenerateListensOnSubscribe(int4,int4) is
+ 'GenerateListensOnSubscribe(p_provider, p_receiver)
+ 
+ Invoked by subscribeSet() and moveSet(), this revises the sl_listen
+ entries, adding in those entries required to allow communications
+ between other nodes and the receiver node that is being subscribed.';
+ 
  -- ----------------------------------------------------------------------
  -- FUNCTION tableHasSerialKey (tab_fqname)
  --

-- 
"cbbrowne","@","ca.afilias.info"
<http://dev6.int.libertyrms.com/>
Christopher Browne
(416) 673-4124 (land)


More information about the Slony1-general mailing list