List:Commits« Previous MessageNext Message »
From:Luís Soares Date:October 20 2009 12:04pm
Subject:Re: bzr commit into nuts branch (Serge.Kozlov:356) WL#5038
View as plain text  
Hi Serge,

  Good work. Please find my review comments below.

STATUS
------

  Not approved.

REQUIRED CHANGES
----------------

  RC1. I could not execute the test case:

$ perl bin/nuts.pl --verbose --build ../mysql-5.1-rep+2/ --test
semi_sync
[12:11:19] rep::semi_sync .. 
1..0
skipped: (no reason given)
[12:12:13]
Files=1, Tests=0, 54 wallclock secs ( 0.31 usr  0.17 sys +  0.79 cusr
0.54 csys =  1.81 CPU)
Result: NOTESTS

       I think this is because the check for semisync
       availability may be wrong. Shouldn't one:

         1. Load the master plugin
         2. Load the slave plugin
         3. Check that the plugins were installed
            successfully. Maybe, check results for:

       select * from mysql.plugin where name like '%semi_sync_master';
       select * from mysql.plugin where name like '%
semi_sync_slave';       

       It's probably safe to load both plugins on every host and
       just activate them when needed (as it is today in the:
       change_rpl_mode function).

  RC2. I think one needs to sync master and slave for both async
       and semisync replication. If one does not sync in the case
       of semisync replication, there can be the case that some
       events were not replayed by the SQL thread. 

       If it was fully synchronous replication (meaning that the
       slave would only reply to the client once the transaction
       was replayed in all (a majority, or just one slave -
       depends on the resilience wanted), then we would not need
       to sync the slave(s). 

       So the loop below the comment:
       # Sync master and slave for async replication
      
       needs to sync all slaves, not just the async ones.

REQUESTS
--------

  R1. "attach" is starting the slave implicitely... I wonder if
      it should do it or not. We do have the "start_replication"
      function.

      In this test attach starts the slave to immediately after
      stop it, reconfigure semisync and start it again. Perhaps
      we should consider removing the:

      return ( $slave->execute ("START SLAVE") );

      from attach function.

SUGGESTIONS
-----------
  
  S1. Perhaps I would consider making the function
      change_rpl_mode as part of the replication library. This
      function could:

         1. Check whether semisync is active.
         2. stop replication.
         3. wait for replication to stop.
         4. Set the correct active profile (master/slave).
         5. start replication.
         6. wait for replication to start.

       We could name it:
       
       enable_semi_sync or ok_enable_semisync.

  S2. As part of the replication library, why not also make the
      functions (this is just a suggestion):

         1. is_plugin_available_semi_sync_master
         2. install_plugin_semi_sync_master
         3. install_plugin_semi_sync_slave

       Each of these functions would act as a facade for a two
       functions:

         1. is_plugin_available(PLUGIN_ID)
         2. install_plugin(PLUGIN_ID)

       So that, one could have something like:

          sub install_plugin_semi_sync_master()
          {
            return install_plugin(PLUGIN_SEMI_SYNC_MASTER_ID);
          }

  These are just suggestions, but something done in this context
  would be great (I think). But Alfranio should have a saying in
  this as well.

DETAILS 
-------

  Please find some minor comments inline.

On Tue, 2009-09-29 at 01:48 +0400, Serge Kozlov wrote:
> #At file:///home/ksm/sun/repo/WL5038/nuts-commit/ based on
> revid:serge.kozlov@stripped
> 
>   356 Serge Kozlov	2009-09-29
>       WL#5038 Test case
>       added:
>         suites/rep/semi_sync.pm
>       modified:
>         lib/My/Nuts/Library/Kernel/ServerResult.pm
> 
> === modified file 'lib/My/Nuts/Library/Kernel/ServerResult.pm'
> --- a/lib/My/Nuts/Library/Kernel/ServerResult.pm	2009-09-25 11:24:12 +0000
> +++ b/lib/My/Nuts/Library/Kernel/ServerResult.pm	2009-09-28 21:48:49 +0000
> @@ -2,7 +2,7 @@ package My::Nuts::Library::Kernel::Serve
>  use Exporter;
>  our @ISA = qw(Exporter);
>  our @EXPORT =
> -  qw(compare_dbs ok_compare_dbs get_supported_engines get_table_list);
> +  qw(compare_dbs ok_compare_dbs get_supported_engines get_table_list get_variable);
>  use strict;
>  use warnings;
>  use My;
> @@ -139,6 +139,21 @@ sub get_table_list
>      return $tables;
>  }
>  
> +sub get_variable
> +{
> +    my $params = shift;
> +    my $conn = $params->{"conn"};
> +    my $var = $params->{"var"};
> +    my $result = undef;
> +    my $rs = sql ($conn, "SHOW VARIABLES LIKE '" . $var . "';");
> +    my @rs_data = get_next($rs);
> +    if (defined $rs_data[0])
> +    {
> +	$result = $rs_data[1];
> +    }    
> +    return $result;
> +}

Good. Nice that you've done it.

>  1;
>  
>  __END__;
> 
> === added file 'suites/rep/semi_sync.pm'
> --- a/suites/rep/semi_sync.pm	1970-01-01 00:00:00 +0000
> +++ b/suites/rep/semi_sync.pm	2009-09-28 21:48:49 +0000
> @@ -0,0 +1,171 @@
> +package rep::semi_sync;
> +use Exporter;
> +our @ISA = qw(Exporter My::Nuts::Library::Tests::SimpleTest);
> +use strict;
> +use warnings;
> +use My;
> +use My::Nuts::Library::Kernel::Server;
> +use My::Nuts::Library::Kernel::ServerResult;
> +use My::Nuts::Library::Kernel::Manager;
> +use My::Nuts::Library::Kernel::Result;
> +use My::Nuts::Library::Tests::SimpleTest;
> +use My::Nuts::Library::Kernel::Replication;
> +use Test::More;
> +use DataSource;
> +
> +sub prepare
> +{
> +    return;
> +}
> +
> +sub startup
> +{
> +    return;
> +}
> +
> +sub fire
> +{
> +    my ($test) = @_;
> +    # Create 3 servers
> +    my $server1 = ok_server ($test);
> +    my $server2 = ok_server ($test);
> +    my $server3 = ok_server ($test);
> +    # Move server to hash
> +    my $servers = {
> +	 "A" => $server1,
> +	 "B" => $server2,
> +	 "C" => $server3
> +    };
> +    # List of test schemas
> +    my $schemas = [
> +	[
> +	    {"topology" => "A->B"},
> +	    {"A->B" => "async"},
> +	    {"A->B" => "semisync"}
> +	],
> +	[
> +	    {"topology" => "A->B,B->C"},
> +	    {"A->B" => "semisync", "B->C" => "semisync"},
> +	    {"A->B" => "semisync", "B->C" => "async"}
> +	],
> +	[
> +	    {"topology" => "A->B,A->C"},
> +	    {"A->B" => "semisync", "A->C" => "semisync"},
> +	    {"A->B" => "semisync", "A->C" => "async"}
> +	]
> +    ];
> +    # Init stuff
> +    my $dbname  = "test";    
> +    my $init_queries =[
> +	"DROP DATABASE IF EXISTS " . $dbname,
> +	"CREATE DATABASE " . $dbname,
> +	"USE " . $dbname
> +    ];
> +
> +    # Check semisync support
> +    my $semisync_enabled = 1;
> +    foreach my $server (values %$servers)
> +    {
> +	$semisync_enabled = 0 if (!defined(get_variable ( {"conn" => $server, "var"
> => "rpl_semi_sync_master_enabled"})));    

Before this, we need the plugin to be loaded. Do we load 
it elsewhere? I cannot find the INSTALL PLUGIN clause and the
test run I did would not succeed, bailing out with skipped...

> +    }
> +    if ($semisync_enabled == 1)
> +    {
> +	# Get statements from data source and add creating db
> +	my $data = get_data_from_source();
> +	unshift(@$data, @$init_queries);
> +	    
> +	# Plan
> +	plan tests => scalar(@$schemas) * scalar(@$data) + 53;
> +    
> +	# Main loop
> +	foreach my $schema (@$schemas)
> +	{
> +	    # Create pairs master->slave and store them into hash
> +	    #print $schema->[0]->{"topology"} . "\n";
> +	    my @atomic = split(",", $schema->[0]->{"topology"});
> +	    my $cur_servers = {};
> +	    foreach my $pair (@atomic)
> +	    {
> +		$pair =~ m/(.+)\-\>(.+)/i;
> +		$cur_servers->{$pair}->{"master"} = $servers->{$1};
> +		$cur_servers->{$pair}->{"slave"} = $servers->{$2};
> +		attach($cur_servers->{$pair}->{"master"},
> $cur_servers->{$pair}->{"slave"});

I don't recall why attach does an implicit start slave,
but maybe it should not... What do you think? Alfranio?

> +		ok_wait_start_replication($cur_servers->{$pair}->{"slave"});
> +	    }
> +	    my $num = scalar(@$schema) - 1;
> +	    my $block_start = 0;
> +	    my $block_end = 0;
> +	    for (my $i = 1; $i <= $num; $i++)
> +	    {
> +		# Prepare replication
> +		foreach my $detail (keys %{$schema->[$i]})
> +		{
> +		    change_rpl_mode($cur_servers->{$detail}->{"master"},
> $cur_servers->{$detail}->{"slave"}, $schema->[$i]->{$detail})
> +		}
> +		# Run bulk of statements on master
> +		$block_start = $block_end;
> +		$block_end = int (($i/$num) * scalar(@$data));
> +		for (my $j = $block_start; $j < $block_end; $j++)
> +		{
> +		    ok_sql($servers->{"A"}, $data->[$j]);
> +		}	    
> +		# Sync master and slave for async replication
> +		foreach my $detail (keys %{$schema->[$i]})
> +		{
> +		    if ($schema->[$i]->{$detail} =~ m/async/i)
> +		    {
> +			ok_synchronize($cur_servers->{$detail}->{"master"},
> $cur_servers->{$detail}->{"slave"});
> +		    }

I think one needs to synchronize both async and semisync
master->slave(s).

> +		}
> +	    }
> +	    # Check DBs
> +	    foreach my $pair (keys %{$cur_servers})
> +	    {
> +		ok_compare_dbs([
> +		    {"conn" => $cur_servers->{$pair}->{"master"}, "dbname" =>
> $dbname}
> +		]);	
> +	    }
> +	    # Stop replication links and clean up servers
> +	    foreach my $pair (keys %{$cur_servers})
> +	    {
> +		stop_replication($cur_servers->{$pair}->{"slave"});
> +		reset_master($cur_servers->{$pair}->{"master"});
> +		reset_slave($cur_servers->{$pair}->{"slave"});		
> +	    }	    
> +	}
> +    }
> +}
> +
> +sub shutdown
> +{
> +    return;
> +}
> +
> +sub change_rpl_mode
> +{
> +    my ($master, $slave, $mode) = @_;
> +    my $modes = {
> +	"async" => 0,
> +	"semisync" => 1	
> +    };
> +    sql($master, "SET GLOBAL rpl_semi_sync_master_enabled = " .
> $modes->{$mode});
> +    sql($slave, "SET GLOBAL rpl_semi_sync_slave_enabled = " . $modes->{$mode});
> +    ok_stop_replication($slave);
> +    ok_wait_stop_replication($slave);
> +    ok_start_replication($slave);    
> +    ok_wait_start_replication($slave);    
> +}
> +
> +1;
> +__END__;
> +
> +=head1 NAME
> +
> +rep::semi_sync - Semisynchronous replication
> +
> +=head1 SYNOPSIS
> +
> +Semisynchronous replication for different topologies (A->B, A->B->C,
> B<-A->C) and switching
> +to asynchronous and back.
> +
> +=back
> 
> 
-- 
Luís

Thread
bzr commit into nuts branch (Serge.Kozlov:356) WL#5038Serge Kozlov28 Sep
  • Re: bzr commit into nuts branch (Serge.Kozlov:356) WL#5038Luís Soares20 Oct
    • Re: bzr commit into nuts branch (Serge.Kozlov:356) WL#5038Serge Kozlov20 Oct
      • Re: bzr commit into nuts branch (Serge.Kozlov:356) WL#5038Luís Soares21 Oct
    • Re: bzr commit into nuts branch (Serge.Kozlov:356) WL#5038Serge Kozlov26 Oct