From: magnus.blaudd Date: April 27 2012 8:14am Subject: bzr push into mysql-trunk branch (magnus.blaudd:3749 to 3750) List-Archive: http://lists.mysql.com/commits/143662 Message-Id: <201204270814.q3R8E3b8011164@acsmt358.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3750 magnus.blaudd@stripped 2012-04-27 [merge] Merge trunk-wl5960 -> trunk added: mysql-test/lib/My/Memcache.pm modified: mysql-test/lib/My/ConfigFactory.pm mysql-test/lib/mtr_cases.pm mysql-test/mysql-test-run.pl 3749 Norvald H. Ryeng 2012-04-27 Bug#13735712 SELECT W/ SUBQUERY PRODUCES MORE ROWS WHEN USING VARIABLES Outer join queries with ALL may return incorrect results because the optimizer incorrectly rewrites them to use inner join. E.g.: SELECT * FROM t2 RIGHT JOIN t3 ON(t3.c = t2.b) WHERE t2.b < ALL(SELECT t1.a FROM t1 WHERE t1.a <= 7); is first rewritten by Item_in_subselect::single_value_transformer() into: SELECT * FROM t2 RIGHT JOIN t3 ON(t3.c = t2.b) WHERE (t2.b >= (SELECT MIN(t1.a) FROM t1 WHERE t1.a <= 7)); When simplify_joins() checks not_null_tables() on the condition to find out if the outer join can be transformed into an inner join, Item_func::not_null_tables() returns its arguments' not_null_tables(). This means that simplify_joins() is told that the condition will be false if t2.b is NULL. But the condition is actually true if t1 has no rows where t1.a <= 7. This leads to the optimizer incorrectly rewriting the query to use inner join. Fix: Let Item_func_not_all::not_null_tables() return a zero table map. @ mysql-test/include/subquery.inc Add test cases for bugs #13735712. @ mysql-test/r/subquery_all.result Add test cases for bugs #13735712. @ mysql-test/r/subquery_all_bka.result Add test cases for bugs #13735712. @ mysql-test/r/subquery_all_bka_nixbnl.result Add test cases for bugs #13735712. @ mysql-test/r/subquery_nomat_nosj.result Add test cases for bugs #13735712. @ mysql-test/r/subquery_nomat_nosj_bka.result Add test cases for bugs #13735712. @ mysql-test/r/subquery_nomat_nosj_bka_nixbnl.result Add test cases for bugs #13735712. @ mysql-test/r/subquery_none.result Add test cases for bugs #13735712. @ mysql-test/r/subquery_none_bka.result Add test cases for bugs #13735712. @ mysql-test/r/subquery_none_bka_nixbnl.result Add test cases for bugs #13735712. @ sql/item_cmpfunc.h Return 0 from Item_func_not_all::not_null_tables(). modified: mysql-test/include/subquery.inc mysql-test/r/subquery_all.result mysql-test/r/subquery_all_bka.result mysql-test/r/subquery_all_bka_nixbnl.result mysql-test/r/subquery_nomat_nosj.result mysql-test/r/subquery_nomat_nosj_bka.result mysql-test/r/subquery_nomat_nosj_bka_nixbnl.result mysql-test/r/subquery_none.result mysql-test/r/subquery_none_bka.result mysql-test/r/subquery_none_bka_nixbnl.result sql/item_cmpfunc.h === modified file 'mysql-test/lib/My/ConfigFactory.pm' --- a/mysql-test/lib/My/ConfigFactory.pm 2011-09-07 10:08:09 +0000 +++ b/mysql-test/lib/My/ConfigFactory.pm 2012-04-27 07:50:48 +0000 @@ -309,6 +309,16 @@ my @ndbd_rules= # +# Rules to run for each memcached in the config +# - will be run in order listed here +# +my @memcached_rules= +( + { '#host' => \&fix_host }, + { 'port' => \&fix_port }, +); + +# # Rules to run for each cluster_config section # - will be run in order listed here # @@ -678,6 +688,10 @@ sub new_config { 'mysqld.', @mysqld_rules); + $self->run_section_rules($config, + 'memcached.', + @memcached_rules); + # [mysqlbinlog] need additional settings $self->run_rules_for_group($config, $config->insert('mysqlbinlog'), === added file 'mysql-test/lib/My/Memcache.pm' --- a/mysql-test/lib/My/Memcache.pm 1970-01-01 00:00:00 +0000 +++ b/mysql-test/lib/My/Memcache.pm 2012-04-18 14:41:57 +0000 @@ -0,0 +1,572 @@ +# -*- cperl -*- +# Copyright (c) 2011, Oracle and/or its affiliates. +# All rights reserved. +# +# 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 + + +########## Memcache Client Library for Perl +### +### $mc = My::Memcache->new() create an ascii-protocol client +### $mc = My::Memcache::Binary->new() create a binary-protocol client +### +### $mc->connect(host, port) returns 1 on success, 0 on failure +### +### $mc->{error} holds most recent error/status message +### +### $mc->set(key, value) returns 1 on success, 0 on failure +### $mc->add(key, value) set if record does not exist +### $mc->replace(key, value) set if record exists +### $mc->append(key, value) append value to existing data +### $mc->prepend(key, value) prepend value to existing data +### $mc->get(key) returns value or undef +### $mc->delete(key) returns 1 on success, 0 on failure +### $mc->stats(stat_key) get stats; returns a hash +### $mc->incr(key, amount) returns the new value or undef +### $mc->decr(key, amount) like incr +### $mc->flush() flush_all +### +### $mc->set_expires(sec) Set TTL for all store operations +### $mc->set_flags(int_flags) Set numeric flags for store operations +### +### $mc->note_config_version() +### Store the generation number of the running config in the filesystem, +### for later use by wait_for_reconf() +### +### $mc->wait_for_reconf() +### Wait for NDB/Memcache to complete online reconfiguration. +### Returns the generation number of the newly running configuration, +### or zero on timeout/error. + +use strict; +use lib 'lib'; +use IO::Socket::INET; +use IO::File; +use Carp; +use mtr_report; # for main::mtr_verbose() + +require "mtr_process.pl"; # for mtr_ping_port() +require "mtr_misc.pl"; # for mtr_milli_sleep() + +package My::Memcache; + +sub new { + my $pkg = shift; + bless { "created" => 1 , "error" => "" , "cf_gen" => 0, + "exptime" => 0 , "flags" => 0 + }, $pkg; +} + +sub connect { + my $self = shift; + my $host = shift; + my $port = shift; + + # Wait for memcached to be ready, up to ten seconds. + my $retries = 100; + while($retries && (::mtr_ping_port($port) == 0)) + { + ::mtr_milli_sleep(100); + $retries--; + } + + my $conn = IO::Socket::INET->new(PeerAddr => "$host:$port", Proto => "tcp"); + if($conn) { + $self->{connection} = $conn; + $self->{connected} = 1; + $self->{server} = "$host:$port"; + $self->{bin_req_id} = 0; + return 1; + } + $self->{error} = "CONNECTION_FAILED"; + return 0; +} + +sub DESTROY { + my $self = shift; + $self->{connection}->close(); +} + +sub note_config_version { + my $self = shift; + + my $vardir = $ENV{MYSQLTEST_VARDIR}; + # Fetch the memcached current config generation number and save it + my %stats = $self->stats("reconf"); + my $F = IO::File->new("$vardir/tmp/memcache_cf_gen", "w") or die; + my $ver = $stats{"Running"}; + print $F "$ver\n"; + $F->close(); + + $self->{cf_gen} = $ver; +} + +sub set_expires { + my $self = shift; + my $delta = shift; + + $self->{exptime} = $delta; +} + +sub set_flags { + my $self = shift; + my $flags = shift; + + $self->{flags} = $flags; +} + +sub wait_for_reconf { + my $self = shift; + + if($self->{cf_gen} == 0) { + my $cfgen = 0; + my $vardir = $ENV{MYSQLTEST_VARDIR}; + my $F = IO::File->new("$vardir/tmp/memcache_cf_gen", "r"); + if(defined $F) { + chomp($cfgen = <$F>); + undef $F; + } + $self->{cf_gen} = $cfgen; + } + + print STDERR "Config generation is : " . $self->{cf_gen} . "\n"; + my $wait_for = $self->{cf_gen} + 1 ; + print STDERR "Waiting for: $wait_for \n"; + + my $new_gen = $self->wait_for_config_generation($wait_for); + if($new_gen > 0) { + $self->{cf_gen} = $new_gen; + } + else { + print STDERR "Timed out.\n"; + } + + return $new_gen; +} + + +# wait_for_config_generation($cf_gen) +# Wait until memcached is running config generation >= to $cf_gen +# Returns 0 on error/timeout, or the actual running generation number +# +sub wait_for_config_generation { + my $self = shift; + my $cf_gen = shift; + my $ready = 0; + my $retries = 100; # 100 retries x 100 ms = 10s + + while($retries && ! $ready) { + ::mtr_milli_sleep(100); + my %stats = $self->stats("reconf"); + if($stats{"Running"} >= $cf_gen) { + $ready = $stats{"Running"}; + } + else { + $retries -= 1; + } + } + return $ready; +} + + +sub delete { + my $self = shift; + my $key = shift; + my $sock = $self->{connection}; + + $sock->print("delete $key\r\n") || Carp::confess "send error"; + + $self->{error} = $sock->getline(); + return $self->{error} =~ "^DELETED" ? 1 : $self->normalize_error(); +} + + +sub _txt_store { + my $self = shift; + my $cmd = shift; + my $key = shift; + my $value = shift; + my $sock = $self->{connection}; + + $sock->printf("%s %s %d %d %d\r\n%s\r\n",$cmd, $key, + $self->{flags}, $self->{exptime}, length($value), $value); + return $sock->getline(); +} + + +sub set { + my ($self, $key, $value) = @_; + + $self->{error} = $self->_txt_store("set", $key, $value); + return $self->{error} =~ "^STORED" ? 1 : $self->normalize_error(); +} + + +sub add { + my ($self, $key, $value) = @_; + + $self->{error} = $self->_txt_store("add", $key, $value); + return $self->{error} =~ "^STORED" ? 1 : $self->normalize_error(); +} + + +sub append { + my ($self, $key, $value) = @_; + + $self->{error} = $self->_txt_store("append", $key, $value); + return $self->{error} =~ "^STORED" ? 1 : $self->normalize_error(); +} + + +sub prepend { + my ($self, $key, $value) = @_; + + $self->{error} = $self->_txt_store("prepend", $key, $value); + return $self->{error} =~ "^STORED" ? 1 : $self->normalize_error(); +} + + +sub replace { + my ($self, $key, $value) = @_; + + $self->{error} = $self->_txt_store("replace", $key, $value); + return $self->{error} =~ "^STORED" ? 1 : $self->normalize_error(); +} + + +sub get { + my $self = shift; + my $key = shift; + my $sock = $self->{connection}; + + $sock->print("get $key\r\n") || Carp::confess "send error"; + my $response = $sock->getline(); + my $val; + + if ($response =~ /^END/) + { + $self->{error} = "NOT_FOUND"; + return undef; + } + else + { + $response =~ /^VALUE (.*) (\d+) (\d+)/; + $self->{flags} = $2; + my $len = $3; + $sock->read($val, $len); + $sock->getline(); # \r\n after value + $sock->getline(); # END\r\n + + return $val; + } +} + + +sub _txt_math { + my ($self, $cmd, $key, $delta) = @_; + my $sock = $self->{connection}; + + $sock->print("$cmd $key $delta \r\n") || Carp::confess "send error"; + my $response = $sock->getline(); + my $val; + + if ($response =~ "^NOT_FOUND") + { + $self->{error} = "NOT_FOUND"; + return undef; + } + elsif ($response =~ "ERROR") + { + $self->{error} = $response; + $self->normalize_error(); + return undef; + } + + $response =~ /(\d+)/; + return $1; +} + + +sub incr { + my ($self, $key, $delta) = @_; + return $self->_txt_math("incr", $key, $delta); +} + + +sub decr { + my ($self, $key, $delta) = @_; + return $self->_txt_math("decr", $key, $delta); +} + + +sub stats { + my $self = shift; + my $key = shift; + my $sock = $self->{connection}; + + $sock->print("stats $key\r\n") || Carp::confess "send error"; + + $self->{error} = "OK"; + my %response = (); + my $line = ""; + while($line !~ "^END") { + if(($line) && ($line =~ /^STAT(\s+)(\S+)(\s+)(\S+)/)) { + $response{$2} = $4; + } + $line = $sock->getline(); + } + + return %response; +} + +sub flush { + my $self = shift; + my $key = shift; + my $sock = $self->{connection}; + + $sock->print("flush_all\r\n") || Carp::confess "send error"; + + $self->{error} = $sock->getline(); + return $self->{error} =~ "^OK" ? 1 : $self->normalize_error(); +} + + +# Try to provide consistent error messagees across ascii & binary protocols +sub normalize_error { + my $self = shift; + my %error_message = ( + "STORED\r\n" => "OK", + "EXISTS\r\n" => "KEY_EXISTS", + "CLIENT_ERROR value too big\r\n" => "VALUE_TOO_LARGE", + "SERVER_ERROR object too large for cache\r\n" => "VALUE_TOO_LARGE", + "CLIENT_ERROR invalid arguments\r\n" => "INVALID_ARGUMENTS", + "SERVER_ERROR not my vbucket\r\n" => "NOT_MY_VBUCKET", + "SERVER_ERROR out of memory\r\n" => "SERVER_OUT_OF_MEMORY", + "SERVER_ERROR not supported\r\n" => "NOT_SUPPORTED", + "SERVER_ERROR internal\r\n" => "INTERNAL_ERROR" + ); + my $norm_error = $error_message{$self->{error}}; + $self->{error} = $norm_error if(defined($norm_error)); + return 0; +} + +# ----------------------------------------------------------------------- +# ------------------ BINARY PROTOCOL -------------------- +# ----------------------------------------------------------------------- + +package My::Memcache::Binary; +@My::Memcache::Binary::ISA = "My::Memcache"; + +use constant BINARY_HEADER_FMT => "CCnCCnNNNN"; +use constant BINARY_REQUEST => 0x80; +use constant BINARY_RESPONSE => 0x81; + +use constant BIN_CMD_GET => 0x00; +use constant BIN_CMD_SET => 0x01; +use constant BIN_CMD_ADD => 0x02; +use constant BIN_CMD_REPLACE => 0x03; +use constant BIN_CMD_DELETE => 0x04; +use constant BIN_CMD_INCR => 0x05; +use constant BIN_CMD_DECR => 0x06; +use constant BIN_CMD_QUIT => 0x07; +use constant BIN_CMD_FLUSH => 0x08; +use constant BIN_CMD_NOOP => 0x0A; +use constant BIN_CMD_APPEND => 0x0E; +use constant BIN_CMD_PREPEND => 0x0F; +use constant BIN_CMD_STAT => 0x10; + +my %error_message = ( + 0x00 => "OK", + 0x01 => "NOT_FOUND", + 0x02 => "KEY_EXISTS", + 0x03 => "VALUE_TOO_LARGE", + 0x04 => "INVALID_ARGUMENTS", + 0x05 => "NOT_STORED", + 0x06 => "NON_NUMERIC_VALUE", + 0x07 => "NOT_MY_VBUCKET", + 0x81 => "UNKNOWN_COMMAND", + 0x82 => "SERVER_OUT_OF_MEMORY", + 0x83 => "NOT_SUPPORTED", + 0x84 => "INTERNAL_ERROR", + 0x85 => "SERVER_BUSY", + 0x86 => "SERVER_TEMPORARY_ERROR" +); + + +sub send_binary_request { + my $self = shift; + my ($cmd, $key, $val, $extra_header) = @_; + my $sock = $self->{connection}; + my $key_len = length($key); + my $val_len = length($val); + my $extra_len = length($extra_header); + my $total_len = $key_len + $val_len + $extra_len; + my $cas_hi = 0; + my $cas_lo = 0; + + $self->{bin_req_id}++; + + my $header = pack(BINARY_HEADER_FMT, BINARY_REQUEST, $cmd, + $key_len, $extra_len, 0, 0, $total_len, + $self->{bin_req_id}, $cas_hi, $cas_lo); + my $packet = $header . $extra_header . $key . $val; + + $sock->send($packet) || Carp::confess "send failed"; +} + + +sub get_binary_response { + my $self = shift; + my $sock = $self->{connection}; + my $header_len = length(pack(BINARY_HEADER_FMT)); + my $expected = $self->{bin_req_id}; + my $header; + my $body=""; + + $sock->recv($header, $header_len); + + my ($magic, $cmd, $key_len, $extra_len, $datatype, $status, $body_len, + $opaque, $cas_hi, $cas_lo) = unpack(BINARY_HEADER_FMT, $header); + + ($magic == BINARY_RESPONSE) || Carp::confess "Bad magic number in response"; + ($opaque == $expected) || Carp::confess "Response out of order ($expected/$opaque)"; + + while($body_len - length($body) > 0) { + my $buf; + $sock->recv($buf, $body_len - length($body)); + $body .= $buf; + } + $self->{error} = $error_message{$status}; + + # Packet structure is: header .. extras .. key .. value + my $l = $extra_len + $key_len; + my $extras = substr $body, 0, $extra_len; + my $key = substr $body, $extra_len, $key_len; + my $value = substr $body, $l, $body_len - $l; + + return ($status, $value, $key, $extras); +} + + +sub bin_math { + my $self = shift; + my ($cmd, $key, $delta, $initial, $expires) = @_; + + my $extra_header = pack "NNNNN", + ($delta / (2 ** 32)), # delta hi + ($delta % (2 ** 32)), # delta lo + ($initial / (2 ** 32)), # initial hi + ($initial % (2 ** 32)), # initial lo + $expires; + $self->send_binary_request($cmd, $key, '', $extra_header); + my ($status, $value) = $self->get_binary_response(); + return ($status == 0) ? $value : undef; +} + + +sub bin_store { + my $self = shift; + my $cmd = shift; + my $key = shift; + my $value = shift; + + my $extra_header = pack "NN", $self->{flags}, $self->{exptime}; + $self->send_binary_request($cmd, $key, $value, $extra_header); + + my ($status) = $self->get_binary_response(); + return ($status == 0) ? 1 : 0; +} + + +sub get { + my $self = shift; + my $key = shift; + + $self->send_binary_request(BIN_CMD_GET, $key, '', ''); + my ($status, $value) = $self->get_binary_response(); + return ($status == 0) ? $value : undef; +} + +sub stats { + my $self = shift; + my $key = shift; + my %response, my $status, my $value, my $klen, my $tlen; + + $self->send_binary_request(BIN_CMD_STAT, $key, '', ''); + do { + ($status, $value, $key) = $self->get_binary_response(); + if($status == 0) { + $response{$key} = $value; + } + } while($status == 0 && $key); + + return %response; +} + +sub flush { + my ($self, $key, $value) = @_; + $self->send_binary_request(BIN_CMD_FLUSH, $key, '', ''); + my ($status, $value) = $self->get_binary_response(); + return ($status == 0) ? 1 : 0; +} + +sub set { + my ($self, $key, $value) = @_; + return $self->bin_store(BIN_CMD_SET, $key, $value); +} + +sub add { + my ($self, $key, $value) = @_; + return $self->bin_store(BIN_CMD_ADD, $key, $value); +} + +sub replace { + my ($self, $key, $value) = @_; + return $self->bin_store(BIN_CMD_REPLACE, $key, $value); +} + +sub append { + my ($self, $key, $value) = @_; + $self->send_binary_request(BIN_CMD_APPEND, $key, $value, ''); + my ($status) = $self->get_binary_response(); + return ($status == 0) ? 1 : 0; +} + +sub prepend { + my ($self, $key, $value) = @_; + $self->send_binary_request(BIN_CMD_PREPEND, $key, $value, ''); + my ($status) = $self->get_binary_response(); + return ($status == 0) ? 1 : 0; +} + +sub delete { + my ($self, $key) = @_; + $self->send_binary_request(BIN_CMD_DELETE, $key, '', ''); + my ($status, $value) = $self->get_binary_response(); + return ($status == 0) ? 1 : 0; +} + +sub incr { + my ($self, $key, $delta) = @_; + return $self->bin_math(BIN_CMD_INCR, $key, $delta, 0, 0xffffffff); +} + +sub decr { + my ($self, $key, $delta) = @_; + return $self->bin_math(BIN_CMD_DECR, $key, $delta, 0, 0xffffffff); +} + + +1; + === modified file 'mysql-test/lib/mtr_cases.pm' --- a/mysql-test/lib/mtr_cases.pm 2012-03-06 14:29:42 +0000 +++ b/mysql-test/lib/mtr_cases.pm 2012-04-18 14:56:21 +0000 @@ -1090,6 +1090,13 @@ sub collect_one_test_case { } } + if ( $tinfo->{'not_windows'} && IS_WINDOWS ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test not supported on Windows"; + return $tinfo; + } + # ---------------------------------------------------------------------- # Find config file to use if not already selected in .opt file # ---------------------------------------------------------------------- @@ -1172,6 +1179,7 @@ my @tags= ["include/not_embedded.inc", "not_embedded", 1], ["include/have_ssl.inc", "need_ssl", 1], ["include/have_ssl_communication.inc", "need_ssl", 1], + ["include/not_windows.inc", "not_windows", 1], ); === modified file 'mysql-test/mysql-test-run.pl' --- a/mysql-test/mysql-test-run.pl 2012-04-23 11:00:29 +0000 +++ b/mysql-test/mysql-test-run.pl 2012-04-27 08:11:57 +0000 @@ -411,7 +411,6 @@ sub main { unshift(@$tests, $tinfo); } - print "vardir: $opt_vardir\n"; initialize_servers(); ####################################################################### @@ -2817,7 +2816,7 @@ sub check_ndbcluster_support ($) { mtr_report(" - MySQL Cluster"); # Enable ndb engine and add more test suites $opt_include_ndbcluster = 1; - $DEFAULT_SUITES.=",ndb,ndb_binlog,rpl_ndb,ndb_rpl"; + $DEFAULT_SUITES.=",ndb,ndb_binlog,rpl_ndb,ndb_rpl,ndb_memcache"; } if ($opt_include_ndbcluster) @@ -3082,6 +3081,126 @@ sub ndbd_start { } +sub memcached_start { + my ($cluster, $memcached) = @_; + + my $name = $memcached->name(); + mtr_verbose("memcached_start '$name'"); + + my $found_perl_source = my_find_file($basedir, + ["storage/ndb/memcache", # source + "mysql-test/lib", # install + "share/mysql-test/lib"], # install + "memcached_path.pl", NOT_REQUIRED); + + mtr_verbose("Found memcache script: '$found_perl_source'"); + $found_perl_source ne "" or return; + + my $found_so = my_find_file($bindir, + ["storage/ndb/memcache", # source or build + "lib", "lib64"], # install + "ndb_engine.so"); + mtr_verbose("Found memcache plugin: '$found_so'"); + + require "$found_perl_source"; + if(! memcached_is_available()) + { + mtr_error("Memcached not available."); + } + my $exe = ""; + if(memcached_is_bundled()) + { + $exe = my_find_bin($bindir, + ["libexec", "sbin", "bin", "storage/ndb/memcache/extra/memcached"], + "memcached", NOT_REQUIRED); + } + else + { + $exe = get_memcached_exe_path(); + } + $exe ne "" or mtr_error("Failed to find memcached."); + + my $args; + mtr_init_args(\$args); + # TCP port number to listen on + mtr_add_arg($args, "-p %d", $memcached->value('port')); + # Max simultaneous connections + mtr_add_arg($args, "-c %d", $memcached->value('max_connections')); + # Load engine as storage engine, ie. /path/ndb_engine.so + mtr_add_arg($args, "-E"); + mtr_add_arg($args, $found_so); + # Config options for loaded storage engine + { + my @opts; + push(@opts, "connectstring=" . $memcached->value('ndb_connectstring')); + push(@opts, $memcached->if_exist("options")); + mtr_add_arg($args, "-e"); + mtr_add_arg($args, join(";", @opts)); + } + + if($opt_gdb) + { + gdb_arguments(\$args, \$exe, "memcached"); + } + + my $proc = My::SafeProcess->new + ( name => $name, + path => $exe, + args => \$args, + output => "$opt_vardir/log/$name.out", + error => "$opt_vardir/log/$name.out", + append => 1, + verbose => $opt_verbose, + ); + mtr_verbose("Started $proc"); + + $memcached->{proc} = $proc; + + return; +} + + +sub memcached_load_metadata($) { + my $cluster= shift; + + foreach my $mysqld (mysqlds()) + { + if(-d $mysqld->value('datadir') . "/" . "ndbmemcache") + { + mtr_verbose("skipping memcache metadata (already stored)"); + return; + } + } + + my $sql_script= my_find_file($bindir, + ["share/mysql/memcache-api", # RPM install + "share/memcache-api", # Other installs + "scripts" # Build tree + ], + "ndb_memcache_metadata.sql", NOT_REQUIRED); + mtr_verbose("memcached_load_metadata: '$sql_script'"); + if (-f $sql_script ) + { + my $args; + mtr_init_args(\$args); + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix()); + mtr_add_arg($args, "--connect-timeout=20"); + if ( My::SafeProcess->run( + name => "ndbmemcache config loader", + path => $exe_mysql, + args => \$args, + input => $sql_script, + output => "$opt_vardir/log/memcache_config.log", + error => "$opt_vardir/log/memcache_config.log" + ) != 0) + { + mtr_error("Could not load ndb_memcache_metadata.sql file"); + } + } +} + + sub ndbcluster_start ($) { my $cluster= shift; @@ -4254,7 +4373,7 @@ sub run_testcase ($) { } # Try to dump core for mysqltest and all servers - foreach my $proc ($test, started(all_servers())) + foreach my $proc ($test, started(all_servers())) { mtr_print("Trying to dump core for $proc"); if ($proc->dump_core()) @@ -5280,8 +5399,8 @@ sub mysqlds { return _like('mysqld.'); } sub ndbds { return _like('cluster_config.ndbd.');} sub ndb_mgmds { return _like('cluster_config.ndb_mgmd.'); } sub clusters { return _like('mysql_cluster.'); } -sub all_servers { return ( mysqlds(), ndb_mgmds(), ndbds() ); } - +sub memcacheds { return _like('memcached.'); } +sub all_servers { return ( mysqlds(), ndb_mgmds(), ndbds(), memcacheds() ); } # # Filter a list of servers and return only those that are part @@ -5353,7 +5472,7 @@ sub stop_servers($$) { # cluster processes My::SafeProcess::shutdown( $opt_shutdown_timeout, - started(ndbds(), ndb_mgmds()) ); + started(ndbds(), ndb_mgmds(), memcacheds()) ); } else { @@ -5548,6 +5667,23 @@ sub start_servers($) { return 1; } } + + # Start memcached(s) for each cluster + foreach my $cluster ( clusters() ) + { + next if !in_cluster($cluster, memcacheds()); + + # Load the memcache metadata into this cluster + memcached_load_metadata($cluster); + + # Start memcached(s) + foreach my $memcached ( in_cluster($cluster, memcacheds())) + { + next if started($memcached); + memcached_start($cluster, $memcached); + } + } + return 0; } No bundle (reason: useless for push emails).