Tue May 31 17:11:11 PDT 2005
- Previous message: [Slony1-commit] By cbbrowne: Darcy's addition of the "--with-docs" option must be added
- Next message: [Slony1-commit] By cbbrowne: Indicate the renaming of altperl scripts with "slonik_"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Log Message: ----------- As per discussion on list, rename scripts to a "Hungarian style" notation where the scripts that generate slonik are prefixed with "slonik_". Modified Files: -------------- slony1-engine/tools/altperl: README (r1.12 -> r1.13) ToDo (r1.3 -> r1.4) Added Files: ----------- slony1-engine/tools/altperl: slonik_build_env.pl (r1.1) slonik_create_set.pl (r1.1) slonik_drop_node.pl (r1.1) slonik_drop_set.pl (r1.1) slonik_execute_script.pl (r1.1) slonik_failover.pl (r1.1) slonik_init_cluster.pl (r1.1) slonik_merge_sets.pl (r1.1) slonik_move_set.pl (r1.1) slonik_restart_node.pl (r1.1) slonik_store_node.pl (r1.1) slonik_subscribe_set.pl (r1.1) slonik_uninstall_nodes.pl (r1.1) slonik_unsubscribe_set.pl (r1.1) slonik_update_nodes.pl (r1.1) slony_show_configuration.pl (r1.1) Removed Files: ------------- slony1-engine/tools/altperl: build_env.pl create_set.pl drop_node.pl drop_set.pl execute_script.pl failover.pl init_cluster.pl merge_sets.pl move_set.pl restart_node.pl store_node.pl subscribe_set.pl uninstall_nodes.pl unsubscribe_set.pl update_nodes.pl -------------- next part -------------- --- /dev/null +++ tools/altperl/slonik_update_nodes.pl @@ -0,0 +1,37 @@ +#!@@PERL@@ +# $Id: slonik_update_nodes.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: update_nodes [--config file] + + Updates the functions on all nodes. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +open(SLONIK, ">", "/tmp/update_nodes.$$"); +print SLONIK genheader(); +foreach my $node (@NODES) { + print SLONIK " update functions (id = $node);\n"; +}; +close SLONIK; +run_slonik_script("/tmp/update_nodes.$$"); --- /dev/null +++ tools/altperl/slonik_subscribe_set.pl @@ -0,0 +1,75 @@ +#!@@PERL@@ +# $Id: slonik_subscribe_set.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: subscribe_set [--config file] set# node# + + Begins replicating a set to the specified node. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my ($set, $node) = @ARGV; +if ($node =~ /^(?:node)?(\d+)$/) { + $node = $1; +} else { + print "Need to specify node!\n"; + die $USAGE; +} + +if ($set =~ /^(?:set)?(\d+)$/) { + $set = $1; +} else { + print "Need to specify set!\n"; + die $USAGE; +} + +get_set($set) or die "Non-existent set specified.\n"; + +$FILE="/tmp/slonik-subscribe.$$"; +open(SLONIK, ">$FILE"); +print SLONIK genheader(); +print SLONIK " try {\n"; + +if ($DSN[$node]) { + my $provider = $SET_ORIGIN; + my $forward; + if ($PARENT[$node]) { + $provider = $PARENT[$node]; + } + if ($NOFORWARD[$node] eq "yes") { + $forward = "no"; + } else { + $forward = "yes"; + } + print SLONIK " subscribe set (id = $set, provider = $provider, receiver = $node, forward = $forward);\n"; +} else { + die "Node $node not found\n"; +} + +print SLONIK " }\n"; +print SLONIK " on error {\n"; +print SLONIK " exit 1;\n"; +print SLONIK " }\n"; +print SLONIK " echo 'Subscribed nodes to set $set';\n"; +close SLONIK; +run_slonik_script($FILE); --- tools/altperl/create_set.pl +++ /dev/null @@ -1,126 +0,0 @@ -#!@@PERL@@ -# $Id: create_set.pl,v 1.15 2005/02/23 20:30:51 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: create_set [--config file] set - - set The name or ID of the set to be created - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my ($set) = @ARGV; -$SET_ID = get_set($set); -unless ($SET_ID) { - die $USAGE; -} - -$FILE="/tmp/add_tables.$$"; -open (SLONIK, ">", $FILE); -print SLONIK genheader(); - -# Tables without primary keys -print SLONIK "\n"; -print SLONIK "# TABLE ADD KEY\n"; -foreach my $table (@SERIALTABLES) { - $table = ensure_namespace($table); - print SLONIK " echo ' Adding unique key to table $table...';\n"; - print SLONIK " table add key (\n"; - print SLONIK " node id = $SET_ORIGIN,\n"; - print SLONIK " full qualified name='$table'\n"; - print SLONIK " );\n"; -} - -# CREATE SET -print SLONIK "\n"; -print SLONIK "# CREATE SET\n"; -print SLONIK " try {\n"; -print SLONIK " create set (id = $SET_ID, origin = $SET_ORIGIN, comment = 'Set $SET_ID for $CLUSTER_NAME');\n"; -print SLONIK " } on error {\n"; -print SLONIK " echo 'Could not create subscription set $SET_ID for $CLUSTER_NAME!';\n"; -print SLONIK " exit -1;\n"; -print SLONIK " }\n"; - -# SET ADD TABLE -print SLONIK "\n"; -print SLONIK "# SET ADD TABLE\n"; -print SLONIK " echo 'Subscription set $SET_ID created';\n"; -print SLONIK " echo 'Adding tables to the subscription set';\n"; - -$TABLE_ID = 1 if $TABLE_ID < 1; - -foreach my $table (@SERIALTABLES) { - $table = ensure_namespace($table); - print SLONIK " set add table (set id = $SET_ID, origin = $SET_ORIGIN, id = $TABLE_ID,\n"; - print SLONIK " full qualified name = '$table', key=serial,\n"; - print SLONIK " comment = 'Table $table without primary key');\n"; - print SLONIK " echo 'Add unkeyed table $table';\n"; - $TABLE_ID++; -} - -foreach my $table (@PKEYEDTABLES) { - $table = ensure_namespace($table); - print SLONIK " set add table (set id = $SET_ID, origin = $SET_ORIGIN, id = $TABLE_ID,\n"; - print SLONIK " full qualified name = '$table',\n"; - print SLONIK " comment = 'Table $table with primary key');\n"; - print SLONIK " echo 'Add primary keyed table $table';\n"; - $TABLE_ID++; -} - -foreach my $table (keys %KEYEDTABLES) { - my $key = $KEYEDTABLES{$table}; - $table = ensure_namespace($table); - print SLONIK " set add table (set id = $SET_ID, origin = $SET_ORIGIN, id = $TABLE_ID,\n"; - print SLONIK " full qualified name = '$table', key='$key'\n"; - print SLONIK " comment = 'Table $table with candidate primary key $key');\n"; - print SLONIK " echo 'Add candidate primary keyed table $table';\n"; - $TABLE_ID++; -} - -# SET ADD SEQUENCE -print SLONIK "\n"; -print SLONIK "# SET ADD SEQUENCE\n"; -print SLONIK " echo 'Adding sequences to the subscription set';\n"; - -$SEQUENCE_ID = 1 if $SEQUENCE_ID < 1; -foreach my $seq (@SEQUENCES) { - $seq = ensure_namespace($seq); - print SLONIK " set add sequence (set id = $SET_ID, origin = $SET_ORIGIN, id = $SEQUENCE_ID,\n"; - print SLONIK " full qualified name = '$seq',\n"; - print SLONIK " comment = 'Sequence $seq');\n"; - print SLONIK " echo 'Add sequence $seq';\n"; - $SEQUENCE_ID++; -} -print SLONIK " echo 'All tables added';\n"; - -close SLONIK; -run_slonik_script($FILE); - -### If object hasn't a namespace specified, assume it's in "public", and make it so... -sub ensure_namespace { - my ($object) = @_; - if ($object =~ /^(.*\..*)$/) { - # Table has a namespace specified - } else { - $object = "public.$object"; - } - return $object; -} --- tools/altperl/subscribe_set.pl +++ /dev/null @@ -1,75 +0,0 @@ -#!@@PERL@@ -# $Id: subscribe_set.pl,v 1.10 2005/02/23 20:30:51 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: subscribe_set [--config file] set# node# - - Begins replicating a set to the specified node. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my ($set, $node) = @ARGV; -if ($node =~ /^(?:node)?(\d+)$/) { - $node = $1; -} else { - print "Need to specify node!\n"; - die $USAGE; -} - -if ($set =~ /^(?:set)?(\d+)$/) { - $set = $1; -} else { - print "Need to specify set!\n"; - die $USAGE; -} - -get_set($set) or die "Non-existent set specified.\n"; - -$FILE="/tmp/slonik-subscribe.$$"; -open(SLONIK, ">$FILE"); -print SLONIK genheader(); -print SLONIK " try {\n"; - -if ($DSN[$node]) { - my $provider = $SET_ORIGIN; - my $forward; - if ($PARENT[$node]) { - $provider = $PARENT[$node]; - } - if ($NOFORWARD[$node] eq "yes") { - $forward = "no"; - } else { - $forward = "yes"; - } - print SLONIK " subscribe set (id = $set, provider = $provider, receiver = $node, forward = $forward);\n"; -} else { - die "Node $node not found\n"; -} - -print SLONIK " }\n"; -print SLONIK " on error {\n"; -print SLONIK " exit 1;\n"; -print SLONIK " }\n"; -print SLONIK " echo 'Subscribed nodes to set $set';\n"; -close SLONIK; -run_slonik_script($FILE); --- tools/altperl/init_cluster.pl +++ /dev/null @@ -1,228 +0,0 @@ -#!@@PERL@@ -# $Id: init_cluster.pl,v 1.12 2005/02/23 20:30:51 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -my $CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -my $SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: init_cluster [--config file] - - Generates the slonik commands necessary to create a cluster and - prepare the nodes for use. Also displays a report showing the - relationships between the various nodes. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my $FILE="/tmp/init-cluster.$$"; - -# INIT CLUSTER -open(SLONIK, ">", $FILE); -print SLONIK "\n# INIT CLUSTER\n"; -print SLONIK genheader(); -my ($dbname, $dbhost) = ($DBNAME[$MASTERNODE], $HOST[$MASTERNODE]); -print SLONIK " init cluster (id = $MASTERNODE, comment = 'Node $MASTERNODE - $dbname\@$dbhost');\n"; - -# STORE NODE -print SLONIK "\n# STORE NODE\n"; -foreach my $node (@NODES) { - if ($node != $MASTERNODE) { # skip the master node; it's already initialized! - my ($dbname, $dbhost) = ($DBNAME[$node], $HOST[$node]); - print SLONIK " store node (id = $node, event node = $MASTERNODE, comment = 'Node $node - $dbname\@$dbhost');\n"; - } -} -print SLONIK " echo 'Set up replication nodes';\n"; - -# STORE PATH -print SLONIK "\n# STORE PATH\n"; - -my @COST; -my @VIA; -my @PATH; -generate_listen_paths(); - -print SLONIK " echo 'Next: configure paths for each node/origin';\n"; -foreach my $nodea (@NODES) { - my $dsna = $DSN[$nodea]; - foreach my $nodeb (@NODES) { - if ($nodea != $nodeb) { - my $dsnb = $DSN[$nodeb]; - my $providerba = $VIA[$nodea][$nodeb]; - my $providerab = $VIA[$nodeb][$nodea]; - if (!$printed[$nodea][$nodeb] and $providerab == $nodea) { - print SLONIK " store path (server = $nodea, client = $nodeb, conninfo = '$dsna');\n"; - $printed[$nodea][$nodeb] = "done"; - } - if (!$printed[$nodeb][$nodea] and $providerba == $nodea) { - print SLONIK " store path (server = $nodeb, client = $nodea, conninfo = '$dsnb');\n"; - $printed[$nodeb][$nodea] = "done"; - } - } - } -} - -# STORE LISTEN -print SLONIK "\n# STORE LISTEN\n"; -foreach my $origin (@NODES) { - my $dsna = $DSN[$origin]; - foreach my $receiver (@NODES) { - if ($origin != $receiver) { - my $provider = $VIA[$origin][$receiver]; - print SLONIK " store listen (origin = $origin, receiver = $receiver, provider = $provider);\n"; - } - } -} -print SLONIK " echo 'Replication nodes prepared';\n"; -print SLONIK " echo 'Please start a slon replication daemon for each node';\n"; -close SLONIK; -run_slonik_script($FILE); -report_on_paths(); - -sub generate_listen_paths { - my $infinity = 10000000; # Initial costs are all infinite - foreach my $node1 (@NODES) { - foreach my $node2 (@NODES) { - $COST[$node1][$node2] = $infinity; - } - } - - # Initialize paths between parents and children, and based on them, - # generate initial seeding of listener paths, @VIA - - foreach my $node1 (@NODES) { - $COST[$node1][$node1] = 0; - $VIA[$node1][$node1] = 0; - foreach my $node2 (@NODES) { - if ($node2 != $node1) { - if ((not ($PARENT[$node1] or $PARENT[$node2])) or - ($PARENT[$node1] and $PARENT[$node1] == $node2) or - ($PARENT[$node2] and $PARENT[$node2] == $node1)) { - $PATH[$node1][$node2] = 1; - $PATH[$node2][$node1] = 1; - # Set up a cost 1 path between them - # Parent to child - $COST[$node1][$node2] = 1; - $VIA[$node1][$node2] = $node1; - - # Child to parent - $COST[$node2][$node1] = 1; - $VIA[$node2][$node1] = $node2; - } - } - } - } - - # Now, update the listener paths... - # 4 level nested iteration: - # 1 while not done, do - # 2 for each node, node1 - # 3 for each node, node2, where node2 <> node1, where we don't - # yet have a listener path - # 4 for each node node3 (<> node1 or node2), - # consider introducing the listener path: - # node1 to node2 then node2 to node3 - # In concept, it's an O(n^4) algorithm; since the number of nodes, n, - # is not likely to get particularly large, it's not worth tuning - # further. - $didwork = "yes"; - while ($didwork eq "yes") { - $didwork = "no"; - foreach my $node1 (@NODES) { - foreach my $node3 (@NODES) { - if (($VIA[$node3][$node1] == 0) && ($node3 != $node1)) { - foreach my $node2 (@NODES) { - if ($PATH[$node1][$node2] && ($VIA[$node2][$node3] != 0) && ($node2 != $node3) && ($node2 != $node1)) { - # Consider introducing a path from n1 to n2 then n2 to n3 - # as a cheaper alternative to going direct from n1 to n3 - my $oldcost = $COST[$node3][$node1]; - my $newcost = $COST[$node1][$node2] + $COST[$node2][$node3]; - if ($newcost < $oldcost) { - $didwork = "yes"; - # So we go via node 2 - $VIA[$node3][$node1] = $node2; - $COST[$node3][$node1] = $newcost; - - $VIA[$node1][$node3] = $node2; - $COST[$node1][$node3] = $newcost; - } - } - } - } - } - } - } -} - -sub report_on_paths { - print "# Configuration Summary:\n"; - print "#\n"; - print "# COST\n"; - print "# "; - foreach my $node2 (@NODES) { - printf "| %3d ", $node2; - } - print "|\n# "; - print ("-----+" x (scalar(@NODES) + 1)); - print "\n"; - foreach my $node1 (@NODES) { - printf "# %3d ", $node1; - foreach my $node2 (@NODES) { - if ($COST[$node2][$node1] == $infinity) { - printf "| inf "; - } else { - printf "|%4d ", $COST[$node2][$node1]; - } - } - print "|\n"; - } - print "# \n"; - print "# VIA\n"; - print "# "; - foreach my $node2 (@NODES) { - printf "| %3d ", $node2; - } - print "|\n# "; - print ("-----+" x (scalar(@NODES) + 1)); - print "\n"; - foreach my $node1 (@NODES) { - printf "# %3d ", $node1; - foreach my $node2 (@NODES) { - printf "|%4d ", $VIA[$node2][$node1]; - } - print "|\n"; - } - - print "# \n"; - print "# PATHS\n"; - print "# "; - foreach my $node2 (@NODES) { - printf "| %3d ", $node2; - } - print "|\n# "; - print ("-----+" x (scalar(@NODES) + 1)); - print "\n"; - foreach my $node1 (@NODES) { - printf "# %3d ", $node1; - foreach my $node2 (@NODES) { - printf "|%4d ", $PATH[$node2][$node1]; - } - print "|\n"; - } - print "\n"; -} --- /dev/null +++ tools/altperl/slonik_create_set.pl @@ -0,0 +1,126 @@ +#!@@PERL@@ +# $Id: slonik_create_set.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: create_set [--config file] set + + set The name or ID of the set to be created + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my ($set) = @ARGV; +$SET_ID = get_set($set); +unless ($SET_ID) { + die $USAGE; +} + +$FILE="/tmp/add_tables.$$"; +open (SLONIK, ">", $FILE); +print SLONIK genheader(); + +# Tables without primary keys +print SLONIK "\n"; +print SLONIK "# TABLE ADD KEY\n"; +foreach my $table (@SERIALTABLES) { + $table = ensure_namespace($table); + print SLONIK " echo ' Adding unique key to table $table...';\n"; + print SLONIK " table add key (\n"; + print SLONIK " node id = $SET_ORIGIN,\n"; + print SLONIK " full qualified name='$table'\n"; + print SLONIK " );\n"; +} + +# CREATE SET +print SLONIK "\n"; +print SLONIK "# CREATE SET\n"; +print SLONIK " try {\n"; +print SLONIK " create set (id = $SET_ID, origin = $SET_ORIGIN, comment = 'Set $SET_ID for $CLUSTER_NAME');\n"; +print SLONIK " } on error {\n"; +print SLONIK " echo 'Could not create subscription set $SET_ID for $CLUSTER_NAME!';\n"; +print SLONIK " exit -1;\n"; +print SLONIK " }\n"; + +# SET ADD TABLE +print SLONIK "\n"; +print SLONIK "# SET ADD TABLE\n"; +print SLONIK " echo 'Subscription set $SET_ID created';\n"; +print SLONIK " echo 'Adding tables to the subscription set';\n"; + +$TABLE_ID = 1 if $TABLE_ID < 1; + +foreach my $table (@SERIALTABLES) { + $table = ensure_namespace($table); + print SLONIK " set add table (set id = $SET_ID, origin = $SET_ORIGIN, id = $TABLE_ID,\n"; + print SLONIK " full qualified name = '$table', key=serial,\n"; + print SLONIK " comment = 'Table $table without primary key');\n"; + print SLONIK " echo 'Add unkeyed table $table';\n"; + $TABLE_ID++; +} + +foreach my $table (@PKEYEDTABLES) { + $table = ensure_namespace($table); + print SLONIK " set add table (set id = $SET_ID, origin = $SET_ORIGIN, id = $TABLE_ID,\n"; + print SLONIK " full qualified name = '$table',\n"; + print SLONIK " comment = 'Table $table with primary key');\n"; + print SLONIK " echo 'Add primary keyed table $table';\n"; + $TABLE_ID++; +} + +foreach my $table (keys %KEYEDTABLES) { + my $key = $KEYEDTABLES{$table}; + $table = ensure_namespace($table); + print SLONIK " set add table (set id = $SET_ID, origin = $SET_ORIGIN, id = $TABLE_ID,\n"; + print SLONIK " full qualified name = '$table', key='$key'\n"; + print SLONIK " comment = 'Table $table with candidate primary key $key');\n"; + print SLONIK " echo 'Add candidate primary keyed table $table';\n"; + $TABLE_ID++; +} + +# SET ADD SEQUENCE +print SLONIK "\n"; +print SLONIK "# SET ADD SEQUENCE\n"; +print SLONIK " echo 'Adding sequences to the subscription set';\n"; + +$SEQUENCE_ID = 1 if $SEQUENCE_ID < 1; +foreach my $seq (@SEQUENCES) { + $seq = ensure_namespace($seq); + print SLONIK " set add sequence (set id = $SET_ID, origin = $SET_ORIGIN, id = $SEQUENCE_ID,\n"; + print SLONIK " full qualified name = '$seq',\n"; + print SLONIK " comment = 'Sequence $seq');\n"; + print SLONIK " echo 'Add sequence $seq';\n"; + $SEQUENCE_ID++; +} +print SLONIK " echo 'All tables added';\n"; + +close SLONIK; +run_slonik_script($FILE); + +### If object hasn't a namespace specified, assume it's in "public", and make it so... +sub ensure_namespace { + my ($object) = @_; + if ($object =~ /^(.*\..*)$/) { + # Table has a namespace specified + } else { + $object = "public.$object"; + } + return $object; +} --- /dev/null +++ tools/altperl/slonik_drop_node.pl @@ -0,0 +1,49 @@ +#!@@PERL@@ +# $Id: slonik_drop_node.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: drop_node [--config file] node# + + Drops a node. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my ($node) = @ARGV; +if ($node =~ /^(?:node)?(\d+)$/) { + $node = $1; +} else { + die $USAGE; +} + +my $FILE="/tmp/slonik-drop.$$"; +open(SLONIK, ">", $FILE); +print SLONIK genheader(); +print SLONIK " try {\n"; +print SLONIK " drop node (id = $node, event node = $MASTERNODE);\n"; +print SLONIK " } on error {\n"; +print SLONIK " echo 'Failed to drop node $node from cluster';\n"; +print SLONIK " exit 1;\n"; +print SLONIK " }\n"; +print SLONIK " echo 'dropped node $node cluster';\n"; +close SLONIK; +run_slonik_script($FILE); --- tools/altperl/store_node.pl +++ /dev/null @@ -1,233 +0,0 @@ -#!@@PERL@@ -# $Id: store_node.pl,v 1.1 2005/03/10 18:03:10 smsimms Exp $ -# Author: Steve Simms -# Copyright 2005 PostgreSQL Global Development Group - -use Getopt::Long; - -# Defaults -my $CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -my $SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: store_node [--config file] node# - - Generates the slonik commands necessary to add a node to a - cluster. Also displays a report showing the relationships between - the various nodes. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -$node = $ARGV[0]; - -# Node can be passed either as "node1" or just "1" -if ($node =~ /^(?:node)?(\d+)$/) { - $node = $1; -} else { - die $USAGE; -} - -my $FILE="/tmp/store_node.$$"; - -open(SLONIK, ">", $FILE); -print SLONIK genheader(); - -# STORE NODE -print SLONIK "\n# STORE NODE\n"; -my ($dbname, $dbhost) = ($DBNAME[$node], $HOST[$node]); -print SLONIK " store node (id = $node, event node = $MASTERNODE, comment = 'Node $node - $dbname\@$dbhost');\n"; -print SLONIK " echo 'Set up replication nodes';\n"; - -# STORE PATH -print SLONIK "\n# STORE PATH\n"; - -my @COST; -my @VIA; -my @PATH; -generate_listen_paths(); - -print SLONIK " echo 'Next: configure paths for each node/origin';\n"; -foreach my $nodea (@NODES) { - my $dsna = $DSN[$nodea]; - foreach my $nodeb (@NODES) { - if ($nodea != $nodeb) { - next unless ($node == $nodea or $node == $nodeb); - my $dsnb = $DSN[$nodeb]; - my $providerba = $VIA[$nodea][$nodeb]; - my $providerab = $VIA[$nodeb][$nodea]; - if (!$printed[$nodea][$nodeb] and $providerab == $nodea) { - print SLONIK " store path (server = $nodea, client = $nodeb, conninfo = '$dsna');\n"; - $printed[$nodea][$nodeb] = "done"; - } - if (!$printed[$nodeb][$nodea] and $providerba == $nodea) { - print SLONIK " store path (server = $nodeb, client = $nodea, conninfo = '$dsnb');\n"; - $printed[$nodeb][$nodea] = "done"; - } - } - } -} - -# STORE LISTEN -print SLONIK "\n# STORE LISTEN\n"; -foreach my $origin (@NODES) { - my $dsna = $DSN[$origin]; - foreach my $receiver (@NODES) { - if ($origin != $receiver) { - my $provider = $VIA[$origin][$receiver]; - next unless ($node == $origin or - $node == $receiver or - $node == $provider); - print SLONIK " store listen (origin = $origin, receiver = $receiver, provider = $provider);\n"; - } - } -} -print SLONIK " echo 'Replication nodes prepared';\n"; -print SLONIK " echo 'Please start a slon replication daemon for each node';\n"; -close SLONIK; -run_slonik_script($FILE); -report_on_paths(); - -sub generate_listen_paths { - my $infinity = 10000000; # Initial costs are all infinite - foreach my $node1 (@NODES) { - foreach my $node2 (@NODES) { - $COST[$node1][$node2] = $infinity; - } - } - - # Initialize paths between parents and children, and based on them, - # generate initial seeding of listener paths, @VIA - - foreach my $node1 (@NODES) { - $COST[$node1][$node1] = 0; - $VIA[$node1][$node1] = 0; - foreach my $node2 (@NODES) { - if ($node2 != $node1) { - if ((not ($PARENT[$node1] or $PARENT[$node2])) or - ($PARENT[$node1] and $PARENT[$node1] == $node2) or - ($PARENT[$node2] and $PARENT[$node2] == $node1)) { - $PATH[$node1][$node2] = 1; - $PATH[$node2][$node1] = 1; - # Set up a cost 1 path between them - # Parent to child - $COST[$node1][$node2] = 1; - $VIA[$node1][$node2] = $node1; - - # Child to parent - $COST[$node2][$node1] = 1; - $VIA[$node2][$node1] = $node2; - } - } - } - } - - # Now, update the listener paths... - # 4 level nested iteration: - # 1 while not done, do - # 2 for each node, node1 - # 3 for each node, node2, where node2 <> node1, where we don't - # yet have a listener path - # 4 for each node node3 (<> node1 or node2), - # consider introducing the listener path: - # node1 to node2 then node2 to node3 - # In concept, it's an O(n^4) algorithm; since the number of nodes, n, - # is not likely to get particularly large, it's not worth tuning - # further. - $didwork = "yes"; - while ($didwork eq "yes") { - $didwork = "no"; - foreach my $node1 (@NODES) { - foreach my $node3 (@NODES) { - if (($VIA[$node3][$node1] == 0) && ($node3 != $node1)) { - foreach my $node2 (@NODES) { - if ($PATH[$node1][$node2] && ($VIA[$node2][$node3] != 0) && ($node2 != $node3) && ($node2 != $node1)) { - # Consider introducing a path from n1 to n2 then n2 to n3 - # as a cheaper alternative to going direct from n1 to n3 - my $oldcost = $COST[$node3][$node1]; - my $newcost = $COST[$node1][$node2] + $COST[$node2][$node3]; - if ($newcost < $oldcost) { - $didwork = "yes"; - # So we go via node 2 - $VIA[$node3][$node1] = $node2; - $COST[$node3][$node1] = $newcost; - - $VIA[$node1][$node3] = $node2; - $COST[$node1][$node3] = $newcost; - } - } - } - } - } - } - } -} - -sub report_on_paths { - print "# Configuration Summary:\n"; - print "#\n"; - print "# COST\n"; - print "# "; - foreach my $node2 (@NODES) { - printf "| %3d ", $node2; - } - print "|\n# "; - print ("-----+" x (scalar(@NODES) + 1)); - print "\n"; - foreach my $node1 (@NODES) { - printf "# %3d ", $node1; - foreach my $node2 (@NODES) { - if ($COST[$node2][$node1] == $infinity) { - printf "| inf "; - } else { - printf "|%4d ", $COST[$node2][$node1]; - } - } - print "|\n"; - } - print "# \n"; - print "# VIA\n"; - print "# "; - foreach my $node2 (@NODES) { - printf "| %3d ", $node2; - } - print "|\n# "; - print ("-----+" x (scalar(@NODES) + 1)); - print "\n"; - foreach my $node1 (@NODES) { - printf "# %3d ", $node1; - foreach my $node2 (@NODES) { - printf "|%4d ", $VIA[$node2][$node1]; - } - print "|\n"; - } - - print "# \n"; - print "# PATHS\n"; - print "# "; - foreach my $node2 (@NODES) { - printf "| %3d ", $node2; - } - print "|\n# "; - print ("-----+" x (scalar(@NODES) + 1)); - print "\n"; - foreach my $node1 (@NODES) { - printf "# %3d ", $node1; - foreach my $node2 (@NODES) { - printf "|%4d ", $PATH[$node2][$node1]; - } - print "|\n"; - } - print "\n"; -} --- tools/altperl/drop_node.pl +++ /dev/null @@ -1,49 +0,0 @@ -#!@@PERL@@ -# $Id: drop_node.pl,v 1.9 2005/02/22 16:51:09 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: drop_node [--config file] node# - - Drops a node. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my ($node) = @ARGV; -if ($node =~ /^(?:node)?(\d+)$/) { - $node = $1; -} else { - die $USAGE; -} - -my $FILE="/tmp/slonik-drop.$$"; -open(SLONIK, ">", $FILE); -print SLONIK genheader(); -print SLONIK " try {\n"; -print SLONIK " drop node (id = $node, event node = $MASTERNODE);\n"; -print SLONIK " } on error {\n"; -print SLONIK " echo 'Failed to drop node $node from cluster';\n"; -print SLONIK " exit 1;\n"; -print SLONIK " }\n"; -print SLONIK " echo 'dropped node $node cluster';\n"; -close SLONIK; -run_slonik_script($FILE); --- tools/altperl/move_set.pl +++ /dev/null @@ -1,64 +0,0 @@ -#!@@PERL@@ -# $Id: move_set.pl,v 1.10 2005/05/19 18:14:45 cbbrowne Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: move_set [--config file] set# from_node# to_node# - - Change a set's origin. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my ($set, $node1, $node2) = @ARGV; -if ($set =~ /^(?:set)?(\d+)$/) { - # Node name is in proper form - $set = $1; -} else { - print "Valid set names are set1, set2, ...\n\n"; - die $USAGE; -} - -if ($node1 =~ /^(?:node)?(\d+)$/) { - $node1 = $1; -} else { - print "Valid node names are node1, node2, ...\n\n"; - die $USAGE; -} - -if ($node2 =~ /^(?:node)?(\d+)$/) { - $node2 = $1; -} else { - print "Valid node names are node1, node2, ...\n\n"; - die $USAGE; -} - -open(SLONIK, ">", "/tmp/slonik.$$"); -print SLONIK genheader(); -print SLONIK " echo 'Locking down set $set on node $node1';\n"; -print SLONIK " lock set (id = $set, origin = $node1);\n"; -print SLONIK " echo 'Locked down - moving it';\n"; -print SLONIK " move set (id = $set, old origin = $node1, new origin = $node2);\n"; -print SLONIK " echo 'Replication set $set moved from node $node1 to $node2. Remember to';\n"; -print SLONIK " echo 'update your configuration file, if necessary, to note the new location';\n"; -print SLONIK " echo 'for the set.';\n"; -close SLONIK; -run_slonik_script("/tmp/slonik.$$"); --- /dev/null +++ tools/altperl/slonik_build_env.pl @@ -0,0 +1,108 @@ +#!@@PERL@@ +# $Id: slonik_build_env.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Contributed by: +# Joe Kalash +# kalash at savicom.net + +# This script, given parameters concerning the database nodes, +# generates output for "slon_tools.conf" consisting of: +# - A set of add_node() calls to configure the cluster +# - The arrays @KEYEDTABLES, @SERIALTABLES, and @SEQUENCES + +use DBI; +use Getopt::Long; +use strict; + +my $dataBase; +my $host; +my $dataBaseUser; +my $dataBasePassword; +my $dataBasePort; +my @nodes; +my $usage = "$0 -node host:database:user[:password:port] [-node ...] +First node is assumed to be the master.\n"; + +&usage if(!GetOptions('node=s@'=>\@nodes)); + +die "At least one node is required" if ( scalar(@nodes) < 1 ); + +my $nodeNumber = 1; +my $parentString; +foreach my $node (@nodes) +{ + my($tmpHost,$tmpDataBase,$tmpDataBaseUser,$tmpDataBasePassword,$tmpPort) = + split(/:/,$node); + die "Host is required" if ( !$tmpHost ); + die "database is required" if ( !$tmpDataBase ); + die "user is required" if ( !$tmpDataBaseUser ); + $tmpPort = 5432 if ( !$tmpPort ); + $host = $tmpHost if ( !$host ); + $dataBase = $tmpDataBase if ( !$dataBase ); + if ( !$dataBaseUser ) { + $dataBaseUser = $tmpDataBaseUser; + $dataBasePassword = $tmpDataBasePassword if ( $tmpDataBasePassword ); + $dataBasePort = $tmpPort if ( $tmpPort ); + } + print "&add_node(host => '$tmpHost', dbname => '$tmpDataBase', port =>$tmpPort, + user=>'$tmpDataBaseUser', password=>'$tmpDataBasePassword', node=>$nodeNumber $parentString);\n"; + $parentString = ', parent=>1'; + $nodeNumber++; + +} +my $connectString = "dbi:Pg:dbname=$dataBase;host=$host;port=$dataBasePort"; +my $dbh = DBI->connect($connectString,$dataBaseUser,$dataBasePassword, + {RaiseError => 0, PrintError => 0, AutoCommit => 1}); +die "connect: $DBI::errstr" if ( !defined($dbh) || $DBI::err ); +# Read in all the user 'normal' tables in public. +my $tableQuery = $dbh->prepare(" +SELECT pg_namespace.nspname || '.' || pg_class.relname,pg_class.relkind,pg_class.relhaspkey +FROM pg_namespace,pg_class +WHERE pg_class.reltype > 0 +AND pg_class.relnamespace = pg_catalog.pg_namespace.oid +AND (pg_class.relkind = 'r' OR pg_class.relkind = 'S') +AND pg_namespace.nspname = 'public' AND pg_namespace.oid = pg_class.relnamespace"); + +die "prepare(tableQuery): $DBI::errstr" if ( !defined($tableQuery) || $DBI::err ); +die "execute(tableQuery): $DBI::errstr" if ( !$tableQuery->execute() ); + +my @tablesWithIndexes; +my @tablesWithoutIndexes; +my @sequences; +while ( my $row = $tableQuery->fetchrow_arrayref() ) { + my $relname = @$row[0]; + my $relkind = @$row[1]; + my $relhaspkey = @$row[2]; + push(@sequences,$relname) if ( $relkind eq 'S' ); + push(@tablesWithIndexes,$relname) if ( $relkind eq 'r' && $relhaspkey == 1 ); + push(@tablesWithoutIndexes,$relname) if ( $relkind eq 'r' && $relhaspkey == 0 ); +} +$tableQuery->finish(); +$dbh->disconnect(); + +if ( scalar(@tablesWithIndexes) > 1 ) { + print '@KEYEDTABLES=(' . "\n"; + foreach my $table (sort @tablesWithIndexes) { + print "\t\"$table\",\n"; + } + print ");\n"; +} +if ( scalar(@tablesWithoutIndexes) > 1 ) { + print '@SERIALTABLES=(' . "\n"; + foreach my $table (sort @tablesWithoutIndexes) { + print "\t\"$table\",\n"; + } + print ");\n"; +} +if ( scalar(@sequences) > 1 ) { + print '@SEQUENCES=(' . "\n"; + foreach my $table (sort @sequences) { + print "\t\"$table\",\n"; + } + print ");\n"; +} +exit 0; + +sub usage { + print "$usage"; + exit 0; +} --- /dev/null +++ tools/altperl/slonik_uninstall_nodes.pl @@ -0,0 +1,40 @@ +#!@@PERL@@ +# $Id: slonik_uninstall_nodes.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: uninstall_nodes [--config file] + + Removes Slony configuration from all nodes in a cluster. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +$FILE="/tmp/slonik.$$"; +open(SLONIK, ">$FILE"); +print SLONIK genheader(); +foreach my $node (@NODES) { + next if $node == $MASTERNODE; # Do this one last + print SLONIK " uninstall node (id=$node);\n"; +} +print SLONIK " uninstall node (id=$MASTERNODE);\n"; +close SLONIK; +run_slonik_script($FILE); --- tools/altperl/build_env.pl +++ /dev/null @@ -1,108 +0,0 @@ -#!@@PERL@@ -# $Id: build_env.pl,v 1.8 2005/02/10 06:22:41 smsimms Exp $ -# Contributed by: -# Joe Kalash -# kalash at savicom.net - -# This script, given parameters concerning the database nodes, -# generates output for "slon_tools.conf" consisting of: -# - A set of add_node() calls to configure the cluster -# - The arrays @KEYEDTABLES, @SERIALTABLES, and @SEQUENCES - -use DBI; -use Getopt::Long; -use strict; - -my $dataBase; -my $host; -my $dataBaseUser; -my $dataBasePassword; -my $dataBasePort; -my @nodes; -my $usage = "$0 -node host:database:user[:password:port] [-node ...] -First node is assumed to be the master.\n"; - -&usage if(!GetOptions('node=s@'=>\@nodes)); - -die "At least one node is required" if ( scalar(@nodes) < 1 ); - -my $nodeNumber = 1; -my $parentString; -foreach my $node (@nodes) -{ - my($tmpHost,$tmpDataBase,$tmpDataBaseUser,$tmpDataBasePassword,$tmpPort) = - split(/:/,$node); - die "Host is required" if ( !$tmpHost ); - die "database is required" if ( !$tmpDataBase ); - die "user is required" if ( !$tmpDataBaseUser ); - $tmpPort = 5432 if ( !$tmpPort ); - $host = $tmpHost if ( !$host ); - $dataBase = $tmpDataBase if ( !$dataBase ); - if ( !$dataBaseUser ) { - $dataBaseUser = $tmpDataBaseUser; - $dataBasePassword = $tmpDataBasePassword if ( $tmpDataBasePassword ); - $dataBasePort = $tmpPort if ( $tmpPort ); - } - print "&add_node(host => '$tmpHost', dbname => '$tmpDataBase', port =>$tmpPort, - user=>'$tmpDataBaseUser', password=>'$tmpDataBasePassword', node=>$nodeNumber $parentString);\n"; - $parentString = ', parent=>1'; - $nodeNumber++; - -} -my $connectString = "dbi:Pg:dbname=$dataBase;host=$host;port=$dataBasePort"; -my $dbh = DBI->connect($connectString,$dataBaseUser,$dataBasePassword, - {RaiseError => 0, PrintError => 0, AutoCommit => 1}); -die "connect: $DBI::errstr" if ( !defined($dbh) || $DBI::err ); -# Read in all the user 'normal' tables in public. -my $tableQuery = $dbh->prepare(" -SELECT pg_namespace.nspname || '.' || pg_class.relname,pg_class.relkind,pg_class.relhaspkey -FROM pg_namespace,pg_class -WHERE pg_class.reltype > 0 -AND pg_class.relnamespace = pg_catalog.pg_namespace.oid -AND (pg_class.relkind = 'r' OR pg_class.relkind = 'S') -AND pg_namespace.nspname = 'public' AND pg_namespace.oid = pg_class.relnamespace"); - -die "prepare(tableQuery): $DBI::errstr" if ( !defined($tableQuery) || $DBI::err ); -die "execute(tableQuery): $DBI::errstr" if ( !$tableQuery->execute() ); - -my @tablesWithIndexes; -my @tablesWithoutIndexes; -my @sequences; -while ( my $row = $tableQuery->fetchrow_arrayref() ) { - my $relname = @$row[0]; - my $relkind = @$row[1]; - my $relhaspkey = @$row[2]; - push(@sequences,$relname) if ( $relkind eq 'S' ); - push(@tablesWithIndexes,$relname) if ( $relkind eq 'r' && $relhaspkey == 1 ); - push(@tablesWithoutIndexes,$relname) if ( $relkind eq 'r' && $relhaspkey == 0 ); -} -$tableQuery->finish(); -$dbh->disconnect(); - -if ( scalar(@tablesWithIndexes) > 1 ) { - print '@KEYEDTABLES=(' . "\n"; - foreach my $table (sort @tablesWithIndexes) { - print "\t\"$table\",\n"; - } - print ");\n"; -} -if ( scalar(@tablesWithoutIndexes) > 1 ) { - print '@SERIALTABLES=(' . "\n"; - foreach my $table (sort @tablesWithoutIndexes) { - print "\t\"$table\",\n"; - } - print ");\n"; -} -if ( scalar(@sequences) > 1 ) { - print '@SEQUENCES=(' . "\n"; - foreach my $table (sort @sequences) { - print "\t\"$table\",\n"; - } - print ");\n"; -} -exit 0; - -sub usage { - print "$usage"; - exit 0; -} --- tools/altperl/update_nodes.pl +++ /dev/null @@ -1,37 +0,0 @@ -#!@@PERL@@ -# $Id: update_nodes.pl,v 1.7 2005/02/22 17:11:18 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: update_nodes [--config file] - - Updates the functions on all nodes. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -open(SLONIK, ">", "/tmp/update_nodes.$$"); -print SLONIK genheader(); -foreach my $node (@NODES) { - print SLONIK " update functions (id = $node);\n"; -}; -close SLONIK; -run_slonik_script("/tmp/update_nodes.$$"); --- /dev/null +++ tools/altperl/slonik_merge_sets.pl @@ -0,0 +1,66 @@ +#!@@PERL@@ +# $Id: slonik_merge_sets.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: merge_sets [--config file] node# set# set# + + Merges the contents of the second set into the first one. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my ($node, $set1, $set2) = @ARGV; +if ($node =~ /^(?:node)?(\d+)$/) { + # Set name is in proper form + $node = $1; +} else { + print "Valid node names are node1, node2, ...\n\n"; + die $USAGE; +} + +if ($set1 =~ /^(?:set)?(\d+)$/) { + $set1 = $1; +} else { + print "Valid set names are set1, set2, ...\n\n"; + die $USAGE; +} + +if ($set2 =~ /^(?:set)?(\d+)$/) { + $set2 = $1; +} else { + print "Valid set names are set1, set2, ...\n\n"; + die $USAGE; +} + +my ($dbname, $dbhost) = ($DBNAME[$MASTERNODE], $HOST[$MASTERNODE]); + +open(SLONIK, ">", "/tmp/slonik.$$"); +print SLONIK genheader(); +print SLONIK " try {\n"; +print SLONIK " merge set (id = $set1, add id = $set2, origin = $node);\n"; +print SLONIK " } on error {\n"; +print SLONIK " echo 'Failure to merge sets $set1 and $set2 with origin $node';\n"; +print SLONIK " exit 1;\n"; +print SLONIK " }\n"; +print SLONIK " echo 'Replication set $set2 merged in with $set1 on origin $node';\n"; +close SLONIK; +run_slonik_script("/tmp/slonik.$$"); --- /dev/null +++ tools/altperl/slony_show_configuration.pl @@ -0,0 +1,56 @@ +#!@@PERL@@ +# $Id: slony_show_configuration.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +# This script simply displays an overview of node configuration +# for a given SLONY node set + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: show_configuration [--config file] + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +print "Slony Configuration\n-------------------------------------\n"; +if ($ENV{"SLONYNODES"}) { + print "With node configuration from ", $ENV{"SLONYNODES"}, "\n"; +} +if ($ENV{"SLONYSET"}) { + print "With set configuration from ", $ENV{"SLONYSET"}, "\n"; +} + +print qq{ +Slony-I Cluster: $CLUSTER_NAME +Logs stored under $LOGDIR +Slony Binaries in: @@PGBINDIR@@ +}; +if ($APACHE_ROTATOR) { + print "Rotating logs using Apache Rotator: $APACHE_ROTATOR\n"; +} +print qq{ +Node information +-------------------------------- +}; +foreach $node (@NODES) { + printf("Node: %2d Host: %15s User: %8s Port: %4d Forwarding? %4s Parent: %2d Database: %10s\n DSN: %s\n", + $node, $HOST[$node], $USER[$node], $PORT[$node], $NOFORWARD[$node], + $PARENT[$node], $DBNAME[$node], $DSN[$node]); +} --- tools/altperl/merge_sets.pl +++ /dev/null @@ -1,66 +0,0 @@ -#!@@PERL@@ -# $Id: merge_sets.pl,v 1.9 2005/02/22 17:11:18 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: merge_sets [--config file] node# set# set# - - Merges the contents of the second set into the first one. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my ($node, $set1, $set2) = @ARGV; -if ($node =~ /^(?:node)?(\d+)$/) { - # Set name is in proper form - $node = $1; -} else { - print "Valid node names are node1, node2, ...\n\n"; - die $USAGE; -} - -if ($set1 =~ /^(?:set)?(\d+)$/) { - $set1 = $1; -} else { - print "Valid set names are set1, set2, ...\n\n"; - die $USAGE; -} - -if ($set2 =~ /^(?:set)?(\d+)$/) { - $set2 = $1; -} else { - print "Valid set names are set1, set2, ...\n\n"; - die $USAGE; -} - -my ($dbname, $dbhost) = ($DBNAME[$MASTERNODE], $HOST[$MASTERNODE]); - -open(SLONIK, ">", "/tmp/slonik.$$"); -print SLONIK genheader(); -print SLONIK " try {\n"; -print SLONIK " merge set (id = $set1, add id = $set2, origin = $node);\n"; -print SLONIK " } on error {\n"; -print SLONIK " echo 'Failure to merge sets $set1 and $set2 with origin $node';\n"; -print SLONIK " exit 1;\n"; -print SLONIK " }\n"; -print SLONIK " echo 'Replication set $set2 merged in with $set1 on origin $node';\n"; -close SLONIK; -run_slonik_script("/tmp/slonik.$$"); --- /dev/null +++ tools/altperl/slonik_drop_set.pl @@ -0,0 +1,51 @@ +#!@@PERL@@ +# $Id: slonik_drop_set.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: drop_set [--config file] set# + + Drops a set. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my ($set) = @ARGV; +if ($set =~ /^(?:set)?(\d+)$/) { + $set = $1; +} else { + print "Need set identifier\n"; + die $USAGE; +} + +get_set($set) or die "Non-existent set specified.\n"; + +$FILE = "/tmp/dropset.$$"; +open(SLONIK, ">", $FILE); +print SLONIK genheader(); +print SLONIK " try {\n"; +print SLONIK " drop set (id = $set, origin = $SET_ORIGIN);\n"; +print SLONIK " } on error {\n"; +print SLONIK " exit 1;\n"; +print SLONIK " }\n"; +print SLONIK " echo 'Dropped set $set';\n"; +close SLONIK; +run_slonik_script($FILE); --- /dev/null +++ tools/altperl/slonik_restart_node.pl @@ -0,0 +1,57 @@ +#!/usr/bin/perl +# $Id: slonik_restart_node.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; +$ALL_NODES = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE, + "all" => \$ALL_NODES); + +my $USAGE = +"Usage: restart_node [--config file] [--all] [node# ...] + + Restart one or more nodes + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my @nodes; +if ($ALL_NODES) { + @nodes = @NODES; +} +else { + foreach my $node (@ARGV) { + if ($node =~ /^(?:node)?(\d+)$/) { + push @nodes, ($1); + } + else { + die $USAGE; + } + } +} + +die $USAGE unless scalar @nodes; + +my $FILE="/tmp/restart.$$"; +open(SLONIK, ">", $FILE); +print SLONIK genheader(); +foreach my $node (@nodes) { + print SLONIK " restart node $node;\n"; +} +close SLONIK; +run_slonik_script($FILE); --- tools/altperl/drop_set.pl +++ /dev/null @@ -1,51 +0,0 @@ -#!@@PERL@@ -# $Id: drop_set.pl,v 1.10 2005/02/23 20:30:51 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: drop_set [--config file] set# - - Drops a set. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my ($set) = @ARGV; -if ($set =~ /^(?:set)?(\d+)$/) { - $set = $1; -} else { - print "Need set identifier\n"; - die $USAGE; -} - -get_set($set) or die "Non-existent set specified.\n"; - -$FILE = "/tmp/dropset.$$"; -open(SLONIK, ">", $FILE); -print SLONIK genheader(); -print SLONIK " try {\n"; -print SLONIK " drop set (id = $set, origin = $SET_ORIGIN);\n"; -print SLONIK " } on error {\n"; -print SLONIK " exit 1;\n"; -print SLONIK " }\n"; -print SLONIK " echo 'Dropped set $set';\n"; -close SLONIK; -run_slonik_script($FILE); --- /dev/null +++ tools/altperl/slonik_failover.pl @@ -0,0 +1,58 @@ +#!@@PERL@@ +# $Id: slonik_failover.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: failover [--config file] dead_node backup_node + + Abandons dead_node, making backup_node the origin for all sets on + dead_node. + + move_set should be used if dead_node is still available, so that + transactions are not lost. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my ($node1, $node2) = @ARGV; +if ($node1 =~ /^(?:node)?(\d+)$/) { + $node1 = $1; +} else { + die $USAGE; +} + +if ($node2 =~ /^(?:node)?(\d+)$/) { + $node2 = $1; +} else { + die $USAGE; +} + +open(SLONIK, ">", "/tmp/slonik.$$"); +print SLONIK genheader(); +print SLONIK " try {\n"; +print SLONIK " failover (id = $node1, backup node = $node2);\n"; +print SLONIK " } on error {\n"; +print SLONIK " echo 'Failure to fail node $node1 over to $node2';\n"; +print SLONIK " exit 1;\n"; +print SLONIK " }\n"; +print SLONIK " echo 'Replication sets originating on $node1 failed over to $node2';\n"; +close SLONIK; +run_slonik_script("/tmp/slonik.$$"); --- /dev/null +++ tools/altperl/slonik_unsubscribe_set.pl @@ -0,0 +1,57 @@ +#!@@PERL@@ +# $Id: slonik_unsubscribe_set.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: unsubscribe_set [--config file] set# node# + + Stops replicating a set on the specified node. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my ($set, $node) = @ARGV; +if ($node =~ /^(?:node)?(\d+)$/) { + $node = $1; +} else { + print "Need to specify node!\n\n"; + die $USAGE; +} + +if ($set =~ /^(?:set)?(\d+)$/) { + $set = $1; +} else { + print "Need to specify set!\n\n"; + die $USAGE; +} + +open(SLONIK, ">", "/tmp/slonik-unsubscribe.$$"); +print SLONIK genheader(); +print SLONIK " try {\n"; +print SLONIK " unsubscribe set (id = $set, receiver = $node);\n"; +print SLONIK " }\n"; +print SLONIK " on error {\n"; +print SLONIK " echo 'Failed to unsubscribe node $node from set $set';\n"; +print SLONIK " exit 1;\n"; +print SLONIK " }\n"; +print SLONIK " echo 'unsubscribed node $node from set $set';\n"; +close SLONIK; +run_slonik_script("/tmp/slonik-unsubscribe.$$"); --- tools/altperl/unsubscribe_set.pl +++ /dev/null @@ -1,57 +0,0 @@ -#!@@PERL@@ -# $Id: unsubscribe_set.pl,v 1.7 2005/02/22 16:51:10 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: unsubscribe_set [--config file] set# node# - - Stops replicating a set on the specified node. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my ($set, $node) = @ARGV; -if ($node =~ /^(?:node)?(\d+)$/) { - $node = $1; -} else { - print "Need to specify node!\n\n"; - die $USAGE; -} - -if ($set =~ /^(?:set)?(\d+)$/) { - $set = $1; -} else { - print "Need to specify set!\n\n"; - die $USAGE; -} - -open(SLONIK, ">", "/tmp/slonik-unsubscribe.$$"); -print SLONIK genheader(); -print SLONIK " try {\n"; -print SLONIK " unsubscribe set (id = $set, receiver = $node);\n"; -print SLONIK " }\n"; -print SLONIK " on error {\n"; -print SLONIK " echo 'Failed to unsubscribe node $node from set $set';\n"; -print SLONIK " exit 1;\n"; -print SLONIK " }\n"; -print SLONIK " echo 'unsubscribed node $node from set $set';\n"; -close SLONIK; -run_slonik_script("/tmp/slonik-unsubscribe.$$"); --- tools/altperl/failover.pl +++ /dev/null @@ -1,58 +0,0 @@ -#!@@PERL@@ -# $Id: failover.pl,v 1.8 2005/02/22 16:51:09 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: failover [--config file] dead_node backup_node - - Abandons dead_node, making backup_node the origin for all sets on - dead_node. - - move_set should be used if dead_node is still available, so that - transactions are not lost. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my ($node1, $node2) = @ARGV; -if ($node1 =~ /^(?:node)?(\d+)$/) { - $node1 = $1; -} else { - die $USAGE; -} - -if ($node2 =~ /^(?:node)?(\d+)$/) { - $node2 = $1; -} else { - die $USAGE; -} - -open(SLONIK, ">", "/tmp/slonik.$$"); -print SLONIK genheader(); -print SLONIK " try {\n"; -print SLONIK " failover (id = $node1, backup node = $node2);\n"; -print SLONIK " } on error {\n"; -print SLONIK " echo 'Failure to fail node $node1 over to $node2';\n"; -print SLONIK " exit 1;\n"; -print SLONIK " }\n"; -print SLONIK " echo 'Replication sets originating on $node1 failed over to $node2';\n"; -close SLONIK; -run_slonik_script("/tmp/slonik.$$"); --- tools/altperl/restart_node.pl +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/perl -# $Id: restart_node.pl,v 1.7 2005/02/22 16:51:09 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; -$ALL_NODES = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE, - "all" => \$ALL_NODES); - -my $USAGE = -"Usage: restart_node [--config file] [--all] [node# ...] - - Restart one or more nodes - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my @nodes; -if ($ALL_NODES) { - @nodes = @NODES; -} -else { - foreach my $node (@ARGV) { - if ($node =~ /^(?:node)?(\d+)$/) { - push @nodes, ($1); - } - else { - die $USAGE; - } - } -} - -die $USAGE unless scalar @nodes; - -my $FILE="/tmp/restart.$$"; -open(SLONIK, ">", $FILE); -print SLONIK genheader(); -foreach my $node (@nodes) { - print SLONIK " restart node $node;\n"; -} -close SLONIK; -run_slonik_script($FILE); Index: ToDo =================================================================== RCS file: /usr/local/cvsroot/slony1/slony1-engine/tools/altperl/ToDo,v retrieving revision 1.3 retrieving revision 1.4 diff -Ltools/altperl/ToDo -Ltools/altperl/ToDo -u -w -r1.3 -r1.4 --- tools/altperl/ToDo +++ tools/altperl/ToDo @@ -1,13 +1,17 @@ +ToDo List +---------------- +$Id$ + - Need to write a "repair_cluster.pl" script that modifies configuration to reflect new configuration, dropping and adding paths and listeners. - This would compare the configuration computed (as in init_cluster) - with the configuration actually found on some node, add "additional" - bits, and drop obsolete bits. + This would compare the configuration computed (as in + slonik_init_cluster) with the configuration actually found on some + node, add "additional" bits, and drop obsolete bits. - [Note: If drop_node and store_node are used, this may not be as - immediately necessary, but would still be nice to have.] + [Note: If slonik_drop_node and slonik_store_node are used, this may + not be as immediately necessary, but would still be nice to have.] - At present, the configuration generated by this set of tools is fairly fragile. If just about any sort of error is made, it is --- tools/altperl/execute_script.pl +++ /dev/null @@ -1,92 +0,0 @@ -#!@@PERL@@ -# $Id: execute_script.pl,v 1.2 2005/03/16 21:15:10 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; -$SCRIPT_ARG = ""; - -# Allow this to be specified. Otherwise it will be pulled from -# the get_set function. -$node = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE, - "c=s" => \$SCRIPT_ARG, - "n|node=s" => \$node); - -my $USAGE = -"Usage: - execute_script [options] set# full_path_to_sql_script_file - execute_script [options] -c SCRIPT set# - - Executes the contents of a SQL script file on the specified set. - The script only needs to exist on the machine running the slon - daemon. - - set# The set to which this script applies. - - -c SCRIPT Pass the SQL to be executed via the command line instead - of as a file. - - -n NUM - --node=NUM Override the set origin specified in the configuration - file. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -my ($set, $file) = @ARGV; -if ($set =~ /^(?:set)?(\d+)$/) { - $set = $1; -} else { - print "Invalid set identifier\n\n"; - die $USAGE; -} - -get_set($set) or die "Non-existent set specified.\n"; -$node = $SET_ORIGIN unless $node; - -# We can either have -c SCRIPT or a filename as an argument. The -# latter takes precedence. -if ($file) { - unless ($file =~ /^\// and -f $file) { - print STDERR "SQL script path needs to be a full path, e.g. /tmp/my_script.sql\n\n"; - die $USAGE; - } -} -elsif ($SCRIPT_ARG) { - # Put the script into a file - $file = "/tmp/execute_script.sql.$$"; - my $fh; - open $fh, ">", $file; - print $fh $SCRIPT_ARG; - close $fh; -} -else { - print STDERR "You must include either a filename or a SQL statement on the command line to be run.\n\n"; - die $USAGE; -} - -my $FILE="/tmp/gensql.$$"; -open(SLONIK, ">", $FILE); -print SLONIK genheader(); -print SLONIK " execute script (\n"; -print SLONIK " set id = $set,\n"; -print SLONIK " filename = '$file',\n"; -print SLONIK " event node = $node\n"; -print SLONIK " );\n"; -close SLONIK; -run_slonik_script($FILE); --- tools/altperl/uninstall_nodes.pl +++ /dev/null @@ -1,40 +0,0 @@ -#!@@PERL@@ -# $Id: uninstall_nodes.pl,v 1.8 2005/03/11 18:55:44 smsimms Exp $ -# Author: Christopher Browne -# Copyright 2004 Afilias Canada - -use Getopt::Long; - -# Defaults -$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; -$SHOW_USAGE = 0; - -# Read command-line options -GetOptions("config=s" => \$CONFIG_FILE, - "help" => \$SHOW_USAGE); - -my $USAGE = -"Usage: uninstall_nodes [--config file] - - Removes Slony configuration from all nodes in a cluster. - -"; - -if ($SHOW_USAGE) { - print $USAGE; - exit 0; -} - -require '@@PGLIBDIR@@/slon-tools.pm'; -require $CONFIG_FILE; - -$FILE="/tmp/slonik.$$"; -open(SLONIK, ">$FILE"); -print SLONIK genheader(); -foreach my $node (@NODES) { - next if $node == $MASTERNODE; # Do this one last - print SLONIK " uninstall node (id=$node);\n"; -} -print SLONIK " uninstall node (id=$MASTERNODE);\n"; -close SLONIK; -run_slonik_script($FILE); --- /dev/null +++ tools/altperl/slonik_store_node.pl @@ -0,0 +1,233 @@ +#!@@PERL@@ +# $Id: slonik_store_node.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Steve Simms +# Copyright 2005 PostgreSQL Global Development Group + +use Getopt::Long; + +# Defaults +my $CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +my $SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: store_node [--config file] node# + + Generates the slonik commands necessary to add a node to a + cluster. Also displays a report showing the relationships between + the various nodes. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +$node = $ARGV[0]; + +# Node can be passed either as "node1" or just "1" +if ($node =~ /^(?:node)?(\d+)$/) { + $node = $1; +} else { + die $USAGE; +} + +my $FILE="/tmp/store_node.$$"; + +open(SLONIK, ">", $FILE); +print SLONIK genheader(); + +# STORE NODE +print SLONIK "\n# STORE NODE\n"; +my ($dbname, $dbhost) = ($DBNAME[$node], $HOST[$node]); +print SLONIK " store node (id = $node, event node = $MASTERNODE, comment = 'Node $node - $dbname\@$dbhost');\n"; +print SLONIK " echo 'Set up replication nodes';\n"; + +# STORE PATH +print SLONIK "\n# STORE PATH\n"; + +my @COST; +my @VIA; +my @PATH; +generate_listen_paths(); + +print SLONIK " echo 'Next: configure paths for each node/origin';\n"; +foreach my $nodea (@NODES) { + my $dsna = $DSN[$nodea]; + foreach my $nodeb (@NODES) { + if ($nodea != $nodeb) { + next unless ($node == $nodea or $node == $nodeb); + my $dsnb = $DSN[$nodeb]; + my $providerba = $VIA[$nodea][$nodeb]; + my $providerab = $VIA[$nodeb][$nodea]; + if (!$printed[$nodea][$nodeb] and $providerab == $nodea) { + print SLONIK " store path (server = $nodea, client = $nodeb, conninfo = '$dsna');\n"; + $printed[$nodea][$nodeb] = "done"; + } + if (!$printed[$nodeb][$nodea] and $providerba == $nodea) { + print SLONIK " store path (server = $nodeb, client = $nodea, conninfo = '$dsnb');\n"; + $printed[$nodeb][$nodea] = "done"; + } + } + } +} + +# STORE LISTEN +print SLONIK "\n# STORE LISTEN\n"; +foreach my $origin (@NODES) { + my $dsna = $DSN[$origin]; + foreach my $receiver (@NODES) { + if ($origin != $receiver) { + my $provider = $VIA[$origin][$receiver]; + next unless ($node == $origin or + $node == $receiver or + $node == $provider); + print SLONIK " store listen (origin = $origin, receiver = $receiver, provider = $provider);\n"; + } + } +} +print SLONIK " echo 'Replication nodes prepared';\n"; +print SLONIK " echo 'Please start a slon replication daemon for each node';\n"; +close SLONIK; +run_slonik_script($FILE); +report_on_paths(); + +sub generate_listen_paths { + my $infinity = 10000000; # Initial costs are all infinite + foreach my $node1 (@NODES) { + foreach my $node2 (@NODES) { + $COST[$node1][$node2] = $infinity; + } + } + + # Initialize paths between parents and children, and based on them, + # generate initial seeding of listener paths, @VIA + + foreach my $node1 (@NODES) { + $COST[$node1][$node1] = 0; + $VIA[$node1][$node1] = 0; + foreach my $node2 (@NODES) { + if ($node2 != $node1) { + if ((not ($PARENT[$node1] or $PARENT[$node2])) or + ($PARENT[$node1] and $PARENT[$node1] == $node2) or + ($PARENT[$node2] and $PARENT[$node2] == $node1)) { + $PATH[$node1][$node2] = 1; + $PATH[$node2][$node1] = 1; + # Set up a cost 1 path between them + # Parent to child + $COST[$node1][$node2] = 1; + $VIA[$node1][$node2] = $node1; + + # Child to parent + $COST[$node2][$node1] = 1; + $VIA[$node2][$node1] = $node2; + } + } + } + } + + # Now, update the listener paths... + # 4 level nested iteration: + # 1 while not done, do + # 2 for each node, node1 + # 3 for each node, node2, where node2 <> node1, where we don't + # yet have a listener path + # 4 for each node node3 (<> node1 or node2), + # consider introducing the listener path: + # node1 to node2 then node2 to node3 + # In concept, it's an O(n^4) algorithm; since the number of nodes, n, + # is not likely to get particularly large, it's not worth tuning + # further. + $didwork = "yes"; + while ($didwork eq "yes") { + $didwork = "no"; + foreach my $node1 (@NODES) { + foreach my $node3 (@NODES) { + if (($VIA[$node3][$node1] == 0) && ($node3 != $node1)) { + foreach my $node2 (@NODES) { + if ($PATH[$node1][$node2] && ($VIA[$node2][$node3] != 0) && ($node2 != $node3) && ($node2 != $node1)) { + # Consider introducing a path from n1 to n2 then n2 to n3 + # as a cheaper alternative to going direct from n1 to n3 + my $oldcost = $COST[$node3][$node1]; + my $newcost = $COST[$node1][$node2] + $COST[$node2][$node3]; + if ($newcost < $oldcost) { + $didwork = "yes"; + # So we go via node 2 + $VIA[$node3][$node1] = $node2; + $COST[$node3][$node1] = $newcost; + + $VIA[$node1][$node3] = $node2; + $COST[$node1][$node3] = $newcost; + } + } + } + } + } + } + } +} + +sub report_on_paths { + print "# Configuration Summary:\n"; + print "#\n"; + print "# COST\n"; + print "# "; + foreach my $node2 (@NODES) { + printf "| %3d ", $node2; + } + print "|\n# "; + print ("-----+" x (scalar(@NODES) + 1)); + print "\n"; + foreach my $node1 (@NODES) { + printf "# %3d ", $node1; + foreach my $node2 (@NODES) { + if ($COST[$node2][$node1] == $infinity) { + printf "| inf "; + } else { + printf "|%4d ", $COST[$node2][$node1]; + } + } + print "|\n"; + } + print "# \n"; + print "# VIA\n"; + print "# "; + foreach my $node2 (@NODES) { + printf "| %3d ", $node2; + } + print "|\n# "; + print ("-----+" x (scalar(@NODES) + 1)); + print "\n"; + foreach my $node1 (@NODES) { + printf "# %3d ", $node1; + foreach my $node2 (@NODES) { + printf "|%4d ", $VIA[$node2][$node1]; + } + print "|\n"; + } + + print "# \n"; + print "# PATHS\n"; + print "# "; + foreach my $node2 (@NODES) { + printf "| %3d ", $node2; + } + print "|\n# "; + print ("-----+" x (scalar(@NODES) + 1)); + print "\n"; + foreach my $node1 (@NODES) { + printf "# %3d ", $node1; + foreach my $node2 (@NODES) { + printf "|%4d ", $PATH[$node2][$node1]; + } + print "|\n"; + } + print "\n"; +} --- /dev/null +++ tools/altperl/slonik_init_cluster.pl @@ -0,0 +1,228 @@ +#!@@PERL@@ +# $Id: slonik_init_cluster.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +my $CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +my $SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: init_cluster [--config file] + + Generates the slonik commands necessary to create a cluster and + prepare the nodes for use. Also displays a report showing the + relationships between the various nodes. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my $FILE="/tmp/init-cluster.$$"; + +# INIT CLUSTER +open(SLONIK, ">", $FILE); +print SLONIK "\n# INIT CLUSTER\n"; +print SLONIK genheader(); +my ($dbname, $dbhost) = ($DBNAME[$MASTERNODE], $HOST[$MASTERNODE]); +print SLONIK " init cluster (id = $MASTERNODE, comment = 'Node $MASTERNODE - $dbname\@$dbhost');\n"; + +# STORE NODE +print SLONIK "\n# STORE NODE\n"; +foreach my $node (@NODES) { + if ($node != $MASTERNODE) { # skip the master node; it's already initialized! + my ($dbname, $dbhost) = ($DBNAME[$node], $HOST[$node]); + print SLONIK " store node (id = $node, event node = $MASTERNODE, comment = 'Node $node - $dbname\@$dbhost');\n"; + } +} +print SLONIK " echo 'Set up replication nodes';\n"; + +# STORE PATH +print SLONIK "\n# STORE PATH\n"; + +my @COST; +my @VIA; +my @PATH; +generate_listen_paths(); + +print SLONIK " echo 'Next: configure paths for each node/origin';\n"; +foreach my $nodea (@NODES) { + my $dsna = $DSN[$nodea]; + foreach my $nodeb (@NODES) { + if ($nodea != $nodeb) { + my $dsnb = $DSN[$nodeb]; + my $providerba = $VIA[$nodea][$nodeb]; + my $providerab = $VIA[$nodeb][$nodea]; + if (!$printed[$nodea][$nodeb] and $providerab == $nodea) { + print SLONIK " store path (server = $nodea, client = $nodeb, conninfo = '$dsna');\n"; + $printed[$nodea][$nodeb] = "done"; + } + if (!$printed[$nodeb][$nodea] and $providerba == $nodea) { + print SLONIK " store path (server = $nodeb, client = $nodea, conninfo = '$dsnb');\n"; + $printed[$nodeb][$nodea] = "done"; + } + } + } +} + +# STORE LISTEN +print SLONIK "\n# STORE LISTEN\n"; +foreach my $origin (@NODES) { + my $dsna = $DSN[$origin]; + foreach my $receiver (@NODES) { + if ($origin != $receiver) { + my $provider = $VIA[$origin][$receiver]; + print SLONIK " store listen (origin = $origin, receiver = $receiver, provider = $provider);\n"; + } + } +} +print SLONIK " echo 'Replication nodes prepared';\n"; +print SLONIK " echo 'Please start a slon replication daemon for each node';\n"; +close SLONIK; +run_slonik_script($FILE); +report_on_paths(); + +sub generate_listen_paths { + my $infinity = 10000000; # Initial costs are all infinite + foreach my $node1 (@NODES) { + foreach my $node2 (@NODES) { + $COST[$node1][$node2] = $infinity; + } + } + + # Initialize paths between parents and children, and based on them, + # generate initial seeding of listener paths, @VIA + + foreach my $node1 (@NODES) { + $COST[$node1][$node1] = 0; + $VIA[$node1][$node1] = 0; + foreach my $node2 (@NODES) { + if ($node2 != $node1) { + if ((not ($PARENT[$node1] or $PARENT[$node2])) or + ($PARENT[$node1] and $PARENT[$node1] == $node2) or + ($PARENT[$node2] and $PARENT[$node2] == $node1)) { + $PATH[$node1][$node2] = 1; + $PATH[$node2][$node1] = 1; + # Set up a cost 1 path between them + # Parent to child + $COST[$node1][$node2] = 1; + $VIA[$node1][$node2] = $node1; + + # Child to parent + $COST[$node2][$node1] = 1; + $VIA[$node2][$node1] = $node2; + } + } + } + } + + # Now, update the listener paths... + # 4 level nested iteration: + # 1 while not done, do + # 2 for each node, node1 + # 3 for each node, node2, where node2 <> node1, where we don't + # yet have a listener path + # 4 for each node node3 (<> node1 or node2), + # consider introducing the listener path: + # node1 to node2 then node2 to node3 + # In concept, it's an O(n^4) algorithm; since the number of nodes, n, + # is not likely to get particularly large, it's not worth tuning + # further. + $didwork = "yes"; + while ($didwork eq "yes") { + $didwork = "no"; + foreach my $node1 (@NODES) { + foreach my $node3 (@NODES) { + if (($VIA[$node3][$node1] == 0) && ($node3 != $node1)) { + foreach my $node2 (@NODES) { + if ($PATH[$node1][$node2] && ($VIA[$node2][$node3] != 0) && ($node2 != $node3) && ($node2 != $node1)) { + # Consider introducing a path from n1 to n2 then n2 to n3 + # as a cheaper alternative to going direct from n1 to n3 + my $oldcost = $COST[$node3][$node1]; + my $newcost = $COST[$node1][$node2] + $COST[$node2][$node3]; + if ($newcost < $oldcost) { + $didwork = "yes"; + # So we go via node 2 + $VIA[$node3][$node1] = $node2; + $COST[$node3][$node1] = $newcost; + + $VIA[$node1][$node3] = $node2; + $COST[$node1][$node3] = $newcost; + } + } + } + } + } + } + } +} + +sub report_on_paths { + print "# Configuration Summary:\n"; + print "#\n"; + print "# COST\n"; + print "# "; + foreach my $node2 (@NODES) { + printf "| %3d ", $node2; + } + print "|\n# "; + print ("-----+" x (scalar(@NODES) + 1)); + print "\n"; + foreach my $node1 (@NODES) { + printf "# %3d ", $node1; + foreach my $node2 (@NODES) { + if ($COST[$node2][$node1] == $infinity) { + printf "| inf "; + } else { + printf "|%4d ", $COST[$node2][$node1]; + } + } + print "|\n"; + } + print "# \n"; + print "# VIA\n"; + print "# "; + foreach my $node2 (@NODES) { + printf "| %3d ", $node2; + } + print "|\n# "; + print ("-----+" x (scalar(@NODES) + 1)); + print "\n"; + foreach my $node1 (@NODES) { + printf "# %3d ", $node1; + foreach my $node2 (@NODES) { + printf "|%4d ", $VIA[$node2][$node1]; + } + print "|\n"; + } + + print "# \n"; + print "# PATHS\n"; + print "# "; + foreach my $node2 (@NODES) { + printf "| %3d ", $node2; + } + print "|\n# "; + print ("-----+" x (scalar(@NODES) + 1)); + print "\n"; + foreach my $node1 (@NODES) { + printf "# %3d ", $node1; + foreach my $node2 (@NODES) { + printf "|%4d ", $PATH[$node2][$node1]; + } + print "|\n"; + } + print "\n"; +} --- /dev/null +++ tools/altperl/slonik_move_set.pl @@ -0,0 +1,64 @@ +#!@@PERL@@ +# $Id: slonik_move_set.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE); + +my $USAGE = +"Usage: move_set [--config file] set# from_node# to_node# + + Change a set's origin. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my ($set, $node1, $node2) = @ARGV; +if ($set =~ /^(?:set)?(\d+)$/) { + # Node name is in proper form + $set = $1; +} else { + print "Valid set names are set1, set2, ...\n\n"; + die $USAGE; +} + +if ($node1 =~ /^(?:node)?(\d+)$/) { + $node1 = $1; +} else { + print "Valid node names are node1, node2, ...\n\n"; + die $USAGE; +} + +if ($node2 =~ /^(?:node)?(\d+)$/) { + $node2 = $1; +} else { + print "Valid node names are node1, node2, ...\n\n"; + die $USAGE; +} + +open(SLONIK, ">", "/tmp/slonik.$$"); +print SLONIK genheader(); +print SLONIK " echo 'Locking down set $set on node $node1';\n"; +print SLONIK " lock set (id = $set, origin = $node1);\n"; +print SLONIK " echo 'Locked down - moving it';\n"; +print SLONIK " move set (id = $set, old origin = $node1, new origin = $node2);\n"; +print SLONIK " echo 'Replication set $set moved from node $node1 to $node2. Remember to';\n"; +print SLONIK " echo 'update your configuration file, if necessary, to note the new location';\n"; +print SLONIK " echo 'for the set.';\n"; +close SLONIK; +run_slonik_script("/tmp/slonik.$$"); --- /dev/null +++ tools/altperl/slonik_execute_script.pl @@ -0,0 +1,92 @@ +#!@@PERL@@ +# $Id: slonik_execute_script.pl,v 1.1 2005/05/31 16:11:05 cbbrowne Exp $ +# Author: Christopher Browne +# Copyright 2004 Afilias Canada + +use Getopt::Long; + +# Defaults +$CONFIG_FILE = '@@SYSCONFDIR@@/slon_tools.conf'; +$SHOW_USAGE = 0; +$SCRIPT_ARG = ""; + +# Allow this to be specified. Otherwise it will be pulled from +# the get_set function. +$node = 0; + +# Read command-line options +GetOptions("config=s" => \$CONFIG_FILE, + "help" => \$SHOW_USAGE, + "c=s" => \$SCRIPT_ARG, + "n|node=s" => \$node); + +my $USAGE = +"Usage: + execute_script [options] set# full_path_to_sql_script_file + execute_script [options] -c SCRIPT set# + + Executes the contents of a SQL script file on the specified set. + The script only needs to exist on the machine running the slon + daemon. + + set# The set to which this script applies. + + -c SCRIPT Pass the SQL to be executed via the command line instead + of as a file. + + -n NUM + --node=NUM Override the set origin specified in the configuration + file. + +"; + +if ($SHOW_USAGE) { + print $USAGE; + exit 0; +} + +require '@@PGLIBDIR@@/slon-tools.pm'; +require $CONFIG_FILE; + +my ($set, $file) = @ARGV; +if ($set =~ /^(?:set)?(\d+)$/) { + $set = $1; +} else { + print "Invalid set identifier\n\n"; + die $USAGE; +} + +get_set($set) or die "Non-existent set specified.\n"; +$node = $SET_ORIGIN unless $node; + +# We can either have -c SCRIPT or a filename as an argument. The +# latter takes precedence. +if ($file) { + unless ($file =~ /^\// and -f $file) { + print STDERR "SQL script path needs to be a full path, e.g. /tmp/my_script.sql\n\n"; + die $USAGE; + } +} +elsif ($SCRIPT_ARG) { + # Put the script into a file + $file = "/tmp/execute_script.sql.$$"; + my $fh; + open $fh, ">", $file; + print $fh $SCRIPT_ARG; + close $fh; +} +else { + print STDERR "You must include either a filename or a SQL statement on the command line to be run.\n\n"; + die $USAGE; +} + +my $FILE="/tmp/gensql.$$"; +open(SLONIK, ">", $FILE); +print SLONIK genheader(); +print SLONIK " execute script (\n"; +print SLONIK " set id = $set,\n"; +print SLONIK " filename = '$file',\n"; +print SLONIK " event node = $node\n"; +print SLONIK " );\n"; +close SLONIK; +run_slonik_script($FILE); Index: README =================================================================== RCS file: /usr/local/cvsroot/slony1/slony1-engine/tools/altperl/README,v retrieving revision 1.12 retrieving revision 1.13 diff -Ltools/altperl/README -Ltools/altperl/README -u -w -r1.12 -r1.13 --- tools/altperl/README +++ tools/altperl/README @@ -39,11 +39,11 @@ 4. Initialize the Slony-I cluster: - /usr/local/slony/bin/init_cluster + /usr/local/slony/bin/slonik_init_cluster Verify that the output looks reasonable, then run: - /usr/local/slony/bin/init_cluster | /usr/local/pgsql/bin/slonik + /usr/local/slony/bin/slonik_init_cluster | /usr/local/pgsql/bin/slonik 5. Start up slon daemons for both servers: @@ -52,11 +52,11 @@ 6. Set up set 1 on the "master" node: - /usr/local/slony/bin/create_set set1 + /usr/local/slony/bin/slonik_create_set set1 7. Subscribe node 2 to set 1: - /usr/local/slony/bin/subscribe_set set1 node2 + /usr/local/slony/bin/slonik_subscribe_set set1 node2 After some period of time (from a few seconds to a few days depending on the size of the set), you should have a working replica of the
- Previous message: [Slony1-commit] By cbbrowne: Darcy's addition of the "--with-docs" option must be added
- Next message: [Slony1-commit] By cbbrowne: Indicate the renaming of altperl scripts with "slonik_"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Slony1-commit mailing list