diff --git a/client/mysqltest.c b/client/mysqltest.c index a81854733de..d49693fa324 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -802,7 +802,7 @@ void abort_not_supported_test(const char *fmt, ...) void abort_not_in_this_version() { - die("Not available in mysqltest for MySQL %s", VERSION); + die("Not available in this version of mysqltest"); } diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 009269f382e..bb92730444c 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -5,11 +5,14 @@ # same name. use File::Basename; +use IO::File(); use strict; sub collect_test_cases ($); sub collect_one_test_case ($$$$$$$); +sub mtr_options_from_test_file($$); + ############################################################################## # # Collect information about test cases we are to run @@ -37,12 +40,29 @@ sub collect_test_cases ($) { opendir(TESTDIR, $testdir) or mtr_error("Can't open dir \"$testdir\": $!"); + # ---------------------------------------------------------------------- + # Disable some tests listed in disabled.def + # ---------------------------------------------------------------------- + my %disabled; + if ( open(DISABLED, "$testdir/disabled.def" ) ) + { + while ( ) + { + chomp; + if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ ) + { + $disabled{$1}= $2; + } + } + close DISABLED; + } + if ( @::opt_cases ) { foreach my $tname ( @::opt_cases ) { # Run in specified order, no sort my $elem= undef; my $component_id= undef; - + # Get rid of directory part (path). Leave the extension since it is used # to understand type of the test. @@ -100,30 +120,13 @@ sub collect_test_cases ($) { } } - collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,{}, + collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%disabled, $component_id); } closedir TESTDIR; } else { - # ---------------------------------------------------------------------- - # Disable some tests listed in disabled.def - # ---------------------------------------------------------------------- - my %disabled; - if ( ! $::opt_ignore_disabled_def and open(DISABLED, "$testdir/disabled.def" ) ) - { - while ( ) - { - chomp; - if ( /^\s*([^\s:]+)\s*:\s*(.*?)\s*$/ ) - { - $disabled{$1}= $2; - } - } - close DISABLED; - } - foreach my $elem ( sort readdir(TESTDIR) ) { my $component_id= undef; my $tname= undef; @@ -247,48 +250,54 @@ sub collect_one_test_case($$$$$$$) { if ( $::opt_skip_rpl ) { $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No replication tests(--skip-rpl)"; return; } $tinfo->{'slave_num'}= 1; # Default, use one slave - # FIXME currently we always restart slaves - $tinfo->{'slave_restart'}= 1; - if ( $tname eq 'rpl_failsafe' or $tname eq 'rpl_chain_temp_table' ) { -# $tinfo->{'slave_num'}= 3; # Not 3 ? Check old code, strange + # $tinfo->{'slave_num'}= 3; # Not 3 ? Check old code, strange } } if ( defined mtr_match_prefix($tname,"federated") ) { - $tinfo->{'slave_num'}= 1; # Default, use one slave - - # FIXME currently we always restart slaves - $tinfo->{'slave_restart'}= 1; + # Default, federated uses the first slave as it's federated database + $tinfo->{'slave_num'}= 1; } - # Cluster is needed by test case if testname contains ndb - if ( defined mtr_match_substring($tname,"ndb") ) + if ( $::opt_with_ndbcluster or defined mtr_match_substring($tname,"ndb") ) { + # This is an ndb test or all tests should be run with ndb cluster started $tinfo->{'ndb_test'}= 1; if ( $::opt_skip_ndbcluster ) { - # Skip all ndb tests + # All ndb test's should be skipped $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No ndbcluster test(--skip-ndbcluster)"; return; } - if ( ! $::opt_with_ndbcluster ) + if ( ! $::opt_ndbcluster_supported ) { # Ndb is not supported, skip them $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No ndbcluster support"; return; } } else { + # This is not a ndb test $tinfo->{'ndb_test'}= 0; + if ( $::opt_with_ndbcluster_only ) + { + # Only the ndb test should be run, all other should be skipped + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Only ndbcluster tests(--with-ndbcluster-only)"; + return; + } } # FIXME what about embedded_server + ndbcluster, skip ?! @@ -380,6 +389,8 @@ sub collect_one_test_case($$$$$$$) { if ( $::glob_win32_perl ) { $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No tests with sh scripts on Windows"; + return; } else { @@ -393,6 +404,8 @@ sub collect_one_test_case($$$$$$$) { if ( $::glob_win32_perl ) { $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No tests with sh scripts on Windows"; + return; } else { @@ -411,45 +424,95 @@ sub collect_one_test_case($$$$$$$) { } # FIXME why this late? + my $marked_as_disabled= 0; if ( $disabled->{$tname} ) { - $tinfo->{'skip'}= 1; - $tinfo->{'disable'}= 1; # Sub type of 'skip' - $tinfo->{'comment'}= $disabled->{$tname} if $disabled->{$tname}; + $marked_as_disabled= 1; + $tinfo->{'comment'}= $disabled->{$tname}; } if ( -f $disabled_file ) { - $tinfo->{'skip'}= 1; - $tinfo->{'disable'}= 1; # Sub type of 'skip' + $marked_as_disabled= 1; $tinfo->{'comment'}= mtr_fromfile($disabled_file); } + # If test was marked as disabled, either opt_enable_disabled is off and then + # we skip this test, or it is on and then we run this test but warn + + if ( $marked_as_disabled ) + { + if ( $::opt_enable_disabled ) + { + $tinfo->{'dont_skip_though_disabled'}= 1; + } + else + { + $tinfo->{'skip'}= 1; + $tinfo->{'disable'}= 1; # Sub type of 'skip' + return; + } + } + if ( $component_id eq 'im' ) { if ( $::glob_use_embedded_server ) { $tinfo->{'skip'}= 1; - - mtr_report( - "Instance Manager tests are not available in embedded mode. " . - "Test case '$tname' is skipped."); + $tinfo->{'comment'}= "No IM with embedded server"; + return; } elsif ( $::opt_ps_protocol ) { $tinfo->{'skip'}= 1; - - mtr_report( - "Instance Manager tests are not run with --ps-protocol. " . - "Test case '$tname' is skipped."); + $tinfo->{'comment'}= "No IM with --ps-protocol"; + return; } elsif ( $::opt_skip_im ) { $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No IM tests(--skip-im)"; + return; + } + } + else + { + mtr_options_from_test_file($tinfo,"$testdir/${tname}.test"); - mtr_report( - "Instance Manager executable is unavailable." . - "Test case '$tname' is skipped."); + if ( $tinfo->{'big_test'} and ! $::opt_big_test ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test need 'big-test' option"; + return; + } + + if ( $tinfo->{'ndb_extra'} and ! $::opt_ndb_extra_test ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test need 'ndb_extra' option"; + return; + } + + if ( $tinfo->{'require_manager'} ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test need the _old_ manager(to be removed)"; + return; + } + + if ( defined $tinfo->{'binlog_format'} and + ! ( $tinfo->{'binlog_format'} eq $::used_binlog_format ) ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Not running with binlog format '$tinfo->{'binlog_format'}'"; + return; + } + + if ( $tinfo->{'need_debug'} && ! $::debug_compiled_binaries ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test need debug binaries"; + return; } } @@ -459,8 +522,58 @@ sub collect_one_test_case($$$$$$$) { ( $tinfo->{'master_restart'} or $tinfo->{'slave_restart'} ) ) { $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Can't restart a running server"; + return; } + } +# List of tags in the .test files that if found should set +# the specified value in "tinfo" +our @tags= +( + ["include/have_innodb.inc", "innodb_test", 1], + ["include/have_binlog_format_row.inc", "binlog_format", "row"], + ["include/have_binlog_format_statement.inc", "binlog_format", "stmt"], + ["include/big_test.inc", "big_test", 1], + ["include/have_debug.inc", "need_debug", 1], + ["include/have_ndb_extra.inc", "ndb_extra", 1], + ["require_manager", "require_manager", 1], +); + +sub mtr_options_from_test_file($$) { + my $tinfo= shift; + my $file= shift; + #mtr_verbose("$file"); + my $F= IO::File->new($file) or mtr_error("can't open file \"$file\": $!"); + + while ( my $line= <$F> ) + { + next if ( $line !~ /^--/ ); + + # Match this line against tag in "tags" array + foreach my $tag (@tags) + { + if ( index($line, $tag->[0]) >= 0 ) + { + # Tag matched, assign value to "tinfo" + $tinfo->{"$tag->[1]"}= $tag->[2]; + } + } + + # If test sources another file, open it as well + if ( $line =~ /^\-\-([[:space:]]*)source(.*)$/ ) + { + my $value= $2; + $value =~ s/^\s+//; # Remove leading space + $value =~ s/[[:space:]]+$//; # Remove ending space + + my $sourced_file= "$::glob_mysql_test_dir/$value"; + mtr_options_from_test_file($tinfo, $sourced_file); + } + + } +} + 1; diff --git a/mysql-test/lib/mtr_im.pl b/mysql-test/lib/mtr_im.pl new file mode 100644 index 00000000000..ca17516278e --- /dev/null +++ b/mysql-test/lib/mtr_im.pl @@ -0,0 +1,761 @@ +# -*- cperl -*- + +# This is a library file used by the Perl version of mysql-test-run, +# and is part of the translation of the Bourne shell script with the +# same name. + +use strict; + +# Private IM-related operations. + +sub mtr_im_kill_process ($$$$); +sub mtr_im_load_pids ($); +sub mtr_im_terminate ($); +sub mtr_im_check_alive ($); +sub mtr_im_check_main_alive ($); +sub mtr_im_check_angel_alive ($); +sub mtr_im_check_mysqlds_alive ($); +sub mtr_im_check_mysqld_alive ($); +sub mtr_im_cleanup ($); +sub mtr_im_rm_file ($); +sub mtr_im_errlog ($); +sub mtr_im_kill ($); +sub mtr_im_wait_for_connection ($$$); +sub mtr_im_wait_for_mysqld($$$); + +# Public IM-related operations. + +sub mtr_im_start ($$); +sub mtr_im_stop ($); + +############################################################################## +# +# Private operations. +# +############################################################################## + +sub mtr_im_kill_process ($$$$) { + my $pid_lst= shift; + my $signal= shift; + my $total_retries= shift; + my $timeout= shift; + + my %pids; + + foreach my $pid ( @{$pid_lst} ) + { + $pids{$pid}= 1; + } + + for ( my $cur_attempt= 1; $cur_attempt <= $total_retries; ++$cur_attempt ) + { + foreach my $pid ( keys %pids ) + { + mtr_debug("Sending $signal to $pid..."); + + kill($signal, $pid); + + unless ( kill (0, $pid) ) + { + mtr_debug("Process $pid died."); + delete $pids{$pid}; + } + } + + return if scalar keys %pids == 0; + + mtr_debug("Sleeping $timeout second(s) waiting for processes to die..."); + + sleep($timeout); + } + + mtr_debug("Process(es) " . + join(' ', keys %pids) . + " is still alive after $total_retries " . + "of sending signal $signal."); +} + +########################################################################### + +sub mtr_im_load_pids($) { + my $im= shift; + + mtr_debug("Loading PID files..."); + + # Obtain mysqld-process pids. + + my $instances = $im->{'instances'}; + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + mtr_debug("IM-guarded mysqld[$idx] PID file: '" . + $instances->[$idx]->{'path_pid'} . "'."); + + my $mysqld_pid; + + if ( -r $instances->[$idx]->{'path_pid'} ) + { + $mysqld_pid= mtr_get_pid_from_file($instances->[$idx]->{'path_pid'}); + mtr_debug("IM-guarded mysqld[$idx] PID: $mysqld_pid."); + } + else + { + $mysqld_pid= undef; + mtr_debug("IM-guarded mysqld[$idx]: no PID file."); + } + + $instances->[$idx]->{'pid'}= $mysqld_pid; + } + + # Re-read Instance Manager PIDs from the file, since during tests Instance + # Manager could have been restarted, so its PIDs could have been changed. + + # - IM-main + + mtr_debug("IM-main PID file: '$im->{path_pid}'."); + + if ( -f $im->{'path_pid'} ) + { + $im->{'pid'} = + mtr_get_pid_from_file($im->{'path_pid'}); + + mtr_debug("IM-main PID: $im->{pid}."); + } + else + { + mtr_debug("IM-main: no PID file."); + $im->{'pid'}= undef; + } + + # - IM-angel + + mtr_debug("IM-angel PID file: '$im->{path_angel_pid}'."); + + if ( -f $im->{'path_angel_pid'} ) + { + $im->{'angel_pid'} = + mtr_get_pid_from_file($im->{'path_angel_pid'}); + + mtr_debug("IM-angel PID: $im->{'angel_pid'}."); + } + else + { + mtr_debug("IM-angel: no PID file."); + $im->{'angel_pid'} = undef; + } +} + +########################################################################### + +sub mtr_im_terminate($) { + my $im= shift; + + # Load pids from pid-files. We should do it first of all, because IM deletes + # them on shutdown. + + mtr_im_load_pids($im); + + mtr_debug("Shutting Instance Manager down..."); + + # Ignoring SIGCHLD so that all children could rest in peace. + + start_reap_all(); + + # Send SIGTERM to IM-main. + + if ( defined $im->{'pid'} ) + { + mtr_debug("IM-main pid: $im->{pid}."); + mtr_debug("Stopping IM-main..."); + + mtr_im_kill_process([ $im->{'pid'} ], 'TERM', 10, 1); + } + else + { + mtr_debug("IM-main pid: n/a."); + } + + # If IM-angel was alive, wait for it to die. + + if ( defined $im->{'angel_pid'} ) + { + mtr_debug("IM-angel pid: $im->{'angel_pid'}."); + mtr_debug("Waiting for IM-angel to die..."); + + my $total_attempts= 10; + + for ( my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt ) + { + unless ( kill (0, $im->{'angel_pid'}) ) + { + mtr_debug("IM-angel died."); + last; + } + + sleep(1); + } + } + else + { + mtr_debug("IM-angel pid: n/a."); + } + + stop_reap_all(); + + # Re-load PIDs. + + mtr_im_load_pids($im); +} + +########################################################################### + +sub mtr_im_check_alive($) { + my $im= shift; + + mtr_debug("Checking whether IM-components are alive..."); + + return 1 if mtr_im_check_main_alive($im); + + return 1 if mtr_im_check_angel_alive($im); + + return 1 if mtr_im_check_mysqlds_alive($im); + + return 0; +} + +########################################################################### + +sub mtr_im_check_main_alive($) { + my $im= shift; + + # Check that the process, that we know to be IM's, is dead. + + if ( defined $im->{'pid'} ) + { + if ( kill (0, $im->{'pid'}) ) + { + mtr_debug("IM-main (PID: $im->{pid}) is alive."); + return 1; + } + else + { + mtr_debug("IM-main (PID: $im->{pid}) is dead."); + } + } + else + { + mtr_debug("No PID file for IM-main."); + } + + # Check that IM does not accept client connections. + + if ( mtr_ping_port($im->{'port'}) ) + { + mtr_debug("IM-main (port: $im->{port}) " . + "is accepting connections."); + + mtr_im_errlog("IM-main is accepting connections on port " . + "$im->{port}, but there is no " . + "process information."); + return 1; + } + else + { + mtr_debug("IM-main (port: $im->{port}) " . + "does not accept connections."); + return 0; + } +} + +########################################################################### + +sub mtr_im_check_angel_alive($) { + my $im= shift; + + # Check that the process, that we know to be the Angel, is dead. + + if ( defined $im->{'angel_pid'} ) + { + if ( kill (0, $im->{'angel_pid'}) ) + { + mtr_debug("IM-angel (PID: $im->{angel_pid}) is alive."); + return 1; + } + else + { + mtr_debug("IM-angel (PID: $im->{angel_pid}) is dead."); + return 0; + } + } + else + { + mtr_debug("No PID file for IM-angel."); + return 0; + } +} + +########################################################################### + +sub mtr_im_check_mysqlds_alive($) { + my $im= shift; + + mtr_debug("Checking for IM-guarded mysqld instances..."); + + my $instances = $im->{'instances'}; + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + mtr_debug("Checking mysqld[$idx]..."); + + return 1 + if mtr_im_check_mysqld_alive($instances->[$idx]); + } +} + +########################################################################### + +sub mtr_im_check_mysqld_alive($) { + my $mysqld_instance= shift; + + # Check that the process is dead. + + if ( defined $mysqld_instance->{'pid'} ) + { + if ( kill (0, $mysqld_instance->{'pid'}) ) + { + mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is alive."); + return 1; + } + else + { + mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is dead."); + } + } + else + { + mtr_debug("No PID file for mysqld instance."); + } + + # Check that mysqld does not accept client connections. + + if ( mtr_ping_port($mysqld_instance->{'port'}) ) + { + mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " . + "is accepting connections."); + + mtr_im_errlog("Mysqld is accepting connections on port " . + "$mysqld_instance->{port}, but there is no " . + "process information."); + return 1; + } + else + { + mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " . + "does not accept connections."); + return 0; + } +} + +########################################################################### + +sub mtr_im_cleanup($) { + my $im= shift; + + mtr_im_rm_file($im->{'path_pid'}); + mtr_im_rm_file($im->{'path_sock'}); + + mtr_im_rm_file($im->{'path_angel_pid'}); + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + mtr_im_rm_file($im->{'instances'}->[$idx]->{'path_pid'}); + mtr_im_rm_file($im->{'instances'}->[$idx]->{'path_sock'}); + } +} + +########################################################################### + +sub mtr_im_rm_file($) +{ + my $file_path= shift; + + if ( -f $file_path ) + { + mtr_debug("Removing '$file_path'..."); + + unless ( unlink($file_path) ) + { + mtr_warning("Can not remove '$file_path'.") + } + } + else + { + mtr_debug("File '$file_path' does not exist already."); + } +} + +########################################################################### + +sub mtr_im_errlog($) { + my $msg= shift; + + # Complain in error log so that a warning will be shown. + # + # TODO: unless BUG#20761 is fixed, we will print the warning to stdout, so + # that it can be seen on console and does not produce pushbuild error. + + # my $errlog= "$opt_vardir/log/mysql-test-run.pl.err"; + # + # open (ERRLOG, ">>$errlog") || + # mtr_error("Can not open error log ($errlog)"); + # + # my $ts= localtime(); + # print ERRLOG + # "Warning: [$ts] $msg\n"; + # + # close ERRLOG; + + my $ts= localtime(); + print "Warning: [$ts] $msg\n"; +} + +########################################################################### + +sub mtr_im_kill($) { + my $im= shift; + + # Re-load PIDs. That can be useful because some processes could have been + # restarted. + + mtr_im_load_pids($im); + + # Ignoring SIGCHLD so that all children could rest in peace. + + start_reap_all(); + + # Kill IM-angel first of all. + + if ( defined $im->{'angel_pid'} ) + { + mtr_debug("Killing IM-angel (PID: $im->{angel_pid})..."); + mtr_im_kill_process([ $im->{'angel_pid'} ], 'KILL', 10, 1) + } + else + { + mtr_debug("IM-angel is dead."); + } + + # Re-load PIDs again. + + mtr_im_load_pids($im); + + # Kill IM-main. + + if ( defined $im->{'pid'} ) + { + mtr_debug("Killing IM-main (PID: $im->pid})..."); + mtr_im_kill_process([ $im->{'pid'} ], 'KILL', 10, 1); + } + else + { + mtr_debug("IM-main is dead."); + } + + # Re-load PIDs again. + + mtr_im_load_pids($im); + + # Kill guarded mysqld instances. + + my @mysqld_pids; + + mtr_debug("Collecting PIDs of mysqld instances to kill..."); + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + my $pid= $im->{'instances'}->[$idx]->{'pid'}; + + unless ( defined $pid ) + { + next; + } + + mtr_debug(" - IM-guarded mysqld[$idx] PID: $pid."); + + push (@mysqld_pids, $pid); + } + + if ( scalar @mysqld_pids > 0 ) + { + mtr_debug("Killing IM-guarded mysqld instances..."); + mtr_im_kill_process(\@mysqld_pids, 'KILL', 10, 1); + } + + # That's all. + + stop_reap_all(); +} + +############################################################################## + +sub mtr_im_wait_for_connection($$$) { + my $im= shift; + my $total_attempts= shift; + my $connect_timeout= shift; + + mtr_debug("Waiting for IM on port $im->{port} " . + "to start accepting connections..."); + + for ( my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt ) + { + mtr_debug("Trying to connect to IM ($cur_attempt of $total_attempts)..."); + + if ( mtr_ping_port($im->{'port'}) ) + { + mtr_debug("IM is accepting connections " . + "on port $im->{port}."); + return 1; + } + + mtr_debug("Sleeping $connect_timeout..."); + sleep($connect_timeout); + } + + mtr_debug("IM does not accept connections " . + "on port $im->{port} after " . + ($total_attempts * $connect_timeout) . " seconds."); + + return 0; +} + +############################################################################## + +sub mtr_im_wait_for_mysqld($$$) { + my $mysqld= shift; + my $total_attempts= shift; + my $connect_timeout= shift; + + mtr_debug("Waiting for IM-guarded mysqld on port $mysqld->{port} " . + "to start accepting connections..."); + + for ( my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt ) + { + mtr_debug("Trying to connect to mysqld " . + "($cur_attempt of $total_attempts)..."); + + if ( mtr_ping_port($mysqld->{'port'}) ) + { + mtr_debug("Mysqld is accepting connections " . + "on port $mysqld->{port}."); + return 1; + } + + mtr_debug("Sleeping $connect_timeout..."); + sleep($connect_timeout); + } + + mtr_debug("Mysqld does not accept connections " . + "on port $mysqld->{port} after " . + ($total_attempts * $connect_timeout) . " seconds."); + + return 0; +} + +############################################################################## +# +# Public operations. +# +############################################################################## + +sub mtr_im_start($$) { + my $im = shift; + my $opts = shift; + + mtr_debug("Starting Instance Manager..."); + + my $args; + mtr_init_args(\$args); + mtr_add_arg($args, "--defaults-file=%s", $im->{'defaults_file'}); + + foreach my $opt ( @{$opts} ) + { + mtr_add_arg($args, $opt); + } + + $im->{'pid'} = + mtr_spawn( + $::exe_im, # path to the executable + $args, # cmd-line args + '', # stdin + $im->{'path_log'}, # stdout + $im->{'path_err'}, # stderr + '', # pid file path (not used) + { append_log_file => 1 } # append log files + ); + + unless ( $im->{'pid'} ) + { + mtr_error('Could not start Instance Manager.') + } + + # Instance Manager can be run in daemon mode. In this case, it creates + # several processes and the parent process, created by mtr_spawn(), exits just + # after start. So, we have to obtain Instance Manager PID from the PID file. + + mtr_debug("Waiting for IM to create PID file (" . + "path: '$im->{path_pid}'; " . + "timeout: $im->{start_timeout})..."); + + unless ( sleep_until_file_created($im->{'path_pid'}, + $im->{'start_timeout'}, + -1) ) # real PID is still unknown + { + mtr_debug("IM has not created PID file in $im->{start_timeout} secs."); + mtr_debug("Aborting test suite..."); + + mtr_kill_leftovers(); + + mtr_report("IM has not created PID file in $im->{start_timeout} secs."); + return 0; + } + + $im->{'pid'}= mtr_get_pid_from_file($im->{'path_pid'}); + + mtr_debug("Instance Manager started. PID: $im->{pid}."); + + # Wait until we can connect to IM. + + my $IM_CONNECT_TIMEOUT= 30; + + unless ( mtr_im_wait_for_connection($im, + $IM_CONNECT_TIMEOUT, 1) ) + { + mtr_debug("Can not connect to Instance Manager " . + "in $IM_CONNECT_TIMEOUT seconds after start."); + mtr_debug("Aborting test suite..."); + + mtr_kill_leftovers(); + + mtr_report("Can not connect to Instance Manager " . + "in $IM_CONNECT_TIMEOUT seconds after start."); + return 0; + } + + # Wait for IM to start guarded instances: + # - wait for PID files; + + mtr_debug("Waiting for guarded mysqlds instances to create PID files..."); + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + my $mysqld= $im->{'instances'}->[$idx]; + + if ( exists $mysqld->{'nonguarded'} ) + { + next; + } + + mtr_debug("Waiting for mysqld[$idx] to create PID file (" . + "path: '$mysqld->{path_pid}'; " . + "timeout: $mysqld->{start_timeout})..."); + + unless ( sleep_until_file_created($mysqld->{'path_pid'}, + $mysqld->{'start_timeout'}, + -1) ) # real PID is still unknown + { + mtr_debug("mysqld[$idx] has not created PID file in " . + "$mysqld->{start_timeout} secs."); + mtr_debug("Aborting test suite..."); + + mtr_kill_leftovers(); + + mtr_report("mysqld[$idx] has not created PID file in " . + "$mysqld->{start_timeout} secs."); + return 0; + } + + mtr_debug("PID file for mysqld[$idx] ($mysqld->{path_pid} created."); + } + + # Wait until we can connect to guarded mysqld-instances + # (in other words -- wait for IM to start guarded instances). + + mtr_debug("Waiting for guarded mysqlds to start accepting connections..."); + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + my $mysqld= $im->{'instances'}->[$idx]; + + if ( exists $mysqld->{'nonguarded'} ) + { + next; + } + + mtr_debug("Waiting for mysqld[$idx] to accept connection..."); + + unless ( mtr_im_wait_for_mysqld($mysqld, 30, 1) ) + { + mtr_debug("Can not connect to mysqld[$idx] " . + "in $IM_CONNECT_TIMEOUT seconds after start."); + mtr_debug("Aborting test suite..."); + + mtr_kill_leftovers(); + + mtr_report("Can not connect to mysqld[$idx] " . + "in $IM_CONNECT_TIMEOUT seconds after start."); + return 0; + } + + mtr_debug("mysqld[$idx] started."); + } + + mtr_debug("Instance Manager and its components are up and running."); + + return 1; +} + +############################################################################## + +sub mtr_im_stop($) { + my $im= shift; + + mtr_debug("Stopping Instance Manager..."); + + # Try graceful shutdown. + + mtr_im_terminate($im); + + # Check that all processes died. + + unless ( mtr_im_check_alive($im) ) + { + mtr_debug("Instance Manager has been stopped successfully."); + mtr_im_cleanup($im); + return 1; + } + + # Instance Manager don't want to die. We should kill it. + + mtr_im_errlog("Instance Manager did not shutdown gracefully."); + + mtr_im_kill($im); + + # Check again that all IM-related processes have been killed. + + my $im_is_alive= mtr_im_check_alive($im); + + mtr_im_cleanup($im); + + if ( $im_is_alive ) + { + mtr_debug("Can not kill Instance Manager or its children."); + return 0; + } + + mtr_debug("Instance Manager has been killed successfully."); + return 1; +} + +########################################################################### + +1; diff --git a/mysql-test/lib/mtr_io.pl b/mysql-test/lib/mtr_io.pl index bdf91212b59..8a7fc56269c 100644 --- a/mysql-test/lib/mtr_io.pl +++ b/mysql-test/lib/mtr_io.pl @@ -11,6 +11,8 @@ sub mtr_get_opts_from_file ($); sub mtr_fromfile ($); sub mtr_tofile ($@); sub mtr_tonewfile($@); +sub mtr_lastlinefromfile($); +sub mtr_appendfile_to_file ($$); ############################################################################## # @@ -139,6 +141,20 @@ sub mtr_fromfile ($) { return $text; } +sub mtr_lastlinefromfile ($) { + my $file= shift; + my $text; + + open(FILE,"<",$file) or mtr_error("can't open file \"$file\": $!"); + while (my $line= ) + { + $text= $line; + } + close FILE; + return $text; +} + + sub mtr_tofile ($@) { my $file= shift; @@ -155,5 +171,17 @@ sub mtr_tonewfile ($@) { close FILE; } +sub mtr_appendfile_to_file ($$) { + my $from_file= shift; + my $to_file= shift; + + open(TOFILE,">>",$to_file) or mtr_error("can't open file \"$to_file\": $!"); + open(FROMFILE,">>",$from_file) + or mtr_error("can't open file \"$from_file\": $!"); + print TOFILE while (); + close FROMFILE; + close TOFILE; +} + 1; diff --git a/mysql-test/lib/mtr_misc.pl b/mysql-test/lib/mtr_misc.pl index 0ab09a40b37..dd9d24ebc8e 100644 --- a/mysql-test/lib/mtr_misc.pl +++ b/mysql-test/lib/mtr_misc.pl @@ -139,6 +139,8 @@ sub mtr_copy_dir($$) { my $from_dir= shift; my $to_dir= shift; +# mtr_verbose("Copying from $from_dir to $to_dir"); + mkpath("$to_dir"); opendir(DIR, "$from_dir") or mtr_error("Can't find $from_dir$!"); diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index bf869ca91c4..5e21248790e 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -4,7 +4,6 @@ # and is part of the translation of the Bourne shell script with the # same name. -#use Carp qw(cluck); use Socket; use Errno; use strict; @@ -14,35 +13,17 @@ use POSIX 'WNOHANG'; sub mtr_run ($$$$$$;$); sub mtr_spawn ($$$$$$;$); -sub mtr_stop_mysqld_servers ($); +sub mtr_check_stop_servers ($); sub mtr_kill_leftovers (); +sub mtr_wait_blocking ($); sub mtr_record_dead_children (); +sub mtr_ndbmgm_start($$); +sub mtr_mysqladmin_start($$$); sub mtr_exit ($); sub sleep_until_file_created ($$$); sub mtr_kill_processes ($); -sub mtr_ping_mysqld_server ($); - -# Private IM-related operations. - -sub mtr_im_kill_process ($$$$); -sub mtr_im_load_pids ($); -sub mtr_im_terminate ($); -sub mtr_im_check_alive ($); -sub mtr_im_check_main_alive ($); -sub mtr_im_check_angel_alive ($); -sub mtr_im_check_mysqlds_alive ($); -sub mtr_im_check_mysqld_alive ($$); -sub mtr_im_cleanup ($); -sub mtr_im_rm_file ($); -sub mtr_im_errlog ($); -sub mtr_im_kill ($); -sub mtr_im_wait_for_connection ($$$); -sub mtr_im_wait_for_mysqld($$$); - -# Public IM-related operations. - -sub mtr_im_start ($$); -sub mtr_im_stop ($); +sub mtr_ping_with_timeout($); +sub mtr_ping_port ($); # static in C sub spawn_impl ($$$$$$$$); @@ -54,7 +35,6 @@ sub spawn_impl ($$$$$$$$); ############################################################################## # This function try to mimic the C version used in "netware/mysql_test_run.c" -# FIXME learn it to handle append mode as well, a "new" flag or a "append" sub mtr_run ($$$$$$;$) { my $path= shift; @@ -135,6 +115,9 @@ sub spawn_impl ($$$$$$$$) { print STDERR "#### ", "-" x 78, "\n"; } + mtr_error("Can't spawn with empty \"path\"") unless defined $path; + + FORK: { my $pid= fork(); @@ -167,17 +150,6 @@ sub spawn_impl ($$$$$$$$) { $SIG{INT}= 'DEFAULT'; # Parent do some stuff, we don't - if ( $::glob_cygwin_shell and $mode eq 'test' ) - { - # Programs started from mysqltest under Cygwin, are to - # execute them within Cygwin. Else simple things in test - # files like - # --system "echo 1 > file" - # will fail. - # FIXME not working :-( -# $ENV{'COMSPEC'}= "$::glob_cygwin_shell -c"; - } - my $log_file_open_mode = '>'; if ($spawn_opts and $spawn_opts->{'append_log_file'}) @@ -187,7 +159,15 @@ sub spawn_impl ($$$$$$$$) { if ( $output ) { - if ( ! open(STDOUT,$log_file_open_mode,$output) ) + if ( $::glob_win32_perl ) + { + # Don't redirect stdout on ActiveState perl since this is + # just another thread in the same process. + # Should be fixed so that the thread that is created with fork + # executes the exe in another process and wait's for it to return. + # In the meanwhile, we get all the output from mysqld's to screen + } + elsif ( ! open(STDOUT,$log_file_open_mode,$output) ) { mtr_child_error("can't redirect STDOUT to \"$output\": $!"); } @@ -239,8 +219,7 @@ sub spawn_parent_impl { { # Simple run of command, we wait for it to return my $ret_pid= waitpid($pid,0); - - if ( $ret_pid <= 0 ) + if ( $ret_pid != $pid ) { mtr_error("$path ($pid) got lost somehow"); } @@ -268,7 +247,6 @@ sub spawn_parent_impl { # Someone terminated, don't know who. Collect # status info first before $? is lost, # but not $exit_value, this is flagged from - # my $timer_name= mtr_timer_timeout($::glob_timers, $ret_pid); if ( $timer_name ) @@ -295,45 +273,22 @@ sub spawn_parent_impl { last; } - # If one of the mysqld processes died, we want to - # mark this, and kill the mysqltest process. + # One of the child processes died, unless this was expected + # mysqltest should be killed and test aborted - foreach my $idx (0..1) - { - if ( $::master->[$idx]->{'pid'} eq $ret_pid ) - { - mtr_debug("child $ret_pid was master[$idx], " . - "exit during mysqltest run"); - $::master->[$idx]->{'pid'}= 0; - last; - } - } - - foreach my $idx (0..2) - { - if ( $::slave->[$idx]->{'pid'} eq $ret_pid ) - { - mtr_debug("child $ret_pid was slave[$idx], " . - "exit during mysqltest run"); - $::slave->[$idx]->{'pid'}= 0; - last; - } - } - - mtr_debug("waitpid() catched exit of unknown child $ret_pid, " . - "exit during mysqltest run"); + check_expected_crash_and_restart($ret_pid); } if ( $ret_pid != $pid ) { # We terminated the waiting because a "mysqld" process died. # Kill the mysqltest process. - + mtr_verbose("Kill mysqltest because another process died"); kill(9,$pid); $ret_pid= waitpid($pid,0); - if ( $ret_pid == -1 ) + if ( $ret_pid != $pid ) { mtr_error("$path ($pid) got lost somehow"); } @@ -374,64 +329,101 @@ sub mtr_process_exit_status { # ############################################################################## -# We just "ping" on the ports, and if we can't do a socket connect -# we assume the server is dead. So we don't *really* know a server -# is dead, we just hope that it after letting the listen port go, -# it is dead enough for us to start a new server. +# Kill all processes(mysqld, ndbd, ndb_mgmd and im) that would conflict with +# this run +# Make sure to remove the PID file, if any. +# kill IM manager first, else it will restart the servers sub mtr_kill_leftovers () { + mtr_report("Killing Possible Leftover Processes"); mtr_debug("mtr_kill_leftovers(): started."); - mtr_im_stop($::instance_manager); + mkpath("$::opt_vardir/log"); # Needed for mysqladmin log - # Kill mysqld servers (masters and slaves) that would conflict with this - # run. Make sure to remove the PID file, if any. - # Don't touch IM-managed mysqld instances -- they should be stopped by - # mtr_im_stop(). + # Stop or kill Instance Manager and all its children. If we failed to do + # that, we can only abort -- there is nothing left to do. - mtr_debug("Collecting mysqld-instances to shutdown..."); +# mtr_error("Failed to stop Instance Manager.") +# unless mtr_im_stop($::instance_manager); - my @args; + # Start shutdown of masters and slaves. Don't touch IM-managed mysqld + # instances -- they should be stopped by mtr_im_stop(). - for ( my $idx= 0; $idx < 2; $idx++ ) + mtr_debug("Shutting down mysqld-instances..."); + + my @kill_pids; + my %admin_pids; + + foreach my $srv (@{$::master}, @{$::slave}) { - my $pidfile= $::master->[$idx]->{'path_mypid'}; - my $sockfile= $::master->[$idx]->{'path_mysock'}; - my $port= $::master->[$idx]->{'path_myport'}; + mtr_debug(" - mysqld " . + "(pid: $srv->{pid}; " . + "pid file: '$srv->{path_pid}'; " . + "socket: '$srv->{path_sock}'; ". + "port: $srv->{port})"); - push(@args,{ - pid => 0, # We don't know the PID - pidfile => $pidfile, - sockfile => $sockfile, - port => $port, - }); + my $pid= mtr_mysqladmin_start($srv, "shutdown", 70); - mtr_debug(" - Master mysqld " . - "(idx: $idx; pid: '$pidfile'; socket: '$sockfile'; port: $port)"); - $::master->[$idx]->{'pid'}= 0; # Assume we are done with it + # Save the pid of the mysqladmin process + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $srv->{'pid'}, + pidfile => $srv->{'path_pid'}, + sockfile => $srv->{'path_sock'}, + port => $srv->{'port'}, + }); + $srv->{'pid'}= 0; # Assume we are done with it } - for ( my $idx= 0; $idx < 3; $idx++ ) + if ( ! $::opt_skip_ndbcluster ) { - my $pidfile= $::slave->[$idx]->{'path_mypid'}; - my $sockfile= $::slave->[$idx]->{'path_mysock'}; - my $port= $::slave->[$idx]->{'path_myport'}; + # Start shutdown of clusters. + mtr_debug("Shutting down cluster..."); - push(@args,{ - pid => 0, # We don't know the PID - pidfile => $pidfile, - sockfile => $sockfile, - port => $port, - }); + foreach my $cluster (@{$::clusters}) + { + mtr_debug(" - cluster " . + "(pid: $cluster->{pid}; " . + "pid file: '$cluster->{path_pid})"); - mtr_debug(" - Slave mysqld " . - "(idx: $idx; pid: '$pidfile'; socket: '$sockfile'; port: $port)"); + my $pid= mtr_ndbmgm_start($cluster, "shutdown"); - $::slave->[$idx]->{'pid'}= 0; # Assume we are done with it + # Save the pid of the ndb_mgm process + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $cluster->{'pid'}, + pidfile => $cluster->{'path_pid'} + }); + + $cluster->{'pid'}= 0; # Assume we are done with it + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + mtr_debug(" - ndbd " . + "(pid: $ndbd->{pid}; " . + "pid file: '$ndbd->{path_pid})"); + + push(@kill_pids,{ + pid => $ndbd->{'pid'}, + pidfile => $ndbd->{'path_pid'}, + }); + $ndbd->{'pid'}= 0; # Assume we are done with it + } + } } - mtr_mysqladmin_shutdown(\@args, 20); + # Wait for all the admin processes to complete + mtr_wait_blocking(\%admin_pids); + + # If we trusted "mysqladmin --shutdown_timeout= ..." we could just + # terminate now, but we don't (FIXME should be debugged). + # So we try again to ping and at least wait the same amount of time + # mysqladmin would for all to die. + + mtr_ping_with_timeout(\@kill_pids); # We now have tried to terminate nice. We have waited for the listen # port to be free, but can't really tell if the mysqld process died @@ -470,14 +462,6 @@ sub mtr_kill_leftovers () { mtr_debug("Got pid: $pid from file '$pidfile'"); - # Race, could have been removed between I tested with -f - # and the unlink() below, so I better check again with -f - - if ( ! unlink($pidfile) and -f $pidfile ) - { - mtr_error("can't remove $pidfile"); - } - if ( $::glob_cygwin_perl or kill(0, $pid) ) { mtr_debug("There is process with pid $pid -- scheduling for kill."); @@ -513,7 +497,7 @@ sub mtr_kill_leftovers () { { mtr_debug("Sending SIGKILL to pids: " . join(' ', @pids)); kill(9, @pids); - mtr_debug("Sleep 1 second waiting for processes to die"); + mtr_report("Sleep 1 second waiting for processes to die"); sleep(1) # Wait one second } while ( $retries-- and kill(0, @pids) ); @@ -531,57 +515,65 @@ sub mtr_kill_leftovers () { mtr_debug("Directory for PID files ($rundir) does not exist."); } - # We may have failed everything, bug we now check again if we have + # We may have failed everything, but we now check again if we have # the listen ports free to use, and if they are free, just go for it. mtr_debug("Checking known mysqld servers..."); - foreach my $srv ( @args ) + foreach my $srv ( @kill_pids ) { - if ( mtr_ping_mysqld_server($srv->{'port'}) ) + if ( defined $srv->{'port'} and mtr_ping_port($srv->{'port'}) ) { - mtr_warning("can't kill old mysqld holding port $srv->{'port'}"); + mtr_warning("can't kill old process holding port $srv->{'port'}"); } } mtr_debug("mtr_kill_leftovers(): finished."); } -############################################################################## -# -# Shut down mysqld servers we have started from this run of this script -# -############################################################################## - -# To speed things we kill servers in parallel. The argument is a list -# of 'ports', 'pids', 'pidfiles' and 'socketfiles'. +# Check that all processes in list are killed +# The argument is a list of 'ports', 'pids', 'pidfiles' and 'socketfiles' +# for which shutdown has been started. Make sure they all get killed +# in one way or the other. +# # FIXME On Cygwin, and maybe some other platforms, $srv->{'pid'} and -# $srv->{'pidfile'} will not be the same PID. We need to try to kill +# the pid in $srv->{'pidfile'} will not be the same PID. We need to try to kill # both I think. -sub mtr_stop_mysqld_servers ($) { +sub mtr_check_stop_servers ($) { my $spec= shift; - # ---------------------------------------------------------------------- - # First try nice normal shutdown using 'mysqladmin' - # ---------------------------------------------------------------------- + # Return if no processes are defined + return if ! @$spec; - # Shutdown time must be high as slave may be in reconnect - mtr_mysqladmin_shutdown($spec, 70); + #mtr_report("mtr_check_stop_servers"); + + mtr_ping_with_timeout(\@$spec); # ---------------------------------------------------------------------- # We loop with waitpid() nonblocking to see how many of the ones we - # are to kill, actually got killed by mtr_mysqladmin_shutdown(). - # Note that we don't rely on this, the mysqld server might have stop + # are to kill, actually got killed by mysqladmin or ndb_mgm + # + # Note that we don't rely on this, the mysqld server might have stopped # listening to the port, but still be alive. But it is a start. # ---------------------------------------------------------------------- foreach my $srv ( @$spec ) { - if ( $srv->{'pid'} and (waitpid($srv->{'pid'},&WNOHANG) == $srv->{'pid'}) ) + my $ret_pid; + if ( $srv->{'pid'} ) { - $srv->{'pid'}= 0; + $ret_pid= waitpid($srv->{'pid'},&WNOHANG); + if ($ret_pid == $srv->{'pid'}) + { + mtr_verbose("Caught exit of process $ret_pid"); + $srv->{'pid'}= 0; + } + else + { + # mtr_warning("caught exit of unknown child $ret_pid"); + } } } @@ -615,13 +607,12 @@ sub mtr_stop_mysqld_servers ($) { } # ---------------------------------------------------------------------- - # If the processes where started from this script, and we had no PIDS + # If all the processes in list already have been killed, # then we don't have to do anything. # ---------------------------------------------------------------------- if ( ! keys %mysqld_pids ) { - # cluck "This is how we got here!"; return; } @@ -670,123 +661,127 @@ sub mtr_stop_mysqld_servers ($) { foreach my $file ($srv->{'pidfile'}, $srv->{'sockfile'}) { # Know it is dead so should be no race, careful anyway - if ( -f $file and ! unlink($file) and -f $file ) + if ( defined $file and -f $file and ! unlink($file) and -f $file ) { $errors++; mtr_warning("couldn't delete $file"); } } + $srv->{'pid'}= 0; } } } if ( $errors ) { - # We are in trouble, just die.... - mtr_error("we could not kill or clean up all processes"); + # There where errors killing processes + # do one last attempt to ping the servers + # and if they can't be pinged, assume they are dead + if ( ! mtr_ping_with_timeout( \@$spec ) ) + { + mtr_error("we could not kill or clean up all processes"); + } + else + { + mtr_verbose("All ports were free, continuing"); + } } } # FIXME We just assume they are all dead, for Cygwin we are not # really sure - + +} + +# Wait for all the process in the list to terminate +sub mtr_wait_blocking($) { + my $admin_pids= shift; + + + # Return if no processes defined + return if ! %$admin_pids; + + mtr_verbose("mtr_wait_blocking"); + + # Wait for all the started processes to exit + # As mysqladmin is such a simple program, we trust it to terminate itself. + # I.e. we wait blocking, and wait for them all before we go on. + foreach my $pid (keys %{$admin_pids}) + { + my $ret_pid= waitpid($pid,0); + + } +} + +# Start "mysqladmin shutdown" for a specific mysqld +sub mtr_mysqladmin_start($$$) { + my $srv= shift; + my $command= shift; + my $adm_shutdown_tmo= shift; + + my $args; + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--user=%s", $::opt_user); + mtr_add_arg($args, "--password="); + mtr_add_arg($args, "--silent"); + if ( -e $srv->{'path_sock'} ) + { + mtr_add_arg($args, "--socket=%s", $srv->{'path_sock'}); + } + if ( $srv->{'port'} ) + { + mtr_add_arg($args, "--port=%s", $srv->{'port'}); + } + if ( $srv->{'port'} and ! -e $srv->{'path_sock'} ) + { + mtr_add_arg($args, "--protocol=tcp"); # Needed if no --socket + } + mtr_add_arg($args, "--connect_timeout=5"); + + # Shutdown time must be high as slave may be in reconnect + mtr_add_arg($args, "--shutdown_timeout=$adm_shutdown_tmo"); + mtr_add_arg($args, "$command"); + my $path_mysqladmin_log= "$::opt_vardir/log/mysqladmin.log"; + my $pid= mtr_spawn($::exe_mysqladmin, $args, + "", $path_mysqladmin_log, $path_mysqladmin_log, "", + { append_log_file => 1 }); + mtr_verbose("mtr_mysqladmin_start, pid: $pid"); + return $pid; + +} + +# Start "ndb_mgm shutdown" for a specific cluster, it will +# shutdown all data nodes and leave the ndb_mgmd running +sub mtr_ndbmgm_start($$) { + my $cluster= shift; + my $command= shift; + + my $args; + + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--core"); + mtr_add_arg($args, "--try-reconnect=1"); + mtr_add_arg($args, "--ndb_connectstring=%s", $cluster->{'connect_string'}); + mtr_add_arg($args, "-e"); + mtr_add_arg($args, "$command"); + + my $pid= mtr_spawn($::exe_ndb_mgm, $args, + "", "/dev/null", "/dev/null", "", + {}); + mtr_verbose("mtr_ndbmgm_start, pid: $pid"); + return $pid; + } -############################################################################## -# -# Shut down mysqld servers using "mysqladmin ... shutdown". -# To speed this up, we start them in parallel and use waitpid() to -# catch their termination. Note that this doesn't say the servers -# are terminated, just that 'mysqladmin' is terminated. -# -# Note that mysqladmin will ask the server about what PID file it uses, -# and mysqladmin will wait for it to be removed before it terminates -# (unless passes timeout). -# -# This function will take at most about 20 seconds, and we still are not -# sure we killed them all. If none is responding to ping, we return 1, -# else we return 0. -# -############################################################################## - -sub mtr_mysqladmin_shutdown { +# Ping all servers in list, exit when none of them answers +# or when timeout has passed +sub mtr_ping_with_timeout($) { my $spec= shift; - my $adm_shutdown_tmo= shift; - - my %mysql_admin_pids; - my @to_kill_specs; - - mtr_debug("mtr_mysqladmin_shutdown(): starting..."); - mtr_debug("Collecting mysqld-instances to shutdown..."); - - foreach my $srv ( @$spec ) - { - if ( mtr_ping_mysqld_server($srv->{'port'}) ) - { - mtr_debug("Mysqld (port: $srv->{port}) needs to be stopped."); - - push(@to_kill_specs, $srv); - } - } - - - foreach my $srv ( @to_kill_specs ) - { - # Shutdown time must be high as slave may be in reconnect - my $args; - - mtr_init_args(\$args); - - mtr_add_arg($args, "--no-defaults"); - mtr_add_arg($args, "--user=%s", $::opt_user); - mtr_add_arg($args, "--password="); - if ( -e $srv->{'sockfile'} ) - { - mtr_add_arg($args, "--socket=%s", $srv->{'sockfile'}); - } - if ( $srv->{'port'} ) - { - mtr_add_arg($args, "--port=%s", $srv->{'port'}); - } - if ( $srv->{'port'} and ! -e $srv->{'sockfile'} ) - { - mtr_add_arg($args, "--protocol=tcp"); # Needed if no --socket - } - mtr_add_arg($args, "--connect_timeout=5"); - mtr_add_arg($args, "--shutdown_timeout=$adm_shutdown_tmo"); - mtr_add_arg($args, "shutdown"); - - mtr_debug("Shutting down mysqld " . - "(port: $srv->{port}; socket: '$srv->{sockfile}')..."); - - my $path_mysqladmin_log= "$::opt_vardir/log/mysqladmin.log"; - my $pid= mtr_spawn($::exe_mysqladmin, $args, - "", $path_mysqladmin_log, $path_mysqladmin_log, "", - { append_log_file => 1 }); - $mysql_admin_pids{$pid}= 1; - - # We don't wait for termination of mysqladmin - } - - # As mysqladmin is such a simple program, we trust it to terminate. - # I.e. we wait blocking, and wait wait for them all before we go on. - while (keys %mysql_admin_pids) - { - foreach my $pid (keys %mysql_admin_pids) - { - if ( waitpid($pid,0) > 0 ) - { - delete $mysql_admin_pids{$pid}; - } - } - } - - # If we trusted "mysqladmin --shutdown_timeout= ..." we could just - # terminate now, but we don't (FIXME should be debugged). - # So we try again to ping and at least wait the same amount of time - # mysqladmin would for all to die. - - my $timeout= 20; # 20 seconds max + my $timeout= 200; # 20 seconds max my $res= 1; # If we just fall through, we are done # in the sense that the servers don't # listen to their ports any longer @@ -796,16 +791,25 @@ sub mtr_mysqladmin_shutdown { TIME: while ( $timeout-- ) { - foreach my $srv ( @to_kill_specs ) + foreach my $srv ( @$spec ) { $res= 1; # We are optimistic - if ( mtr_ping_mysqld_server($srv->{'port'}) ) + if ( $srv->{'pid'} and defined $srv->{'port'} ) { - mtr_debug("Mysqld (port: $srv->{port}) is still alive."); - mtr_debug("Sleep 1 second waiting for processes to stop using port"); - sleep(1); # One second - $res= 0; - next TIME; + if ( mtr_ping_port($srv->{'port'}) ) + { + mtr_verbose("waiting for process $srv->{'pid'} to stop ". + "using port $srv->{'port'}"); + + # Millisceond sleep emulated with select + select(undef, undef, undef, (0.1)); + $res= 0; + next TIME; + } + else + { + # Process was not using port + } } } last; # If we got here, we are done @@ -813,16 +817,134 @@ sub mtr_mysqladmin_shutdown { if ($res) { - mtr_debug("mtr_mysqladmin_shutdown(): All mysqld instances are down."); + mtr_debug("mtr_ping_with_timeout(): All mysqld instances are down."); } else { - mtr_debug("mtr_mysqladmin_shutdown(): At least one server is alive."); + mtr_report("mtr_ping_with_timeout(): At least one server is alive."); } return $res; } + +# +# Loop through our list of processes and look for and entry +# with the provided pid +# Set the pid of that process to 0 if found +# +sub mark_process_dead($) +{ + my $ret_pid= shift; + + foreach my $mysqld (@{$::master}, @{$::slave}) + { + if ( $mysqld->{'pid'} eq $ret_pid ) + { + mtr_verbose("$mysqld->{'type'} $mysqld->{'idx'} exited, pid: $ret_pid"); + $mysqld->{'pid'}= 0; + return; + } + } + + foreach my $cluster (@{$::clusters}) + { + if ( $cluster->{'pid'} eq $ret_pid ) + { + mtr_verbose("$cluster->{'name'} cluster ndb_mgmd exited, pid: $ret_pid"); + $cluster->{'pid'}= 0; + return; + } + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + if ( $ndbd->{'pid'} eq $ret_pid ) + { + mtr_verbose("$cluster->{'name'} cluster ndbd exited, pid: $ret_pid"); + $ndbd->{'pid'}= 0; + return; + } + } + } + mtr_warning("mark_process_dead couldn't find an entry for pid: $ret_pid"); + +} + +# +# Loop through our list of processes and look for and entry +# with the provided pid, if found check for the file indicating +# expected crash and restart it. +# +sub check_expected_crash_and_restart($) +{ + my $ret_pid= shift; + + foreach my $mysqld (@{$::master}, @{$::slave}) + { + if ( $mysqld->{'pid'} eq $ret_pid ) + { + mtr_verbose("$mysqld->{'type'} $mysqld->{'idx'} exited, pid: $ret_pid"); + $mysqld->{'pid'}= 0; + + # Check if crash expected and restart if it was + my $expect_file= "$::opt_vardir/tmp/" . "$mysqld->{'type'}" . + "$mysqld->{'idx'}" . ".expect"; + if ( -f $expect_file ) + { + mtr_verbose("Crash was expected, file $expect_file exists"); + mysqld_start($mysqld, $mysqld->{'start_opts'}, + $mysqld->{'start_slave_master_info'}); + unlink($expect_file); + } + + return; + } + } + + foreach my $cluster (@{$::clusters}) + { + if ( $cluster->{'pid'} eq $ret_pid ) + { + mtr_verbose("$cluster->{'name'} cluster ndb_mgmd exited, pid: $ret_pid"); + $cluster->{'pid'}= 0; + + # Check if crash expected and restart if it was + my $expect_file= "$::opt_vardir/tmp/ndb_mgmd_" . "$cluster->{'type'}" . + ".expect"; + if ( -f $expect_file ) + { + mtr_verbose("Crash was expected, file $expect_file exists"); + ndbmgmd_start($cluster); + unlink($expect_file); + } + return; + } + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + if ( $ndbd->{'pid'} eq $ret_pid ) + { + mtr_verbose("$cluster->{'name'} cluster ndbd exited, pid: $ret_pid"); + $ndbd->{'pid'}= 0; + + # Check if crash expected and restart if it was + my $expect_file= "$::opt_vardir/tmp/ndbd_" . "$cluster->{'type'}" . + "$ndbd->{'idx'}" . ".expect"; + if ( -f $expect_file ) + { + mtr_verbose("Crash was expected, file $expect_file exists"); + ndbd_start($cluster, $ndbd->{'idx'}, + $ndbd->{'start_extra_args'}); + unlink($expect_file); + } + return; + } + } + } + mtr_warning("check_expected_crash_and_restart couldn't find an entry for pid: $ret_pid"); + +} + ############################################################################## # # The operating system will keep information about dead children, @@ -833,32 +955,18 @@ sub mtr_mysqladmin_shutdown { sub mtr_record_dead_children () { + my $process_died= 0; my $ret_pid; - # FIXME the man page says to wait for -1 to terminate, - # but on OS X we get '0' all the time... - while ( ($ret_pid= waitpid(-1,&WNOHANG)) > 0 ) + # Wait without blockinng to see if any processes had died + # -1 or 0 means there are no more procesess to wait for + while ( ($ret_pid= waitpid(-1,&WNOHANG)) != 0 and $ret_pid != -1) { - mtr_debug("waitpid() catched exit of child $ret_pid"); - foreach my $idx (0..1) - { - if ( $::master->[$idx]->{'pid'} eq $ret_pid ) - { - mtr_debug("child $ret_pid was master[$idx]"); - $::master->[$idx]->{'pid'}= 0; - } - } - - foreach my $idx (0..2) - { - if ( $::slave->[$idx]->{'pid'} eq $ret_pid ) - { - mtr_debug("child $ret_pid was slave[$idx]"); - $::slave->[$idx]->{'pid'}= 0; - last; - } - } + mtr_warning("mtr_record_dead_children: $ret_pid"); + mark_process_dead($ret_pid); + $process_died= 1; } + return $process_died; } sub start_reap_all { @@ -870,16 +978,24 @@ sub start_reap_all { # here. If a process terminated before setting $SIG{CHLD} (but after # any attempt to waitpid() it), it will still be a zombie. So we # have to handle any such process here. - while(waitpid(-1, &WNOHANG) > 0) { }; + my $pid; + while(($pid= waitpid(-1, &WNOHANG)) != 0 and $pid != -1) + { + mtr_warning("start_reap_all pid: $pid"); + mark_process_dead($pid); + }; } sub stop_reap_all { $SIG{CHLD}= 'DEFAULT'; } -sub mtr_ping_mysqld_server ($) { + +sub mtr_ping_port ($) { my $port= shift; + mtr_verbose("mtr_ping_port: $port"); + my $remote= "localhost"; my $iaddr= inet_aton($remote); if ( ! $iaddr ) @@ -897,13 +1013,13 @@ sub mtr_ping_mysqld_server ($) { if ( connect(SOCK, $paddr) ) { - mtr_debug("Server (port: $port) is alive."); close(SOCK); # FIXME check error? + mtr_verbose("USED"); return 1; } else { - mtr_debug("Server (port: $port) is dead."); + mtr_verbose("FREE"); return 0; } } @@ -933,15 +1049,15 @@ sub sleep_until_file_created ($$$) { # Check if it died after the fork() was successful if ( $pid != 0 && waitpid($pid,&WNOHANG) == $pid ) { + mtr_warning("Process $pid died"); return 0; } - mtr_debug("Sleep $sleeptime milliseconds waiting for ". - "creation of $pidfile"); + mtr_debug("Sleep $sleeptime milliseconds waiting for $pidfile"); # Print extra message every 60 seconds my $seconds= ($loop * $sleeptime) / 1000; - if ( $seconds > 1 and $seconds % 60 == 0 ) + if ( $seconds > 1 and int($seconds) % 60 == 0 ) { my $left= $timeout - $seconds; mtr_warning("Waited $seconds seconds for $pidfile to be created, " . @@ -959,20 +1075,18 @@ sub sleep_until_file_created ($$$) { sub mtr_kill_processes ($) { my $pids = shift; - foreach my $sig (15, 9) - { - my $retries= 10; - while (1) - { - kill($sig, @{$pids}); - last unless kill (0, @{$pids}) and $retries--; + mtr_verbose("mtr_kill_processes " . join(" ", @$pids)); - mtr_debug("Sleep 2 second waiting for processes to die"); - sleep(2); + foreach my $pid (@$pids) + { + foreach my $sig (15, 9) + { + last if mtr_im_kill_process([ $pid ], $sig, 10, 1); } } } + ############################################################################## # # When we exit, we kill off all children @@ -982,7 +1096,7 @@ sub mtr_kill_processes ($) { # FIXME something is wrong, we sometimes terminate with "Hangup" written # to tty, and no STDERR output telling us why. -# FIXME for some readon, setting HUP to 'IGNORE' will cause exit() to +# FIXME for some reason, setting HUP to 'IGNORE' will cause exit() to # write out "Hangup", and maybe loose some output. We insert a sleep... sub mtr_exit ($) { @@ -997,681 +1111,11 @@ sub mtr_exit ($) { # set ourselves as the group leader at startup (with # POSIX::setpgrp(0,0)), but then care must be needed to always do # proper child process cleanup. - kill('HUP', -$$) if $$ == getpgrp(); - sleep 2; + kill('HUP', -$$) if !$::glob_win32_perl and $$ == getpgrp(); + exit($code); } -############################################################################## -# -# Instance Manager management routines. -# -############################################################################## - -sub mtr_im_kill_process ($$$$) { - my $pid_lst= shift; - my $signal= shift; - my $total_retries= shift; - my $timeout= shift; - - my %pids; - - foreach my $pid (@{$pid_lst}) - { - $pids{$pid}= 1; - } - - for (my $cur_attempt= 1; $cur_attempt <= $total_retries; ++$cur_attempt) - { - foreach my $pid (keys %pids) - { - mtr_debug("Sending $signal to $pid..."); - - kill($signal, $pid); - - unless (kill (0, $pid)) - { - mtr_debug("Process $pid died."); - delete $pids{$pid}; - } - } - - return if scalar keys %pids == 0; - - mtr_debug("Sleeping $timeout second(s) waiting for processes to die..."); - - sleep($timeout); - } - - mtr_debug("Process(es) " . - join(' ', keys %pids) . - " is still alive after $total_retries " . - "of sending signal $signal."); -} - -########################################################################### - -sub mtr_im_load_pids($) { - my $instance_manager= shift; - - mtr_debug("Loading PID files..."); - - # Obtain mysqld-process pids. - - my $instances = $instance_manager->{'instances'}; - - for (my $idx= 0; $idx < 2; ++$idx) - { - mtr_debug("IM-guarded mysqld[$idx] PID file: '" . - $instances->[$idx]->{'path_pid'} . "'."); - - my $mysqld_pid; - - if (-r $instances->[$idx]->{'path_pid'}) - { - $mysqld_pid= mtr_get_pid_from_file($instances->[$idx]->{'path_pid'}); - mtr_debug("IM-guarded mysqld[$idx] PID: $mysqld_pid."); - } - else - { - $mysqld_pid= undef; - mtr_debug("IM-guarded mysqld[$idx]: no PID file."); - } - - $instances->[$idx]->{'pid'}= $mysqld_pid; - } - - # Re-read Instance Manager PIDs from the file, since during tests Instance - # Manager could have been restarted, so its PIDs could have been changed. - - # - IM-main - - mtr_debug("IM-main PID file: '$instance_manager->{path_pid}'."); - - if (-f $instance_manager->{'path_pid'}) - { - $instance_manager->{'pid'} = - mtr_get_pid_from_file($instance_manager->{'path_pid'}); - - mtr_debug("IM-main PID: $instance_manager->{pid}."); - } - else - { - mtr_debug("IM-main: no PID file."); - $instance_manager->{'pid'}= undef; - } - - # - IM-angel - - mtr_debug("IM-angel PID file: '$instance_manager->{path_angel_pid}'."); - - if (-f $instance_manager->{'path_angel_pid'}) - { - $instance_manager->{'angel_pid'} = - mtr_get_pid_from_file($instance_manager->{'path_angel_pid'}); - - mtr_debug("IM-angel PID: $instance_manager->{'angel_pid'}."); - } - else - { - mtr_debug("IM-angel: no PID file."); - $instance_manager->{'angel_pid'} = undef; - } -} - -########################################################################### - -sub mtr_im_terminate($) { - my $instance_manager= shift; - - # Load pids from pid-files. We should do it first of all, because IM deletes - # them on shutdown. - - mtr_im_load_pids($instance_manager); - - mtr_debug("Shutting Instance Manager down..."); - - # Ignoring SIGCHLD so that all children could rest in peace. - - start_reap_all(); - - # Send SIGTERM to IM-main. - - if (defined $instance_manager->{'pid'}) - { - mtr_debug("IM-main pid: $instance_manager->{pid}."); - mtr_debug("Stopping IM-main..."); - - mtr_im_kill_process([ $instance_manager->{'pid'} ], 'TERM', 10, 1); - } - else - { - mtr_debug("IM-main pid: n/a."); - } - - # If IM-angel was alive, wait for it to die. - - if (defined $instance_manager->{'angel_pid'}) - { - mtr_debug("IM-angel pid: $instance_manager->{'angel_pid'}."); - mtr_debug("Waiting for IM-angel to die..."); - - my $total_attempts= 10; - - for (my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt) - { - unless (kill (0, $instance_manager->{'angel_pid'})) - { - mtr_debug("IM-angel died."); - last; - } - - sleep(1); - } - } - else - { - mtr_debug("IM-angel pid: n/a."); - } - - stop_reap_all(); - - # Re-load PIDs. - - mtr_im_load_pids($instance_manager); -} - -########################################################################### - -sub mtr_im_check_alive($) { - my $instance_manager= shift; - - mtr_debug("Checking whether IM-components are alive..."); - - return 1 if mtr_im_check_main_alive($instance_manager); - - return 1 if mtr_im_check_angel_alive($instance_manager); - - return 1 if mtr_im_check_mysqlds_alive($instance_manager); - - return 0; -} - -########################################################################### - -sub mtr_im_check_main_alive($) { - my $instance_manager= shift; - - # Check that the process, that we know to be IM's, is dead. - - if (defined $instance_manager->{'pid'}) - { - if (kill (0, $instance_manager->{'pid'})) - { - mtr_debug("IM-main (PID: $instance_manager->{pid}) is alive."); - return 1; - } - else - { - mtr_debug("IM-main (PID: $instance_manager->{pid}) is dead."); - } - } - else - { - mtr_debug("No PID file for IM-main."); - } - - # Check that IM does not accept client connections. - - if (mtr_ping_mysqld_server($instance_manager->{'port'})) - { - mtr_debug("IM-main (port: $instance_manager->{port}) " . - "is accepting connections."); - - mtr_im_errlog("IM-main is accepting connections on port " . - "$instance_manager->{port}, but there is no " . - "process information."); - return 1; - } - else - { - mtr_debug("IM-main (port: $instance_manager->{port}) " . - "does not accept connections."); - return 0; - } -} - -########################################################################### - -sub mtr_im_check_angel_alive($) { - my $instance_manager= shift; - - # Check that the process, that we know to be the Angel, is dead. - - if (defined $instance_manager->{'angel_pid'}) - { - if (kill (0, $instance_manager->{'angel_pid'})) - { - mtr_debug("IM-angel (PID: $instance_manager->{angel_pid}) is alive."); - return 1; - } - else - { - mtr_debug("IM-angel (PID: $instance_manager->{angel_pid}) is dead."); - return 0; - } - } - else - { - mtr_debug("No PID file for IM-angel."); - return 0; - } -} - -########################################################################### - -sub mtr_im_check_mysqlds_alive($) { - my $instance_manager= shift; - - mtr_debug("Checking for IM-guarded mysqld instances..."); - - my $instances = $instance_manager->{'instances'}; - - for (my $idx= 0; $idx < 2; ++$idx) - { - mtr_debug("Checking mysqld[$idx]..."); - - return 1 - if mtr_im_check_mysqld_alive($instance_manager, $instances->[$idx]); - } -} - -########################################################################### - -sub mtr_im_check_mysqld_alive($$) { - my $instance_manager= shift; - my $mysqld_instance= shift; - - # Check that the process is dead. - - if (defined $instance_manager->{'pid'}) - { - if (kill (0, $instance_manager->{'pid'})) - { - mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is alive."); - return 1; - } - else - { - mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is dead."); - } - } - else - { - mtr_debug("No PID file for mysqld instance."); - } - - # Check that mysqld does not accept client connections. - - if (mtr_ping_mysqld_server($mysqld_instance->{'port'})) - { - mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " . - "is accepting connections."); - - mtr_im_errlog("Mysqld is accepting connections on port " . - "$mysqld_instance->{port}, but there is no " . - "process information."); - return 1; - } - else - { - mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " . - "does not accept connections."); - return 0; - } -} - -########################################################################### - -sub mtr_im_cleanup($) { - my $instance_manager= shift; - - mtr_im_rm_file($instance_manager->{'path_pid'}); - mtr_im_rm_file($instance_manager->{'path_sock'}); - - mtr_im_rm_file($instance_manager->{'path_angel_pid'}); - - for (my $idx= 0; $idx < 2; ++$idx) - { - mtr_im_rm_file($instance_manager->{'instances'}->[$idx]->{'path_pid'}); - mtr_im_rm_file($instance_manager->{'instances'}->[$idx]->{'path_sock'}); - } -} - -########################################################################### - -sub mtr_im_rm_file($) -{ - my $file_path= shift; - - if (-f $file_path) - { - mtr_debug("Removing '$file_path'..."); - - mtr_warning("Can not remove '$file_path'.") - unless unlink($file_path); - } - else - { - mtr_debug("File '$file_path' does not exist already."); - } -} - -########################################################################### - -sub mtr_im_errlog($) { - my $msg= shift; - - # Complain in error log so that a warning will be shown. - # - # TODO: unless BUG#20761 is fixed, we will print the warning to stdout, so - # that it can be seen on console and does not produce pushbuild error. - - # my $errlog= "$opt_vardir/log/mysql-test-run.pl.err"; - # - # open (ERRLOG, ">>$errlog") || - # mtr_error("Can not open error log ($errlog)"); - # - # my $ts= localtime(); - # print ERRLOG - # "Warning: [$ts] $msg\n"; - # - # close ERRLOG; - - my $ts= localtime(); - print "Warning: [$ts] $msg\n"; -} - -########################################################################### - -sub mtr_im_kill($) { - my $instance_manager= shift; - - # Re-load PIDs. That can be useful because some processes could have been - # restarted. - - mtr_im_load_pids($instance_manager); - - # Ignoring SIGCHLD so that all children could rest in peace. - - start_reap_all(); - - # Kill IM-angel first of all. - - if (defined $instance_manager->{'angel_pid'}) - { - mtr_debug("Killing IM-angel (PID: $instance_manager->{angel_pid})..."); - mtr_im_kill_process([ $instance_manager->{'angel_pid'} ], 'KILL', 10, 1) - } - else - { - mtr_debug("IM-angel is dead."); - } - - # Re-load PIDs again. - - mtr_im_load_pids($instance_manager); - - # Kill IM-main. - - if (defined $instance_manager->{'pid'}) - { - mtr_debug("Killing IM-main (PID: $instance_manager->pid})..."); - mtr_im_kill_process([ $instance_manager->{'pid'} ], 'KILL', 10, 1); - } - else - { - mtr_debug("IM-main is dead."); - } - - # Re-load PIDs again. - - mtr_im_load_pids($instance_manager); - - # Kill guarded mysqld instances. - - my @mysqld_pids; - - mtr_debug("Collecting PIDs of mysqld instances to kill..."); - - for (my $idx= 0; $idx < 2; ++$idx) - { - my $pid= $instance_manager->{'instances'}->[$idx]->{'pid'}; - - next unless defined $pid; - - mtr_debug(" - IM-guarded mysqld[$idx] PID: $pid."); - - push (@mysqld_pids, $pid); - } - - if (scalar @mysqld_pids > 0) - { - mtr_debug("Killing IM-guarded mysqld instances..."); - mtr_im_kill_process(\@mysqld_pids, 'KILL', 10, 1); - } - - # That's all. - - stop_reap_all(); -} - -############################################################################## - -sub mtr_im_wait_for_connection($$$) { - my $instance_manager= shift; - my $total_attempts= shift; - my $connect_timeout= shift; - - mtr_debug("Waiting for IM on port $instance_manager->{port} " . - "to start accepting connections..."); - - for (my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt) - { - mtr_debug("Trying to connect to IM ($cur_attempt of $total_attempts)..."); - - if (mtr_ping_mysqld_server($instance_manager->{'port'})) - { - mtr_debug("IM is accepting connections " . - "on port $instance_manager->{port}."); - return 1; - } - - mtr_debug("Sleeping $connect_timeout..."); - sleep($connect_timeout); - } - - mtr_debug("IM does not accept connections " . - "on port $instance_manager->{port} after " . - ($total_attempts * $connect_timeout) . " seconds."); - - return 0; -} - -############################################################################## - -sub mtr_im_wait_for_mysqld($$$) { - my $mysqld= shift; - my $total_attempts= shift; - my $connect_timeout= shift; - - mtr_debug("Waiting for IM-guarded mysqld on port $mysqld->{port} " . - "to start accepting connections..."); - - for (my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt) - { - mtr_debug("Trying to connect to mysqld " . - "($cur_attempt of $total_attempts)..."); - - if (mtr_ping_mysqld_server($mysqld->{'port'})) - { - mtr_debug("Mysqld is accepting connections " . - "on port $mysqld->{port}."); - return 1; - } - - mtr_debug("Sleeping $connect_timeout..."); - sleep($connect_timeout); - } - - mtr_debug("Mysqld does not accept connections " . - "on port $mysqld->{port} after " . - ($total_attempts * $connect_timeout) . " seconds."); - - return 0; -} - -############################################################################## - -sub mtr_im_start($$) { - my $instance_manager = shift; - my $opts = shift; - - mtr_debug("Starting Instance Manager..."); - - my $args; - mtr_init_args(\$args); - mtr_add_arg($args, "--defaults-file=%s", - $instance_manager->{'defaults_file'}); - - foreach my $opt (@{$opts}) - { - mtr_add_arg($args, $opt); - } - - $instance_manager->{'pid'} = - mtr_spawn( - $::exe_im, # path to the executable - $args, # cmd-line args - '', # stdin - $instance_manager->{'path_log'}, # stdout - $instance_manager->{'path_err'}, # stderr - '', # pid file path (not used) - { append_log_file => 1 } # append log files - ); - - if ( ! $instance_manager->{'pid'} ) - { - mtr_report('Could not start Instance Manager'); - return; - } - - # Instance Manager can be run in daemon mode. In this case, it creates - # several processes and the parent process, created by mtr_spawn(), exits just - # after start. So, we have to obtain Instance Manager PID from the PID file. - - if ( ! sleep_until_file_created( - $instance_manager->{'path_pid'}, - $instance_manager->{'start_timeout'}, - -1)) # real PID is still unknown - { - mtr_report("Instance Manager PID file is missing"); - return; - } - - $instance_manager->{'pid'} = - mtr_get_pid_from_file($instance_manager->{'path_pid'}); - - mtr_debug("Instance Manager started. PID: $instance_manager->{pid}."); - - # Wait until we can connect to IM. - - my $IM_CONNECT_TIMEOUT= 30; - - unless (mtr_im_wait_for_connection($instance_manager, - $IM_CONNECT_TIMEOUT, 1)) - { - mtr_debug("Can not connect to Instance Manager " . - "in $IM_CONNECT_TIMEOUT seconds after start."); - mtr_debug("Aborting test suite..."); - - mtr_kill_leftovers(); - - mtr_error("Can not connect to Instance Manager " . - "in $IM_CONNECT_TIMEOUT seconds after start."); - } - - # Wait until we can connect to guarded mysqld-instances - # (in other words -- wait for IM to start guarded instances). - - for (my $idx= 0; $idx < 2; ++$idx) - { - my $mysqld= $instance_manager->{'instances'}->[$idx]; - - next if exists $mysqld->{'nonguarded'}; - - mtr_debug("Waiting for mysqld[$idx] to start..."); - - unless (mtr_im_wait_for_mysqld($mysqld, 30, 1)) - { - mtr_debug("Can not connect to mysqld[$idx] " . - "in $IM_CONNECT_TIMEOUT seconds after start."); - mtr_debug("Aborting test suite..."); - - mtr_kill_leftovers(); - - mtr_error("Can not connect to mysqld[$idx] " . - "in $IM_CONNECT_TIMEOUT seconds after start."); - } - - mtr_debug("mysqld[$idx] started."); - } - - mtr_debug("Instance Manager started."); -} - -############################################################################## - -sub mtr_im_stop($) { - my $instance_manager= shift; - - mtr_debug("Stopping Instance Manager..."); - - # Try graceful shutdown. - - mtr_im_terminate($instance_manager); - - # Check that all processes died. - - unless (mtr_im_check_alive($instance_manager)) - { - mtr_debug("Instance Manager has been stopped successfully."); - mtr_im_cleanup($instance_manager); - return 1; - } - - # Instance Manager don't want to die. We should kill it. - - mtr_im_errlog("Instance Manager did not shutdown gracefully."); - - mtr_im_kill($instance_manager); - - # Check again that all IM-related processes have been killed. - - my $im_is_alive= mtr_im_check_alive($instance_manager); - - mtr_im_cleanup($instance_manager); - - if ($im_is_alive) - { - mtr_error("Can not kill Instance Manager or its children."); - return 0; - } - - mtr_debug("Instance Manager has been killed successfully."); - return 1; -} - ########################################################################### 1; diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 69d19709d16..6e3796133f2 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -10,6 +10,7 @@ sub mtr_report_test_name($); sub mtr_report_test_passed($); sub mtr_report_test_failed($); sub mtr_report_test_skipped($); +sub mtr_report_test_not_skipped_though_disabled($); sub mtr_show_failed_diff ($); sub mtr_report_stats ($); @@ -21,6 +22,7 @@ sub mtr_warning (@); sub mtr_error (@); sub mtr_child_error (@); sub mtr_debug (@); +sub mtr_verbose (@); ############################################################################## @@ -96,7 +98,24 @@ sub mtr_report_test_skipped ($) { } else { - print "[ skipped ]\n"; + print "[ skipped ] $tinfo->{'comment'}\n"; + } +} + +sub mtr_report_tests_not_skipped_though_disabled ($) { + my $tests= shift; + + if ( $::opt_enable_disabled ) + { + my @disabled_tests= grep {$_->{'dont_skip_though_disabled'}} @$tests; + if ( @disabled_tests ) + { + print "\nTest(s) which will be run though they are marked as disabled:\n"; + foreach my $tinfo ( sort {$a->{'name'} cmp $b->{'name'}} @disabled_tests ) + { + printf " %-20s : %s\n", $tinfo->{'name'}, $tinfo->{'comment'}; + } + } } } @@ -107,7 +126,7 @@ sub mtr_report_test_passed ($) { if ( $::opt_timer and -f "$::opt_vardir/log/timer" ) { $timer= mtr_fromfile("$::opt_vardir/log/timer"); - $::glob_tot_real_time += $timer; + $::glob_tot_real_time += ($timer/1000); $timer= sprintf "%12s", $timer; } $tinfo->{'result'}= 'MTR_RES_PASSED'; @@ -122,7 +141,7 @@ sub mtr_report_test_failed ($) { { print "[ fail ] timeout\n"; } - elsif ( $tinfo->{'ndb_test'} and !$::flag_ndb_status_ok) + elsif ( $tinfo->{'ndb_test'} and $::cluster->[0]->{'installed_ok'} eq "NO") { print "[ fail ] ndbcluster start failure\n"; return; @@ -157,6 +176,7 @@ sub mtr_report_stats ($) { my $tot_passed= 0; my $tot_failed= 0; my $tot_tests= 0; + my $tot_restarts= 0; my $found_problems= 0; # Some warnings are errors... foreach my $tinfo (@$tests) @@ -175,6 +195,10 @@ sub mtr_report_stats ($) { $tot_tests++; $tot_failed++; } + if ( $tinfo->{'restarted'} ) + { + $tot_restarts++; + } } # ---------------------------------------------------------------------- @@ -197,6 +221,14 @@ sub mtr_report_stats ($) { "the documentation at\n", "http://www.mysql.com/doc/en/MySQL_test_suite.html\n"; } + print + "The servers were restarted $tot_restarts times\n"; + + if ( $::opt_timer ) + { + print + "Spent $::glob_tot_real_time seconds actually executing testcases\n" + } # ---------------------------------------------------------------------- # If a debug run, there might be interesting information inside @@ -216,7 +248,10 @@ sub mtr_report_stats ($) { else { # We report different types of problems in order - foreach my $pattern ( "^Warning:", "^Error:", "^==.* at 0x" ) + foreach my $pattern ( "^Warning:", "^Error:", "^==.* at 0x", + "InnoDB: Warning", "missing DBUG_RETURN", + "mysqld: Warning", + "Attempting backtrace", "Assertion .* failed" ) { foreach my $errlog ( sort glob("$::opt_vardir/log/*.err") ) { @@ -230,7 +265,8 @@ sub mtr_report_stats ($) { # Skip some non fatal warnings from the log files if ( /Warning:\s+Table:.* on (delete|rename)/ or /Warning:\s+Setting lower_case_table_names=2/ or - /Warning:\s+One can only use the --user.*root/ ) + /Warning:\s+One can only use the --user.*root/ or + /InnoDB: Warning: we did not need to do crash recovery/) { next; # Skip these lines } @@ -241,11 +277,11 @@ sub mtr_report_stats ($) { } } } - if ( $found_problems ) - { - mtr_warning("Got errors/warnings while running tests, please examine", - "\"$warnlog\" for details."); - } + } + if ( $found_problems ) + { + mtr_warning("Got errors/warnings while running tests, please examine", + "\"$warnlog\" for details."); } } } @@ -331,5 +367,11 @@ sub mtr_debug (@) { print STDERR "####: ",join(" ", @_),"\n"; } } +sub mtr_verbose (@) { + if ( $::opt_verbose ) + { + print STDERR "> ",join(" ", @_),"\n"; + } +} 1; diff --git a/mysql-test/lib/mtr_stress.pl b/mysql-test/lib/mtr_stress.pl index 77c3d8bb030..a7d4b68b69d 100644 --- a/mysql-test/lib/mtr_stress.pl +++ b/mysql-test/lib/mtr_stress.pl @@ -21,15 +21,13 @@ sub run_stress_test () { my $args; - my $stress_basedir; my $stress_suitedir; mtr_report("Starting stress testing\n"); - if ( ! $::glob_use_embedded_server and ! $::opt_local_master ) + if ( ! $::glob_use_embedded_server ) { - $::master->[0]->{'pid'}= mysqld_start('master',0,[],[],0); - if ( ! $::master->[0]->{'pid'} ) + if ( ! mysqld_start($::master->[0],[],[]) ) { mtr_error("Can't start the mysqld server"); } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index f0eb7f3bda4..3ad083dbd0c 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -66,10 +66,6 @@ # "http://www.plover.com/~mjd/perl/Trace/" and run this script like # "perl -d:Trace mysql-test-run.pl" # -# FIXME Save a PID file from this code as well, to record the process -# id we think it has. In Cygwin, a fork creates one Cygwin process, -# and then the real Win32 process. Cygwin Perl can only kill Cygwin -# processes. And "mysqld --bootstrap ..." doesn't save a PID file. $Devel::Trace::TRACE= 0; # Don't trace boring init stuff @@ -80,14 +76,19 @@ use File::Copy; use Cwd; use Getopt::Long; use Sys::Hostname; -#use Carp; use IO::Socket; use IO::Socket::INET; use Data::Dumper; use strict; #use diagnostics; +our $glob_win32_perl= ($^O eq "MSWin32"); # ActiveState Win32 Perl +our $glob_cygwin_perl= ($^O eq "cygwin"); # Cygwin Perl +our $glob_win32= ($glob_win32_perl or $glob_cygwin_perl); +our $glob_netware= ($^O eq "NetWare"); # NetWare + require "lib/mtr_cases.pl"; +require "lib/mtr_im.pl"; require "lib/mtr_process.pl"; require "lib/mtr_timer.pl"; require "lib/mtr_io.pl"; @@ -129,10 +130,7 @@ our @mysqld_src_dirs= # structs. We let each struct be a separate hash. # Misc global variables - -our $glob_win32= 0; # OS and native Win32 executables -our $glob_win32_perl= 0; # ActiveState Win32 Perl -our $glob_cygwin_perl= 0; # Cygwin Perl +our $mysql_version_id; our $glob_mysql_test_dir= undef; our $glob_mysql_bench_dir= undef; our $glob_hostname= undef; @@ -140,36 +138,30 @@ our $glob_scriptname= undef; our $glob_timers= undef; our $glob_use_running_server= 0; our $glob_use_running_ndbcluster= 0; +our $glob_use_running_ndbcluster_slave= 0; our $glob_use_embedded_server= 0; our @glob_test_mode; -our $using_ndbcluster_master= 0; - our $glob_basedir; -# The total result - our $path_charsetsdir; our $path_client_bindir; our $path_language; our $path_timefile; our $path_snapshot; -our $path_slave_load_tmpdir; # What is this?! our $path_mysqltest_log; our $path_current_test_log; our $path_my_basedir; + our $opt_vardir; # A path but set directly on cmd line -our $opt_vardir_trace; # unix formatted opt_vardir for trace files +our $path_vardir_trace; # unix formatted opt_vardir for trace files our $opt_tmpdir; # A path but set directly on cmd line our $opt_usage; our $opt_suite; -our $opt_netware; - our $opt_script_debug= 0; # Script debugging, enable with --script-debug - -# Options FIXME not all.... +our $opt_verbose= 0; # Verbose output, enable with --verbose our $exe_master_mysqld; our $exe_mysql; @@ -177,12 +169,15 @@ our $exe_mysqladmin; our $exe_mysqlbinlog; our $exe_mysql_client_test; our $exe_mysqld; -our $exe_mysqlcheck; # Called from test case -our $exe_mysqldump; # Called from test case -our $exe_mysqlimport; # Called from test case -our $exe_mysqlshow; # Called from test case +our $exe_mysqlcheck; +our $exe_mysqldump; +our $exe_mysqlslap; +our $exe_mysqlimport; +our $exe_mysqlshow; our $exe_mysql_fix_system_tables; our $exe_mysqltest; +our $exe_ndbd; +our $exe_ndb_mgmd; our $exe_slave_mysqld; our $exe_im; our $exe_my_print_defaults; @@ -196,7 +191,6 @@ our $opt_big_test= 0; # Send --big-test to mysqltest our @opt_extra_mysqld_opt; -our $opt_comment; our $opt_compress; our $opt_ssl; our $opt_skip_ssl; @@ -213,7 +207,8 @@ our $opt_embedded_server; our $opt_extern; our $opt_fast; our $opt_force; -our $opt_reorder; +our $opt_reorder= 0; +our $opt_enable_disabled; our $opt_gcov; our $opt_gcov_err; @@ -235,18 +230,16 @@ our $opt_gprof_dir; our $opt_gprof_master; our $opt_gprof_slave; -our $opt_local; -our $opt_local_master; - -our $master; # Will be struct in C +our $master; our $slave; +our $clusters; our $instance_manager; our $opt_ndbcluster_port; our $opt_ndbconnectstring; - -our $opt_old_master; +our $opt_ndbcluster_port_slave; +our $opt_ndbconnectstring_slave; our $opt_record; our $opt_check_testcases; @@ -255,7 +248,8 @@ our $opt_result_ext; our $opt_skip; our $opt_skip_rpl; -our $use_slaves; +our $max_slave_num= 0; +our $use_innodb; our $opt_skip_test; our $opt_skip_im; @@ -266,7 +260,7 @@ our $opt_sleep_time_for_delete= 10; our $opt_testcase_timeout; our $opt_suite_timeout; my $default_testcase_timeout= 15; # 15 min max -my $default_suite_timeout= 120; # 2 hours max +my $default_suite_timeout= 180; # 3 hours max our $opt_socket; @@ -278,7 +272,7 @@ our $opt_start_from; our $opt_strace_client; -our $opt_timer; +our $opt_timer= 1; our $opt_user; our $opt_user_test; @@ -286,9 +280,10 @@ our $opt_user_test; our $opt_valgrind= 0; our $opt_valgrind_mysqld= 0; our $opt_valgrind_mysqltest= 0; -our $default_valgrind_options= "-v --show-reachable=yes"; +our $default_valgrind_options= "--show-reachable=yes"; our $opt_valgrind_options; our $opt_valgrind_path; +our $opt_callgrind; our $opt_stress= ""; our $opt_stress_suite= "main"; @@ -308,20 +303,31 @@ our $opt_warnings; our $opt_udiff; -our $opt_skip_ndbcluster; -our $opt_with_ndbcluster; -our $opt_with_ndbcluster_only= 0; # dummy, ignored - -our $opt_with_openssl; +our $opt_skip_ndbcluster= 0; +our $opt_skip_ndbcluster_slave= 0; +our $opt_with_ndbcluster= 0; +our $opt_with_ndbcluster_only= 0; +our $opt_ndbcluster_supported= 0; +our $opt_ndb_extra_test= 0; +our $opt_skip_master_binlog= 0; +our $opt_skip_slave_binlog= 0; our $exe_ndb_mgm; +our $exe_ndb_waiter; our $path_ndb_tools_dir; -our $path_ndb_data_dir; -our $file_ndb_testrun_log; -our $flag_ndb_status_ok= 1; +our $path_ndb_examples_dir; +our $exe_ndb_example; +our $path_ndb_testrun_log; our @data_dir_lst; +our $used_binlog_format; +our $debug_compiled_binaries; +our $glob_tot_real_time= 0; + +# Default values read from mysqld +our $default_mysqld_port; + ###################################################################### # # Function declarations @@ -336,25 +342,31 @@ sub executable_setup (); sub environment_setup (); sub kill_running_server (); sub cleanup_stale_files (); -sub check_ssl_support (); +sub check_ssl_support ($); sub check_running_as_root(); -sub check_ndbcluster_support (); -sub ndbcluster_install (); -sub ndbcluster_start ($); -sub ndbcluster_stop (); +sub check_ndbcluster_support ($); +sub rm_ndbcluster_tables ($); +sub ndbcluster_start_install ($); +sub ndbcluster_start ($$); +sub ndbcluster_wait_started ($$); +sub mysqld_wait_started($); sub run_benchmarks ($); sub initialize_servers (); sub mysql_install_db (); sub install_db ($$); +sub copy_install_db ($$); sub run_testcase ($); +sub run_testcase_stop_servers ($$$); +sub run_testcase_start_servers ($); +sub run_testcase_check_skip_test($); sub report_failure_and_restart ($); sub do_before_start_master ($$); sub do_before_start_slave ($$); -sub mysqld_start ($$$$$); -sub mysqld_arguments ($$$$$$); -sub stop_masters_slaves (); -sub stop_masters (); -sub stop_slaves (); +sub ndbd_start ($$$); +sub ndb_mgmd_start ($); +sub mysqld_start ($$$); +sub mysqld_arguments ($$$$$); +sub stop_all_servers (); sub run_mysqltest ($); sub usage ($); @@ -371,10 +383,6 @@ sub main () { initial_setup(); command_line_setup(); executable_setup(); - - check_ndbcluster_support(); # We check whether to actually use it later - check_ssl_support(); - environment_setup(); signal_setup(); @@ -409,9 +417,17 @@ sub main () { { $need_ndbcluster||= $test->{ndb_test}; $need_im||= $test->{component_id} eq 'im'; - $use_slaves||= $test->{slave_num}; + + # Count max number of slaves used by a test case + if ( $test->{slave_num} > $max_slave_num) + { + $max_slave_num= $test->{slave_num}; + mtr_error("Too many slaves") if $max_slave_num > 3; + } + $use_innodb||= $test->{'innodb_test'}; } - $opt_with_ndbcluster= 0 unless $need_ndbcluster; + $opt_skip_ndbcluster= $opt_skip_ndbcluster_slave= 1 + unless $need_ndbcluster; $opt_skip_im= 1 unless $need_im; snapshot_setup(); @@ -436,13 +452,8 @@ sub initial_setup () { $glob_scriptname= basename($0); - $glob_win32_perl= ($^O eq "MSWin32"); - $glob_cygwin_perl= ($^O eq "cygwin"); - $glob_win32= ($glob_win32_perl or $glob_cygwin_perl); - # We require that we are in the "mysql-test" directory # to run mysql-test-run - if (! -f $glob_scriptname) { mtr_error("Can't find the location for the mysql-test-run script\n" . @@ -466,10 +477,10 @@ sub initial_setup () { chomp($glob_mysql_test_dir); } $glob_basedir= dirname($glob_mysql_test_dir); - $glob_mysql_bench_dir= "$glob_basedir/mysql-bench"; # FIXME make configurable - # needs to be same length to test logging (FIXME what???) - $path_slave_load_tmpdir= "../../var/tmp"; + # Expect mysql-bench to be located adjacent to the source tree, by default + $glob_mysql_bench_dir= "$glob_basedir/../mysql-bench" + unless defined $glob_mysql_bench_dir; $path_my_basedir= $opt_source_dist ? $glob_mysql_test_dir : $glob_basedir; @@ -490,12 +501,15 @@ sub command_line_setup () { # These are defaults for things that are set on the command line $opt_suite= "main"; # Special default suite - my $opt_master_myport= 9306; - my $opt_slave_myport= 9308; - $opt_ndbcluster_port= 9350; - my $im_port= 9311; - my $im_mysqld1_port= 9312; - my $im_mysqld2_port= 9314; + my $opt_comment; + + my $opt_master_myport= 9306; + my $opt_slave_myport= 9308; + $opt_ndbcluster_port= 9310; + $opt_ndbcluster_port_slave= 9311; + my $im_port= 9312; + my $im_mysqld1_port= 9313; + my $im_mysqld2_port= 9314; # # To make it easier for different devs to work on the same host, @@ -514,12 +528,13 @@ sub command_line_setup () { if ( $ENV{'MTR_BUILD_THREAD'} ) { # Up to two masters, up to three slaves - $opt_master_myport= $ENV{'MTR_BUILD_THREAD'} * 10 + 10000; # and 1 - $opt_slave_myport= $opt_master_myport + 2; # and 3 4 - $opt_ndbcluster_port= $opt_master_myport + 5; - $im_port= $opt_master_myport + 6; - $im_mysqld1_port= $opt_master_myport + 7; - $im_mysqld2_port= $opt_master_myport + 8; + $opt_master_myport= $ENV{'MTR_BUILD_THREAD'} * 10 + 10000; # and 1 + $opt_slave_myport= $opt_master_myport + 2; # and 3 4 + $opt_ndbcluster_port= $opt_master_myport + 5; + $opt_ndbcluster_port_slave= $opt_master_myport + 6; + $im_port= $opt_master_myport + 7; + $im_mysqld1_port= $opt_master_myport + 8; + $im_mysqld2_port= $opt_master_myport + 9; } if ( $opt_master_myport < 5001 or $opt_master_myport + 10 >= 32767 ) @@ -554,18 +569,26 @@ sub command_line_setup () { # Control what test suites or cases to run 'force' => \$opt_force, 'with-ndbcluster' => \$opt_with_ndbcluster, - 'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster, 'with-ndbcluster-only' => \$opt_with_ndbcluster_only, + 'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster, + 'skip-ndbcluster-slave|skip-ndb-slave' + => \$opt_skip_ndbcluster_slave, + 'ndb-extra-test' => \$opt_ndb_extra_test, + 'skip-master-binlog' => \$opt_skip_master_binlog, + 'skip-slave-binlog' => \$opt_skip_slave_binlog, 'do-test=s' => \$opt_do_test, + 'start-from=s' => \$opt_start_from, 'suite=s' => \$opt_suite, 'skip-rpl' => \$opt_skip_rpl, 'skip-im' => \$opt_skip_im, 'skip-test=s' => \$opt_skip_test, + 'big-test' => \$opt_big_test, # Specify ports 'master_port=i' => \$opt_master_myport, 'slave_port=i' => \$opt_slave_myport, - 'ndbcluster_port=i' => \$opt_ndbcluster_port, + 'ndbcluster-port|ndbcluster_port=i' => \$opt_ndbcluster_port, + 'ndbcluster-port-slave=i' => \$opt_ndbcluster_port_slave, 'im-port=i' => \$im_port, # Instance Manager port. 'im-mysqld1-port=i' => \$im_mysqld1_port, # Port of mysqld, controlled by IM 'im-mysqld2-port=i' => \$im_mysqld2_port, # Port of mysqld, controlled by IM @@ -574,12 +597,13 @@ sub command_line_setup () { 'record' => \$opt_record, 'check-testcases' => \$opt_check_testcases, - # ??? + # Extra options used when starting mysqld 'mysqld=s' => \@opt_extra_mysqld_opt, # Run test on running server 'extern' => \$opt_extern, - 'ndbconnectstring=s' => \$opt_ndbconnectstring, + 'ndb-connectstring=s' => \$opt_ndbconnectstring, + 'ndb-connectstring-slave=s' => \$opt_ndbconnectstring_slave, # Debugging 'gdb' => \$opt_gdb, @@ -602,6 +626,7 @@ sub command_line_setup () { 'valgrind-mysqld' => \$opt_valgrind_mysqld, 'valgrind-options=s' => \$opt_valgrind_options, 'valgrind-path=s' => \$opt_valgrind_path, + 'callgrind' => \$opt_callgrind, # Stress testing 'stress' => \$opt_stress, @@ -617,24 +642,21 @@ sub command_line_setup () { # Directories 'tmpdir=s' => \$opt_tmpdir, 'vardir=s' => \$opt_vardir, + 'benchdir=s' => \$glob_mysql_bench_dir, # Misc - 'big-test' => \$opt_big_test, 'comment=s' => \$opt_comment, 'debug' => \$opt_debug, 'fast' => \$opt_fast, - 'local' => \$opt_local, - 'local-master' => \$opt_local_master, - 'netware' => \$opt_netware, - 'old-master' => \$opt_old_master, 'reorder' => \$opt_reorder, + 'enable-disabled' => \$opt_enable_disabled, 'script-debug' => \$opt_script_debug, + 'verbose' => \$opt_verbose, 'sleep=i' => \$opt_sleep, 'socket=s' => \$opt_socket, 'start-dirty' => \$opt_start_dirty, 'start-and-exit' => \$opt_start_and_exit, - 'start-from=s' => \$opt_start_from, - 'timer' => \$opt_timer, + 'timer!' => \$opt_timer, 'unified-diff|udiff' => \$opt_udiff, 'user-test=s' => \$opt_user_test, 'user=s' => \$opt_user, @@ -646,10 +668,7 @@ sub command_line_setup () { 'help|h' => \$opt_usage, ) or usage("Can't read options"); - if ( $opt_usage ) - { - usage(""); - } + usage("") if $opt_usage; if ( $opt_comment ) { @@ -659,11 +678,6 @@ sub command_line_setup () { print '#' x 78, "\n\n"; } - if ( $opt_with_ndbcluster_only ) - { - print "# Option '--with-ndbcluster-only' is ignored in this release.\n"; - } - foreach my $arg ( @ARGV ) { if ( $arg =~ /^--skip-/ ) @@ -686,6 +700,21 @@ sub command_line_setup () { } } + # -------------------------------------------------------------------------- + # Find out type of logging that are being used + # -------------------------------------------------------------------------- + + # NOTE if the default binlog format is changed, this has to be changed + $used_binlog_format= "stmt"; + foreach my $arg ( @opt_extra_mysqld_opt ) + { + if ( defined mtr_match_substring($arg,"binlog-format=row")) + { + $used_binlog_format= "row"; + } + } + mtr_report("Using binlog format '$used_binlog_format'"); + # -------------------------------------------------------------------------- # Set the "var/" directory, as it is the base for everything else # -------------------------------------------------------------------------- @@ -694,9 +723,15 @@ sub command_line_setup () { { $opt_vardir= "$glob_mysql_test_dir/var"; } - $opt_vardir_trace= $opt_vardir; + elsif ( $mysql_version_id < 50000 ) + { + # --vardir was specified + mtr_error("--vardir option not supported until MySQL 5.0"); + } + + $path_vardir_trace= $opt_vardir; # Chop off any "c:", DBUG likes a unix path ex: c:/src/... => /src/... - $opt_vardir_trace=~ s/^\w://; + $path_vardir_trace=~ s/^\w://; # We make the path absolute, as the server will do a chdir() before usage unless ( $opt_vardir =~ m,^/, or @@ -717,17 +752,6 @@ sub command_line_setup () { # Do sanity checks of command line arguments # -------------------------------------------------------------------------- - if ( $opt_extern and $opt_local ) - { - mtr_error("Can't use --extern and --local at the same time"); - } - - if ( ! $opt_socket ) - { # FIXME set default before reading options? -# $opt_socket= '@MYSQL_UNIX_ADDR@'; - $opt_socket= "/tmp/mysql.sock"; # FIXME - } - # -------------------------------------------------------------------------- # Look at the command line options and set script flags # -------------------------------------------------------------------------- @@ -742,7 +766,8 @@ sub command_line_setup () { $glob_use_embedded_server= 1; push(@glob_test_mode, "embedded"); $opt_skip_rpl= 1; # We never run replication with embedded - $opt_skip_ndbcluster= 1; + $opt_skip_ndbcluster= 1; # Turn off use of NDB cluster + $opt_skip_ssl= 1; # Turn off use of SSL if ( $opt_extern ) { @@ -755,11 +780,40 @@ sub command_line_setup () { push(@glob_test_mode, "ps-protocol"); } - # FIXME don't understand what this is -# if ( $opt_local_master ) -# { -# $opt_master_myport= 3306; -# } + if ( $opt_with_ndbcluster and $opt_skip_ndbcluster) + { + mtr_error("Can't specify both --with-ndbcluster and --skip-ndbcluster"); + } + + if ( $opt_ndbconnectstring ) + { + $glob_use_running_ndbcluster= 1; + mtr_error("Can't specify --ndb-connectstring and --skip-ndbcluster") + if $opt_skip_ndbcluster; + mtr_error("Can't specify --ndb-connectstring and --ndbcluster-port") + if $opt_ndbcluster_port; + } + else + { + # Set default connect string + $opt_ndbconnectstring= "host=localhost:$opt_ndbcluster_port"; + } + + if ( $opt_ndbconnectstring_slave ) + { + $glob_use_running_ndbcluster_slave= 1; + mtr_error("Can't specify ndb-connectstring_slave and " . + "--skip-ndbcluster-slave") + if $opt_skip_ndbcluster; + mtr_error("Can't specify --ndb-connectstring-slave and " . + "--ndbcluster-port-slave") + if $opt_ndbcluster_port_slave; + } + else + { + # Set default connect string + $opt_ndbconnectstring_slave= "host=localhost:$opt_ndbcluster_port_slave"; + } if ( $opt_small_bench ) { @@ -791,28 +845,12 @@ sub command_line_setup () { } } - if ( $opt_ndbconnectstring ) - { - $glob_use_running_ndbcluster= 1; - $opt_with_ndbcluster= 1; - } - else - { - $opt_ndbconnectstring= "host=localhost:$opt_ndbcluster_port"; - } - - if ( $opt_skip_ndbcluster ) - { - $opt_with_ndbcluster= 0; - } - # Check IM arguments if ( $glob_win32 ) { mtr_report("Disable Instance manager - not supported on Windows"); $opt_skip_im= 1; } - # Check valgrind arguments if ( $opt_valgrind or $opt_valgrind_path or defined $opt_valgrind_options) { @@ -832,6 +870,17 @@ sub command_line_setup () { $opt_valgrind= 1; } + if ( $opt_callgrind ) + { + mtr_report("Turning on valgrind with callgrind for mysqld(s)"); + $opt_valgrind= 1; + $opt_valgrind_mysqld= 1; + + # Set special valgrind options unless options passed on command line + $opt_valgrind_options="--trace-children=yes" + unless defined $opt_valgrind_options; + } + if ( $opt_valgrind ) { # Set valgrind_options to default unless already defined @@ -844,13 +893,13 @@ sub command_line_setup () { if ( ! $opt_testcase_timeout ) { $opt_testcase_timeout= $default_testcase_timeout; - $opt_testcase_timeout*= 10 if defined $opt_valgrind; + $opt_testcase_timeout*= 10 if $opt_valgrind; } if ( ! $opt_suite_timeout ) { $opt_suite_timeout= $default_suite_timeout; - $opt_suite_timeout*= 4 if defined $opt_valgrind; + $opt_suite_timeout*= 6 if $opt_valgrind; } # Increase times to wait for executables to start if using valgrind @@ -882,59 +931,83 @@ sub command_line_setup () { $master->[0]= { + pid => 0, + type => "master", + idx => 0, path_myddir => "$opt_vardir/master-data", path_myerr => "$opt_vardir/log/master.err", path_mylog => "$opt_vardir/log/master.log", - path_mypid => "$opt_vardir/run/master.pid", - path_mysock => "$sockdir/master.sock", - path_myport => $opt_master_myport, + path_pid => "$opt_vardir/run/master.pid", + path_sock => "$sockdir/master.sock", + port => $opt_master_myport, start_timeout => 400, # enough time create innodb tables - - ndbcluster => 1, # ndbcluster not started + cluster => 0, # index in clusters list + start_opts => [], }; $master->[1]= { + pid => 0, + type => "master", + idx => 1, path_myddir => "$opt_vardir/master1-data", path_myerr => "$opt_vardir/log/master1.err", path_mylog => "$opt_vardir/log/master1.log", - path_mypid => "$opt_vardir/run/master1.pid", - path_mysock => "$sockdir/master1.sock", - path_myport => $opt_master_myport + 1, + path_pid => "$opt_vardir/run/master1.pid", + path_sock => "$sockdir/master1.sock", + port => $opt_master_myport + 1, start_timeout => 400, # enough time create innodb tables + cluster => 0, # index in clusters list + start_opts => [], }; $slave->[0]= { + pid => 0, + type => "slave", + idx => 0, path_myddir => "$opt_vardir/slave-data", path_myerr => "$opt_vardir/log/slave.err", path_mylog => "$opt_vardir/log/slave.log", - path_mypid => "$opt_vardir/run/slave.pid", - path_mysock => "$sockdir/slave.sock", - path_myport => $opt_slave_myport, + path_pid => "$opt_vardir/run/slave.pid", + path_sock => "$sockdir/slave.sock", + port => $opt_slave_myport, start_timeout => 400, + + cluster => 1, # index in clusters list + start_opts => [], }; $slave->[1]= { + pid => 0, + type => "slave", + idx => 1, path_myddir => "$opt_vardir/slave1-data", path_myerr => "$opt_vardir/log/slave1.err", path_mylog => "$opt_vardir/log/slave1.log", - path_mypid => "$opt_vardir/run/slave1.pid", - path_mysock => "$sockdir/slave1.sock", - path_myport => $opt_slave_myport + 1, + path_pid => "$opt_vardir/run/slave1.pid", + path_sock => "$sockdir/slave1.sock", + port => $opt_slave_myport + 1, start_timeout => 300, + cluster => -1, # index in clusters list + start_opts => [], }; $slave->[2]= { + pid => 0, + type => "slave", + idx => 2, path_myddir => "$opt_vardir/slave2-data", path_myerr => "$opt_vardir/log/slave2.err", path_mylog => "$opt_vardir/log/slave2.log", - path_mypid => "$opt_vardir/run/slave2.pid", - path_mysock => "$sockdir/slave2.sock", - path_myport => $opt_slave_myport + 2, + path_pid => "$opt_vardir/run/slave2.pid", + path_sock => "$sockdir/slave2.sock", + port => $opt_slave_myport + 2, start_timeout => 300, + cluster => -1, # index in clusters list + start_opts => [], }; $instance_manager= @@ -960,6 +1033,8 @@ sub command_line_setup () { path_datadir => "$opt_vardir/im_mysqld_1.data", path_sock => "$sockdir/mysqld_1.sock", path_pid => "$opt_vardir/run/mysqld_1.pid", + start_timeout => 400, # enough time create innodb tables + old_log_format => 1 }; $instance_manager->{'instances'}->[1]= @@ -970,18 +1045,63 @@ sub command_line_setup () { path_sock => "$sockdir/mysqld_2.sock", path_pid => "$opt_vardir/run/mysqld_2.pid", nonguarded => 1, + start_timeout => 400, # enough time create innodb tables + old_log_format => 1 }; + my $data_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port"; + $clusters->[0]= + { + name => "Master", + nodes => 2, + port => "$opt_ndbcluster_port", + data_dir => "$data_dir", + connect_string => "$opt_ndbconnectstring", + path_pid => "$data_dir/ndb_3.pid", # Nodes + 1 + pid => 0, # pid of ndb_mgmd + installed_ok => 0, + }; + + $data_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port_slave"; + $clusters->[1]= + { + name => "Slave", + nodes => 1, + port => "$opt_ndbcluster_port_slave", + data_dir => "$data_dir", + connect_string => "$opt_ndbconnectstring_slave", + path_pid => "$data_dir/ndb_2.pid", # Nodes + 1 + pid => 0, # pid of ndb_mgmd + installed_ok => 0, + }; + + # Init pids of ndbd's + foreach my $cluster ( @{$clusters} ) + { + for ( my $idx= 0; $idx < $cluster->{'nodes'}; $idx++ ) + { + my $nodeid= $idx+1; + $cluster->{'ndbds'}->[$idx]= + { + pid => 0, + nodeid => $nodeid, + path_pid => "$cluster->{'data_dir'}/ndb_${nodeid}.pid", + path_fs => "$cluster->{'data_dir'}/ndb_${nodeid}_fs", + }; + } + } + if ( $opt_extern ) { $glob_use_running_server= 1; $opt_skip_rpl= 1; # We don't run rpl test cases - $master->[0]->{'path_mysock'}= $opt_socket; + $master->[0]->{'path_sock'}= $opt_socket; } $path_timefile= "$opt_vardir/log/mysqltest-time"; $path_mysqltest_log= "$opt_vardir/log/mysqltest.log"; $path_current_test_log= "$opt_vardir/log/current_test"; + $path_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; $path_snapshot= "$opt_tmpdir/snapshot_$opt_master_myport/"; } @@ -993,11 +1113,9 @@ sub snapshot_setup () { $master->[0]->{'path_myddir'}, $master->[1]->{'path_myddir'}); - if ($use_slaves) + for (my $idx= 0; $idx < $max_slave_num; $idx++) { - push @data_dir_lst, ($slave->[0]->{'path_myddir'}, - $slave->[1]->{'path_myddir'}, - $slave->[2]->{'path_myddir'}); + push(@data_dir_lst, $slave->[$idx]->{'path_myddir'}); } unless ($opt_skip_im) @@ -1016,6 +1134,96 @@ sub snapshot_setup () { # ############################################################################## + +sub check_mysqld_features () { + # + # Execute "mysqld --no-defaults --help --verbose", that will + # print out version and a list of all features and settings + # + my $found_variable_list_start= 0; + my $spec_file= "$opt_vardir/mysqld.spec"; + if ( mtr_run($exe_mysqld, + ["--no-defaults", + "--verbose", + "--help"], + "", "$spec_file", "$spec_file", "") != 0 ) + { + mtr_error("Failed to get version and list of features from %s", + $exe_mysqld); + } + + my %mysqld_variables; + my $F= IO::File->new($spec_file) or + mtr_error("can't open file \"$spec_file\": $!"); + + while ( my $line= <$F> ) + { + # First look for version + if ( !$mysql_version_id ) + { + # Look for version + if ( $line =~ /^$exe_mysqld\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)/ ) + { + print "Major: $1 Minor: $2 Build: $3\n"; + $mysql_version_id= $1*10000 + $2*100 + $3; + print "mysql_version_id: $mysql_version_id\n"; + } + } + else + { + if (!$found_variable_list_start) + { + # Look for start of variables list + if ( $line =~ /[\-]+\s[\-]+/ ) + { + $found_variable_list_start= 1; + } + } + else + { + # Put variables into hash + if ( $line =~ /^([\S]+)[ \t]+(.*)$/ ) + { + # print "$1=$2\n"; + $mysqld_variables{$1}= $2; + } + else + { + # The variable list is ended with a blank line, so when a line + # doesn't match the above regex, break the loop + last; + } + } + } + } + unlink($spec_file); + mtr_error("Could not find version of MySQL") unless $mysql_version_id; + mtr_error("Could not find variabes list") unless $found_variable_list_start; + + check_ndbcluster_support(\%mysqld_variables); + check_ssl_support(\%mysqld_variables); + check_debug_support(\%mysqld_variables); + + if ( $mysql_version_id < 50000 ) + { + # Instance manager is not supported until 5.0 + $opt_skip_im= 1; + + } + + if ( $mysql_version_id < 50100 ) + { + # Slave cluster is not supported until 5.1 + $opt_skip_ndbcluster_slave= 1; + + } + + # Set default values from mysqld_variables + $opt_socket= %mysqld_variables->{'socket'}; + $default_mysqld_port = %mysqld_variables->{'port'}; +} + + sub executable_setup () { # @@ -1033,155 +1241,147 @@ sub executable_setup () { } } - if ( $opt_source_dist ) - { - if ( $glob_win32 ) - { - $path_client_bindir= mtr_path_exists("$glob_basedir/client_release", - "$glob_basedir/client_debug", - "$glob_basedir/client/release", - "$glob_basedir/client/debug", - "$glob_basedir/bin",); - $exe_mysqld= mtr_exe_exists ("$path_client_bindir/mysqld-max-nt", - "$path_client_bindir/mysqld-max", - "$path_client_bindir/mysqld-nt", - "$path_client_bindir/mysqld", - "$path_client_bindir/mysqld-debug", - "$path_client_bindir/mysqld-max", - "$glob_basedir/sql/release/mysqld", - "$glob_basedir/sql/debug/mysqld"); - $path_language= mtr_path_exists("$glob_basedir/share/english/", - "$glob_basedir/sql/share/english/"); - $path_charsetsdir= mtr_path_exists("$glob_basedir/share/charsets", - "$glob_basedir/sql/share/charsets/"); - $exe_my_print_defaults= - mtr_exe_exists("$path_client_bindir/my_print_defaults", - "$glob_basedir/extra/release/my_print_defaults", - "$glob_basedir/extra/debug/my_print_defaults"); - $exe_perror= - mtr_exe_exists("$path_client_bindir/perror", - "$glob_basedir/extra/release/perror", - "$glob_basedir/extra/debug/perror"); - } - else - { - $path_client_bindir= mtr_path_exists("$glob_basedir/client"); - $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld"); - $path_language= mtr_path_exists("$glob_basedir/sql/share/english/"); - $path_charsetsdir= mtr_path_exists("$glob_basedir/sql/share/charsets"); + # Look for the path where to find the client binaries + $path_client_bindir= mtr_path_exists("$glob_basedir/client", + "$glob_basedir/client_release", + "$glob_basedir/client_debug", + "$glob_basedir/client/release", + "$glob_basedir/client/debug", + "$glob_basedir/bin"); - $exe_im= mtr_exe_exists( - "$glob_basedir/server-tools/instance-manager/mysqlmanager"); - $exe_my_print_defaults= - mtr_exe_exists("$glob_basedir/extra/my_print_defaults"); - $exe_perror= - mtr_exe_exists("$glob_basedir/extra/perror"); - } - - if ( $glob_use_embedded_server ) - { - my $path_examples= "$glob_basedir/libmysqld/examples"; - $exe_mysqltest= mtr_exe_exists("$path_examples/mysqltest_embedded"); - $exe_mysql_client_test= - mtr_exe_exists("$path_examples/mysql_client_test_embedded", - "/usr/bin/false"); - } - else - { - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test", - "$path_client_bindir/mysql_client_test", - "$glob_basedir/tests/release/mysql_client_test", - "$glob_basedir/tests/debug/mysql_client_test", - "$path_client_bindir/mysql_client_test", - "/usr/bin/false"); - } - $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); - $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); - $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); - $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); - $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); - $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); - $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); - $exe_mysql_fix_system_tables= - mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables", - "/usr/bin/false"); - $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools"); - $exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm"; - $lib_udf_example= - mtr_file_exists("$glob_basedir/sql/.libs/udf_example.so"); - } - else - { - $path_client_bindir= mtr_path_exists("$glob_basedir/bin"); - $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); - $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); - $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); - $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); - $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); - $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); - $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); - $exe_mysql_fix_system_tables= - mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables", - "$glob_basedir/scripts/mysql_fix_privilege_tables", - "/usr/bin/false"); - $exe_my_print_defaults= - mtr_exe_exists("$path_client_bindir/my_print_defaults"); - $exe_perror= - mtr_exe_exists("$path_client_bindir/perror"); - - $path_language= mtr_path_exists("$glob_basedir/share/mysql/english/", - "$glob_basedir/share/english/"); - $path_charsetsdir= mtr_path_exists("$glob_basedir/share/mysql/charsets", - "$glob_basedir/share/charsets"); - - if ( $glob_win32 ) - { - $exe_mysqld= mtr_exe_exists ("$glob_basedir/bin/mysqld-nt", - "$glob_basedir/bin/mysqld", - "$glob_basedir/bin/mysqld-debug",); - } - else - { - $exe_mysqld= mtr_exe_exists ("$glob_basedir/libexec/mysqld", - "$glob_basedir/bin/mysqld"); - } - $exe_im= mtr_exe_exists("$glob_basedir/libexec/mysqlmanager", - "$glob_basedir/bin/mysqlmanager"); - if ( $glob_use_embedded_server ) - { - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest_embedded"); - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test_embedded", - "$path_client_bindir/mysql_client_test_embedded", - "/usr/bin/false"); - } - else - { - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest", - "$glob_basedir/client/release/mysqltest", - "$glob_basedir/client/debug/mysqltest"); - $exe_mysql_client_test= - mtr_exe_exists("$path_client_bindir/mysql_client_test", - "/usr/bin/false"); # FIXME temporary - } - - $path_ndb_tools_dir= "$glob_basedir/bin"; - $exe_ndb_mgm= "$glob_basedir/bin/ndb_mgm"; - } + # Look for the mysqld executable + $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld", + "$path_client_bindir/mysqld-max-nt", + "$path_client_bindir/mysqld-max", + "$path_client_bindir/mysqld-nt", + "$path_client_bindir/mysqld", + "$path_client_bindir/mysqld-debug", + "$path_client_bindir/mysqld-max", + "$glob_basedir/libexec/mysqld", + "$glob_basedir/sql/release/mysqld", + "$glob_basedir/sql/debug/mysqld"); $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; - $path_ndb_data_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port"; - $file_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; + # Use the mysqld found above to find out what features are available + check_mysqld_features(); + + # Look for language files and charsetsdir, use same share + my $path_share= mtr_path_exists("$glob_basedir/share", + "$glob_basedir/sql/share", + "$glob_basedir/share/mysql", + "$glob_basedir/share"); + + $path_language= mtr_path_exists("$path_share/english"); + $path_charsetsdir= mtr_path_exists("$path_share/charsets"); + + # Look for my_print_defaults + $exe_my_print_defaults= + mtr_exe_exists("$path_client_bindir/my_print_defaults", + "$glob_basedir/extra/my_print_defaults", + "$glob_basedir/extra/release/my_print_defaults", + "$glob_basedir/extra/debug/my_print_defaults"); + + # Look for perror + $exe_perror= mtr_exe_exists("$glob_basedir/extra/perror", + "$path_client_bindir/perror", + "$glob_basedir/extra/release/perror", + "$glob_basedir/extra/debug/perror"); + + + if ( ! $opt_skip_im ) + { + # Look for instance manager binary - mysqlmanager + $exe_im= + mtr_exe_exists( + "$glob_basedir/server-tools/instance-manager/mysqlmanager", + "$glob_basedir/libexec/mysqlmanager"); + } + + # Look for the client binaries + $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); + $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); + $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); + $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); + $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); + $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); + $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); + + # Look for mysql_fix_system_table script + $exe_mysql_fix_system_tables= + mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables", + "$path_client_bindir/mysql_fix_privilege_tables"); + + if ( ! $opt_skip_ndbcluster) + { + # Look for ndb tols and binaries + my $ndb_path= mtr_path_exists("$glob_basedir/ndb", + "$glob_basedir/storage/ndb"); + + $path_ndb_tools_dir= mtr_path_exists("$ndb_path/tools", + "$glob_basedir/bin"); + $exe_ndb_mgm= + mtr_exe_exists("$ndb_path/src/mgmclient/ndb_mgm", + "$glob_basedir/bin/ndb_mgm"); + $exe_ndb_mgmd= + mtr_exe_exists("$ndb_path/src/mgmsrv/ndb_mgmd", + "$glob_basedir/bin/ndb_mgmd"); + $exe_ndb_waiter= + mtr_exe_exists("$ndb_path/tools/ndb_waiter", + "$glob_basedir/bin/ndb_waiter"); + $exe_ndbd= + mtr_exe_exists("$ndb_path/src/kernel/ndbd", + "$glob_basedir/bin/ndbd"); + } + + # Look for the udf_example library + $lib_udf_example= + mtr_file_exists("$glob_basedir/sql/.libs/udf_example.so"); + + + # Look for mysqltest executable + if ( $glob_use_embedded_server ) + { + $exe_mysqltest= + mtr_exe_exists("$glob_basedir/libmysqld/examples/mysqltest_embedded", + "$path_client_bindir/mysqltest_embedded"); + } + else + { + $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); + + + } + + # Look for mysql_client_test executable + if ( $glob_use_embedded_server ) + { + $exe_mysql_client_test= + mtr_exe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded", + "$glob_basedir/tests/mysqltest_embedded"); + } + else + { + $exe_mysql_client_test= + mtr_exe_exists("$glob_basedir/tests/mysql_client_test"); + } +} + + +sub generate_cmdline_mysqldump ($) { + my($mysqld) = @_; + return + "$exe_mysqldump --no-defaults -uroot " . + "--port=$mysqld->{'port'} " . + "--socket=$mysqld->{'path_sock'} --password="; } ############################################################################## # -# Set environment to be used by childs of this process +# Set environment to be used by childs of this process for +# things that are constant duting the whole lifetime of mysql-test-run.pl # ############################################################################## @@ -1189,7 +1389,9 @@ sub executable_setup () { sub environment_setup () { - my $extra_ld_library_paths; + umask(022); + + my @ld_library_paths; # -------------------------------------------------------------------------- # Setup LD_LIBRARY_PATH so the libraries from this distro/clone @@ -1197,30 +1399,56 @@ sub environment_setup () { # -------------------------------------------------------------------------- if ( $opt_source_dist ) { - $extra_ld_library_paths= "$glob_basedir/libmysql/.libs/"; + push(@ld_library_paths, "$glob_basedir/libmysql/.libs/", + "$glob_basedir/libmysql_r/.libs/"); } else { - $extra_ld_library_paths= "$glob_basedir/lib"; + push(@ld_library_paths, "$glob_basedir/lib"); + } + + # -------------------------------------------------------------------------- + # Add the path where libndbclient can be found + # -------------------------------------------------------------------------- + if ( $opt_ndbcluster_supported ) + { + push(@ld_library_paths, "$glob_basedir/storage/ndb/src/.libs"); } # -------------------------------------------------------------------------- # Add the path where mysqld will find udf_example.so # -------------------------------------------------------------------------- - $extra_ld_library_paths .= ":" . - ($lib_udf_example ? dirname($lib_udf_example) : ""); + if ( $lib_udf_example ) + { + push(@ld_library_paths, dirname($lib_udf_example)); + } + + # -------------------------------------------------------------------------- + # Valgrind need to be run with debug libraries otherwise it's almost + # impossible to add correct supressions, that means if "/usr/lib/debug" + # is available, it should be added to + # LD_LIBRARY_PATH + # -------------------------------------------------------------------------- + my $debug_libraries_path= "/usr/lib/debug"; + if ( $opt_valgrind and -d $debug_libraries_path ) + { + push(@ld_library_paths, $debug_libraries_path); + } + + $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths, + split(':', $ENV{'LD_LIBRARY_PATH'})); + mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}"); + + $ENV{'DYLD_LIBRARY_PATH'}= join(":", @ld_library_paths, + split(':', $ENV{'DYLD_LIBRARY_PATH'})); + mtr_debug("DYLD_LIBRARY_PATH: $ENV{'DYLD_LIBRARY_PATH'}"); - $ENV{'LD_LIBRARY_PATH'}= - "$extra_ld_library_paths" . - ($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : ""); - $ENV{'DYLD_LIBRARY_PATH'}= - "$extra_ld_library_paths" . - ($ENV{'DYLD_LIBRARY_PATH'} ? ":$ENV{'DYLD_LIBRARY_PATH'}" : ""); # -------------------------------------------------------------------------- # Also command lines in .opt files may contain env vars # -------------------------------------------------------------------------- + $ENV{'CHARSETSDIR'}= $path_charsetsdir; $ENV{'UMASK'}= "0660"; # The octal *string* $ENV{'UMASK_DIR'}= "0770"; # The octal *string* $ENV{'LC_COLLATE'}= "C"; @@ -1228,22 +1456,47 @@ sub environment_setup () { $ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir; $ENV{'MYSQLTEST_VARDIR'}= $opt_vardir; $ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir; - $ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_mysock'}; - $ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_mysock'}; - $ENV{'MASTER_MYPORT'}= $master->[0]->{'path_myport'}; - $ENV{'MASTER_MYPORT1'}= $master->[1]->{'path_myport'}; - $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'path_myport'}; - $ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'path_myport'}; - $ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'path_myport'}; -# $ENV{'MYSQL_TCP_PORT'}= '@MYSQL_TCP_PORT@'; # FIXME - $ENV{'MYSQL_TCP_PORT'}= 3306; + $ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_sock'}; + $ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_sock'}; + $ENV{'MASTER_MYPORT'}= $master->[0]->{'port'}; + $ENV{'MASTER_MYPORT1'}= $master->[1]->{'port'}; + $ENV{'SLAVE_MYSOCK'}= $slave->[0]->{'path_sock'}; + $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'port'}; + $ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'port'}; + $ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'port'}; + $ENV{'MYSQL_TCP_PORT'}= $default_mysqld_port; - $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; - $ENV{'NDB_STATUS_OK'}= "YES"; + $ENV{MTR_BUILD_THREAD}= 0 unless $ENV{MTR_BUILD_THREAD}; # Set if not set + # ---------------------------------------------------- + # Setup env for NDB + # ---------------------------------------------------- + $ENV{'NDB_MGM'}= $exe_ndb_mgm; + + $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; + $ENV{'NDBCLUSTER_PORT_SLAVE'}= $opt_ndbcluster_port_slave; + + $ENV{'NDB_EXTRA_TEST'}= $opt_ndb_extra_test; + + $ENV{'NDB_BACKUP_DIR'}= $clusters->[0]->{'data_dir'}; + $ENV{'NDB_DATA_DIR'}= $clusters->[0]->{'data_dir'}; + $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; + $ENV{'NDB_TOOLS_OUTPUT'}= $path_ndb_testrun_log; + $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; + + $ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir; + $ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example; + $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; + + # ---------------------------------------------------- + # Setup env for IM + # ---------------------------------------------------- + $ENV{'IM_EXE'}= $exe_im; $ENV{'IM_PATH_PID'}= $instance_manager->{path_pid}; $ENV{'IM_PATH_ANGEL_PID'}= $instance_manager->{path_angel_pid}; $ENV{'IM_PORT'}= $instance_manager->{port}; + $ENV{'IM_DEFAULTS_PATH'}= $instance_manager->{defaults_file}; + $ENV{'IM_PASSWORD_PATH'}= $instance_manager->{password_file}; $ENV{'IM_MYSQLD1_SOCK'}= $instance_manager->{instances}->[0]->{path_sock}; $ENV{'IM_MYSQLD1_PORT'}= $instance_manager->{instances}->[0]->{port}; @@ -1252,19 +1505,205 @@ sub environment_setup () { $ENV{'IM_MYSQLD2_PORT'}= $instance_manager->{instances}->[1]->{port}; $ENV{'IM_MYSQLD2_PATH_PID'}=$instance_manager->{instances}->[1]->{path_pid}; - $ENV{MTR_BUILD_THREAD}= 0 unless $ENV{MTR_BUILD_THREAD}; # Set if not set + # ---------------------------------------------------- + # Setup env so childs can execute mysqlcheck + # ---------------------------------------------------- + my $cmdline_mysqlcheck= + "$exe_mysqlcheck --no-defaults -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password="; + if ( $opt_debug ) + { + $cmdline_mysqlcheck .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlcheck.trace"; + } + $ENV{'MYSQL_CHECK'}= $cmdline_mysqlcheck; + + # ---------------------------------------------------- + # Setup env to childs can execute myqldump + # ---------------------------------------------------- + my $cmdline_mysqldump= generate_cmdline_mysqldump($master->[0]); + my $cmdline_mysqldumpslave= generate_cmdline_mysqldump($slave->[0]); + + if ( $opt_debug ) + { + $cmdline_mysqldump .= + " --debug=d:t:A,$path_vardir_trace/log/mysqldump-master.trace"; + $cmdline_mysqldumpslave .= + " --debug=d:t:A,$path_vardir_trace/log/mysqldump-slave.trace"; + } + $ENV{'MYSQL_DUMP'}= $cmdline_mysqldump; + $ENV{'MYSQL_DUMP_SLAVE'}= $cmdline_mysqldumpslave; + + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlslap + # ---------------------------------------------------- + unless ( $glob_win32 ) + { + my $cmdline_mysqlslap= + "$exe_mysqlslap -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password= " . + "--lock-directory=$opt_tmpdir"; + + if ( $opt_debug ) + { + $cmdline_mysqlslap .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace"; + } + $ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap; + } + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlimport + # ---------------------------------------------------- + my $cmdline_mysqlimport= + "$exe_mysqlimport -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password="; + + if ( $opt_debug ) + { + $cmdline_mysqlimport .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlimport.trace"; + } + $ENV{'MYSQL_IMPORT'}= $cmdline_mysqlimport; + + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlshow + # ---------------------------------------------------- + my $cmdline_mysqlshow= + "$exe_mysqlshow -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password="; + + if ( $opt_debug ) + { + $cmdline_mysqlshow .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlshow.trace"; + } + $ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow; + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlbinlog + # ---------------------------------------------------- + my $cmdline_mysqlbinlog= + "$exe_mysqlbinlog" . + " --no-defaults --local-load=$opt_tmpdir"; + if ( $mysql_version_id >= 50000 ) + { + $cmdline_mysqlbinlog .=" --character-sets-dir=$path_charsetsdir"; + } + + if ( $opt_debug ) + { + $cmdline_mysqlbinlog .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlbinlog.trace"; + } + $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; + + # ---------------------------------------------------- + # Setup env so childs can execute mysql + # ---------------------------------------------------- + my $cmdline_mysql= + "$exe_mysql --no-defaults --host=localhost --user=root --password= " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} ". + "--character-sets-dir=$path_charsetsdir"; + + $ENV{'MYSQL'}= $cmdline_mysql; + + # ---------------------------------------------------- + # Setup env so childs can execute mysql_client_test + # ---------------------------------------------------- + my $cmdline_mysql_client_test= + "$exe_mysql_client_test --no-defaults --testcase --user=root --silent " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'}"; + if ( $mysql_version_id >= 50000 ) + { + $cmdline_mysql_client_test .=" --vardir=$opt_vardir"; + } + + if ( $opt_debug ) + { + $cmdline_mysql_client_test .= + " --debug=d:t:A,$path_vardir_trace/log/mysql_client_test.trace"; + } + + if ( $glob_use_embedded_server ) + { + $cmdline_mysql_client_test.= + " -A --language=$path_language" . + " -A --datadir=$slave->[0]->{'path_myddir'}" . + " -A --character-sets-dir=$path_charsetsdir"; + } + $ENV{'MYSQL_CLIENT_TEST'}= $cmdline_mysql_client_test; + + + # ---------------------------------------------------- + # Setup env so childs can execute mysql_fix_system_tables + # ---------------------------------------------------- + my $cmdline_mysql_fix_system_tables= + "$exe_mysql_fix_system_tables --no-defaults --host=localhost " . + "--user=root --password= " . + "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'}"; + + $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables; + + # ---------------------------------------------------- + # Setup env so childs can execute my_print_defaults + # ---------------------------------------------------- + $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= $exe_my_print_defaults; + + + # ---------------------------------------------------- + # Setup env so childs can execute perror + # ---------------------------------------------------- + $ENV{'MY_PERROR'}= $exe_perror; + + # ---------------------------------------------------- + # Add the path where mysqld will find udf_example.so + # ---------------------------------------------------- + $ENV{'UDF_EXAMPLE_LIB'}= + ($lib_udf_example ? basename($lib_udf_example) : ""); + + $ENV{'LD_LIBRARY_PATH'}= + ($lib_udf_example ? dirname($lib_udf_example) : "") . + ($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : ""); + + + # ---------------------------------------------------- # We are nice and report a bit about our settings - print "Using MTR_BUILD_THREAD = $ENV{MTR_BUILD_THREAD}\n"; - print "Using MASTER_MYPORT = $ENV{MASTER_MYPORT}\n"; - print "Using MASTER_MYPORT1 = $ENV{MASTER_MYPORT1}\n"; - print "Using SLAVE_MYPORT = $ENV{SLAVE_MYPORT}\n"; - print "Using SLAVE_MYPORT1 = $ENV{SLAVE_MYPORT1}\n"; - print "Using SLAVE_MYPORT2 = $ENV{SLAVE_MYPORT2}\n"; - print "Using NDBCLUSTER_PORT = $ENV{NDBCLUSTER_PORT}\n"; - print "Using IM_PORT = $ENV{IM_PORT}\n"; - print "Using IM_MYSQLD1_PORT = $ENV{IM_MYSQLD1_PORT}\n"; - print "Using IM_MYSQLD2_PORT = $ENV{IM_MYSQLD2_PORT}\n"; + # ---------------------------------------------------- + if (!$opt_extern) + { + print "Using MTR_BUILD_THREAD = $ENV{MTR_BUILD_THREAD}\n"; + print "Using MASTER_MYPORT = $ENV{MASTER_MYPORT}\n"; + print "Using MASTER_MYPORT1 = $ENV{MASTER_MYPORT1}\n"; + print "Using SLAVE_MYPORT = $ENV{SLAVE_MYPORT}\n"; + print "Using SLAVE_MYPORT1 = $ENV{SLAVE_MYPORT1}\n"; + print "Using SLAVE_MYPORT2 = $ENV{SLAVE_MYPORT2}\n"; + if ( ! $opt_skip_ndbcluster ) + { + print "Using NDBCLUSTER_PORT = $ENV{NDBCLUSTER_PORT}\n"; + if ( ! $opt_skip_ndbcluster_slave ) + { + print "Using NDBCLUSTER_PORT_SLAVE = $ENV{NDBCLUSTER_PORT_SLAVE}\n"; + } + } + if ( ! $opt_skip_im ) + { + print "Using IM_PORT = $ENV{IM_PORT}\n"; + print "Using IM_MYSQLD1_PORT = $ENV{IM_MYSQLD1_PORT}\n"; + print "Using IM_MYSQLD2_PORT = $ENV{IM_MYSQLD2_PORT}\n"; + } + } } @@ -1283,7 +1722,7 @@ sub signal_setup () { sub handle_int_signal () { $SIG{INT}= 'DEFAULT'; # If we get a ^C again, we die... mtr_warning("got INT signal, cleaning up....."); - stop_masters_slaves(); + stop_all_servers(); mtr_error("We die from ^C signal from user"); } @@ -1299,28 +1738,21 @@ sub kill_running_server () { if ( $opt_fast or $glob_use_embedded_server ) { # FIXME is embedded server really using PID files?! - unlink($master->[0]->{'path_mypid'}); - unlink($master->[1]->{'path_mypid'}); - unlink($slave->[0]->{'path_mypid'}); - unlink($slave->[1]->{'path_mypid'}); - unlink($slave->[2]->{'path_mypid'}); + unlink($master->[0]->{'path_pid'}); + unlink($master->[1]->{'path_pid'}); + unlink($slave->[0]->{'path_pid'}); + unlink($slave->[1]->{'path_pid'}); + unlink($slave->[2]->{'path_pid'}); } else { # Ensure that no old mysqld test servers are running # This is different from terminating processes we have - # started from ths run of the script, this is terminating + # started from this run of the script, this is terminating # leftovers from previous runs. - mtr_report("Killing Possible Leftover Processes"); - mkpath("$opt_vardir/log"); # Needed for mysqladmin log - mtr_kill_leftovers(); - - $using_ndbcluster_master= $opt_with_ndbcluster; - ndbcluster_stop(); - $master->[0]->{'ndbcluster'}= 1; - } + } } sub cleanup_stale_files () { @@ -1422,10 +1854,10 @@ sub check_running_as_root () { } +sub check_ssl_support ($) { + my $mysqld_variables= shift; -sub check_ssl_support () { - - if ($opt_skip_ssl) + if ($opt_skip_ssl || $opt_extern) { mtr_report("Skipping SSL"); $opt_ssl_supported= 0; @@ -1433,13 +1865,7 @@ sub check_ssl_support () { return; } - # check ssl support by testing using a switch - # that is only available in that case - if ( mtr_run($exe_mysqld, - ["--no-defaults", - "--ssl", - "--help"], - "", "/dev/null", "/dev/null", "") != 0 ) + if ( ! $mysqld_variables->{'ssl'} ) { if ( $opt_ssl) { @@ -1456,120 +1882,294 @@ sub check_ssl_support () { } +sub check_debug_support ($) { + my $mysqld_variables= shift; + + if ( $mysqld_variables->{'debug'} ) + { + #mtr_report("Binaries are not debug compiled"); + $debug_compiled_binaries= 0; + + if ( $opt_debug ) + { + mtr_error("Can't use --debug, binaries does not support it"); + } + return; + } + mtr_report("Binaries are debug compiled"); + $debug_compiled_binaries= 1; +} + ############################################################################## # # Start the ndb cluster # ############################################################################## -sub check_ndbcluster_support () { +sub check_ndbcluster_support ($) { + my $mysqld_variables= shift; if ($opt_skip_ndbcluster) { mtr_report("Skipping ndbcluster"); - $opt_with_ndbcluster= 0; + $opt_skip_ndbcluster_slave= 1; return; } - if ($opt_with_ndbcluster) - { - mtr_report("Using ndbcluster if necessary"); - return; - } - - # check ndbcluster support by testing using a switch - # that is only available in that case - if ( mtr_run($exe_mysqld, - ["--no-defaults", - "--ndb-use-exact-count", - "--help"], - "", "/dev/null", "/dev/null", "") != 0 ) + if ( ! $mysqld_variables->{'ndb-connectstring'} ) { mtr_report("Skipping ndbcluster, mysqld not compiled with ndbcluster"); - $opt_with_ndbcluster= 0; + $opt_skip_ndbcluster= 1; + $opt_skip_ndbcluster_slave= 1; return; } - mtr_report("Using ndbcluster if necessary, mysqld supports it"); - $opt_with_ndbcluster= 1; + $opt_ndbcluster_supported= 1; + mtr_report("Using ndbcluster when necessary, mysqld supports it"); return; } -sub ndbcluster_install () { +sub ndbcluster_start_install ($) { + my $cluster= shift; - if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) + if ( $opt_skip_ndbcluster or $glob_use_running_ndbcluster ) { return 0; } - mtr_report("Install ndbcluster"); - my $ndbcluster_opts= $opt_bench ? "" : "--small"; - if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", - ["--port=$opt_ndbcluster_port", - "--data-dir=$opt_vardir", - $ndbcluster_opts, - "--initial"], - "", "", "", "") ) + + mtr_report("Installing $cluster->{'name'} Cluster"); + + mkdir($cluster->{'data_dir'}); + + # Create a config file from template + my $ndb_no_ord=512; + my $ndb_no_attr=2048; + my $ndb_con_op=105000; + my $ndb_dmem="80M"; + my $ndb_imem="24M"; + my $ndb_pbmem="32M"; + my $nodes= $cluster->{'nodes'}; + my $ndb_host= "localhost"; + my $ndb_diskless= 0; + + if (!$opt_bench) { - return 1; + # Use a smaller configuration + $ndb_no_ord=32; + $ndb_con_op=5000; + $ndb_dmem="20M"; + $ndb_imem="1M"; + $ndb_pbmem="4M"; } - $using_ndbcluster_master= 1; - ndbcluster_stop(); - $master->[0]->{'ndbcluster'}= 1; + my $config_file_template= "ndb/ndb_config_${nodes}_node.ini"; + my $config_file= "$cluster->{'data_dir'}/config.ini"; + + open(IN, $config_file_template) + or mtr_error("Can't open $config_file_template: $!"); + open(OUT, ">", $config_file) + or mtr_error("Can't write to $config_file: $!"); + while () + { + chomp; + + s/CHOOSE_MaxNoOfAttributes/$ndb_no_attr/; + s/CHOOSE_MaxNoOfOrderedIndexes/$ndb_no_ord/; + s/CHOOSE_MaxNoOfConcurrentOperations/$ndb_con_op/; + s/CHOOSE_DataMemory/$ndb_dmem/; + s/CHOOSE_IndexMemory/$ndb_imem/; + s/CHOOSE_Diskless/$ndb_diskless/; + s/CHOOSE_HOSTNAME_.*/$ndb_host/; + s/CHOOSE_FILESYSTEM/$cluster->{'data_dir'}/; + s/CHOOSE_PORT_MGM/$cluster->{'port'}/; + if ( $mysql_version_id < 50000 ) + { + my $base_port= $cluster->{'port'} + 1; + s/CHOOSE_PORT_TRANSPORTER/$base_port/; + } + s/CHOOSE_DiskPageBufferMemory/$ndb_pbmem/; + + print OUT "$_ \n"; + } + close OUT; + close IN; + + + # Start cluster with "--initial" + + ndbcluster_start($cluster, "--initial"); return 0; } -sub ndbcluster_start ($) { - my $use_ndbcluster= shift; +sub ndbcluster_wait_started($$){ + my $cluster= shift; + my $ndb_waiter_extra_opt= shift; + my $path_waiter_log= "$cluster->{'data_dir'}/ndb_waiter.log"; + my $args; - if ( ! $use_ndbcluster ) + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--core"); + mtr_add_arg($args, "--ndb-connectstring=%s", $cluster->{'connect_string'}); + mtr_add_arg($args, "--timeout=60"); + + if ($ndb_waiter_extra_opt) { - $using_ndbcluster_master= 0; - return 0; + mtr_add_arg($args, "$ndb_waiter_extra_opt"); } + + # Start the ndb_waiter which will connect to the ndb_mgmd + # and poll it for state of the ndbd's, will return when + # all nodes in the cluster is started + my $res= mtr_run($exe_ndb_waiter, $args, + "", $path_waiter_log, $path_waiter_log, ""); + mtr_verbose("ndbcluster_wait_started, returns: $res") if $res; + return $res; +} + + + +sub mysqld_wait_started($){ + my $mysqld= shift; + + my $res= sleep_until_file_created($mysqld->{'path_pid'}, + $mysqld->{'start_timeout'}, + $mysqld->{'pid'}); + return $res == 0; +} + + +sub ndb_mgmd_wait_started($) { + my ($cluster)= @_; + + my $retries= 100; + while (ndbcluster_wait_started($cluster, "--no-contact") and + $retries) + { + # Millisceond sleep emulated with select + select(undef, undef, undef, (0.1)); + + $retries--; + } + + return $retries == 0; + +} + +sub ndb_mgmd_start ($) { + my $cluster= shift; + + my $args; # Arg vector + my $pid= -1; + + mtr_init_args(\$args); + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--core"); + mtr_add_arg($args, "--nodaemon"); + mtr_add_arg($args, "--config-file=%s", "$cluster->{'data_dir'}/config.ini"); + + + my $path_ndb_mgmd_log= "$cluster->{'data_dir'}/\l$cluster->{'name'}_ndb_mgmd.log"; + $pid= mtr_spawn($exe_ndb_mgmd, $args, "", + $path_ndb_mgmd_log, + $path_ndb_mgmd_log, + "", + { append_log_file => 1 }); + + # FIXME Should not be needed + # Unfortunately the cluster nodes will fail to start + # if ndb_mgmd has not started properly + if (ndb_mgmd_wait_started($cluster)) + { + mtr_error("Failed to wait for start of ndb_mgmd"); + } + + # Remember pid of ndb_mgmd + $cluster->{'pid'}= $pid; + + mtr_verbose("ndb_mgmd_start, pid: $pid"); + + return $pid; +} + + +sub ndbd_start ($$$) { + my $cluster= shift; + my $idx= shift; + my $extra_args= shift; + + my $args; # Arg vector + my $pid= -1; + + mtr_init_args(\$args); + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--core"); + mtr_add_arg($args, "--ndb-connectstring=%s", "$cluster->{'connect_string'}"); + if ( $mysql_version_id >= 50000) + { + mtr_add_arg($args, "--character-sets-dir=%s", "$path_charsetsdir"); + } + mtr_add_arg($args, "--nodaemon"); + mtr_add_arg($args, "$extra_args"); + + my $nodeid= $cluster->{'ndbds'}->[$idx]->{'nodeid'}; + my $path_ndbd_log= "$cluster->{'data_dir'}/ndb_${nodeid}.log"; + $pid= mtr_spawn($exe_ndbd, $args, "", + $path_ndbd_log, + $path_ndbd_log, + "", + { append_log_file => 1 }); + + # Add pid to list of pids for this cluster + $cluster->{'ndbds'}->[$idx]->{'pid'}= $pid; + + # Rememeber options used when starting + $cluster->{'ndbds'}->[$idx]->{'start_extra_args'}= $extra_args; + $cluster->{'ndbds'}->[$idx]->{'idx'}= $idx; + + mtr_verbose("ndbd_start, pid: $pid"); + + return $pid; +} + + +sub ndbcluster_start ($$) { + my $cluster= shift; + my $extra_args= shift; + + mtr_verbose("ndbcluster_start '$cluster->{'name'}'"); + if ( $glob_use_running_ndbcluster ) { - $using_ndbcluster_master= 1; return 0; } - if ( $using_ndbcluster_master ) - { - # Master already started - return 0; - } - # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null - if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", - ["--port=$opt_ndbcluster_port", - "--data-dir=$opt_vardir", - "--character-sets-dir=$path_charsetsdir"], - "", "/dev/null", "", "") ) - { - mtr_error("Error ndbcluster_start"); - return 1; - } - $using_ndbcluster_master= 1; + if ( $cluster->{'pid'} ) + { + mtr_error("Cluster '$cluster->{'name'}' already started"); + } + + ndb_mgmd_start($cluster); + + for ( my $idx= 0; $idx < $cluster->{'nodes'}; $idx++ ) + { + ndbd_start($cluster, $idx, $extra_args); + } + return 0; } -sub ndbcluster_stop () { - if ( ! $using_ndbcluster_master or $glob_use_running_ndbcluster ) +sub rm_ndbcluster_tables ($) { + my $dir= shift; + foreach my $bin ( glob("$dir/cluster/apply_status*"), + glob("$dir/cluster/schema*") ) { - $using_ndbcluster_master= 0; - return; + unlink($bin); } - # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null - mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", - ["--port=$opt_ndbcluster_port", - "--data-dir=$opt_vardir", - "--stop"], - "", "/dev/null", "", ""); - - $using_ndbcluster_master= 0; - return; } @@ -1584,10 +2184,9 @@ sub run_benchmarks ($) { my $args; - if ( ! $glob_use_embedded_server and ! $opt_local_master ) + if ( ! $glob_use_embedded_server ) { - $master->[0]->{'pid'}= mysqld_start('master',0,[],[], - $using_ndbcluster_master); + mysqld_start($master->[0],[],[]); if ( ! $master->[0]->{'pid'} ) { mtr_error("Can't start the mysqld server"); @@ -1596,7 +2195,7 @@ sub run_benchmarks ($) { mtr_init_args(\$args); - mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_mysock'}); + mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'}); mtr_add_arg($args, "--user=%s", $opt_user); if ( $opt_small_bench ) @@ -1610,10 +2209,8 @@ sub run_benchmarks ($) { mtr_add_arg($args, "--create-options=TYPE=ndb"); } - my $benchdir= "$glob_basedir/sql-bench"; - chdir($benchdir); # FIXME check error - - # FIXME write shorter.... + chdir($glob_mysql_bench_dir) + or mtr_error("Couldn't chdir to '$glob_mysql_bench_dir': $!"); if ( ! $benchmark ) { @@ -1646,24 +2243,26 @@ sub run_benchmarks ($) { # ############################################################################## -# FIXME how to specify several suites to run? Comma separated list? - - sub run_suite () { my ($suite, $tests)= @_; mtr_print_thick_line(); - mtr_report("Finding Tests in the '$suite' suite"); - mtr_timer_start($glob_timers,"suite", 60 * $opt_suite_timeout); mtr_report("Starting Tests in the '$suite' suite"); + mtr_report_tests_not_skipped_though_disabled($tests); + mtr_print_header(); foreach my $tinfo ( @$tests ) { + if (run_testcase_check_skip_test($tinfo)) + { + next; + } + mtr_timer_start($glob_timers,"testcase", 60 * $opt_testcase_timeout); run_testcase($tinfo); mtr_timer_stop($glob_timers,"testcase"); @@ -1675,7 +2274,7 @@ sub run_suite () { ! $glob_use_running_server and ! $glob_use_embedded_server ) { - stop_masters_slaves(); + stop_all_servers(); } if ( $opt_gcov ) @@ -1719,15 +2318,15 @@ sub initialize_servers () { sub mysql_install_db () { - # FIXME not exactly true I think, needs improvements install_db('master', $master->[0]->{'path_myddir'}); - install_db('master', $master->[1]->{'path_myddir'}); - if ( $use_slaves ) + # FIXME check if testcase really is using second master + copy_install_db('master', $master->[1]->{'path_myddir'}); + + # Install the number of slave databses needed + for (my $idx= 0; $idx < $max_slave_num; $idx++) { - install_db('slave', $slave->[0]->{'path_myddir'}); - install_db('slave', $slave->[1]->{'path_myddir'}); - install_db('slave', $slave->[2]->{'path_myddir'}); + copy_install_db("slave".($idx+1), $slave->[$idx]->{'path_myddir'}); } if ( ! $opt_skip_im ) @@ -1735,28 +2334,64 @@ sub mysql_install_db () { im_prepare_env($instance_manager); } - if ( ndbcluster_install() ) + my $cluster_started_ok= 1; # Assume it can be started + + if (ndbcluster_start_install($clusters->[0]) || + ($max_slave_num && !$opt_skip_ndbcluster_slave && + ndbcluster_start_install($clusters->[1]))) { - if ( $opt_force) + mtr_warning("Failed to start install of cluster"); + $cluster_started_ok= 0; + } + + foreach my $cluster (@{$clusters}) + { + + next if !$cluster->{'pid'}; + + $cluster->{'installed_ok'}= 1; # Assume install suceeds + + if (ndbcluster_wait_started($cluster, "")) { # failed to install, disable usage and flag that its no ok - mtr_report("ndbcluster_install failed, continuing without cluster"); - $opt_with_ndbcluster= 0; - $flag_ndb_status_ok= 0; - $ENV{'NDB_STATUS_OK'}= "NO"; - } - else - { - print "Aborting: Failed to install ndb cluster\n"; - print "To continue, re-run with '--force'.\n"; - mtr_exit(1); + mtr_report("ndbcluster_install of $cluster->{'name'} failed"); + $cluster->{"installed_ok"}= 0; + + $cluster_started_ok= 0; } } + if ( ! $cluster_started_ok ) + { + if ( $opt_force) + { + # Continue without cluster + } + else + { + mtr_error("To continue, re-run with '--force'."); + } + } + + # Stop clusters... + stop_all_servers(); + return 0; } +sub copy_install_db ($$) { + my $type= shift; + my $data_dir= shift; + + mtr_report("Installing \u$type Database"); + + # Just copy the installed db from first master + mtr_copy_dir($master->[0]->{'path_myddir'}, $data_dir); + +} + + sub install_db ($$) { my $type= shift; my $data_dir= shift; @@ -1801,9 +2436,15 @@ sub install_db ($$) { mtr_add_arg($args, "--datadir=%s", $data_dir); mtr_add_arg($args, "--skip-innodb"); mtr_add_arg($args, "--skip-ndbcluster"); - mtr_add_arg($args, "--skip-bdb"); + mtr_add_arg($args, "--tmpdir=."); - if ( ! $opt_netware ) + if ( $opt_debug ) + { + mtr_add_arg($args, "--debug=d:t:i:A,%s/log/bootstrap_%s.trace", + $path_vardir_trace, $type); + } + + if ( ! $glob_netware ) { mtr_add_arg($args, "--language=%s", $path_language); mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); @@ -1893,12 +2534,12 @@ basedir = $path_my_basedir server_id = $server_id skip-stack-trace skip-innodb -skip-bdb skip-ndbcluster EOF ; print OUT "nonguarded\n" if $instance->{'nonguarded'}; + print OUT "log-output=FILE\n" if $instance->{'old_log_format'}; print OUT "\n"; } @@ -1911,13 +2552,112 @@ sub im_prepare_data_dir($) { foreach my $instance (@{$instance_manager->{'instances'}}) { - install_db( + copy_install_db( 'im_mysqld_' . $instance->{'server_id'}, $instance->{'path_datadir'}); } } + +# +# Restore snapshot of the installed slave databases +# if the snapshot exists +# +sub restore_slave_databases ($) { + my ($num_slaves)= @_; + + if ( -d $path_snapshot) + { + for (my $idx= 0; $idx < $num_slaves; $idx++) + { + my $data_dir= $slave->[$idx]->{'path_myddir'}; + my $name= basename($data_dir); + rmtree($data_dir); + mtr_copy_dir("$path_snapshot/$name", $data_dir); + } + } +} + + +sub run_testcase_check_skip_test($) +{ + my ($tinfo)= @_; + + # ---------------------------------------------------------------------- + # If marked to skip, just print out and return. + # Note that a test case not marked as 'skip' can still be + # skipped later, because of the test case itself in cooperation + # with the mysqltest program tells us so. + # ---------------------------------------------------------------------- + + if ( $tinfo->{'skip'} ) + { + mtr_report_test_name($tinfo); + mtr_report_test_skipped($tinfo); + return 1; + } + + # If test needs cluster, check that master installed ok + if ( $tinfo->{'ndb_test'} and !$clusters->[0]->{'installed_ok'} ) + { + mtr_report_test_name($tinfo); + mtr_report_test_failed($tinfo); + return 1; + } + + # If test needs slave cluster, check that it installed ok + if ( $tinfo->{'ndb_test'} and $tinfo->{'slave_num'} and + !$clusters->[1]->{'installed_ok'} ) + { + mtr_report_test_name($tinfo); + mtr_report_test_failed($tinfo); + return 1; + } + + return 0; +} + + +sub do_before_run_mysqltest($) +{ + my $tinfo= shift; + my $tname= $tinfo->{'name'}; + + # Remove old reject file + if ( $opt_suite eq "main" ) + { + unlink("r/$tname.reject"); + } + else + { + unlink("suite/$opt_suite/r/$tname.reject"); + } + + mtr_tonewfile($path_current_test_log,"$tname\n"); # Always tell where we are + + # output current test to ndbcluster log file to enable diagnostics + mtr_tofile($path_ndb_testrun_log,"CURRENT TEST $tname\n"); + + mtr_tofile($master->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + if ( $master->[1]->{'pid'} ) + { + mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + } +} + +sub do_after_run_mysqltest($) +{ + my $tinfo= shift; + my $tname= $tinfo->{'name'}; + + # Save info from this testcase run to mysqltest.log + mtr_appendfile_to_file($path_timefile, $path_mysqltest_log) + if -f $path_timefile; + mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n"); +} + + ############################################################################## # # Run a single test case @@ -1937,237 +2677,34 @@ sub im_prepare_data_dir($) { sub run_testcase ($) { my $tinfo= shift; - my $tname= $tinfo->{'name'}; + my $master_restart= run_testcase_need_master_restart($tinfo); + my $slave_restart= run_testcase_need_slave_restart($tinfo); - mtr_tonewfile($path_current_test_log,"$tname\n"); # Always tell where we are - - # output current test to ndbcluster log file to enable diagnostics - mtr_tofile($file_ndb_testrun_log,"CURRENT TEST $tname\n"); - - # ---------------------------------------------------------------------- - # If marked to skip, just print out and return. - # Note that a test case not marked as 'skip' can still be - # skipped later, because of the test case itself in cooperation - # with the mysqltest program tells us so. - # ---------------------------------------------------------------------- - - if ( $tinfo->{'skip'} ) + if ($master_restart or $slave_restart) { - mtr_report_test_name($tinfo); - mtr_report_test_skipped($tinfo); - return; + run_testcase_stop_servers($tinfo, $master_restart, $slave_restart); } - - if ( $tinfo->{'ndb_test'} and ! $flag_ndb_status_ok ) + my $died= mtr_record_dead_children(); + if ($died or $master_restart or $slave_restart) { - mtr_report_test_name($tinfo); - mtr_report_test_failed($tinfo); - return; - } - - # ---------------------------------------------------------------------- - # If not using a running servers we may need to stop and restart. - # We restart in the case we have initiation scripts, server options - # etc to run. But we also restart again after the test first restart - # and test is run, to get back to normal server settings. - # - # To make the code a bit more clean, we actually only stop servers - # here, and mark this to be done. Then a generic "start" part will - # start up the needed servers again. - # ---------------------------------------------------------------------- - - if ( ! $glob_use_running_server and ! $glob_use_embedded_server ) - { - # We try to find out if we are to restart the server - my $do_restart= 0; # Assumes we don't have to - - if ( $tinfo->{'master_sh'} ) - { - $do_restart= 1; # Always restart if script to run - } - elsif ( $opt_with_ndbcluster and $tinfo->{'ndb_test'} != $using_ndbcluster_master ) - { - $do_restart= 1; # Restart without cluster - } - elsif ( $master->[0]->{'running_master_is_special'} and - $master->[0]->{'running_master_is_special'}->{'timezone'} eq - $tinfo->{'timezone'} and - mtr_same_opts($master->[0]->{'running_master_is_special'}->{'master_opt'}, - $tinfo->{'master_opt'}) ) - { - # If running master was started with special settings, but - # the current test requuires the same ones, we *don't* restart. - $do_restart= 0; - } - elsif ( $tinfo->{'master_restart'} or - $master->[0]->{'running_master_is_special'} ) - { - $do_restart= 1; - } - - if ( $do_restart ) - { - stop_masters(); - delete $master->[0]->{'running_master_is_special'}; # Forget history - } - - # ---------------------------------------------------------------------- - # Always terminate all slaves, if any. Else we may have useless - # reconnection attempts and error messages in case the slave and - # master servers restart. - # ---------------------------------------------------------------------- - - stop_slaves(); - } - - # ---------------------------------------------------------------------- - # Prepare to start masters. Even if we use embedded, we want to run - # the preparation. - # ---------------------------------------------------------------------- - - $ENV{'TZ'}= $tinfo->{'timezone'}; - - mtr_report_test_name($tinfo); - - mtr_tofile($master->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); - - # FIXME test cases that depend on each other, prevent this from - # being at this location. - # do_before_start_master($tname,$tinfo->{'master_sh'}); - - # ---------------------------------------------------------------------- - # If any mysqld servers running died, we have to know - # ---------------------------------------------------------------------- - - mtr_record_dead_children(); - - # ---------------------------------------------------------------------- - # Start masters - # ---------------------------------------------------------------------- - - if ( ! $glob_use_running_server and ! $glob_use_embedded_server ) - { - # FIXME give the args to the embedded server?! - # FIXME what does $opt_local_master mean?! - # FIXME split up start and check that started so that can do - # starts in parallel, masters and slaves at the same time. - - if ( $tinfo->{'component_id'} eq 'mysqld' and ! $opt_local_master ) - { - if ( $opt_with_ndbcluster and $master->[0]->{'ndbcluster'} ) - { - # Cluster is not started - - # Call ndbcluster_start to check if test case needs cluster - # Start it if not already started - $master->[0]->{'ndbcluster'}= ndbcluster_start($tinfo->{'ndb_test'}); - if ( $master->[0]->{'ndbcluster'} ) - { - report_failure_and_restart($tinfo); - return; - } - } - if ( ! $master->[0]->{'pid'} ) - { - # FIXME not correct location for do_before_start_master() - do_before_start_master($tname,$tinfo->{'master_sh'}); - $master->[0]->{'pid'}= - mysqld_start('master',0,$tinfo->{'master_opt'},[], - $using_ndbcluster_master); - if ( ! $master->[0]->{'pid'} ) - { - report_failure_and_restart($tinfo); - return; - } - } - if ( $using_ndbcluster_master and ! $master->[1]->{'pid'} ) - { - # Test needs cluster, start an extra mysqld connected to cluster - $master->[1]->{'pid'}= - mysqld_start('master',1,$tinfo->{'master_opt'},[], - $using_ndbcluster_master); - if ( ! $master->[1]->{'pid'} ) - { - report_failure_and_restart($tinfo); - return; - } - } - - if ( $tinfo->{'master_restart'} ) - { - # Save this test case information, so next can examine it - $master->[0]->{'running_master_is_special'}= $tinfo; - } - } - elsif ( ! $opt_skip_im and $tinfo->{'component_id'} eq 'im' ) - { - # We have to create defaults file every time, in order to ensure that it - # will be the same for each test. The problem is that test can change the - # file (by SET/UNSET commands), so w/o recreating the file, execution of - # one test can affect the other. - - im_create_defaults_file($instance_manager); - - mtr_im_start($instance_manager, $tinfo->{im_opts}); - } - - # ---------------------------------------------------------------------- - # Start slaves - if needed - # ---------------------------------------------------------------------- - - if ( $tinfo->{'slave_num'} ) - { - mtr_tofile($slave->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); - - do_before_start_slave($tname,$tinfo->{'slave_sh'}); - - for ( my $idx= 0; $idx < $tinfo->{'slave_num'}; $idx++ ) - { - if ( ! $slave->[$idx]->{'pid'} ) - { - $slave->[$idx]->{'pid'}= - mysqld_start('slave',$idx, - $tinfo->{'slave_opt'}, $tinfo->{'slave_mi'}, - 0); - if ( ! $slave->[$idx]->{'pid'} ) - { - report_failure_and_restart($tinfo); - return; - } - } - } - } + run_testcase_start_servers($tinfo); } # ---------------------------------------------------------------------- # If --start-and-exit or --start-dirty given, stop here to let user manually # run tests # ---------------------------------------------------------------------- - if ( $opt_start_and_exit or $opt_start_dirty ) { mtr_report("\nServers started, exiting"); exit(0); } - # ---------------------------------------------------------------------- - # Run the test case - # ---------------------------------------------------------------------- - { - # remove the old reject file - if ( $opt_suite eq "main" ) - { - unlink("r/$tname.reject"); - } - else - { - unlink("suite/$opt_suite/r/$tname.reject"); - } - unlink($path_timefile); + do_before_run_mysqltest($tinfo); my $res= run_mysqltest($tinfo); - + mtr_report_test_name($tinfo); if ( $res == 0 ) { mtr_report_test_passed($tinfo); @@ -2175,6 +2712,12 @@ sub run_testcase ($) { elsif ( $res == 62 ) { # Testcase itself tell us to skip this one + + # Try to get reason from mysqltest.log + my $last_line= mtr_lastlinefromfile($path_timefile) if -f $path_timefile; + my $reason= mtr_match_prefix($last_line, "reason: "); + $tinfo->{'comment'}= + defined $reason ? $reason : "Detected by testcase(reason unknown) "; mtr_report_test_skipped($tinfo); } elsif ( $res == 63 ) @@ -2191,12 +2734,11 @@ sub run_testcase ($) { "mysqltest returned unexpected code $res, " . "it has probably crashed"); } + report_failure_and_restart($tinfo); } - # Save info from this testcase run to mysqltest.log - my $testcase_log= mtr_fromfile($path_timefile) if -f $path_timefile; - mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n"); - mtr_tofile($path_mysqltest_log, $testcase_log); + + do_after_run_mysqltest($tinfo); } # ---------------------------------------------------------------------- @@ -2205,7 +2747,10 @@ sub run_testcase ($) { if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' ) { - mtr_im_stop($instance_manager); + unless ( mtr_im_stop($instance_manager, $tinfo->{'name'}) ) + { + mtr_error("Failed to stop Instance Manager.") + } } } @@ -2256,8 +2801,6 @@ sub restore_installed_db ($) { if ( -d $path_snapshot) { - kill_running_server (); - mtr_report("Restoring snapshot of databases"); foreach my $data_dir (@data_dir_lst) @@ -2267,21 +2810,24 @@ sub restore_installed_db ($) { rmtree("$data_dir"); mtr_copy_dir("$path_snapshot/$name", "$data_dir"); } - if ($opt_with_ndbcluster) + + # Remove the ndb_*_fs dirs for all ndbd nodes + # forcing a clean start of ndb + foreach my $cluster (@{$clusters}) { - # Remove the ndb_*_fs dirs, forcing a clean start of ndb - rmtree("$path_ndb_data_dir/ndb_1_fs"); - rmtree("$path_ndb_data_dir/ndb_2_fs"); + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + rmtree("$ndbd->{'path_fs'}" ); + } } } else { - # No snapshot existed, just stop all processes - stop_masters_slaves(); + # No snapshot existed + mtr_error("No snapshot existed"); } } - sub report_failure_and_restart ($) { my $tinfo= shift; @@ -2290,6 +2836,9 @@ sub report_failure_and_restart ($) { print "\n"; if ( $opt_force ) { + # Stop all servers that are known to be running + stop_all_servers(); + # Restore the snapshot of the installed test db restore_installed_db($tinfo->{'name'}); print "Resuming Tests\n\n"; @@ -2303,7 +2852,7 @@ sub report_failure_and_restart ($) { ! $glob_use_running_server and ! $glob_use_embedded_server ) { - stop_masters_slaves(); + stop_all_servers(); } mtr_exit(1); @@ -2397,18 +2946,17 @@ sub do_before_start_slave ($$) { } -sub mysqld_arguments ($$$$$$) { +sub mysqld_arguments ($$$$$) { my $args= shift; - my $type= shift; # master/slave/bootstrap + my $type= shift; my $idx= shift; my $extra_opt= shift; my $slave_master_info= shift; - my $using_ndbcluster= shift; my $sidx= ""; # Index as string, 0 is empty string if ( $idx > 0 ) { - $sidx= sprintf("%d", $idx); # sprintf not needed in Perl for this + $sidx= "$idx"; } my $prefix= ""; # If mysqltest server arg @@ -2424,8 +2972,12 @@ sub mysqld_arguments ($$$$$$) { mtr_add_arg($args, "%s--console", $prefix); mtr_add_arg($args, "%s--basedir=%s", $prefix, $path_my_basedir); mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir); - mtr_add_arg($args, "%s--core", $prefix); - mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); + + if ( $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); + } + mtr_add_arg($args, "%s--default-character-set=latin1", $prefix); mtr_add_arg($args, "%s--language=%s", $prefix, $path_language); mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); @@ -2433,7 +2985,6 @@ sub mysqld_arguments ($$$$$$) { if ( $opt_valgrind_mysqld ) { mtr_add_arg($args, "%s--skip-safemalloc", $prefix); - mtr_add_arg($args, "%s--skip-bdb", $prefix); } my $pidfile; @@ -2442,26 +2993,31 @@ sub mysqld_arguments ($$$$$$) { { my $id= $idx > 0 ? $idx + 101 : 1; - mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix, - $opt_vardir, $sidx); + if (! $opt_skip_master_binlog) + { + mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix, + $opt_vardir, $sidx); + } mtr_add_arg($args, "%s--pid-file=%s", $prefix, - $master->[$idx]->{'path_mypid'}); + $master->[$idx]->{'path_pid'}); mtr_add_arg($args, "%s--port=%d", $prefix, - $master->[$idx]->{'path_myport'}); + $master->[$idx]->{'port'}); mtr_add_arg($args, "%s--server-id=%d", $prefix, $id); mtr_add_arg($args, "%s--socket=%s", $prefix, - $master->[$idx]->{'path_mysock'}); - mtr_add_arg($args, "%s--innodb_data_file_path=ibdata1:128M:autoextend", $prefix); + $master->[$idx]->{'path_sock'}); + mtr_add_arg($args, "%s--innodb_data_file_path=ibdata1:10M:autoextend", $prefix); mtr_add_arg($args, "%s--local-infile", $prefix); mtr_add_arg($args, "%s--datadir=%s", $prefix, $master->[$idx]->{'path_myddir'}); - if ( $idx > 0 ) + if ( $idx > 0 or !$use_innodb) { mtr_add_arg($args, "%s--skip-innodb", $prefix); } - if ( $opt_skip_ndbcluster || !$using_ndbcluster) + my $cluster= $clusters->[$master->[$idx]->{'cluster'}]; + if ( $opt_skip_ndbcluster || + !$cluster->{'pid'}) { mtr_add_arg($args, "%s--skip-ndbcluster", $prefix); } @@ -2469,7 +3025,11 @@ sub mysqld_arguments ($$$$$$) { { mtr_add_arg($args, "%s--ndbcluster", $prefix); mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, - $opt_ndbconnectstring); + $cluster->{'connect_string'}); + if ( $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + } } } @@ -2480,25 +3040,26 @@ sub mysqld_arguments ($$$$$$) { mtr_add_arg($args, "%s--datadir=%s", $prefix, $slave->[$idx]->{'path_myddir'}); - # FIXME slave get this option twice?! - mtr_add_arg($args, "%s--exit-info=256", $prefix); mtr_add_arg($args, "%s--init-rpl-role=slave", $prefix); - mtr_add_arg($args, "%s--log-bin=%s/log/slave%s-bin", $prefix, - $opt_vardir, $sidx); # FIXME use own dir for binlogs - mtr_add_arg($args, "%s--log-slave-updates", $prefix); - # FIXME option duplicated for slave + if (! $opt_skip_slave_binlog) + { + mtr_add_arg($args, "%s--log-bin=%s/log/slave%s-bin", $prefix, + $opt_vardir, $sidx); # FIXME use own dir for binlogs + mtr_add_arg($args, "%s--log-slave-updates", $prefix); + } + mtr_add_arg($args, "%s--log=%s", $prefix, $slave->[$idx]->{'path_mylog'}); mtr_add_arg($args, "%s--master-retry-count=10", $prefix); mtr_add_arg($args, "%s--pid-file=%s", $prefix, - $slave->[$idx]->{'path_mypid'}); + $slave->[$idx]->{'path_pid'}); mtr_add_arg($args, "%s--port=%d", $prefix, - $slave->[$idx]->{'path_myport'}); + $slave->[$idx]->{'port'}); mtr_add_arg($args, "%s--relay-log=%s/log/slave%s-relay-bin", $prefix, $opt_vardir, $sidx); mtr_add_arg($args, "%s--report-host=127.0.0.1", $prefix); mtr_add_arg($args, "%s--report-port=%d", $prefix, - $slave->[$idx]->{'path_myport'}); + $slave->[$idx]->{'port'}); mtr_add_arg($args, "%s--report-user=root", $prefix); mtr_add_arg($args, "%s--skip-innodb", $prefix); mtr_add_arg($args, "%s--skip-ndbcluster", $prefix); @@ -2510,7 +3071,7 @@ sub mysqld_arguments ($$$$$$) { mtr_add_arg($args, "%s--slave-load-tmpdir=%s", $prefix, "../tmp"); mtr_add_arg($args, "%s--socket=%s", $prefix, - $slave->[$idx]->{'path_mysock'}); + $slave->[$idx]->{'path_sock'}); mtr_add_arg($args, "%s--set-variable=slave_net_timeout=10", $prefix); if ( @$slave_master_info ) @@ -2527,10 +3088,27 @@ sub mysqld_arguments ($$$$$$) { mtr_add_arg($args, "%s--master-host=127.0.0.1", $prefix); mtr_add_arg($args, "%s--master-password=", $prefix); mtr_add_arg($args, "%s--master-port=%d", $prefix, - $master->[0]->{'path_myport'}); # First master + $master->[0]->{'port'}); # First master mtr_add_arg($args, "%s--server-id=%d", $prefix, $slave_server_id); mtr_add_arg($args, "%s--rpl-recovery-rank=%d", $prefix, $slave_rpl_rank); } + + if ( $opt_skip_ndbcluster_slave || + $slave->[$idx]->{'cluster'} == -1 || + !$clusters->[$slave->[$idx]->{'cluster'}]->{'pid'} ) + { + mtr_add_arg($args, "%s--skip-ndbcluster", $prefix); + } + else + { + mtr_add_arg($args, "%s--ndbcluster", $prefix); + mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, + $clusters->[$slave->[$idx]->{'cluster'}]->{'connect_string'}); + if ( $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + } + } } # end slave if ( $opt_debug ) @@ -2538,12 +3116,12 @@ sub mysqld_arguments ($$$$$$) { if ( $type eq 'master' ) { mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/master%s.trace", - $prefix, $opt_vardir_trace, $sidx); + $prefix, $path_vardir_trace, $sidx); } if ( $type eq 'slave' ) { mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/slave%s.trace", - $prefix, $opt_vardir_trace, $sidx); + $prefix, $path_vardir_trace, $sidx); } } @@ -2551,7 +3129,6 @@ sub mysqld_arguments ($$$$$$) { mtr_add_arg($args, "%s--key_buffer_size=1M", $prefix); mtr_add_arg($args, "%s--sort_buffer=256K", $prefix); mtr_add_arg($args, "%s--max_heap_table_size=1M", $prefix); - mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); if ( $opt_ssl_supported ) { @@ -2582,27 +3159,22 @@ sub mysqld_arguments ($$$$$$) { mtr_add_arg($args, "%s--user=root", $prefix); } - if ( $type eq 'master' ) - { - - if ( ! $opt_old_master ) - { - mtr_add_arg($args, "%s--rpl-recovery-rank=1", $prefix); - mtr_add_arg($args, "%s--init-rpl-role=master", $prefix); - } - - # FIXME strange,..... - # FIXME MYSQL_MYPORT is not set anythere?! - if ( $opt_local_master ) - { - mtr_add_arg($args, "%s--host=127.0.0.1", $prefix); - mtr_add_arg($args, "%s--port=%s", $prefix, $ENV{'MYSQL_MYPORT'}); - } - } - + my $found_skip_core= 0; foreach my $arg ( @opt_extra_mysqld_opt, @$extra_opt ) { - mtr_add_arg($args, "%s%s", $prefix, $arg); + # Allow --skip-core-file to be set in master.opt file + if ($arg eq "--skip-core-file") + { + $found_skip_core= 1; + } + else + { + mtr_add_arg($args, "%s%s", $prefix, $arg); + } + } + if ( !$found_skip_core ) + { + mtr_add_arg($args, "%s%s", $prefix, "--core-file"); } if ( $opt_bench ) @@ -2612,7 +3184,6 @@ sub mysqld_arguments ($$$$$$) { } elsif ( $type eq 'master' ) { - mtr_add_arg($args, "%s--exit-info=256", $prefix); mtr_add_arg($args, "%s--open-files-limit=1024", $prefix); mtr_add_arg($args, "%s--log=%s", $prefix, $master->[0]->{'path_mylog'}); } @@ -2627,17 +3198,18 @@ sub mysqld_arguments ($$$$$$) { # ############################################################################## -sub mysqld_start ($$$$$) { - my $type= shift; # master/slave/bootstrap - my $idx= shift; +sub mysqld_start ($$$) { + my $mysqld= shift; my $extra_opt= shift; my $slave_master_info= shift; - my $using_ndbcluster= shift; - my $args; # Arg vector my $exe; my $pid= -1; + my $wait_for_pid_file= 1; + + my $type= $mysqld->{'type'}; + my $idx= $mysqld->{'idx'}; if ( $type eq 'master' ) { @@ -2649,7 +3221,7 @@ sub mysqld_start ($$$$$) { } else { - $exe= $exe_mysqld; + mtr_error("Unknown 'type' \"$type\" passed to mysqld_start"); } mtr_init_args(\$args); @@ -2659,8 +3231,7 @@ sub mysqld_start ($$$$$) { valgrind_arguments($args, \$exe); } - mysqld_arguments($args,$type,$idx,$extra_opt,$slave_master_info, - $using_ndbcluster); + mysqld_arguments($args,$type,$idx,$extra_opt,$slave_master_info); if ( $opt_gdb || $opt_manual_gdb) { @@ -2685,6 +3256,11 @@ sub mysqld_start ($$$$$) { # Indicate the exe should not be started $exe= undef; } + else + { + # Default to not wait until pid file has been created + $wait_for_pid_file= 0; + } if ($exe_libtool and $opt_valgrind) { @@ -2695,105 +3271,534 @@ sub mysqld_start ($$$$$) { } - if ( $type eq 'master' ) + if ( defined $exe ) { - if ( ! defined $exe or - $pid= mtr_spawn($exe, $args, "", - $master->[$idx]->{'path_myerr'}, - $master->[$idx]->{'path_myerr'}, - "", - { append_log_file => 1 }) ) - { - return sleep_until_file_created($master->[$idx]->{'path_mypid'}, - $master->[$idx]->{'start_timeout'}, - $pid); - } + $pid= mtr_spawn($exe, $args, "", + $mysqld->{'path_myerr'}, + $mysqld->{'path_myerr'}, + "", + { append_log_file => 1 }); } - if ( $type eq 'slave' ) + + if ( $wait_for_pid_file && !sleep_until_file_created($mysqld->{'path_pid'}, + $mysqld->{'start_timeout'}, + $pid)) { - if ( ! defined $exe or - $pid= mtr_spawn($exe, $args, "", - $slave->[$idx]->{'path_myerr'}, - $slave->[$idx]->{'path_myerr'}, - "", - { append_log_file => 1 }) ) - { - return sleep_until_file_created($slave->[$idx]->{'path_mypid'}, - $master->[$idx]->{'start_timeout'}, - $pid); - } + + mtr_error("Failed to start mysqld $mysqld->{'type'}"); } - return 0; + + # Remember pid of the started process + $mysqld->{'pid'}= $pid; + + # Remember options used when starting + $mysqld->{'start_opts'}= $extra_opt; + $mysqld->{'start_slave_master_info'}= $slave_master_info; + + mtr_verbose("mysqld pid: $pid"); + return $pid; } -sub stop_masters_slaves () { +sub stop_all_servers () { - print "Ending Tests\n"; + print "Stopping All Servers\n"; - print "Shutting-down Instance Manager\n"; - mtr_im_stop($instance_manager); - - print "Shutting-down MySQL daemon\n\n"; - stop_masters(); - print "Master(s) shutdown finished\n"; - stop_slaves(); - print "Slave(s) shutdown finished\n"; -} - - -sub stop_masters () { - - my @args; - - for ( my $idx; $idx < 2; $idx++ ) + if ( ! $opt_skip_im ) { - # FIXME if we hit ^C before fully started, this test will prevent - # the mysqld process from being killed - if ( $master->[$idx]->{'pid'} ) + print "Shutting-down Instance Manager\n"; + unless (mtr_im_stop($instance_manager, "stop_all_servers")) { - push(@args,{ - pid => $master->[$idx]->{'pid'}, - pidfile => $master->[$idx]->{'path_mypid'}, - sockfile => $master->[$idx]->{'path_mysock'}, - port => $master->[$idx]->{'path_myport'}, - }); - $master->[$idx]->{'pid'}= 0; # Assume we are done with it + mtr_error("Failed to stop Instance Manager.") } } - if ( ! $master->[0]->{'ndbcluster'} ) + my %admin_pids; # hash of admin processes that requests shutdown + my @kill_pids; # list of processes to shutdown/kill + my $pid; + + # Start shutdown of all started masters + foreach my $mysqld (@{$master}, @{$slave}) { - ndbcluster_stop(); - $master->[0]->{'ndbcluster'}= 1; - } - - mtr_stop_mysqld_servers(\@args); -} - - -sub stop_slaves () { - my $force= shift; - - my @args; - - for ( my $idx; $idx < 3; $idx++ ) - { - if ( $slave->[$idx]->{'pid'} ) + if ( $mysqld->{'pid'} ) { - push(@args,{ - pid => $slave->[$idx]->{'pid'}, - pidfile => $slave->[$idx]->{'path_mypid'}, - sockfile => $slave->[$idx]->{'path_mysock'}, - port => $slave->[$idx]->{'path_myport'}, - }); - $slave->[$idx]->{'pid'}= 0; # Assume we are done with it + $pid= mtr_mysqladmin_start($mysqld, "shutdown", 70); + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $mysqld->{'pid'}, + pidfile => $mysqld->{'path_pid'}, + sockfile => $mysqld->{'path_sock'}, + port => $mysqld->{'port'}, + }); + + $mysqld->{'pid'}= 0; # Assume we are done with it } } - mtr_stop_mysqld_servers(\@args); + # Start shutdown of clusters + foreach my $cluster (@{$clusters}) + { + if ( $cluster->{'pid'} ) + { + $pid= mtr_ndbmgm_start($cluster, "shutdown"); + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $cluster->{'pid'}, + pidfile => $cluster->{'path_pid'} + }); + + $cluster->{'pid'}= 0; # Assume we are done with it + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + if ( $ndbd->{'pid'} ) + { + push(@kill_pids,{ + pid => $ndbd->{'pid'}, + pidfile => $ndbd->{'path_pid'}, + }); + $ndbd->{'pid'}= 0; + } + } + } + } + + # Wait blocking until all shutdown processes has completed + mtr_wait_blocking(\%admin_pids); + + # Make sure that process has shutdown else try to kill them + mtr_check_stop_servers(\@kill_pids); + + foreach my $mysqld (@{$master}, @{$slave}) + { + rm_ndbcluster_tables($mysqld->{'path_myddir'}); + } +} + + +sub run_testcase_need_master_restart($) +{ + my ($tinfo)= @_; + + # We try to find out if we are to restart the master(s) + my $do_restart= 0; # Assumes we don't have to + + if ( $tinfo->{'master_sh'} ) + { + $do_restart= 1; # Always restart if script to run + mtr_verbose("Restart because: Always restart if script to run"); + } + elsif ( ! $opt_skip_ndbcluster and + $tinfo->{'ndb_test'} == 0 and + $clusters->[0]->{'pid'} != 0 ) + { + $do_restart= 1; # Restart without cluster + mtr_verbose("Restart because: Test does not need cluster"); + } + elsif ( ! $opt_skip_ndbcluster and + $tinfo->{'ndb_test'} == 1 and + $clusters->[0]->{'pid'} == 0 ) + { + $do_restart= 1; # Restart with cluster + mtr_verbose("Restart because: Test need cluster"); + } + elsif ( $master->[0]->{'running_master_is_special'} and + $master->[0]->{'running_master_is_special'}->{'timezone'} eq + $tinfo->{'timezone'} and + mtr_same_opts($master->[0]->{'running_master_is_special'}->{'master_opt'}, + $tinfo->{'master_opt'}) ) + { + # If running master was started with special settings, but + # the current test requires the same ones, we *don't* restart. + $do_restart= 0; + mtr_verbose("Skip restart: options are equal " . + join(" ", @{$tinfo->{'master_opt'}})); + } + elsif ( $tinfo->{'master_restart'} ) + { + $do_restart= 1; + mtr_verbose("Restart because: master_restart"); + } + elsif ( $master->[0]->{'running_master_is_special'} ) + { + $do_restart= 1; + mtr_verbose("Restart because: running_master_is_special"); + } + # Check that running master was started with same options + # as the current test requires + elsif (! mtr_same_opts($master->[0]->{'start_opts'}, + $tinfo->{'master_opt'}) ) + { + $do_restart= 1; + mtr_verbose("Restart because: running with different options '" . + join(" ", @{$tinfo->{'master_opt'}}) . "' != '" . + join(" ", @{$master->[0]->{'start_opts'}}) . "'" ); + } + + return $do_restart; +} + +sub run_testcase_need_slave_restart($) +{ + my ($tinfo)= @_; + + # We try to find out if we are to restart the slaves + my $do_slave_restart= 0; # Assumes we don't have to + + # FIXME only restart slave when necessary + $do_slave_restart= 1; + +# if ( ! $slave->[0]->{'pid'} ) +# { +# # mtr_verbose("Slave not started, no need to check slave restart"); +# } +# elsif ( $do_restart ) +# { +# $do_slave_restart= 1; # Always restart if master restart +# mtr_verbose("Restart slave because: Master restart"); +# } +# elsif ( $tinfo->{'slave_sh'} ) +# { +# $do_slave_restart= 1; # Always restart if script to run +# mtr_verbose("Restart slave because: Always restart if script to run"); +# } +# elsif ( ! $opt_skip_ndbcluster_slave and +# $tinfo->{'ndb_test'} == 0 and +# $clusters->[1]->{'pid'} != 0 ) +# { +# $do_slave_restart= 1; # Restart without slave cluster +# mtr_verbose("Restart slave because: Test does not need slave cluster"); +# } +# elsif ( ! $opt_with_ndbcluster_slave and +# $tinfo->{'ndb_test'} == 1 and +# $clusters->[1]->{'pid'} == 0 ) +# { +# $do_slave_restart= 1; # Restart with slave cluster +# mtr_verbose("Restart slave because: Test need slave cluster"); +# } +# elsif ( $tinfo->{'slave_restart'} ) +# { +# $do_slave_restart= 1; +# mtr_verbose("Restart slave because: slave_restart"); +# } +# elsif ( $slave->[0]->{'running_slave_is_special'} ) +# { +# $do_slave_restart= 1; +# mtr_verbose("Restart slave because: running_slave_is_special"); +# } +# # Check that running slave was started with same options +# # as the current test requires +# elsif (! mtr_same_opts($slave->[0]->{'start_opts'}, +# $tinfo->{'slave_opt'}) ) +# { +# $do_slave_restart= 1; +# mtr_verbose("Restart slave because: running with different options '" . +# join(" ", @{$tinfo->{'slave_opt'}}) . "' != '" . +# join(" ", @{$slave->[0]->{'start_opts'}}) . "'" ); +# } + + return $do_slave_restart; + +} + +# ---------------------------------------------------------------------- +# If not using a running servers we may need to stop and restart. +# We restart in the case we have initiation scripts, server options +# etc to run. But we also restart again after the test first restart +# and test is run, to get back to normal server settings. +# +# To make the code a bit more clean, we actually only stop servers +# here, and mark this to be done. Then a generic "start" part will +# start up the needed servers again. +# ---------------------------------------------------------------------- + +sub run_testcase_stop_servers($$$) { + my ($tinfo, $do_restart, $do_slave_restart)= @_; + + if ( $glob_use_running_server || $glob_use_embedded_server ) + { + return; + } + + my $pid; + my %admin_pids; # hash of admin processes that requests shutdown + my @kill_pids; # list of processes to shutdown/kill + + # Remember if we restarted for this test case + $tinfo->{'restarted'}= $do_restart; + + if ( $do_restart ) + { + delete $master->[0]->{'running_master_is_special'}; # Forget history + + # Start shutdown of all started masters + foreach my $mysqld (@{$master}) + { + if ( $mysqld->{'pid'} ) + { + $pid= mtr_mysqladmin_start($mysqld, "shutdown", 70); + + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $mysqld->{'pid'}, + pidfile => $mysqld->{'path_pid'}, + sockfile => $mysqld->{'path_sock'}, + port => $mysqld->{'port'}, + }); + + $mysqld->{'pid'}= 0; # Assume we are done with it + } + } + + # Start shutdown of master cluster + my $cluster= $clusters->[0]; + if ( $cluster->{'pid'} ) + { + $pid= mtr_ndbmgm_start($cluster, "shutdown"); + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $cluster->{'pid'}, + pidfile => $cluster->{'path_pid'} + }); + + $cluster->{'pid'}= 0; # Assume we are done with it + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + push(@kill_pids,{ + pid => $ndbd->{'pid'}, + pidfile => $ndbd->{'path_pid'}, + }); + $ndbd->{'pid'}= 0; # Assume we are done with it + } + } + } + + if ( $do_restart || $do_slave_restart ) + { + + delete $slave->[0]->{'running_slave_is_special'}; # Forget history + + # Start shutdown of all started slaves + foreach my $mysqld (@{$slave}) + { + if ( $mysqld->{'pid'} ) + { + $pid= mtr_mysqladmin_start($mysqld, "shutdown", 70); + + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $mysqld->{'pid'}, + pidfile => $mysqld->{'path_pid'}, + sockfile => $mysqld->{'path_sock'}, + port => $mysqld->{'port'}, + }); + + + $mysqld->{'pid'}= 0; # Assume we are done with it + } + } + + # Start shutdown of slave cluster + my $cluster= $clusters->[1]; + if ( $cluster->{'pid'} ) + { + $pid= mtr_ndbmgm_start($cluster, "shutdown"); + + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $cluster->{'pid'}, + pidfile => $cluster->{'path_pid'} + }); + + $cluster->{'pid'}= 0; # Assume we are done with it + + foreach my $ndbd (@{$cluster->{'ndbds'}} ) + { + push(@kill_pids,{ + pid => $ndbd->{'pid'}, + pidfile => $ndbd->{'path_pid'}, + }); + $ndbd->{'pid'}= 0; # Assume we are done with it + } + } + } + + # ---------------------------------------------------------------------- + # Shutdown has now been started and lists for the shutdown processes + # and the processes to be killed has been created + # ---------------------------------------------------------------------- + + # Wait blocking until all shutdown processes has completed + mtr_wait_blocking(\%admin_pids); + + + # Make sure that process has shutdown else try to kill them + mtr_check_stop_servers(\@kill_pids); + + foreach my $mysqld (@{$master}, @{$slave}) + { + if ( ! $mysqld->{'pid'} ) + { + # Remove ndbcluster tables if server is stopped + rm_ndbcluster_tables($mysqld->{'path_myddir'}); + } + } +} + +sub run_testcase_start_servers($) { + my $tinfo= shift; + + my $tname= $tinfo->{'name'}; + + if ( $glob_use_running_server or $glob_use_embedded_server ) + { + return; + } + + # ------------------------------------------------------- + # Init variables that can change between server starts + # ------------------------------------------------------- + $ENV{'TZ'}= $tinfo->{'timezone'}; + + if ( $tinfo->{'component_id'} eq 'mysqld' ) + { + if ( ! $opt_skip_ndbcluster and + !$clusters->[0]->{'pid'} and + $tinfo->{'ndb_test'} ) + { + # Test need cluster, cluster is not started, start it + ndbcluster_start($clusters->[0], ""); + } + + if ( !$master->[0]->{'pid'} ) + { + # Master mysqld is not started + do_before_start_master($tname,$tinfo->{'master_sh'}); + + mysqld_start($master->[0],$tinfo->{'master_opt'},[]); + + } + + if ( $clusters->[0]->{'pid'} and ! $master->[1]->{'pid'} ) + { + # Test needs cluster, start an extra mysqld connected to cluster + + if ( $mysql_version_id >= 50100 ) + { + # First wait for first mysql server to have created ndb system + # tables ok FIXME This is a workaround so that only one mysqld + # create the tables + if ( ! sleep_until_file_created( + "$master->[0]->{'path_myddir'}/cluster/apply_status.ndb", + $master->[0]->{'start_timeout'}, + $master->[0]->{'pid'})) + { + mtr_report_test_name($tinfo); + mtr_report("Failed to create 'cluster/apply_status' table"); + report_failure_and_restart($tinfo); + return; + } + } + mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + + mysqld_start($master->[1],$tinfo->{'master_opt'},[]); + } + + if ( $tinfo->{'master_restart'} ) + { + # Save this test case information, so next can examine it + $master->[0]->{'running_master_is_special'}= $tinfo; + } + } + elsif ( ! $opt_skip_im and $tinfo->{'component_id'} eq 'im' ) + { + # We have to create defaults file every time, in order to ensure that it + # will be the same for each test. The problem is that test can change the + # file (by SET/UNSET commands), so w/o recreating the file, execution of + # one test can affect the other. + + im_create_defaults_file($instance_manager); + + unless ( mtr_im_start($instance_manager, $tinfo->{im_opts}) ) + { + mtr_report_test_name($tinfo); + report_failure_and_restart($tinfo); + mtr_report("Failed to start Instance Manager. " . + "The test '$tname' is marked as failed."); + return; + } + } + + # ---------------------------------------------------------------------- + # Start slaves - if needed + # ---------------------------------------------------------------------- + if ( $tinfo->{'slave_num'} ) + { + mtr_tofile($slave->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + + restore_slave_databases($tinfo->{'slave_num'}); + + do_before_start_slave($tname,$tinfo->{'slave_sh'}); + + if ( ! $opt_skip_ndbcluster_slave and + !$clusters->[1]->{'pid'} and + $tinfo->{'ndb_test'} ) + { + # Test need slave cluster, cluster is not started, start it + ndbcluster_start($clusters->[1], ""); + } + + for ( my $idx= 0; $idx < $tinfo->{'slave_num'}; $idx++ ) + { + if ( ! $slave->[$idx]->{'pid'} ) + { + mysqld_start($slave->[$idx],$tinfo->{'slave_opt'}, + $tinfo->{'slave_mi'}); + + } + } + + if ( $tinfo->{'slave_restart'} ) + { + # Save this test case information, so next can examine it + $slave->[0]->{'running_slave_is_special'}= $tinfo; + } + + } + + # Wait for clusters to start + foreach my $cluster (@{$clusters}) + { + + next if !$cluster->{'pid'}; + + if (ndbcluster_wait_started($cluster, "")) + { + # failed to start + mtr_report("Start of $cluster->{'name'} cluster failed, "); + } + } + + # Wait for mysqld's to start + foreach my $mysqld (@{$master},@{$slave}) + { + + next if !$mysqld->{'pid'}; + + if (mysqld_wait_started($mysqld)) + { + mtr_warning("Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}"); + } + } } # @@ -2801,9 +3806,12 @@ sub stop_slaves () { # Before a testcase, run in record mode, save result file to var # After testcase, run and compare with the recorded file, they should be equal! # -sub run_check_testcase ($) { +sub run_check_testcase ($$) { my $mode= shift; + my $mysqld= shift; + + my $name= "check-" . $mysqld->{'type'} . $mysqld->{'idx'}; my $args; mtr_init_args(\$args); @@ -2814,14 +3822,14 @@ sub run_check_testcase ($) { mtr_add_arg($args, "--skip-safemalloc"); mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); - mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_mysock'}); - mtr_add_arg($args, "--port=%d", $master->[0]->{'path_myport'}); + mtr_add_arg($args, "--socket=%s", $mysqld->{'path_sock'}); + mtr_add_arg($args, "--port=%d", $mysqld->{'port'}); mtr_add_arg($args, "--database=test"); mtr_add_arg($args, "--user=%s", $opt_user); mtr_add_arg($args, "--password="); mtr_add_arg($args, "-R"); - mtr_add_arg($args, "$opt_vardir/tmp/check-testcase.result"); + mtr_add_arg($args, "$opt_vardir/tmp/$name.result"); if ( $mode eq "before" ) { @@ -2834,8 +3842,8 @@ sub run_check_testcase ($) { if ( $res == 1 and $mode = "after") { mtr_run("diff",["-u", - "$opt_vardir/tmp/check-testcase.result", - "$opt_vardir/tmp/check-testcase.reject"], + "$opt_vardir/tmp/$name.result", + "$opt_vardir/tmp/$name.reject"], "", "", "", ""); } elsif ( $res ) @@ -2845,101 +3853,9 @@ sub run_check_testcase ($) { } + sub run_mysqltest ($) { - my $tinfo= shift; - - my $cmdline_mysqlcheck= "$exe_mysqlcheck --no-defaults -uroot " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'} --password="; - if ( $opt_debug ) - { - $cmdline_mysqlcheck .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqlcheck.trace"; - } - - my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'} --password="; - if ( $opt_debug ) - { - $cmdline_mysqldump .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqldump.trace"; - } - my $cmdline_mysqlimport= "$exe_mysqlimport -uroot " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'} --password="; - if ( $opt_debug ) - { - $cmdline_mysqlimport .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqlimport.trace"; - } - - my $cmdline_mysqlshow= "$exe_mysqlshow -uroot " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'} --password="; - if ( $opt_debug ) - { - $cmdline_mysqlshow .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqlshow.trace"; - } - - my $cmdline_mysqlbinlog= - "$exe_mysqlbinlog" . - " --no-defaults --local-load=$opt_tmpdir" . - " --character-sets-dir=$path_charsetsdir"; - - if ( $opt_debug ) - { - $cmdline_mysqlbinlog .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqlbinlog.trace"; - } - - my $cmdline_mysql= - "$exe_mysql --host=localhost --user=root --password= " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'}"; - - my $cmdline_mysql_client_test= - "$exe_mysql_client_test --no-defaults --testcase --user=root --silent " . - "--port=$master->[0]->{'path_myport'} " . - "--vardir=$opt_vardir " . - "--socket=$master->[0]->{'path_mysock'}"; - - if ( $glob_use_embedded_server ) - { - $cmdline_mysql_client_test.= - " -A --language=$path_language" . - " -A --datadir=$slave->[0]->{'path_myddir'}" . - " -A --character-sets-dir=$path_charsetsdir"; - } - - my $cmdline_mysql_fix_system_tables= - "$exe_mysql_fix_system_tables --no-defaults --host=localhost --user=root --password= " . - "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'}"; - - $ENV{'MYSQL'}= $cmdline_mysql; - $ENV{'MYSQL_CHECK'}= $cmdline_mysqlcheck; - $ENV{'MYSQL_DUMP'}= $cmdline_mysqldump; - $ENV{'MYSQL_IMPORT'}= $cmdline_mysqlimport; - $ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow; - $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; - $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables; - $ENV{'MYSQL_CLIENT_TEST'}= $cmdline_mysql_client_test; - $ENV{'CHARSETSDIR'}= $path_charsetsdir; - $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= $exe_my_print_defaults; - $ENV{'UDF_EXAMPLE_LIB'}= - ($lib_udf_example ? basename($lib_udf_example) : ""); - $ENV{'MY_PERROR'}= $exe_perror; - - $ENV{'NDB_MGM'}= $exe_ndb_mgm; - $ENV{'NDB_BACKUP_DIR'}= $path_ndb_data_dir; - $ENV{'NDB_DATA_DIR'}= $path_ndb_data_dir; - $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; - $ENV{'NDB_TOOLS_OUTPUT'}= $file_ndb_testrun_log; - $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; - + my ($tinfo)= @_; my $exe= $exe_mysqltest; my $args; @@ -2960,8 +3876,8 @@ sub run_mysqltest ($) { } else # component_id == mysqld { - mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_mysock'}); - mtr_add_arg($args, "--port=%d", $master->[0]->{'path_myport'}); + mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'}); + mtr_add_arg($args, "--port=%d", $master->[0]->{'port'}); mtr_add_arg($args, "--database=test"); mtr_add_arg($args, "--user=%s", $opt_user); mtr_add_arg($args, "--password="); @@ -3005,6 +3921,11 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--big-test"); } + if ( $opt_valgrind ) + { + mtr_add_arg($args, "--valgrind"); + } + if ( $opt_compress ) { mtr_add_arg($args, "--compress"); @@ -3017,7 +3938,8 @@ sub run_mysqltest ($) { if ( $opt_debug ) { - mtr_add_arg($args, "--debug=d:t:A,%s/log/mysqltest.trace", $opt_vardir_trace); + mtr_add_arg($args, "--debug=d:t:A,%s/log/mysqltest.trace", + $path_vardir_trace); } if ( $opt_ssl_supported ) @@ -3030,9 +3952,9 @@ sub run_mysqltest ($) { $glob_mysql_test_dir); } - # Turn on SSL for all test cases if ( $opt_ssl ) { + # Turn on SSL for _all_ test cases if option --ssl was used mtr_add_arg($args, "--ssl", $glob_mysql_test_dir); } @@ -3048,7 +3970,7 @@ sub run_mysqltest ($) { if ( $glob_use_embedded_server ) { - mysqld_arguments($args,'master',0,$tinfo->{'master_opt'},[],0); + mysqld_arguments($args,'master',0,$tinfo->{'master_opt'},[]); } # ---------------------------------------------------------------------- @@ -3105,14 +4027,26 @@ sub run_mysqltest ($) { if ( $opt_check_testcases ) { - run_check_testcase("before"); + foreach my $mysqld (@{$master}, @{$slave}) + { + if ($mysqld->{'pid'}) + { + run_check_testcase("before", $mysqld); + } + } } my $res = mtr_run_test($exe,$args,"","",$path_timefile,""); if ( $opt_check_testcases ) { - run_check_testcase("after"); + foreach my $mysqld (@{$master}, @{$slave}) + { + if ($mysqld->{'pid'}) + { + run_check_testcase("after", $mysqld); + } + } } return $res; @@ -3291,12 +4225,20 @@ sub valgrind_arguments { my $args= shift; my $exe= shift; - mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option - mtr_add_arg($args, "--alignment=8"); - mtr_add_arg($args, "--leak-check=yes"); - mtr_add_arg($args, "--num-callers=16"); - mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) - if -f "$glob_mysql_test_dir/valgrind.supp"; + if ( $opt_callgrind) + { + mtr_add_arg($args, "--tool=callgrind"); + mtr_add_arg($args, "--base=$opt_vardir/log"); + } + else + { + mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option + mtr_add_arg($args, "--alignment=8"); + mtr_add_arg($args, "--leak-check=yes"); + mtr_add_arg($args, "--num-callers=16"); + mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) + if -f "$glob_mysql_test_dir/valgrind.supp"; + } # Add valgrind options, can be overriden by user mtr_add_arg($args, '%s', $_) for (split(' ', $opt_valgrind_options)); @@ -3323,9 +4265,7 @@ sub usage ($) { print STDERR <