List:Commits« Previous MessageNext Message »
From:Serge Kozlov Date:January 18 2011 11:02pm
Subject:bzr commit into nuts branch (Serge.Kozlov:386) WL#5493
View as plain text  
#At file:///home/ksm/oracle/QA/nuts/ based on revid:serge.kozlov@stripped

  386 Serge Kozlov	2011-01-19
      QA for WL#5493: new test rep_func::crash_safe_master added

    added:
      suites/rep_func/crash_safe_master.pm
    renamed:
      suites/rep_exp/ => suites/rep_func/
    modified:
      lib/My.pm
      lib/My/Nuts/Library/Kernel/Replication.pm
      lib/My/Nuts/Library/Kernel/ServerResult.pm
      suites/rep/client_redirect/client_redirect.pm
      suites/rep_func/mts.pm
=== modified file 'lib/My.pm'
--- a/lib/My.pm	2009-04-13 19:41:13 +0000
+++ b/lib/My.pm	2011-01-18 23:02:07 +0000
@@ -13,7 +13,7 @@ use constant ROLE_MASTER           => 'M
 use constant ROLE_SLAVE            => 'S';
 use constant ROLE_BOTH             => 'B';
 use constant WAIT                  => 1;
-use constant EFFORT                => 5;
+use constant EFFORT                => 10;
 use constant DIE                   => 0;
 use constant CONTINUE              => 1;
 use constant UNDEPLOYED            => 0;

=== modified file 'lib/My/Nuts/Library/Kernel/Replication.pm'
--- a/lib/My/Nuts/Library/Kernel/Replication.pm	2010-03-31 20:40:41 +0000
+++ b/lib/My/Nuts/Library/Kernel/Replication.pm	2011-01-18 23:02:07 +0000
@@ -483,7 +483,7 @@ sub get_changemaster
           $command
           . ( $param{master_connect_retry}
               ? ", MASTER_CONNECT_RETRY = " . $param{master_connect_retry}
-              : "" );
+              : "20" );
         $command =
           $command
           . ( $param{master_heartbeat_period}

=== modified file 'lib/My/Nuts/Library/Kernel/ServerResult.pm'
--- a/lib/My/Nuts/Library/Kernel/ServerResult.pm	2010-12-21 21:34:08 +0000
+++ b/lib/My/Nuts/Library/Kernel/ServerResult.pm	2011-01-18 23:02:07 +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 get_variable get_status 
+  qw(ok_diff_databases diff_databases compare_dbs ok_compare_dbs get_supported_engines get_table_list get_variable get_status 
     get_errmsg_by_num ok_wait_status ok_wait_sql);
 use strict;
 use warnings;
@@ -17,6 +17,124 @@ use My::Nuts::Report::Debug;
 use Test::More;
 
 my $errmsg = undef;
+my $diff = "/usr/bin/diff";
+
+sub diff_databases
+{
+    my $data = [];
+    my @result = ();
+    # Sort input
+    for (my $i = 0; $i < scalar(@_); $i=$i+2)
+    {
+	push(@$data, {"connection" => $_[$i], "database" => $_[$i+1]});
+    }
+    # Get the list of table names
+    my $tablelist_p;
+    my @tablelist;
+    foreach my $data_item ( @$data )
+    {
+	$data_item->{"tablelist"}= get_table_list($data_item->{"connection"}, $data_item->{"database"});
+	$data_item->{"tablelist_p"}= join(",", @{$data_item->{"tablelist"}});
+	if (! defined($tablelist_p))
+	{
+	    $tablelist_p= $data_item->{"tablelist_p"};
+	    @tablelist= @{$data_item->{"tablelist"}};
+	}
+    } 
+    # Compare table names
+    foreach my $data_item ( @$data )
+    {
+	if ($data_item->{"tablelist_p"} ne $tablelist_p)
+	{
+	    push(@result, 1, "Table names are different: $tablelist_p and " . $data_item->{"tablelist_p"});
+	    last;
+	}
+    }
+    # Compare number of records 
+    if (scalar(@result) == 0)
+    {
+	# Get number of records for each table
+	foreach my $data_item ( @$data )
+	{
+	    foreach my $tname ( @tablelist )
+	    {
+		$data_item->{"table_count"}->{$tname}= sql_result($data_item->{"connection"}, "SELECT COUNT(*) FROM $tname");
+	        
+	    }
+	}
+	# Compare number of records for same tables for different connections
+	foreach my $data_item ( @$data )
+	{
+	    foreach my $tname ( @tablelist )
+	    {
+		if ($data->[0]->{"table_count"}->{$tname} != $data_item->{"table_count"}->{$tname})
+		{
+		    push(@result, 1, "Query 'SELECT COUNT(*) FROM $tname' returns different number of rows: " 
+			. $data->[0]->{"database"} . ".$tname: " . $data->[0]->{"table_count"}->{$tname} . ", " 
+			. $data_item->{"database"} . ".$tname: " . $data_item->{"table_count"}->{$tname});
+		    last;
+		}		
+	    }	
+	    if (scalar(@result) > 0)
+	    {
+		last;
+	    }
+	}
+	# Dump rows from tables to files
+	if (scalar(@result) == 0)
+	{
+	    foreach my $data_item ( @$data )
+	    {
+		foreach my $tname ( @tablelist )
+		{
+		    my $order_list = get_table_pk_column_list($data_item->{"connection"}, $tname);
+		    my$select_list = get_table_column_list($data_item->{"connection"}, $tname);
+		    if (!defined($order_list))
+		    {
+			$order_list = $select_list;
+		    }
+		    my $dumpfile = sql_result($data_item->{"connection"}, 'SELECT @@datadir')
+		     . $data_item->{"database"} . ".$tname.dump";
+		    # Dump data to file
+		    my $rs= sql($data_item->{"connection"}, "SELECT " . join(",", @$select_list) . " FROM $tname ORDER BY " . join(",", @$order_list) . " INTO OUTFILE '$dumpfile'");
+		    $data_item->{"table_dumpfile"}->{$tname}= $dumpfile;
+		}		
+	    }		    
+        }
+        # Run diff
+	foreach my $data_item ( @$data )
+	{
+	    foreach my $tname ( @tablelist )
+	    {
+		my $diff_line = $diff . " -q " . $data->[0]->{"table_dumpfile"}->{$tname} . " " . $data_item->{"table_dumpfile"}->{$tname};
+		my $diff_res = `$diff_line`;
+		if ($diff_res =~ m/^.+$/)
+		{
+		    push(@result, 1, "Found diff for dump files of table $tname: " 
+			. $data->[0]->{"table_dumpfile"}->{$tname} . ", " 
+			. $data_item->{"table_dumpfile"}->{$tname});
+		    last;
+		}
+	    }	
+	    if (scalar(@result) > 0)
+	    {
+		last;
+	    }
+	}        
+        # Final conclusion: databases have no diff
+	if (scalar(@result) == 0)
+	{
+	    push(@result, 0, "Databases have no difference");
+        }
+    }
+    return @result;     
+}
+
+sub ok_diff_databases
+{
+  my @result = diff_databases(@_);
+  ok ( $result[0] == 0, $result[1]) or diag ($result[1]);
+}
 
 sub compare_dbs
 {
@@ -137,10 +255,8 @@ sub get_supported_engines
 
 sub get_table_list
 {
-    my $params = shift;
-    my $conn = $params->{"conn"};
-    my $dbname = $params->{"dbname"};
-    my $tables = [];
+    my ($conn, $dbname) = @_;
+    my @tables = ();
     my $rs;
     if (defined $dbname)
     {
@@ -153,10 +269,61 @@ sub get_table_list
     my @rs_data = get_next($rs);
     while (defined $rs_data[0])
     {
-	push(@$tables, $rs_data[0]);
+	push(@tables, $rs_data[0]);
         @rs_data = get_next($rs);
     }    
-    return $tables;
+    return [ sort @tables ];
+}
+
+sub get_show_create_table
+{
+    my ($conn, $tname) = @_;
+    my @cols = ();
+    my $rs = sql ( $conn, "SHOW CREATE TABLE $tname" );
+    my @rs_data = get_next($rs);
+    if (defined $rs_data[1])
+    {
+        return $rs_data[1];;
+    }    
+    return undef;
+}
+
+sub get_table_column_list
+{
+    my @cols = ();
+    my $create = get_show_create_table(@_);
+    if (defined $create)
+    {
+	$create =~ s/(\r|\n|\`|\`)//g;
+	$create =~ s/^create.+?table.+?\(//gi;
+	$create =~ s/primary key.+//gi;
+	$create =~ s/\(\d+\)//gi;
+	$create =~ s/\).+?ENGINE.+//gi;
+	$create =~ s/\, +/,/gi;
+	$create =~ s/ +[a-z\_]+//gi;
+	@cols = split(",", $create);
+	return [@cols];
+    }
+    return undef;
+}
+
+sub get_table_pk_column_list
+{
+    my @cols = ();
+    my $create = get_show_create_table(@_);
+    if (defined $create)
+    {
+	$create =~ s/(\`|\`| )//g;
+	if ($create =~ m/primarykey\((.+?)\)/i)
+	{
+	    @cols = split(",", $1);
+	}
+	if (scalar(@cols) > 0)
+	{
+	    return [@cols];
+	}
+    }
+    return undef;
 }
 
 sub get_variable
@@ -286,14 +453,12 @@ dbname - name of database
 
 =back
 
-=head3 get_table_list(params)
+=head3 get_table_list(conn, dbname)
 
 Description: get list of tables for given server/database
 
 Parameters:
 
-params - reference to hash that must have following keys:
-
 conn - server (connection)
 
 dbname - name of database

=== modified file 'suites/rep/client_redirect/client_redirect.pm'
--- a/suites/rep/client_redirect/client_redirect.pm	2010-08-17 20:30:52 +0000
+++ b/suites/rep/client_redirect/client_redirect.pm	2011-01-18 23:02:07 +0000
@@ -133,7 +133,7 @@ sub fire
             my $cur_tables;
 	    while (($cur_table_num < $orig_table_num) && ($timeout > 0))
 	    {
-	      $cur_tables = get_table_list({"conn" => $master_middle, "dbname" => $dbname1});
+	      $cur_tables = get_table_list($master_middle, $dbname1});
 	      $cur_table_num = scalar(@$cur_tables);
 	      sleep 1;
 	      $timeout--;

=== renamed directory 'suites/rep_exp' => 'suites/rep_func'
=== added file 'suites/rep_func/crash_safe_master.pm'
--- a/suites/rep_func/crash_safe_master.pm	1970-01-01 00:00:00 +0000
+++ b/suites/rep_func/crash_safe_master.pm	2011-01-18 23:02:07 +0000
@@ -0,0 +1,254 @@
+package rep_func::crash_safe_master;
+use Exporter;
+our @ISA = qw(Exporter My::Nuts::Library::Tests::SimpleTest);
+use strict;
+use warnings;
+use DBI;
+use IO::File;
+use My;
+use My::Nuts::Library::Requirement;
+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 My::Nuts::Library::Fault::FaultInjection;
+use My::Nuts::Library::DataSource;
+use Test::More;
+
+my @crash_points = (
+    "crash_commit_before", 
+    "crash_commit_after_prepare", 
+    "crash_commit_after_log", 
+    "crash_commit_after", 
+    "crash_before_writing_xid", 
+    "half_binlogged_transaction"
+);
+
+sub combinations
+{
+    my @combinations = ();
+    foreach my $binlog_format ( ("row", "mixed", "stmt") )
+    {
+	my $idx= 0;
+	foreach my $crash_point ( @crash_points )
+	{
+	    push (@combinations, $binlog_format . "-crashpoint" . $idx);
+	    $idx++;
+	}
+    }
+    return @combinations;
+}
+
+sub prepare
+{
+    return;
+}
+
+sub startup
+{
+    return;
+}
+
+sub fire
+{
+    my ($test) = @_;
+    
+    # Parameters
+    my $dbname = "test";
+    my $timeout= 30;
+    
+    # Decode combination
+    my ($binlog_format, $crash_point) = split(/\-crashpoint/, get_combination($test));
+    $binlog_format = uc $binlog_format;
+    $binlog_format = "STATEMENT" if ($binlog_format eq "STMT");
+    $crash_point = $crash_points[$crash_point];
+    
+    # Read list of statements from data source
+    my $data = get_data_from_source();
+    
+    # Set number od subtests
+    my $subtests = 14;
+    
+    # Skip test if servers compiled withot debug support
+    SKIP: 
+    {
+	# Start master and check debubug support
+	my $master = server ($test);
+	if ( !has_dbug($master) )
+	{
+	    skip "Master compiled without debug support ", $subtests;
+	}
+
+	# Start slave and check debug support
+	my $slave = server ($test);
+	if ( !has_dbug($master) )
+	{
+	    skip "Slave compiled without debug support", $subtests;
+	}
+
+	# Set number of subtests
+	plan tests => $subtests;
+	
+	# Setup topology, binlog format, prepare test db
+	ok_sql ( $master, "SET GLOBAL BINLOG_FORMAT='$binlog_format'");
+	ok_sql ( $master, "SET SESSION BINLOG_FORMAT='$binlog_format'");
+	ok_sql ( $slave, "SET GLOBAL BINLOG_FORMAT='$binlog_format'");
+	ok_attach ( $master, $slave );
+	ok_synchronize ( $master, $slave );
+	ok_sql ( $master, "CREATE DATABASE IF NOT EXISTS $dbname");
+	ok_sql ( $master, "USE $dbname");
+		
+	# Main test
+	
+	# Set common crash position inside range 25-75%
+	my $query_count= scalar(@$data);
+	my $crash_pos = int(rand($query_count/2) + $query_count/4);
+	
+	# Fix position for special cases
+	if ($crash_point =~ m/(crash_commit_after|half_binlogged_transaction)/)
+	{
+	    my ($b_pos, $c_pos) = find_rand_trans($data);
+	    if (defined($c_pos))
+	    {
+		if ($crash_point =~ m/crash_commit_after/)
+		{
+		    $crash_pos = $c_pos;
+		}
+		elsif ($crash_point eq "half_binlogged_transaction")
+		{
+		    $crash_pos = $b_pos + int(($c_pos - $b_pos)/2);
+		}
+		# Print via diag() where we will do a crash
+		for (my $pos = $b_pos; $pos <= $c_pos; $pos++)
+		{
+		    if ($pos == $crash_pos)
+		    {
+			diag("SET SESSION DEBUG='d,$crash_point'");
+		    }
+		    diag($data->[$pos]);
+		}
+	    }
+	    else
+	    {
+		skip "Statement list has no transactions", 7;
+	    }
+	}
+	else 
+	{
+	    diag($data->[$crash_pos-1]) if ($crash_pos > 0);
+	    diag("SET SESSION DEBUG='d,$crash_point'");
+	    diag($data->[$crash_pos+1]) if ($crash_pos < (scalar(@$data)-1));  
+	}
+	
+	# Run queries against master
+	# We do not stop executing even server crashed
+	my $query_num = 0;
+	foreach my $query (@$data)
+	{
+	    if ( $query_num == $crash_pos )
+	    {
+    		ok_sql ( $master, "SET SESSION DEBUG='d,$crash_point'");
+	    }
+	    sql ( $master, $query );
+	    $query_num++;
+	}
+
+	# Wait the crash of master
+	while (check($master) != My::FAILURE && $timeout > 0)
+	{
+	    sleep 1;
+	    $timeout--;
+	}
+
+	# Start master and restore replication
+	if (check($master) == My::FAILURE)
+	{
+	    stop_server($master);
+	    wait_stop_server($master);
+	    start_server($master);
+	    wait_start_server($master);
+	    ok_sql ( $master, "SET GLOBAL BINLOG_FORMAT='$binlog_format'");
+	    ok_sql ( $master, "SET SESSION BINLOG_FORMAT='$binlog_format'");
+	    ok_start_replication($slave);
+	    ok_wait_start_replication($slave);
+	}
+	else
+	{
+	    skip "Master was not crashed at $crash_point.", 4;
+	}
+
+	# Sync slave with master
+	ok_synchronize($master, $slave);
+	# Compare databases
+	ok_diff_databases($master, "test", $slave, "test");
+    }
+}
+
+sub shutdown
+{
+    return;
+}
+
+sub find_rand_trans
+{
+    my ($data)= @_;
+    my @begin_pos_arr = ();
+    my @commit_pos_arr = ();
+    my $begin_pos = undef;
+    my $i = 0;
+    foreach my $query ( @$data )
+    {
+	if ($query =~ m/^BEGIN/i)
+	{
+	    $begin_pos= $i;
+	}
+	elsif (defined($begin_pos) && ($query =~ m/COMMIT/i))
+	{
+	    push(@begin_pos_arr, $begin_pos);
+	    push(@commit_pos_arr, $i);
+	    $begin_pos = undef;
+	}
+	$i++;
+    }
+    if (scalar(@begin_pos_arr) > 0)
+    {
+	my $pos = int(rand(scalar(@begin_pos_arr)));
+	return ($begin_pos_arr[$pos], $commit_pos_arr[$pos]);
+    }
+    else
+    {
+	return (undef, undef);
+    }
+}
+
+1;
+__END__;
+
+=head1 NAME
+
+rep::crash_safe_master - Crash safe master
+
+=head1 SYNOPSIS
+
+The test case emulates the crash at some points on master and possibility to restore the replication back without data loss. 
+Test uses binlog format and crash point number for combinations. The list of statements provided by DataSource library.
+
+=head1 REFERENCES
+
+=over
+
+=item * WL#5439
+
+=back
+
+=head1 AUTHOR
+
+Serge Kozlov S<< <Serge.Kozlov@stripped> >>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+=cut
\ No newline at end of file

=== modified file 'suites/rep_func/mts.pm'
--- a/suites/rep_exp/mts.pm	2010-12-21 21:34:08 +0000
+++ b/suites/rep_func/mts.pm	2011-01-18 23:02:07 +0000
@@ -1,4 +1,4 @@
-package rep_exp::mts;
+package rep_func::mts;
 use Exporter;
 our @ISA = qw(Exporter My::Nuts::Library::Tests::SimpleTest);
 use strict;


Attachment: [text/bzr-bundle] bzr/serge.kozlov@oracle.com-20110118230207-4ujev1ekaqonfv70.bundle
Thread
bzr commit into nuts branch (Serge.Kozlov:386) WL#5493Serge Kozlov19 Jan