#!/usr/bin/perl # Copyright (C) 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA #################### FOR THE MOMENT THIS SCRIPT IS FOR TESTING PURPOSES use lib 'lib'; use lib "$ENV{RQG_HOME}/lib"; use Carp; use strict; use GenTest; use GenTest::Server::MySQLd; $| = 1; if (windows()) { $SIG{CHLD} = "IGNORE"; } if (defined $ENV{RQG_HOME}) { if (windows()) { $ENV{RQG_HOME} = $ENV{RQG_HOME}.'\\'; } else { $ENV{RQG_HOME} = $ENV{RQG_HOME}.'/'; } } use Getopt::Long; use GenTest::Constants; use DBI; use Cwd; my $database = 'test'; my @master_dsns; my ($gendata, @basedirs, @mysqld_options, @vardirs, $rpl_mode, $engine, $help, $debug, $validators, $reporters, $grammar_file, $redefine_file, $seed, $mask, $mask_level, $mem, $rows, $varchar_len, $xml_output, $valgrind, $views, $start_dirty, $filter, $build_thread); my $threads = my $default_threads = 10; my $queries = my $default_queries = 1000; my $duration = my $default_duration = 3600; my @ARGV_saved = @ARGV; my $opt_result = GetOptions( 'mysqld=s@' => \$mysqld_options[0], 'mysqld1=s@' => \$mysqld_options[0], 'mysqld2=s@' => \$mysqld_options[1], 'basedir=s@' => \@basedirs, 'vardir=s@' => \@vardirs, 'rpl_mode=s' => \$rpl_mode, 'engine=s' => \$engine, 'grammar=s' => \$grammar_file, 'redefine=s' => \$redefine_file, 'threads=i' => \$threads, 'queries=s' => \$queries, 'duration=i' => \$duration, 'help' => \$help, 'debug' => \$debug, 'validators:s' => \$validators, 'reporters:s' => \$reporters, 'gendata:s' => \$gendata, 'seed=s' => \$seed, 'mask=i' => \$mask, 'mask-level=i' => \$mask_level, 'mem' => \$mem, 'rows=i' => \$rows, 'varchar-length=i' => \$varchar_len, 'xml-output=s' => \$xml_output, 'valgrind!' => \$valgrind, 'views' => \$views, 'start-dirty' => \$start_dirty, 'filter=s' => \$filter, 'mtr-build-thread=i' => \$build_thread ); if (!$opt_result || $help || $basedirs[0] eq '' || not defined $grammar_file) { help(); exit($help ? 0 : 1); } say("Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms."); say("Please see http://forge.mysql.com/wiki/Category:RandomQueryGenerator for more information on this test framework."); say("Starting \n# $0 \\ \n# ".join(" \\ \n# ", @ARGV_saved)); # # Calculate master and slave ports based on MTR_BUILD_THREAD (MTR # Version 1 behaviour) # if (not defined $build_thread) { if (defined $ENV{MTR_BUILD_THREAD}) { $build_thread = $ENV{MTR_BUILD_THREAD} } else { $build_thread = DEFAULT_MTR_BUILD_THREAD; } } if ( $build_thread eq 'auto' ) { say ("Please set the environment variable MTR_BUILD_THREAD to a value <> 'auto' (recommended) or unset it (will take the value ".DEFAULT_MTR_BUILD_THREAD.") "); exit (STATUS_ENVIRONMENT_FAILURE); } my $master_port = 10000 + 10 * $build_thread; my $slave_port = 10000 + 10 * $build_thread + 2; my @master_ports = ($master_port,$slave_port); say("master_port : $master_port slave_port : $slave_port master_ports : @master_ports MTR_BUILD_THREAD : $build_thread "); $ENV{MTR_BUILD_THREAD} = $build_thread; # # If the user has provided two vardirs and one basedir, start second # server using the same basedir # if ( ($vardirs[1] ne '') && ($basedirs[1] eq '') ) { $basedirs[1] = $basedirs[0]; } if ( ($mysqld_options[1] ne '') && ($basedirs[1] eq '') ) { $basedirs[1] = $basedirs[0]; } # # If the user has provided identical basedirs and vardirs, warn of a # potential overlap. # if ( ($basedirs[0] eq $basedirs[1]) && ($vardirs[0] eq $vardirs[1]) && ($rpl_mode eq '') ) { croak("Please specify either different --basedir[12] or different --vardir[12] in order to start two MySQL servers"); } my $client_basedir; foreach my $path ("$basedirs[0]/client/RelWithDebInfo", "$basedirs[0]/client", "$basedirs[0]/bin") { if (-e $path) { $client_basedir = $path; last; } } # # Start servers. Use rpl_alter if replication is needed. # my @server; foreach my $server_id (0..1) { next if $basedirs[$server_id] eq ''; my @options; push @options, lc("--$engine") if defined $engine && lc($engine) ne lc('myisam'); push @options, "--sql-mode=no_engine_substitution" if join(' ', @ARGV_saved) !~ m{sql-mode}io; if (($rpl_mode ne '') && ($server_id != 0)) { # If we are running in replication, and we start the slave separately (because it is a different binary) # add a few options that allow the slave and the master to be distinguished and SHOW SLAVE HOSTS to work push @options, "--server-id=".($server_id + 1); push @options, "--report-host=127.0.0.1"; push @options, "--report-port=".$master_ports[$server_id]; } if (defined $mysqld_options[$server_id]) { push @options, @{$mysqld_options[$server_id]}; } if ( ($rpl_mode ne '') && ($server_id == 0) && (not defined $vardirs[1]) && (not defined $mysqld_options[1]) ) { push @options, "--slave_port=".$slave_port; } $server[$server_id] = GenTest::Server::MySQLd->new(basedir => $basedirs[$server_id], vardir => $vardirs[$server_id], port => $master_ports[$server_id], start_dirty => $start_dirty, \@options); my $status = $server[$server_id]->startServer; if ($status > STATUS_OK) { stopServers(); say(system("ls -l ".$server[$server_id]->datadir)); croak("Could not start all servers"); } if ( ($server_id == 0) || ($rpl_mode eq '') ) { $master_dsns[$server_id] = $server[$server_id]->dsn($database); } if ((defined $master_dsns[$server_id]) && (defined $engine)) { my $dbh = DBI->connect($master_dsns[$server_id], undef, undef, { RaiseError => 1 } ); $dbh->do("SET GLOBAL storage_engine = '$engine'"); } } my $master_dbh = DBI->connect($server[0]->dsn($database), undef, undef, { RaiseError => 1 } ); if ($rpl_mode) { my $slave_dbh = DBI->connect($server[1]->dsn($database), undef, undef, { RaiseError => 1 } ); say("Establishing replication, mode $rpl_mode ..."); my ($foo, $master_version) = $master_dbh->selectrow_array("SHOW VARIABLES LIKE 'version'"); if (($master_version !~ m{^5\.0}sio) && ($rpl_mode ne 'default')) { $master_dbh->do("SET GLOBAL BINLOG_FORMAT = '$rpl_mode'"); $slave_dbh->do("SET GLOBAL BINLOG_FORMAT = '$rpl_mode'"); } $slave_dbh->do("STOP SLAVE"); $slave_dbh->do("SET GLOBAL storage_engine = '$engine'") if defined $engine; $slave_dbh->do("CHANGE MASTER TO MASTER_PORT = $master_ports[0], MASTER_HOST = '127.0.0.1', MASTER_USER = 'root', MASTER_CONNECT_RETRY = 1 "); $slave_dbh->do("START SLAVE"); } # # Run actual queries # my @gentest_options; push @gentest_options, "--start-dirty" if defined $start_dirty; push @gentest_options, "--gendata=$gendata"; push @gentest_options, "--engine=$engine" if defined $engine; push @gentest_options, "--rpl_mode=$rpl_mode" if defined $rpl_mode; push @gentest_options, map {'--validator='.$_} split(/,/,$validators) if defined $validators; push @gentest_options, map {'--reporter='.$_} split(/,/,$reporters) if defined $reporters; push @gentest_options, "--threads=$threads" if defined $threads; push @gentest_options, "--queries=$queries" if defined $queries; push @gentest_options, "--duration=$duration" if defined $duration; push @gentest_options, "--dsn=$master_dsns[0]" if defined $master_dsns[0]; push @gentest_options, "--dsn=$master_dsns[1]" if defined $master_dsns[1]; push @gentest_options, "--grammar=$grammar_file"; push @gentest_options, "--redefine=$redefine_file" if defined $redefine_file; push @gentest_options, "--seed=$seed" if defined $seed; push @gentest_options, "--mask=$mask" if defined $mask; push @gentest_options, "--mask-level=$mask_level" if defined $mask_level; push @gentest_options, "--rows=$rows" if defined $rows; push @gentest_options, "--views" if defined $views; push @gentest_options, "--varchar-length=$varchar_len" if defined $varchar_len; push @gentest_options, "--xml-output=$xml_output" if defined $xml_output; push @gentest_options, "--debug" if defined $debug; push @gentest_options, "--filter=$filter" if defined $filter; push @gentest_options, "--valgrind" if $valgrind; # Push the number of "worker" threads into the environment. # lib/GenTest/Generator/FromGrammar.pm will generate a corresponding grammar element. $ENV{RQG_THREADS}= $threads; my $gentest_result = system("perl $ENV{RQG_HOME}gentest.pl ".join(' ', @gentest_options)); say("gentest.pl exited with exit status ".($gentest_result >> 8)); exit_test($gentest_result >> 8) if $gentest_result > 0; if ($rpl_mode) { my ($file, $pos) = $master_dbh->selectrow_array("SHOW MASTER STATUS"); say("Waiting for slave to catch up..., file $file, pos $pos ."); exit_test(STATUS_UNKNOWN_ERROR) if !defined $file; my $slave_dbh = DBI->connect($server[1]->dsn($database), undef, undef, { PrintError => 1 } ); exit_test(STATUS_REPLICATION_FAILURE) if not defined $slave_dbh; $slave_dbh->do("START SLAVE"); my $wait_result = $slave_dbh->selectrow_array("SELECT MASTER_POS_WAIT('$file',$pos)"); if (not defined $wait_result) { say("MASTER_POS_WAIT() failed. Slave thread not running."); exit_test(STATUS_REPLICATION_FAILURE); } } # # Compare master and slave, or two masters # if ($rpl_mode || (defined $basedirs[1])) { my @dump_ports = ($master_ports[0]); if ($rpl_mode) { push @dump_ports, $slave_port; } elsif (defined $basedirs[1]) { push @dump_ports, $master_ports[1]; } my @dump_files; foreach my $i (0..$#dump_ports) { say("Dumping server on port $dump_ports[$i]..."); $dump_files[$i] = tmpdir()."/server_".$$."_".$i.".dump"; my $dump_result = system("\"$client_basedir/mysqldump\" --hex-blob --no-tablespaces --skip-triggers --compact --order-by-primary --skip-extended-insert --no-create-info --host=127.0.0.1 --port=$dump_ports[$i] --user=root $database | sort > $dump_files[$i]"); exit_test($dump_result >> 8) if $dump_result > 0; } say("Comparing SQL dumps..."); my $diff_result = system("diff -u $dump_files[0] $dump_files[1]"); $diff_result = $diff_result >> 8; if ($diff_result == 0) { say("No differences were found between servers."); } foreach my $dump_file (@dump_files) { unlink($dump_file); } exit_test($diff_result); } stopServers(); sub stopServers { foreach my $srv (@server) { if ($srv) { $srv->stopServer; } } } sub help { print <