merged 5.1-main -> 5.1-bugteam

This commit is contained in:
Georgi Kodinov 2009-01-30 15:44:49 +02:00
commit 3aec7ca415
1181 changed files with 26524 additions and 14487 deletions

View File

@ -1289,6 +1289,7 @@ mysql-test/funcs_1.log
mysql-test/funcs_1.tar
mysql-test/gmon.out
mysql-test/install_test_db
mysql-test/lib/My/SafeProcess/my_safe_process
mysql-test/lib/init_db.sql
mysql-test/linux_sys_vars.inc
mysql-test/load_sysvars.inc
@ -2097,10 +2098,13 @@ sql/.libs/udf_example.lai
sql/.libs/udf_example.so.0
sql/.libs/udf_example.so.0.0.0
sql/client.c
sql/Doxyfile
sql/f.c
sql/gen_lex_hash
sql/gmon.out
sql/handlerton.cc
sql/html
sql/latex
sql/lex_hash.h
sql/link_sources
sql/max/*

View File

@ -259,3 +259,4 @@ IF(WITH_EMBEDDED_SERVER)
ADD_SUBDIRECTORY(libmysqld)
ADD_SUBDIRECTORY(libmysqld/examples)
ENDIF(WITH_EMBEDDED_SERVER)
ADD_SUBDIRECTORY(mysql-test/lib/My/SafeProcess)

View File

@ -121,6 +121,10 @@ test-reprepare:
test: test-unit test-ns test-pr
smoke:
cd mysql-test ; \
@PERL@ ./mysql-test-run.pl --do-test=s
test-full: test test-nr test-ps
test-force:

View File

@ -32,8 +32,8 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc sql_string.cc ../mysys/my_conio.c)
TARGET_LINK_LIBRARIES(mysql mysqlclient_notls wsock32)
ADD_EXECUTABLE(mysqltest mysqltest.c)
SET_SOURCE_FILES_PROPERTIES(mysqltest.c PROPERTIES COMPILE_FLAGS "-DTHREADS")
ADD_EXECUTABLE(mysqltest mysqltest.cc)
SET_SOURCE_FILES_PROPERTIES(mysqltest.cc PROPERTIES COMPILE_FLAGS "-DTHREADS")
TARGET_LINK_LIBRARIES(mysqltest mysqlclient mysys regex wsock32 dbug)
ADD_EXECUTABLE(mysqlcheck mysqlcheck.c)

View File

@ -86,9 +86,9 @@ mysqlslap_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \
$(LIBMYSQLCLIENT_LA) \
$(top_builddir)/mysys/libmysys.a
mysqltest_SOURCES= mysqltest.c
mysqltest_CFLAGS= -DTHREAD -UUNDEF_THREADS_HACK
mysqltest_LDADD = $(CXXLDFLAGS) \
mysqltest_SOURCES= mysqltest.cc
mysqltest_CXXFLAGS= -DTHREAD -UUNDEF_THREADS_HACK
mysqltest_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \
@CLIENT_EXTRA_LDFLAGS@ \
$(LIBMYSQLCLIENT_LA) \
$(top_builddir)/mysys/libmysys.a \

View File

@ -23,10 +23,6 @@
#include <sys/stat.h>
#include <mysql.h>
#ifdef LATER_HAVE_NDBCLUSTER_DB
#include "../ndb/src/mgmclient/ndb_mgmclient.h"
#endif
#define ADMIN_VERSION "8.42"
#define MAX_MYSQL_VAR 256
#define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */
@ -46,10 +42,6 @@ static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations;
static uint opt_count_iterations= 0, my_end_arg;
static ulong opt_connect_timeout, opt_shutdown_timeout;
static char * unix_port=0;
#ifdef LATER_HAVE_NDBCLUSTER_DB
static my_bool opt_ndbcluster=0;
static char *opt_ndb_connectstring=0;
#endif
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
@ -105,9 +97,6 @@ enum commands {
ADMIN_PING, ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS,
ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE, ADMIN_STOP_SLAVE,
ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD
#ifdef LATER_HAVE_NDBCLUSTER_DB
,ADMIN_NDB_MGM
#endif
};
static const char *command_names[]= {
"create", "drop", "shutdown",
@ -118,9 +107,6 @@ static const char *command_names[]= {
"ping", "extended-status", "flush-status",
"flush-privileges", "start-slave", "stop-slave",
"flush-threads","old-password",
#ifdef LATER_HAVE_NDBCLUSTER_DB
"ndb-mgm",
#endif
NullS
};
@ -224,14 +210,6 @@ static struct my_option my_long_options[] =
{"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (uchar**) &opt_shutdown_timeout,
(uchar**) &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG,
SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0},
#ifdef LATER_HAVE_NDBCLUSTER_DB
{"ndbcluster", OPT_NDBCLUSTER, ""
"", (uchar**) &opt_ndbcluster,
(uchar**) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"ndb-connectstring", OPT_NDB_CONNECTSTRING, ""
"", (uchar**) &opt_ndb_connectstring,
(uchar**) &opt_ndb_connectstring, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@ -984,24 +962,6 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
}
mysql->reconnect=1; /* Automatic reconnect is default */
break;
#ifdef LATER_HAVE_NDBCLUSTER_DB
case ADMIN_NDB_MGM:
{
if (argc < 2)
{
my_printf_error(0, "Too few arguments to ndb-mgm", error_flags);
return 1;
}
{
Ndb_mgmclient_handle cmd=
ndb_mgmclient_handle_create(opt_ndb_connectstring);
ndb_mgmclient_execute(cmd, --argc, ++argv);
ndb_mgmclient_handle_destroy(cmd);
}
argc= 0;
}
break;
#endif
default:
my_printf_error(0, "Unknown command: '%-.60s'", error_flags, argv[0]);
return 1;

File diff suppressed because it is too large Load Diff

View File

@ -2798,8 +2798,8 @@ AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl
server-tools/Makefile server-tools/instance-manager/Makefile dnl
cmd-line-utils/Makefile cmd-line-utils/libedit/Makefile dnl
libmysqld/Makefile libmysqld/examples/Makefile dnl
mysql-test/Makefile dnl
mysql-test/ndb/Makefile netware/Makefile sql-bench/Makefile dnl
mysql-test/Makefile mysql-test/lib/My/SafeProcess/Makefile dnl
netware/Makefile sql-bench/Makefile dnl
include/mysql_version.h plugin/Makefile win/Makefile)
AC_CONFIG_COMMANDS([default], , test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h)

View File

@ -1133,6 +1133,9 @@ typedef char bool; /* Ordinary boolean values 0 1 */
#define dbug_volatile
#endif
/* Some helper macros */
#define YESNO(X) ((X) ? "yes" : "no")
/* Defines for time function */
#define SCALE_SEC 100
#define SCALE_USEC 10000

View File

@ -32,7 +32,7 @@ ADD_EXECUTABLE(mysql_embedded ../../client/completion_hash.cc
TARGET_LINK_LIBRARIES(mysql_embedded debug dbug strings mysys vio yassl taocrypt regex ws2_32)
ADD_DEPENDENCIES(mysql_embedded libmysqld)
ADD_EXECUTABLE(mysqltest_embedded ../../client/mysqltest.c)
ADD_EXECUTABLE(mysqltest_embedded ../../client/mysqltest.cc)
TARGET_LINK_LIBRARIES(mysqltest_embedded debug dbug strings mysys vio yassl taocrypt regex ws2_32)
ADD_DEPENDENCIES(mysqltest_embedded libmysqld)

View File

@ -41,7 +41,7 @@ LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @LIBDL@ $(CXXLDFLAGS) \
@NDB_SCI_LIBS@
mysqltest_embedded_LINK = $(CXXLINK)
nodist_mysqltest_embedded_SOURCES = mysqltest.c
nodist_mysqltest_embedded_SOURCES = mysqltest.cc
mysqltest_embedded_LDADD = $(LDADD) $(top_builddir)/regex/libregex.a
nodist_mysql_SOURCES = mysql.cc readline.cc completion_hash.cc \

View File

@ -17,132 +17,110 @@
## Process this file with automake to create Makefile.in
SUBDIRS = ndb
testdir = $(prefix)/mysql-test
benchdir_root= $(prefix)
testdir = $(benchdir_root)/mysql-test
EXTRA_SCRIPTS = mysql-test-run-shell.sh install_test_db.sh \
valgrind.supp $(PRESCRIPTS)
EXTRA_DIST = $(EXTRA_SCRIPTS) suite
GENSCRIPTS = mysql-test-run-shell install_test_db mtr mysql-test-run
PRESCRIPTS = mysql-test-run.pl mysql-stress-test.pl
test_SCRIPTS = $(GENSCRIPTS) $(PRESCRIPTS)
CLEANFILES = $(GENSCRIPTS)
test_SCRIPTS = mtr \
mysql-test-run \
mysql-test-run.pl \
mysql-stress-test.pl
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I..
nobase_test_DATA = \
lib/v1/mysql-test-run.pl \
lib/v1/mtr_cases.pl \
lib/v1/mtr_io.pl \
lib/v1/mtr_report.pl \
lib/v1/My/Config.pm \
lib/v1/mtr_gcov.pl \
lib/v1/mtr_match.pl \
lib/v1/mtr_stress.pl \
lib/v1/ndb_config_1_node.ini \
lib/v1/ndb_config_2_node.ini \
lib/v1/mtr_gprof.pl \
lib/v1/mtr_misc.pl \
lib/v1/mtr_timer.pl \
lib/v1/mtr_im.pl \
lib/v1/mtr_process.pl \
lib/v1/mtr_unique.pl \
\
lib/mtr_cases.pm \
lib/mtr_gcov.pl \
lib/mtr_gprof.pl \
lib/mtr_io.pl \
lib/mtr_match.pm \
lib/mtr_misc.pl \
lib/mtr_process.pl \
lib/mtr_report.pm \
lib/mtr_stress.pl \
lib/mtr_unique.pm \
lib/My/ConfigFactory.pm \
lib/My/Config.pm \
lib/My/Find.pm \
lib/My/Handles.pm \
lib/My/Options.pm \
lib/My/Test.pm \
lib/My/Platform.pm \
lib/My/SafeProcess.pm \
lib/My/File/Path.pm \
lib/My/SysInfo.pm \
lib/My/CoreDump.pm \
lib/My/SafeProcess/Base.pm \
lib/My/SafeProcess/safe_process.pl
SUBDIRS = lib/My/SafeProcess
EXTRA_DIST = README \
valgrind.supp \
$(test_SCRIPTS) \
$(nobase_test_DATA)
# List of directories containing test + result files and the
# related test data files that should be copied
TEST_DIRS = t r include std_data std_data/parts \
std_data/ndb_backup50 std_data/ndb_backup51 \
std_data/ndb_backup51_data_be std_data/ndb_backup51_data_le \
extra/binlog_tests/ extra/rpl_tests \
suite/binlog suite/binlog/t suite/binlog/r suite/binlog/std_data \
suite/bugs/data suite/bugs/t suite/bugs/r \
suite/federated \
suite/funcs_1 suite/funcs_1/bitdata \
suite/funcs_1/include suite/funcs_1/lib suite/funcs_1/r \
suite/funcs_1/t suite/funcs_1/views suite/funcs_1/cursors \
suite/funcs_1/datadict suite/funcs_1/storedproc suite/funcs_1/triggers \
suite/funcs_2 suite/funcs_2/charset suite/funcs_2/data \
suite/funcs_2/include suite/funcs_2/lib suite/funcs_2/r \
suite/funcs_2/t \
suite/jp suite/jp/t suite/jp/r suite/jp/std_data \
suite/manual/t suite/manual/r \
suite/ndb_team suite/ndb_team/t suite/ndb_team/r \
suite/rpl suite/rpl/data suite/rpl/include suite/rpl/r \
suite/rpl/t \
suite/stress/include suite/stress/t suite/stress/r \
suite/ndb suite/ndb/t suite/ndb/r \
suite/rpl_ndb suite/rpl_ndb/t suite/rpl_ndb/r \
suite/parts suite/parts/t suite/parts/r suite/parts/inc
# Used by dist-hook and install-data-local to copy all
# test files into either dist or install directory
install_test_files:
@if test -z "$(INSTALL_TO_DIR)"; then \
echo "Set INSTALL_TO_DIR!" && exit 1; \
fi
@for dir in $(TEST_DIRS); do \
from_dir="$(srcdir)/$$dir"; \
to_dir="$(INSTALL_TO_DIR)/$$dir"; \
$(mkinstalldirs) "$$to_dir"; \
for f in `(cd $$from_dir && ls)`; do \
if test -f "$$from_dir/$$f"; then \
$(INSTALL_DATA) "$$from_dir/$$f" "$$to_dir/$$f" ; \
fi; \
done \
done
dist-hook:
mkdir -p \
$(distdir)/t \
$(distdir)/extra/binlog_tests \
$(distdir)/extra/rpl_tests \
$(distdir)/r \
$(distdir)/include \
$(distdir)/std_data \
$(distdir)/std_data/ndb_backup50 \
$(distdir)/std_data/ndb_backup51 \
$(distdir)/std_data/ndb_backup51_data_be \
$(distdir)/std_data/ndb_backup51_data_le \
$(distdir)/std_data/parts \
$(distdir)/lib \
$(distdir)/std_data/funcs_1 \
$(distdir)/lib/My
-$(INSTALL_DATA) $(srcdir)/t/*.def $(distdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.test $(distdir)/t
-$(INSTALL_DATA) $(srcdir)/t/*.imtest $(distdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.sql $(distdir)/t
-$(INSTALL_DATA) $(srcdir)/t/*.disabled $(distdir)/t
-$(INSTALL_DATA) $(srcdir)/t/*.opt $(srcdir)/t/*.slave-mi $(distdir)/t
-$(INSTALL_SCRIPT) $(srcdir)/t/*.sh $(distdir)/t
$(INSTALL_DATA) $(srcdir)/extra/binlog_tests/*.test $(distdir)/extra/binlog_tests
$(INSTALL_DATA) $(srcdir)/extra/rpl_tests/*.test $(distdir)/extra/rpl_tests
-$(INSTALL_DATA) $(srcdir)/extra/binlog_tests/*.opt $(distdir)/extra/binlog_tests
-$(INSTALL_DATA) $(srcdir)/extra/rpl_tests/*.opt $(distdir)/extra/rpl_tests
$(INSTALL_DATA) $(srcdir)/include/*.inc $(distdir)/include
$(INSTALL_DATA) $(srcdir)/include/*.sql $(distdir)/include
$(INSTALL_DATA) $(srcdir)/include/*.test $(distdir)/include
$(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.require $(distdir)/r
$(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/Index.xml $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.dat $(srcdir)/std_data/*.000001 $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.pem $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.frm $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.MY* $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.txt $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50/BACKUP* $(distdir)/std_data/ndb_backup50
$(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51/BACKUP* $(distdir)/std_data/ndb_backup51
$(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51_data_be/BACKUP* $(distdir)/std_data/ndb_backup51_data_be
$(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51_data_le/BACKUP* $(distdir)/std_data/ndb_backup51_data_le
$(INSTALL_DATA) $(srcdir)/std_data/parts/part_* $(distdir)/std_data/parts
$(INSTALL_DATA) $(srcdir)/std_data/parts/*.MY* $(distdir)/std_data/parts
$(INSTALL_DATA) $(srcdir)/std_data/funcs_1/* $(distdir)/std_data/funcs_1
$(INSTALL_DATA) $(srcdir)/lib/*.pl $(distdir)/lib
$(INSTALL_DATA) $(srcdir)/lib/My/*.pm $(distdir)/lib/My
-rm -rf `find $(distdir)/suite -type d -name SCCS` $(distdir)/suite/row_lock
$(MAKE) INSTALL_TO_DIR="$(distdir)" install_test_files
install-data-local:
$(mkinstalldirs) \
$(DESTDIR)$(testdir)/t \
$(DESTDIR)$(testdir)/extra/binlog_tests \
$(DESTDIR)$(testdir)/extra/rpl_tests \
$(DESTDIR)$(testdir)/r \
$(DESTDIR)$(testdir)/include \
$(DESTDIR)$(testdir)/std_data \
$(DESTDIR)$(testdir)/std_data/ndb_backup50 \
$(DESTDIR)$(testdir)/std_data/ndb_backup51 \
$(DESTDIR)$(testdir)/std_data/ndb_backup51_data_be \
$(DESTDIR)$(testdir)/std_data/ndb_backup51_data_le \
$(DESTDIR)$(testdir)/std_data/parts \
$(DESTDIR)$(testdir)/lib \
$(DESTDIR)$(testdir)/std_data/funcs_1 \
$(DESTDIR)$(testdir)/lib/My
$(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(testdir)
-$(INSTALL_DATA) $(srcdir)/t/*.def $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.test $(DESTDIR)$(testdir)/t
-$(INSTALL_DATA) $(srcdir)/t/*.imtest $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.sql $(DESTDIR)$(testdir)/t
-$(INSTALL_DATA) $(srcdir)/t/*.disabled $(DESTDIR)$(testdir)/t
-$(INSTALL_DATA) $(srcdir)/t/*.opt $(DESTDIR)$(testdir)/t
-$(INSTALL_SCRIPT) $(srcdir)/t/*.sh $(DESTDIR)$(testdir)/t
-$(INSTALL_DATA) $(srcdir)/t/*.slave-mi $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/r/*.result $(DESTDIR)$(testdir)/r
$(INSTALL_DATA) $(srcdir)/r/*.require $(DESTDIR)$(testdir)/r
$(INSTALL_DATA) $(srcdir)/extra/binlog_tests/*.test $(DESTDIR)$(testdir)/extra/binlog_tests
$(INSTALL_DATA) $(srcdir)/extra/rpl_tests/*.test $(DESTDIR)$(testdir)/extra/rpl_tests
-$(INSTALL_DATA) $(srcdir)/extra/binlog_tests/*.opt $(DESTDIR)$(testdir)/extra/binlog_tests
-$(INSTALL_DATA) $(srcdir)/extra/rpl_tests/*.opt $(DESTDIR)$(testdir)/extra/rpl_tests
$(INSTALL_DATA) $(srcdir)/include/*.inc $(DESTDIR)$(testdir)/include
$(INSTALL_DATA) $(srcdir)/include/*.sql $(DESTDIR)$(testdir)/include
$(INSTALL_DATA) $(srcdir)/include/*.test $(DESTDIR)$(testdir)/include
$(INSTALL_DATA) $(srcdir)/std_data/*.dat $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.*001 $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/Index.xml $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.pem $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.frm $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.MY* $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.txt $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup50
$(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup51
$(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51_data_be/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup51_data_be
$(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51_data_le/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup51_data_le
$(INSTALL_DATA) $(srcdir)/std_data/parts/part_* $(DESTDIR)$(testdir)/std_data/parts
$(INSTALL_DATA) $(srcdir)/std_data/parts/*.MY* $(DESTDIR)$(testdir)/std_data/parts
$(INSTALL_DATA) $(srcdir)/std_data/funcs_1/* $(DESTDIR)$(testdir)/std_data/funcs_1
$(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib
$(INSTALL_DATA) $(srcdir)/lib/My/*.pm $(DESTDIR)$(testdir)/lib/My
for f in `(cd $(srcdir); find suite -type f | egrep -v 'SCCS|row_lock')`; \
do \
d=$(DESTDIR)$(testdir)/`dirname $$f`; \
mkdir -p $$d ; \
$(INSTALL_DATA) $(srcdir)/$$f $$d ; \
done
$(MAKE) INSTALL_TO_DIR="$(DESTDIR)$(testdir)" install_test_files
uninstall-local:
@RM@ -f -r $(DESTDIR)$(testdir)
@ -157,31 +135,5 @@ mysql-test-run:
$(RM) -f mysql-test-run
$(LN_S) mysql-test-run.pl mysql-test-run
SUFFIXES = .sh
.sh:
@RM@ -f $@ $@-t
@SED@ \
-e 's!@''testdir''@!$(testdir)!g' \
-e 's!@''bindir''@!$(bindir)!g' \
-e 's!@''scriptdir''@!$(bindir)!g' \
-e 's!@''prefix''@!$(prefix)!g' \
-e 's!@''datadir''@!$(datadir)!g' \
-e 's!@''localstatedir''@!$(localstatedir)!g' \
-e 's!@''libexecdir''@!$(libexecdir)!g' \
-e 's!@''PERL''@!@PERL@!' \
-e 's!@''VERSION''@!@VERSION@!' \
-e 's!@''MYSQL_TCP_PORT''@!@MYSQL_TCP_PORT@!' \
-e 's!@''MYSQL_TCP_PORT_DEFAULT''@!@MYSQL_TCP_PORT_DEFAULT@!' \
-e 's!@''MYSQL_BASE_VERSION''@!@MYSQL_BASE_VERSION@!' \
-e 's!@''MYSQL_UNIX_ADDR''@!@MYSQL_UNIX_ADDR@!' \
-e 's!@''MYSQL_TCP_PORT''@!@MYSQL_TCP_PORT@!' \
-e 's!@''MYSQL_NO_DASH_VERSION''@!@MYSQL_NO_DASH_VERSION@!' \
-e 's!@''MYSQL_SERVER_SUFFIX''@!@MYSQL_SERVER_SUFFIX@!' \
-e 's!@''USE_NDBCLUSTER''@!@TEST_NDBCLUSTER@!g' \
$< > $@-t
@CHMOD@ +x $@-t
@MV@ $@-t $@
# Don't update the files from bitkeeper
%::SCCS/s.%

View File

@ -1,65 +0,0 @@
#! /bin/sh
# This script is a hack for lazy developers who want to get a quick
# start on the result file. The code here is rather dirty, but it works
# If you have a spare moment feel free to improve it - the right way is
# to start mysqld yourself and run mysqltest -r
RESULT_DIR=r
if [ -z "$EDITOR" ] ; then
EDITOR=vi
fi
function die()
{
echo $1
exit 1
}
function usage()
{
echo "Usage: $0 test_name"
exit 1
}
test_name=$1
[ -z "$test_name" ] && usage
result_file=$RESULT_DIR/$test_name.result
reject_file=$RESULT_DIR/$test_name.reject
[ -f $result_file ] && die "result file $result_file has already been created"
touch $result_file
echo "Running the test case against empty file, will fail, but don't worry"
./mysql-test-run --local $test_name
if [ -f $reject_file ] ; then
echo "Below are the contents of the reject file:"
echo "-----start---------------------"
cat $reject_file
echo "-----end-----------------------"
echo "Is this the output you expected from your test case?(y/n)[n]"
read yes_no
if [ x$yes_no = xy ] ; then
echo "Press any key to edit it in $EDITOR, or Ctrl-C to abort"
read junk
$EDITOR $reject_file
edited="edited"
fi
echo "Save $edited file as master result? (y/n)[y]"
read yes_no
if [ x$yes_no != xn ]; then
mv $reject_file $result_file
fi
else
echo "Your test failed so bad, it did not even produce a reject file"
echo "You need to fix your bugs in the test case, the code, or both"
exit 1
fi

View File

@ -7,7 +7,7 @@
-- source include/have_log_bin.inc
# The server need to be started in $MYSQLTEST_VARDIR since it
# uses ../std_data_ln/
# uses ../../std_data/
-- source include/uses_vardir.inc
--disable_warnings
@ -114,7 +114,7 @@ insert into t1 values(1);
insert ignore into t1 values(1);
replace into t1 values(100);
create table t2 (a varchar(200)) engine=blackhole;
eval load data infile '../std_data_ln/words.dat' into table t2;
eval load data infile '../../std_data/words.dat' into table t2;
alter table t1 add b int;
alter table t1 drop b;
create table t3 like t1;

View File

@ -16,7 +16,8 @@ source include/show_binlog_events.inc;
# escaped).
flush logs;
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
--exec $MYSQL_BINLOG --short-form $MYSQLTEST_VARDIR/log/master-bin.000001
let $MYSQLD_DATADIR= `select @@datadir`;
--exec $MYSQL_BINLOG --short-form $MYSQLD_DATADIR/master-bin.000001
drop table t2;
# End of 4.1 tests

View File

@ -317,17 +317,18 @@ connection con4;
select get_lock("a",10); # wait for rollback to finish
flush logs;
let $MYSQLD_DATADIR= `select @@datadir`;
# we check that the error code of the "ROLLBACK" event is 0 and not
# ER_SERVER_SHUTDOWN (i.e. disconnection just rolls back transaction
# and does not make slave to stop)
if (`select @@binlog_format = 'ROW'`)
{
--exec $MYSQL_BINLOG --start-position=524 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output
--exec $MYSQL_BINLOG --start-position=524 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output
}
if (`select @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
{
--exec $MYSQL_BINLOG --start-position=555 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output
--exec $MYSQL_BINLOG --start-position=555 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output
}
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
@ -618,7 +619,7 @@ CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
# execute
--error ER_DUP_ENTRY
load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
# check
select * from t4;
select count(*) from t1 /* must be 2 */;

View File

@ -278,7 +278,7 @@ CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
# execute
--error ER_DUP_ENTRY
load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
# check
select * from t4;
select count(*) from t1 /* must be 2 */;

View File

@ -20,7 +20,8 @@
eval create table t1 (a int) engine=$engine_type;
flush tables;
remove_file $MYSQLTEST_VARDIR/master-data/test/t1.MYI ;
let $MYSQLD_DATADIR= `select @@datadir`;
remove_file $MYSQLD_DATADIR/test/t1.MYI ;
drop table if exists t1;
save_master_pos;
connection slave;

View File

@ -0,0 +1,168 @@
# ==== Purpose ====
#
# Test that slave behaves well in some conflict situations. The
# following are tested:
#
# - The slave SQL thread sees an 'INSERT' of a row with a key that
# already exists in the table;
#
# - The slave SQL thread sees a 'DELETE' of a row that does not
# exist in the table.
#
# In statement-logging mode, the first conflict type causes the slave
# to stop with an error and the second conflict is ignored.
#
# In row-logging mode, the slave behavior depends the value of
# @@slave_exec_mode on the slave: if @@slave_exec_mode is IDEMPOTENT,
# the slave should ignore the conflicting statement and continue
# normally. If @@slave_exec_mode is STRICT, the slave should stop
# with an error.
#
# This test was previously named rpl_stm_mystery22/rpl_row_mystery22.
#
#
# ==== Method ====
#
# Create a table on master and slave, insert a row on slave, and
# insert the same row on master.
#
# Create a table on master and slave, insert a row on master with
# binlogging turned off, and remove the row on master with binlogging
# turned on.
#
#
# ==== Related bugs ====
#
# BUG#31552: Replication breaks when deleting rows from out-of-sync table without PK
# BUG#31609: Not all RBR slave errors reported as errors
#
# Bug in this test case:
# BUG#37718: rpl.rpl_stm_mystery22 fails sporadically on pushbuild
#
#
# ==== Usage ====
#
# This file assumes the following:
#
# - The test language variable $slave_is_idempotent is set to 1 if the
# slave is expected to stop on duplicate key errors (i.e., if the
# binlog is in statement mode or
# @@global.slave_exec_mode=STRICT). It is set to 0 otherwise.
#
# - Replication has been initialized by include/master-slave.inc
#
# - The test adds a suppression for the following warning:
# Slave: Can't find record in 't1' Error_code: 1032
--echo ==== Initialize ====
--echo [on master]
connection master;
CREATE TABLE t1(a INT PRIMARY KEY);
--echo [on slave]
sync_slave_with_master;
--echo ==== Test: SQL thread sees 'INSERT' of existing key ====
--echo ---- Prepare slave so that it will get duplicate key error ----
# This row will be in the way of the row inserted by master.
INSERT INTO t1 VALUES (1);
--echo ---- Insert rows on master ----
--echo [on master]
connection master;
# Insert the same row on master
INSERT INTO t1 VALUES (1);
save_master_pos;
SELECT * FROM t1;
--echo [on slave]
connection slave;
# If we are statement-logging or if slave_exec_mode=STRICT, we now
# expect to see an error on the slave. Otherwise (i.e., we are
# row-logging and slave_exec_mode=IDEMPOTENT), we expect that the
# duplicate row is ignored by the slave and replication continues.
if (`SELECT @@global.binlog_format != 'ROW' OR @@global.slave_exec_mode = 'STRICT'`) {
--echo ---- Wait until slave stops with an error ----
# Wait until the slave tries to run the query, fails with duplicate
# key error, and stops the SQL thread.
let $slave_sql_errno= 1062; # ER_DUP_ENTRY
source include/wait_for_slave_sql_error.inc;
let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
--echo Last_SQL_Error = $err (expected "duplicate key" error)
SELECT * FROM t1;
--echo ---- Resolve the conflict on the slave and restart SQL thread ----
DELETE FROM t1 WHERE a = 1;
START SLAVE SQL_THREAD;
source include/wait_for_slave_sql_to_start.inc;
}
--echo ---- Sync slave and verify that there is no error ----
sync_with_master;
let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
--echo Last_SQL_Error = '$err' (expected no error)
SELECT * FROM t1;
--echo ==== Test: SQL thread sees 'DELETE' of non-existing row ====
--echo ---- On master, insert two rows, the second with binlogging off ----
--echo [on master]
connection master;
DELETE FROM t1;
INSERT INTO t1 VALUES (1);
--echo [on slave]
sync_slave_with_master;
DELETE FROM t1 WHERE a = 1;
--echo ---- On master, remove the row that does not exist on slave ----
--echo [on master]
connection master;
DELETE FROM t1 WHERE a = 1;
SELECT * FROM t1;
save_master_pos;
--echo [on slave]
connection slave;
# If we are row-logging and slave_exec_mode is STRICT, we now expect
# an error since the row to delete does not exist on slave. Otherwise
# (i.e., either we are statement-logging or slave_exec_mode is
# IDEMPOTENT), the absence of the row to delete is ignored and
# replication continues.
if (`SELECT @@global.binlog_format = 'ROW' AND @@global.slave_exec_mode = 'STRICT'`) {
--echo ---- Wait until slave stops with an error ----
let $slave_sql_errno= 1032; # ER_KEY_NOT_FOUND
source include/wait_for_slave_sql_error.inc;
let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
--echo Last_SQL_Error = $err (expected "can't find record" error)
SELECT * FROM t1;
--echo ---- Resolve the conflict on the slave and restart SQL thread ----
INSERT INTO t1 VALUES (1);
START SLAVE SQL_THREAD;
source include/wait_for_slave_sql_to_start.inc;
}
--echo ---- Sync slave and verify that there is no error ----
# The slave should sync ok, and SHOW SLAVE STATUS should give no
# error.
sync_with_master;
let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
--echo Last_SQL_Error = $err (expected no error)
SELECT * FROM t1;
--echo ==== Clean up ====
--echo [on master]
connection master;
DROP TABLE t1;
--echo [on slave]
sync_slave_with_master;

View File

@ -497,7 +497,7 @@ INSERT INTO t10 () VALUES(1,@b1,DEFAULT,'Kyle',DEFAULT),
--echo ********************************************
--echo
connection slave;
wait_for_slave_to_stop;
source include/wait_for_slave_sql_to_stop.inc;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 #
--query_vertical SHOW SLAVE STATUS
@ -554,7 +554,7 @@ INSERT INTO t11 () VALUES(1,@b1,'Testing is fun','Kyle',DEFAULT),
--echo ********************************************
--echo
connection slave;
wait_for_slave_to_stop;
source include/wait_for_slave_sql_to_stop.inc;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 #
--query_vertical SHOW SLAVE STATUS
@ -697,7 +697,7 @@ SELECT c1,c3,hex(c4),c5,c6 FROM t14 ORDER BY c1;
# Remove below once fixed
#***************************
connection slave;
wait_for_slave_to_stop;
source include/wait_for_slave_sql_to_stop.inc;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 #
--query_vertical SHOW SLAVE STATUS
@ -763,7 +763,7 @@ SELECT c1,hex(c4),c5,c6,c7,c2 FROM t15 ORDER BY c1;
--echo ********************************************
--echo
connection slave;
wait_for_slave_to_stop;
source include/wait_for_slave_sql_to_stop.inc;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 #
--query_vertical SHOW SLAVE STATUS
@ -840,7 +840,7 @@ SELECT c1,hex(c4),c5,c6,c7 FROM t16 ORDER BY c1;
--echo *****************
--echo
connection slave;
wait_for_slave_to_stop;
source include/wait_for_slave_sql_to_stop.inc;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 #
--query_vertical SHOW SLAVE STATUS

View File

@ -94,7 +94,7 @@ SELECT * FROM t2 ORDER BY a;
--echo *** Start Slave ***
connection slave;
START SLAVE;
wait_for_slave_to_stop;
source include/wait_for_slave_sql_to_stop.inc;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 #
--query_vertical SHOW SLAVE STATUS
@ -429,6 +429,7 @@ set @b1 = 'b1b1b1b1';
set @b1 = concat(@b1,@b1);
INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 #

View File

@ -4,8 +4,7 @@
# Test of FLUSH NO_WRITE_TO_BINLOG by the way.
#
-- source include/master-slave.inc
source include/master-slave.inc;
let $SERVER_VERSION=`select version()`;
@ -34,26 +33,32 @@ flush tables;
--replace_column 2 # 5 #
--replace_regex /table_id: [0-9]+/table_id: #/
eval SHOW BINLOG EVENTS FROM $rename_event_pos ;
save_master_pos;
connection slave;
sync_with_master;
sync_slave_with_master;
# Check that the slave is not confused.
select * from t3;
# Note that all this confusion may cause warnings 'table xx is open on rename'
# in the .err files; these are not fatal and are not reported by mysql-test-run.
stop slave;
source include/wait_for_slave_to_stop.inc;
connection master;
drop table t1;
connection slave;
flush tables with read lock;
start slave;
sleep 1;
source include/wait_for_slave_to_start.inc;
--error 1192
stop slave;
# Cleanup
unlock tables;
connection master;
drop table t3, t4, t5;
sync_slave_with_master;
# End of 4.1 tests

View File

@ -23,12 +23,12 @@ connection master;
select last_insert_id();
create table t1(a int not null auto_increment, b int, primary key(a) );
load data infile '../std_data_ln/rpl_loaddata.dat' into table t1;
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
# verify that LAST_INSERT_ID() is set by LOAD DATA INFILE
select last_insert_id();
create temporary table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60));
load data infile '../std_data_ln/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines;
load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines;
create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60));
insert into t3 select * from t2;
@ -56,7 +56,7 @@ sync_with_master;
insert into t1 values(1,10);
connection master;
load data infile '../std_data_ln/rpl_loaddata.dat' into table t1;
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
save_master_pos;
connection slave;
@ -80,7 +80,7 @@ connection master;
set sql_log_bin=0;
delete from t1;
set sql_log_bin=1;
load data infile '../std_data_ln/rpl_loaddata.dat' into table t1;
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
save_master_pos;
connection slave;
# The SQL slave thread should be stopped now.
@ -105,7 +105,7 @@ connection master;
set sql_log_bin=0;
delete from t1;
set sql_log_bin=1;
load data infile '../std_data_ln/rpl_loaddata.dat' into table t1;
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
save_master_pos;
connection slave;
# The SQL slave thread should be stopped now.
@ -125,7 +125,7 @@ reset master;
eval create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60),
unique(day)) engine=$engine_type; # no transactions
--error ER_DUP_ENTRY
load data infile '../std_data_ln/rpl_loaddata2.dat' into table t2 fields
load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
'\n##\n' starting by '>' ignore 1 lines;
select * from t2;
@ -141,24 +141,21 @@ alter table t2 drop key day;
connection master;
delete from t2;
--error ER_DUP_ENTRY
load data infile '../std_data_ln/rpl_loaddata2.dat' into table t2 fields
load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
'\n##\n' starting by '>' ignore 1 lines;
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
drop table t2;
drop table t1, t2;
connection master;
drop table t2;
drop table t1;
drop table t1, t2;
# BUG#17233 LOAD DATA INFILE: failure causes mysqld dbug_assert, binlog not flushed
CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=INNODB;
--error ER_DUP_ENTRY
LOAD DATA INFILE "../std_data_ln/words.dat" INTO TABLE t1;
LOAD DATA INFILE "../../std_data/words.dat" INTO TABLE t1;
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
# End of 4.1 tests

View File

@ -9,10 +9,8 @@
# test the slave immediately writes DROP TEMPORARY TABLE this_old_table).
# We wait for the slave to have written all he wants to the binlog
# (otherwise RESET MASTER may come too early).
save_master_pos;
connection slave;
sync_with_master;
stop slave;
sync_slave_with_master;
source include/stop_slave.inc;
--source include/wait_for_slave_to_stop.inc
reset master;
reset slave;
@ -25,8 +23,13 @@ connection master;
eval create table t1(n int not null auto_increment primary key)ENGINE=$engine_type;
insert into t1 values (NULL);
drop table t1;
let $LOAD_FILE= ../../std_data/words.dat;
if (!`SELECT length(load_file('$LOAD_FILE'))`){
let $LOAD_FILE= ../$LOAD_FILE;
}
eval create table t1 (word char(20) not null)ENGINE=$engine_type;
load data infile '../std_data_ln/words.dat' into table t1 ignore 1 lines;
--replace_result $LOAD_FILE LOAD_FILE
eval load data infile '$LOAD_FILE' into table t1 ignore 1 lines;
select count(*) from t1;
--replace_result $VERSION VERSION
--replace_column 2 # 5 #
@ -67,19 +70,12 @@ eval create table t3 (a int)ENGINE=$engine_type;
connection master;
select * from t1 order by 1 asc;
save_master_pos;
connection slave;
# Note that the above 'slave start' will cause a 3rd rotate event (a fake one)
# to go into the relay log (the master always sends a fake one when replication
# starts).
let $result_pattern= '%127.0.0.1%root%master-bin.000002%slave-relay-bin.000005%Yes%Yes%0%0%None%';
--source include/wait_slave_status.inc
sync_with_master;
sync_slave_with_master;
#check t1 on slave to ensure whether it's identical with on master
select * from t1 order by 1 asc;
flush logs;
stop slave;
--source include/wait_for_slave_to_stop.inc
source include/stop_slave.inc;
source include/start_slave.inc;
connection master;
# Create some entries for second log
@ -93,11 +89,8 @@ source include/show_binlog_events.inc;
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/
show binlog events in 'master-bin.000002';
show binary logs;
save_master_pos;
connection slave;
start slave;
sync_slave_with_master;
--source include/wait_for_slave_to_start.inc
sync_with_master;
show binary logs;
--replace_result $MASTER_MYPORT MASTER_PORT $VERSION VERSION
--replace_column 2 # 5 #
@ -133,9 +126,13 @@ DROP TABLE t3;
# Bug #6880: LAST_INSERT_ID() within a statement
#
# Reset binlog so that show binlog events will not show the tests
# above.
source include/master-slave-reset.inc;
connection master;
create table t1(a int auto_increment primary key, b int);
insert into t1 values (NULL, 1);
reset master;
set insert_id=5;
insert into t1 values (NULL, last_insert_id()), (NULL, last_insert_id());
source include/show_binlog_events.inc;
@ -145,4 +142,3 @@ drop table t1;
# End of 4.1 tests
sync_slave_with_master;

View File

@ -1,7 +1,9 @@
let $LOAD_FILE= $MYSQLTEST_VARDIR/std_data/words.dat;
CREATE TABLE t1 (word CHAR(20) NOT NULL);
LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t1;
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/std_data/words.dat' INTO TABLE t1;
--replace_result $LOAD_FILE LOAD_FILE
eval LOAD DATA INFILE '$LOAD_FILE' INTO TABLE t1;
--replace_result $LOAD_FILE LOAD_FILE
eval LOAD DATA INFILE '$LOAD_FILE' INTO TABLE t1;
SELECT * FROM t1 ORDER BY word LIMIT 10;
#

View File

@ -206,7 +206,7 @@ START TRANSACTION;
-- disable_query_log
-- disable_result_log
let $n=50;
while ($n>3)
while ($n)
{
eval call test.p3($n);
dec $n;

View File

@ -122,7 +122,7 @@ INSERT INTO t1_nodef VALUES (1,2);
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 36 <Last_IO_Error> 38 <Last_SQL_Error>
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 35 <Last_IO_Errno> 36 <Last_IO_Error> 38 <Last_SQL_Error>
--query_vertical SHOW SLAVE STATUS
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
START SLAVE;
@ -142,7 +142,7 @@ sync_slave_with_master;
--echo **** On Slave ****
SELECT * FROM t2;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 36 <Last_IO_Error> 38 <Last_SQL_Error>
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 35 <Last_IO_Errno> 36 <Last_IO_Error> 38 <Last_SQL_Error>
--query_vertical SHOW SLAVE STATUS
connection master;
@ -154,7 +154,7 @@ INSERT INTO t4 VALUES (4);
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 36 <Last_IO_Error> 38 <Last_SQL_Error>
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 35 <Last_IO_Errno> 36 <Last_IO_Error> 38 <Last_SQL_Error>
--query_vertical SHOW SLAVE STATUS
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
START SLAVE;
@ -168,7 +168,7 @@ INSERT INTO t5 VALUES (5,10,25);
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 36 <Last_IO_Error> 38 <Last_SQL_Error>
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 35 <Last_IO_Errno> 36 <Last_IO_Error> 38 <Last_SQL_Error>
--query_vertical SHOW SLAVE STATUS
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
START SLAVE;
@ -182,7 +182,7 @@ INSERT INTO t6 VALUES (6,12,36);
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 36 <Last_IO_Error> 38 <Last_SQL_Error>
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 35 <Last_IO_Errno> 36 <Last_IO_Error> 38 <Last_SQL_Error>
--query_vertical SHOW SLAVE STATUS
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
START SLAVE;
@ -191,7 +191,7 @@ connection master;
INSERT INTO t9 VALUES (6);
sync_slave_with_master;
--replace_result $SLAVE_MYPORT SLAVE_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 36 <Last_IO_Error> 38 <Last_SQL_Error>
--replace_column 1 # 4 # 7 # 8 # 9 # 20 <Last_Error> 22 # 23 # 33 # 35 <Last_IO_Errno> 36 <Last_IO_Error> 38 <Last_SQL_Error>
--query_vertical SHOW SLAVE STATUS
# Testing some tables extra field that can be null and cannot be null

View File

@ -2,7 +2,7 @@
-- source include/master-slave.inc
create table t1 (word char(20) not null);
load data infile '../std_data_ln/words.dat' into table t1;
load data infile '../../std_data/words.dat' into table t1;
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
eval load data local infile '$MYSQL_TEST_DIR/std_data/words.dat' into table t1;
select * from t1 limit 10;

View File

@ -18,13 +18,18 @@ eval create table t1 (a int, unique(a)) engine=$engine_type;
set sql_log_bin=0;
insert into t1 values(2);
set sql_log_bin=1;
save_master_pos;
--error ER_DUP_ENTRY
insert into t1 values(1),(2);
drop table t1;
save_master_pos;
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
let $errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
--echo Error: "$error" (expected different error codes on master and slave)
--echo Errno: "$errno" (expected 0)
drop table t1;
# End of 4.1 tests

View File

@ -14,6 +14,9 @@ START SLAVE;
--echo **** On Master ****
connection master;
SET @old_session_binlog_format= @@session.binlog_format;
SET @old_global_binlog_format= @@global.binlog_format;
eval SET SESSION BINLOG_FORMAT=$format;
eval SET GLOBAL BINLOG_FORMAT=$format;
@ -40,3 +43,5 @@ source include/show_binlog_events.inc;
connection master;
RESET MASTER;
SET @@session.binlog_format= @old_session_binlog_format;
SET @@global.binlog_format= @old_global_binlog_format;

View File

@ -1,22 +0,0 @@
#! /bin/sh
# Sasha's hack to fix results generated with mysql-test-run --record
# to be version and test port independent. In some cases, further minor
# manual edititing may be required, but most of the time it should not
# happen
#It is assumed we are running the script in mysql-test directory
VERSION=4.0.1-alpha-debug-log
TEST_CASE=$1
if [ -z "$TEST_CASE" ] ;
then
echo "usage: $0 test_case_name"
exit 1
fi
../extra/replace $VERSION '$VERSION' 9306 '$MASTER_MYPORT' 9307 \
'$SLAVE_MYPORT' \\ \\\\ -- r/$TEST_CASE.result

View File

@ -0,0 +1,6 @@
SHOW PROCESSLIST;
let $binlog_name= query_get_value("SHOW MASTER STATUS", File, 1);
eval SHOW BINLOG EVENTS IN '$binlog_name';
exit;

View File

@ -0,0 +1,3 @@
SHOW PROCESSLIST;
exit;

View File

@ -1,15 +0,0 @@
# Connect to both master and slave
connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,);
vertical_results;
echo == MASTER ===========================================================;
connection master;
show master status;
show slave status;
echo == SLAVE ===========================================================;
connection slave;
show master status;
show slave status;

View File

@ -1,51 +1,15 @@
#
# This test is executed twice for each test case if mysql-test-run is passed
# the flag --check-testcase.
# Before every testcase it's run with mysqltest in record mode and will
# thus produce an output file
# that can be compared to output from after the tescase.
# In that way it's possible to check that a testcase does not have
# the flag --check-testcase. Before every testcase it is run with mysqltest
# in record mode and will thus produce an output file that can be compared
# to output from after the tescase.
# In that way its possible to check that a testcase does not have
# any unwanted side affects.
#
#
# Dump all global variables
#
SHOW GLOBAL VARIABLES WHERE variable_name != 'timestamp';
#
# Dump all databases
#
SHOW DATABASES;
#
# Dump the "test" database, all it's tables and their data
#
--exec $MYSQL_DUMP --skip-comments --skip-lock-tables test
#
# Dump the "mysql" database and it's tables
# Select data separately to add "order by"
#
--exec $MYSQL_DUMP --skip-comments --skip-lock-tables --no-data mysql
use mysql;
SELECT * FROM columns_priv;
SELECT * FROM db ORDER BY host, db, user;
SELECT * FROM func;
SELECT * FROM help_category;
SELECT * FROM help_keyword;
SELECT * FROM help_relation;
SELECT * FROM help_relation;
SELECT * FROM host;
SELECT * FROM proc;
SELECT * FROM procs_priv;
SELECT * FROM tables_priv;
SELECT * FROM time_zone;
SELECT * FROM time_zone_leap_second;
SELECT * FROM time_zone_name;
SELECT * FROM time_zone_transition;
SELECT * FROM time_zone_transition_type;
SELECT * FROM user;
--disable_query_log
call mtr.check_testcase();
--enable_query_log

View File

@ -0,0 +1,61 @@
#
# This test is executed once after each test to check the servers
# for unexpected warnings found in the servers error log
#
# NOTE! mysql-test-run.pl has already done a rough filtering
# of the file and written any suspicious lines
# to $error_log.warnings file
#
--disable_query_log
# Don't write these queries to binlog
set SQL_LOG_BIN=0;
# Turn off any debug crashes, allow the variable to be
# non existent in release builds
--error 0,1193
set debug="";
use mtr;
create temporary table error_log (
row int auto_increment primary key,
suspicious int default 1,
file_name varchar(255),
line varchar(1024) default null
) engine=myisam;
# Get the name of servers error log
let $log_error= query_get_value(show variables like 'log_error', Value, 1);
let $log_warning= $log_error.warnings;
# Try tload the warnings into a temporary table,
# it might fail with error saying "The MySQL server is
# running with the --secure-file-priv" in which case
# an attempt to load the file using LOAD DATA LOCAL is made
--error 0,1290
eval load data infile '$log_warning' into table error_log
fields terminated by 'xykls37' escaped by ''
ignore 1 lines
(line)
set file_name='$log_error';
if ($mysql_errno)
{
# Try LOAD DATA LOCAL
eval load data local infile '$log_warning' into table error_log
fields terminated by 'xykls37' escaped by ''
ignore 1 lines
(line)
set file_name='$log_error';
}
# Call check_warnings to filter out any warning in
# the error_log table
call mtr.check_warnings(@result);
if (`select @result = 0`){
skip OK;
}
--enable_query_log
echo ^ Found warnings!!;
exit;

View File

@ -0,0 +1,130 @@
#############################################################
#
# Author: Serge Kozlov <skozlov@mysql.com>
# Date: 03/11/2008
# Purpose: Set up circular replication based on schema
# A->B->C->D->A
#
# Notes:
# 1. --slave-num=3 must be added to *-master.opt file
# 2. Even the test uses new names for servers but file names
# of log files are still old:
# master_a -> master.[log|err]
# master_b -> slave.[log|err]
# master_c -> slave1.[log|err]
# master_d -> slave2.[log|err]
#
#############################################################
--source include/master-slave.inc
#
# Set up circular ring by schema A->B->C->D->A
#
--connection slave
STOP SLAVE;
RESET SLAVE;
# master a
--connection master
--disconnect master
connect (master_a,127.0.0.1,root,,test,$MASTER_MYPORT,);
RESET MASTER;
--disable_warnings
STOP SLAVE;
--enable_warnings
RESET SLAVE;
SET auto_increment_increment = 4;
SET auto_increment_offset = 1;
let $_binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
# master b
--connection slave
--disconnect slave
connect (master_b,127.0.0.1,root,,test,$SLAVE_MYPORT,);
RESET MASTER;
RESET SLAVE;
--replace_result $MASTER_MYPORT MASTER_A_PORT $_binlog_file MASTER_A_LOG_FILE
--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$MASTER_MYPORT,master_user='root',MASTER_LOG_FILE='$_binlog_file'
SET auto_increment_increment = 4;
SET auto_increment_offset = 2;
let $_binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
# master c
--connection slave1
--disconnect slave1
connect (master_c,127.0.0.1,root,,test,$SLAVE_MYPORT1,);
RESET MASTER;
--disable_warnings
STOP SLAVE;
--enable_warnings
RESET SLAVE;
--replace_result $SLAVE_MYPORT MASTER_B_PORT $_binlog_file MASTER_B_LOG_FILE
--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$SLAVE_MYPORT,master_user='root',MASTER_LOG_FILE='$_binlog_file'
SET auto_increment_increment = 4;
SET auto_increment_offset = 3;
let $_binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
# master d
connect (master_d,127.0.0.1,root,,test,$SLAVE_MYPORT2,);
RESET MASTER;
--disable_warnings
STOP SLAVE;
--enable_warnings
RESET SLAVE;
--replace_result $SLAVE_MYPORT1 MASTER_C_PORT $_binlog_file MASTER_C_LOG_FILE
--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$SLAVE_MYPORT1,master_user='root',MASTER_LOG_FILE='$_binlog_file'
SET auto_increment_increment = 4;
SET auto_increment_offset = 4;
let $_binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
# master a
--connection master_a
--replace_result $SLAVE_MYPORT2 MASTER_D_PORT $_binlog_file MASTER_D_LOG_FILE
--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$SLAVE_MYPORT2,master_user='root',MASTER_LOG_FILE='$_binlog_file'
# Check server_ids: they should be different
--connection master_a
let $_id_a= query_get_value(SHOW VARIABLES LIKE 'server_id', Value, 1);
SHOW VARIABLES LIKE 'auto_increment_%';
--connection master_b
let $_id_b= query_get_value(SHOW VARIABLES LIKE 'server_id', Value, 1);
SHOW VARIABLES LIKE 'auto_increment_%';
--connection master_c
let $_id_c= query_get_value(SHOW VARIABLES LIKE 'server_id', Value, 1);
SHOW VARIABLES LIKE 'auto_increment_%';
--connection master_d
let $_id_d= query_get_value(SHOW VARIABLES LIKE 'server_id', Value, 1);
SHOW VARIABLES LIKE 'auto_increment_%';
--connection master_a
let $_compared_ids= (($_id_a <> $_id_b) AND ($_id_a <> $_id_c) AND ($_id_a <> $_id_d) AND ($_id_b <> $_id_c) AND ($_id_b <> $_id_d) AND ($_id_c <> $_id_d)) AS a;
let $_compared_ids_result= query_get_value(SELECT $_compared_ids, a, 1);
--echo $_compared_ids_result
# Start ring
--connection master_a
connect(slave,127.0.0.1,root,,test,$MASTER_MYPORT);
START SLAVE;
--source include/wait_for_slave_to_start.inc
--disconnect slave
--connection master_b
connect(slave,127.0.0.1,root,,test,$SLAVE_MYPORT1);
START SLAVE;
--source include/wait_for_slave_to_start.inc
--disconnect slave
--connection master_c
connect(slave,127.0.0.1,root,,test,$SLAVE_MYPORT);
START SLAVE;
--source include/wait_for_slave_to_start.inc
--disconnect slave
--connection master_d
connect(slave,127.0.0.1,root,,test,$SLAVE_MYPORT2);
START SLAVE;
--source include/wait_for_slave_to_start.inc
--disconnect slave

View File

@ -0,0 +1,23 @@
#############################################################
#
# Author: Serge Kozlov <skozlov@mysql.com>
# Date: 03/11/2008
# Purpose: Sync all hosts for circular replication based on
# schema A->B->C->D->A
#
# Notes: see include/circular_rpl_for_4_hosts_init.inc
#
#############################################################
# Make the full loop of sync
--connection master_a
--disable_query_log
--sync_slave_with_master master_b
--sync_slave_with_master master_c
--sync_slave_with_master master_d
--sync_slave_with_master master_a
--sync_slave_with_master master_b
--sync_slave_with_master master_c
--save_master_pos
--connection master_a
--enable_query_log

View File

@ -267,7 +267,7 @@ select * from t2;
insert into t2 (a) values (1026);
--replace_result $MYSQLTEST_VARDIR ..
--error ER_DUP_ENTRY
eval load data infile "../std_data_ln/words.dat" into table t1 (a) set a:=f2(26);
eval load data infile "../../std_data/words.dat" into table t1 (a) set a:=f2(26);
select * from t2;
rollback;

View File

@ -0,0 +1,25 @@
# Use default setting for mysqld processes
!include default_mysqld.cnf
[mysqld.1]
# Run the master.sh script before starting this process
#!run-master-sh
log-bin= master-bin
[mysqlbinlog]
disable-force-if-open
# mysql_fix_privilege_tables.sh does not read from [client] so it
# need its own section
[mysql_fix_privilege_tables]
socket= @client.socket
port= @client.port
user= @client.user
password= @client.password
[ENV]
MASTER_MYPORT= @mysqld.1.port
MASTER_MYSOCK= @mysqld.1.socket

View File

@ -0,0 +1,21 @@
# Default values that applies to all MySQL Servers
[mysqld]
open-files-limit= 1024
local-infile
default-character-set= latin1
# Increase default connect_timeout to avoid intermittent
# disconnects when test servers are put under load see BUG#28359
connect-timeout= 60
log-bin-trust-function-creators=1
key_buffer_size= 1M
sort_buffer= 256K
max_heap_table_size= 1M
loose-innodb_data_file_path= ibdata1:10M:autoextend
slave-net-timeout=120
log-bin=mysqld-bin

View File

@ -0,0 +1,27 @@
[cluster_config]
MaxNoOfSavedMessages= 1000
MaxNoOfConcurrentTransactions= 128
MaxNoOfConcurrentOperations= 10000
DataMemory= 20M
IndexMemory= 1M
Diskless= 0
TimeBetweenWatchDogCheck= 30000
MaxNoOfOrderedIndexes= 32
MaxNoOfAttributes= 2048
TimeBetweenGlobalCheckpoints= 500
NoOfFragmentLogFiles= 4
FragmentLogFileSize= 12M
DiskPageBufferMemory= 4M
# O_DIRECT has issues on 2.4 whach have not been handled, Bug #29612
#ODirect= 1
# the following parametes just function as a small regression
# test that the parameter exists
InitialNoOfOpenFiles= 27
# Increase timeouts for slow test-machines
HeartbeatIntervalDbDb= 30000
HeartbeatIntervalDbApi= 30000
#TransactionDeadlockDetectionTimeout= 7500

View File

@ -1,28 +0,0 @@
--source include/have_log_bin.inc
--source include/not_embedded.inc
--source ./include/have_federated_db.inc
source ./include/master-slave.inc;
# remote table creation
# We have to sync with master, to ensure slave had time to start properly
# before we stop it. If not, we get errors about UNIX_TIMESTAMP() in the log.
connection master;
sync_slave_with_master;
connection slave;
#--replicate-ignore-db=federated
stop slave;
--disable_warnings
# at this point, we are connected to master
DROP DATABASE IF EXISTS federated;
--enable_warnings
CREATE DATABASE federated;
connection master;
--disable_warnings
DROP DATABASE IF EXISTS federated;
--enable_warnings
CREATE DATABASE federated;

View File

@ -1,4 +1,5 @@
disable_query_log;
--require r/true.require
select (support = 'YES' or support = 'DEFAULT') as `TRUE` from information_schema.engines where engine = 'blackhole';
enable_query_log;
if (!`SELECT count(*) FROM information_schema.engines WHERE
(support = 'YES' OR support = 'DEFAULT') AND
engine = 'blackhole'`){
skip Need blackhole engine;
}

View File

@ -1,7 +0,0 @@
#
# Check if the variable MYSQL_BUG25714 is set
#
--require r/have_bug25714.require
disable_query_log;
eval select LENGTH('$MYSQL_BUG25714') > 0 as 'have_bug25714_exe';
enable_query_log;

View File

@ -1,4 +0,0 @@
disable_query_log;
--require r/true.require
select (support = 'YES' or support = 'DEFAULT') as `TRUE` from information_schema.engines where engine = 'federated';
enable_query_log;

View File

@ -1,3 +1,11 @@
# ==== Purpose ====
#
# Ensure that the server is running with binlogging on
#
# ==== Usage ====
#
# source include/have_log_bin.inc;
-- require r/have_log_bin.require
disable_query_log;
show variables like 'log_bin';

View File

@ -1,4 +1,4 @@
--require r/have_ndbapi_examples.require
disable_query_log;
eval select LENGTH('$MY_NDB_EXAMPLES_BINARY') > 0 as 'have_ndb_example';
eval select LENGTH('$NDB_EXAMPLES_BINARY') > 0 as 'have_ndb_example';
enable_query_log;

View File

@ -7,16 +7,20 @@ eval SET SESSION STORAGE_ENGINE = $engine_type;
drop table if exists t1;
--enable_warnings
let $load_file= $MYSQLTEST_VARDIR/std_data/loaddata2.dat;
# NDB does not support the create option 'Binlog of table with BLOB attribute and no PK'
# So use a dummy PK here.
create table t1 (id int unsigned not null auto_increment primary key, a text, b text);
start transaction;
load data infile '../std_data_ln/loaddata2.dat' into table t1 fields terminated by ',' enclosed by '''' (a, b);
--replace_result $load_file LOAD_FILE
eval load data infile '$load_file' into table t1 fields terminated by ',' enclosed by '''' (a, b);
commit;
select count(*) from t1;
truncate table t1;
start transaction;
load data infile '../std_data_ln/loaddata2.dat' into table t1 fields terminated by ',' enclosed by '''' (a, b);
--replace_result $load_file LOAD_FILE
eval load data infile '$load_file' into table t1 fields terminated by ',' enclosed by '''' (a, b);
rollback;
select count(*) from t1;

View File

@ -1,6 +1,13 @@
# Reset the master and the slave to start fresh.
#
# It is necessary to execute RESET MASTER and RESET SLAVE on both
# master and slave since the replication setup might be circular.
#
# Since we expect STOP SLAVE to produce a warning as the slave is
# stopped (the server was started with skip-slave-start), we disable
# warnings when doing STOP SLAVE.
connection slave;
#we expect STOP SLAVE to produce a warning as the slave is stopped
#(the server was started with skip-slave-start)
--disable_warnings
stop slave;
source include/wait_for_slave_to_stop.inc;
@ -13,11 +20,17 @@ use test;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
reset master;
--disable_query_log
reset slave;
--enable_query_log
connection slave;
reset slave;
# Clean up old test tables
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
--disable_query_log
reset master;
--enable_query_log
start slave;
source include/wait_for_slave_to_start.inc;

View File

@ -623,7 +623,8 @@ DROP TABLE t1,t2,t3;
#
create table t1 (a int) engine=innodb;
copy_file $MYSQLTEST_VARDIR/master-data/test/t1.frm $MYSQLTEST_VARDIR/master-data/test/bug29807.frm;
let $MYSQLD_DATADIR= `select @@datadir`;
copy_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/bug29807.frm;
--error 1146
select * from bug29807;
drop table t1;

View File

@ -0,0 +1,59 @@
delimiter ||;
use mtr||
--
-- Procedure used to check if server has been properly
-- restored after testcase has been run
--
CREATE DEFINER=root@localhost PROCEDURE check_testcase()
BEGIN
-- Dump all global variables except those
-- that are supposed to change
SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE variable_name != 'timestamp';
-- Dump all databases, there should be none
-- except those that was created during bootstrap
SELECT * FROM INFORMATION_SCHEMA.SCHEMATA;
-- The test database should not contain any tables
SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema='test';
-- Show "mysql" database, tables and columns
SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql
FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema='mysql' AND table_name != 'ndb_apply_status'
ORDER BY tables_in_mysql;
SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql,
column_name, ordinal_position, column_default, is_nullable,
data_type, character_maximum_length, character_octet_length,
numeric_precision, numeric_scale, character_set_name,
collation_name, column_type, column_key, extra, column_comment
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema='mysql' AND table_name != 'ndb_apply_status'
ORDER BY columns_in_mysql;
-- Checksum system tables to make sure they have been properly
-- restored after test
checksum table
mysql.columns_priv,
mysql.db,
mysql.func,
mysql.help_category,
mysql.help_keyword,
mysql.help_relation,
mysql.host,
mysql.proc,
mysql.procs_priv,
mysql.tables_priv,
mysql.time_zone,
mysql.time_zone_leap_second,
mysql.time_zone_name,
mysql.time_zone_transition,
mysql.time_zone_transition_type,
mysql.user;
END||

View File

@ -0,0 +1,238 @@
delimiter ||;
use mtr||
--
-- Create table where testcases can insert patterns to
-- be suppressed
--
CREATE TABLE test_suppressions (
pattern VARCHAR(255)
) ENGINE=MyISAM||
--
-- Declare a trigger that makes sure
-- no invalid patterns can be inserted
-- into test_suppressions
--
/*!50002
CREATE DEFINER=root@localhost TRIGGER ts_insert
BEFORE INSERT ON test_suppressions
FOR EACH ROW BEGIN
DECLARE dummy INT;
SELECT "" REGEXP NEW.pattern INTO dummy;
END
*/||
--
-- Load table with patterns that will be suppressed globally(always)
--
CREATE TABLE global_suppressions (
pattern VARCHAR(255)
) ENGINE=MyISAM||
-- Declare a trigger that makes sure
-- no invalid patterns can be inserted
-- into global_suppressions
--
/*!50002
CREATE DEFINER=root@localhost TRIGGER gs_insert
BEFORE INSERT ON global_suppressions
FOR EACH ROW BEGIN
DECLARE dummy INT;
SELECT "" REGEXP NEW.pattern INTO dummy;
END
*/||
--
-- Insert patterns that should always be suppressed
--
INSERT INTO global_suppressions VALUES
("'SELECT UNIX_TIMESTAMP\\(\\)' failed on master"),
("Aborted connection"),
("Client requested master to start replication from impossible position"),
("Could not find first log file name in binary log"),
("Enabling keys got errno"),
("Error reading master configuration"),
("Error reading packet"),
("Event Scheduler"),
("Failed to open log"),
("Failed to open the existing master info file"),
("Forcing shutdown of [0-9]* plugins"),
("Forcing close of thread"),
/*
Due to timing issues, it might be that this warning
is printed when the server shuts down and the
computer is loaded.
*/
("Got error [0-9]* when reading table"),
("Incorrect definition of table"),
("Incorrect information in file"),
("InnoDB: Warning: we did not need to do crash recovery"),
("Invalid \\(old\\?\\) table or database name"),
("Lock wait timeout exceeded"),
("Log entry on master is longer than max_allowed_packet"),
("unknown option '--loose-"),
("unknown variable 'loose-"),
("You have forced lower_case_table_names to 0 through a command-line option"),
("Setting lower_case_table_names=2"),
("NDB Binlog:"),
("NDB: failed to setup table"),
("NDB: only row based binary logging"),
("Neither --relay-log nor --relay-log-index were used"),
("Query partially completed"),
("Slave I.O thread aborted while waiting for relay log"),
("Slave SQL thread is stopped because UNTIL condition"),
("Slave SQL thread retried transaction"),
("Slave \\(additional info\\)"),
("Slave: .*Duplicate column name"),
("Slave: .*master may suffer from"),
("Slave: According to the master's version"),
("Slave: Column [0-9]* type mismatch"),
("Slave: Error .* doesn't exist"),
("Slave: Error .*Unknown table"),
("Slave: Error in Write_rows event: "),
("Slave: Field .* of table .* has no default value"),
("Slave: Field .* doesn't have a default value"),
("Slave: Query caused different errors on master and slave"),
("Slave: Table .* doesn't exist"),
("Slave: Table width mismatch"),
("Slave: The incident LOST_EVENTS occured on the master"),
("Slave: Unknown error.* 1105"),
("Slave: Can't drop database.* database doesn't exist"),
("Slave SQL:.*(Error_code: \[\[:digit:\]\]+|Query:.*)"),
("Sort aborted"),
("Time-out in NDB"),
("Warning:\s+One can only use the --user.*root"),
("Warning:\s+Setting lower_case_table_names=2"),
("Warning:\s+Table:.* on (delete|rename)"),
("You have an error in your SQL syntax"),
("deprecated"),
("description of time zone"),
("equal MySQL server ids"),
("error .*connecting to master"),
("error reading log entry"),
("lower_case_table_names is set"),
("skip-name-resolve mode"),
("slave SQL thread aborted"),
("Slave: .*Duplicate entry"),
/*
Special case, made as specific as possible, for:
Bug #28436: Incorrect position in SHOW BINLOG EVENTS causes
server coredump
*/
("Error in Log_event::read_log_event\\\(\\\): 'Sanity check failed', data_len: 258, event_type: 49"),
("Statement is not safe to log in statement format"),
/* test case for Bug#bug29807 copies a stray frm into database */
("InnoDB: Error: table `test`.`bug29807` does not exist in the InnoDB internal"),
("Cannot find or open table test\/bug29807 from"),
/* innodb foreign key tests that fail in ALTER or RENAME produce this */
("InnoDB: Error: in ALTER TABLE `test`.`t[12]`"),
("InnoDB: Error: in RENAME TABLE table `test`.`t1`"),
("InnoDB: Error: table `test`.`t[12]` does not exist in the InnoDB internal"),
/* Test case for Bug#14233 produces the following warnings: */
("Stored routine 'test'.'bug14233_1': invalid value in column mysql.proc"),
("Stored routine 'test'.'bug14233_2': invalid value in column mysql.proc"),
("Stored routine 'test'.'bug14233_3': invalid value in column mysql.proc"),
/*
BUG#32080 - Excessive warnings on Solaris: setrlimit could not
change the size of core files
*/
("setrlimit could not change the size of core files to 'infinity'"),
/*
rpl_extrColmaster_*.test, the slave thread produces warnings
when it get updates to a table that has more columns on the
master
*/
("Slave: Unknown column 'c7' in 't15' Error_code: 1054"),
("Slave: Can't DROP 'c7'.* 1091"),
("Slave: Key column 'c6'.* 1072"),
/* Test case for Bug#31590 in order_by.test produces the following error */
("Out of sort memory; increase server sort buffer size"),
/* Special case for Bug #26402 in show_check.test
- Question marks are not valid file name parts on Windows. Ignore
this error message.
*/
("Can't find file: '.\\\\test\\\\\\?{8}.frm'"),
("THE_LAST_SUPPRESSION")||
--
-- Procedure that uses the above created tables to check
-- the servers error log for warnings
--
CREATE DEFINER=root@localhost PROCEDURE check_warnings(OUT result INT)
BEGIN
DECLARE `pos` bigint unsigned;
-- Don't write these queries to binlog
SET SQL_LOG_BIN=0;
--
-- Remove mark from lines that are suppressed by global suppressions
--
UPDATE error_log el, global_suppressions gs
SET suspicious=0
WHERE el.suspicious=1 AND el.line REGEXP gs.pattern;
--
-- Remove mark from lines that are suppressed by test specific suppressions
--
UPDATE error_log el, test_suppressions ts
SET suspicious=0
WHERE el.suspicious=1 AND el.line REGEXP ts.pattern;
--
-- Get the number of marked lines and return result
--
SELECT COUNT(*) INTO @num_warnings FROM error_log
WHERE suspicious=1;
IF @num_warnings > 0 THEN
SELECT file_name, line
FROM error_log WHERE suspicious=1;
--SELECT * FROM test_suppressions;
-- Return 2 -> check failed
SELECT 2 INTO result;
ELSE
-- Return 0 -> OK
SELECT 0 INTO RESULT;
END IF;
-- Cleanup for next test
TRUNCATE test_suppressions;
DROP TABLE error_log;
END||
--
-- Declare a procedure testcases can use to insert test
-- specific suppressions
--
/*!50001
CREATE DEFINER=root@localhost
PROCEDURE add_suppression(pattern VARCHAR(255))
BEGIN
INSERT INTO test_suppressions (pattern) VALUES (pattern);
END
*/||

View File

@ -1651,7 +1651,7 @@ FLUSH LOGS;
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ /exec_time=[0-9]*/exec_time=#/ /end_log_pos [0-9]*/end_log_pos #/ /# at [0-9]*/# at #/ /Xid = [0-9]*/Xid = #/ /thread_id=[0-9]*/thread_id=#/ /table id [0-9]*/table id #/ /mapped to number [0-9]*/mapped to number #/ /server v [^ ]*/server v #.##.##/ /(@[0-9]*=[0-9-]*[.][0-9]{1,3})[0-9e+-]*[^ ]*[ ]*(.*(FLOAT|DOUBLE).*[*].)/\1... \2/
--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLTEST_VARDIR/log/master-bin.000001
--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLD_DATADIR/master-bin.000001
--echo #
--echo # Cleanup.
@ -1731,7 +1731,7 @@ FLUSH LOGS;
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ /exec_time=[0-9]*/exec_time=#/ /end_log_pos [0-9]*/end_log_pos #/ /# at [0-9]*/# at #/ /Xid = [0-9]*/Xid = #/ /thread_id=[0-9]*/thread_id=#/ /table id [0-9]*/table id #/ /mapped to number [0-9]*/mapped to number #/ /server v [^ ]*/server v #.##.##/ /(@[0-9]*=[0-9-]*[.][0-9]{1,3})[0-9e+-]*[^ ]*[ ]*(.*(FLOAT|DOUBLE).*[*].)/\1... \2/
--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLTEST_VARDIR/log/master-bin.000001
--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLD_DATADIR/master-bin.000001
--echo #
--echo # Cleanup.
@ -1854,7 +1854,7 @@ FLUSH LOGS;
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ /exec_time=[0-9]*/exec_time=#/ /end_log_pos [0-9]*/end_log_pos #/ /# at [0-9]*/# at #/ /Xid = [0-9]*/Xid = #/ /thread_id=[0-9]*/thread_id=#/ /table id [0-9]*/table id #/ /mapped to number [0-9]*/mapped to number #/ /server v [^ ]*/server v #.##.##/ /(@[0-9]*=[0-9-]*[.][0-9]{1,3})[0-9e+-]*[^ ]*[ ]*(.*(FLOAT|DOUBLE).*[*].)/\1... \2/
--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLTEST_VARDIR/log/master-bin.000001
--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLD_DATADIR/master-bin.000001
--echo #
--echo # Cleanup.
@ -1887,7 +1887,7 @@ eval CREATE TABLE t1 (
--echo #
--echo # Load data.
--echo #
LOAD DATA INFILE '../std_data_ln/loaddata5.dat'
LOAD DATA INFILE '../../std_data/loaddata5.dat'
INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (c1,c2)
SET c3 = 'Wow';
@ -1912,7 +1912,7 @@ FLUSH LOGS;
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ /exec_time=[0-9]*/exec_time=#/ /end_log_pos [0-9]*/end_log_pos #/ /# at [0-9]*/# at #/ /Xid = [0-9]*/Xid = #/ /thread_id=[0-9]*/thread_id=#/ /table id [0-9]*/table id #/ /mapped to number [0-9]*/mapped to number #/ /server v [^ ]*/server v #.##.##/ /(@[0-9]*=[0-9-]*[.][0-9]{1,3})[0-9e+-]*[^ ]*[ ]*(.*(FLOAT|DOUBLE).*[*].)/\1... \2/
--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLTEST_VARDIR/log/master-bin.000001
--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLD_DATADIR/master-bin.000001
--echo #
--echo # Cleanup.

View File

@ -1,2 +1,3 @@
echo Output from mysqltest-x.inc;
exit;

View File

@ -2,23 +2,21 @@
# By JBM 2006-02-16 So that the code is not repeated #
# in test cases and can be reused. #
######################################################
--exec $NDB_MGM --no-defaults --ndb-connectstring="localhost:$NDBCLUSTER_PORT" -e "start backup" >> $NDB_TOOLS_OUTPUT
--exec $NDB_MGM --no-defaults --ndb-connectstring="$NDB_CONNECTSTRING" -e "start backup" >> $NDB_TOOLS_OUTPUT
# there is no neat way to find the backupid, this is a hack to find it...
let $dump_file= $MYSQLTEST_VARDIR/tmp/tmp.dat;
--exec $NDB_TOOLS_DIR/ndb_select_all --ndb-connectstring="$NDB_CONNECTSTRING" -d sys --delimiter=',' SYSTAB_0 | grep 520093696 > $dump_file
--exec $NDB_TOOLS_DIR/ndb_select_all --ndb-connectstring="localhost:$NDBCLUSTER_PORT" -d sys --delimiter=',' SYSTAB_0 | grep 520093696 > $MYSQLTEST_VARDIR/tmp.dat
CREATE TEMPORARY TABLE test.backup_info (id INT, backup_id INT) ENGINE = HEAP;
CREATE TEMPORARY TABLE IF NOT EXISTS test.backup_info (id INT, backup_id INT) ENGINE = HEAP;
DELETE FROM test.backup_info;
LOAD DATA INFILE '../tmp.dat' INTO TABLE test.backup_info FIELDS TERMINATED BY ',';
--replace_column 1 <the_backup_id>
SELECT @the_backup_id:=backup_id FROM test.backup_info;
let the_backup_id=`select @the_backup_id`;
--replace_result $dump_file DUMP_FILE
eval LOAD DATA INFILE '$dump_file' INTO TABLE test.backup_info FIELDS TERMINATED BY ',';
# Load backup id into environment variable
let the_backup_id=`SELECT backup_id from test.backup_info`;
DROP TABLE test.backup_info;
remove_file $dump_file;

View File

@ -0,0 +1,136 @@
#############################################################
# Author: Serge Kozlov <skozlov@mysql.com>
# Date: 03/17/2008
# Purpose: Set up circular cluster replication where each
# cluster has two mysqlds and replication directions are
# following:
# master ---> slave
# / \
# cluster A cluster B
# \ /
# master1 <--- slave1
#############################################################
--source include/have_log_bin.inc
# Make connections to mysqlds
connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
connect (master1,127.0.0.1,root,,test,$MASTER_MYPORT1,);
connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,);
connect (slave1,127.0.0.1,root,,test,$SLAVE_MYPORT1,);
# Check that all mysqld compiled with ndb support
--connection master
--disable_query_log
--require r/true.require
SELECT (support = 'YES' or support = 'DEFAULT') AS `TRUE` FROM information_schema.engines WHERE engine = 'ndbcluster';
--source include/ndb_not_readonly.inc
--enable_query_log
--connection master1
--disable_query_log
--require r/true.require
SELECT (support = 'YES' or support = 'DEFAULT') AS `TRUE` FROM information_schema.engines WHERE engine = 'ndbcluster';
--source include/ndb_not_readonly.inc
--enable_query_log
--connection slave
--disable_query_log
--require r/true.require
SELECT (support = 'YES' or support = 'DEFAULT') AS `TRUE` FROM information_schema.engines WHERE engine = 'ndbcluster';
--source include/ndb_not_readonly.inc
--enable_query_log
--connection slave1
--disable_query_log
--require r/true.require
SELECT (support = 'YES' or support = 'DEFAULT') AS `TRUE` FROM information_schema.engines WHERE engine = 'ndbcluster';
--source include/ndb_not_readonly.inc
--enable_query_log
# Stop slaves
--connection master
--disable_warnings
STOP SLAVE;
--wait_for_slave_to_stop
--enable_warnings
--connection master1
--disable_warnings
STOP SLAVE;
--wait_for_slave_to_stop
--enable_warnings
--connection slave
--disable_warnings
STOP SLAVE;
--wait_for_slave_to_stop
--enable_warnings
--connection slave1
--disable_warnings
STOP SLAVE;
--wait_for_slave_to_stop
--enable_warnings
# Reset masters
--connection master
--disable_warnings
--disable_query_log
USE test;
--enable_query_log
DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
RESET MASTER;
--connection master1
--disable_warnings
--disable_query_log
USE test;
--enable_query_log
DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
RESET MASTER;
--connection slave
--disable_warnings
--disable_query_log
USE test;
--enable_query_log
DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
RESET MASTER;
--connection slave1
--disable_warnings
--disable_query_log
USE test;
--enable_query_log
DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
RESET MASTER;
# Start slaves
--connection slave
RESET SLAVE;
--replace_result $MASTER_MYPORT MASTER_MYPORT
--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$MASTER_MYPORT,master_user='root'
START SLAVE;
--source include/wait_for_slave_to_start.inc
--connection master1
RESET SLAVE;
--replace_result $SLAVE_MYPORT1 SLAVE_MYPORT1
--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$SLAVE_MYPORT1,master_user='root'
START SLAVE;
--source include/wait_for_slave_to_start.inc
# Set the default connection to 'master' (cluster A)
connection master;

View File

@ -17,7 +17,7 @@ while ($mysql_errno)
{
if (!$counter)
{
die("Failed while waiting for mysqld to come out of readonly mode");
die Failed while waiting for mysqld to come out of readonly mode;
}
dec $counter;
--sleep 0.1

View File

@ -3,6 +3,6 @@
# in test cases and can be reused. #
######################################################
--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="localhost:$NDBCLUSTER_PORT" -p 8 -b $the_backup_id -n 1 -m -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT
--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="$NDB_CONNECTSTRING" -p 8 -b $the_backup_id -n 1 -m -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT
--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="localhost:$NDBCLUSTER_PORT" -p 8 -b $the_backup_id -n 2 -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT
--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="$NDB_CONNECTSTRING" -p 8 -b $the_backup_id -n 2 -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT

View File

@ -3,9 +3,9 @@
# in test cases and can be reused. #
######################################################
--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="localhost:$NDBCLUSTER_PORT_SLAVE" -p 8 -b $the_backup_id -n 1 -m -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT
--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="$NDB_CONNECTSTRING_SLAVE" -p 8 -b $the_backup_id -n 1 -m -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT
--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="localhost:$NDBCLUSTER_PORT_SLAVE" -p 8 -b $the_backup_id -n 2 -r -e --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT
--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="$NDB_CONNECTSTRING_SLAVE" -p 8 -b $the_backup_id -n 2 -r -e --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT

View File

@ -1,4 +1,3 @@
-- require r/not_as_root.require
disable_query_log;
eval select "$MYSQL_TEST_ROOT" as running_as_root;
enable_query_log;
if ($MYSQL_TEST_ROOT){
skip Not as root;
}

View File

@ -176,6 +176,7 @@ show status like "Qcache_queries_in_cache";
show status like "Qcache_hits";
# Final cleanup
eval set GLOBAL query_cache_size=$save_query_cache_size;
connection default;
drop table t2;
disconnect connection1;

View File

@ -9,3 +9,4 @@ show engines;
show variables;
--echo ===== STOP =====
--enable_query_log
exit;

View File

@ -1,10 +1,8 @@
--echo **** Resetting master and slave ****
connection slave;
STOP SLAVE;
source include/wait_for_slave_to_stop.inc;
source include/stop_slave.inc;
RESET SLAVE;
connection master;
RESET MASTER;
connection slave;
START SLAVE;
source include/wait_for_slave_to_start.inc;
source include/start_slave.inc;

View File

@ -0,0 +1,25 @@
# Write file to make mysql-test-run.pl expect the "crash", but don't start
# it until it's told to
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
wait
EOF
# Send shutdown to the connected server and give
# it 10 seconds to die before zapping it
shutdown_server 10;
# Write file to make mysql-test-run.pl start up the server again
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
restart
EOF
# Turn on reconnect
--enable_reconnect
# Call script that will poll the server waiting for it to be back online again
--source include/wait_until_connected_again.inc
# Turn off reconnect again
--disable_reconnect

View File

@ -9,7 +9,7 @@ select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
sync_slave_with_master;
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
connection master;
DELETE FROM mysqltest1.t1 WHERE id = 42;
DELETE FROM t1 WHERE id = 42;
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
sync_slave_with_master;
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;

View File

@ -0,0 +1,87 @@
# ==== Purpose ====
#
# Print status information for replication, typically used to debug
# test failures.
#
# First, the following is printed on slave:
#
# SHOW SLAVE STATUS
# SHOW PROCESSLIST
# SHOW BINLOG EVENTS IN <binlog_name>
#
# Where <binlog_name> is the currently active binlog.
#
# Then, the following is printed on master:
#
# SHOW MASTER STATUS
# SHOW PROCESSLIST
# SHOW BINLOG EVENTS IN <sql_binlog_name>
# SHOW BINLOG EVENTS IN <io_binlog_name>
#
# Where <sql_binlog_name> is the binlog name that the slave sql thread
# is currently reading from and <io_binlog_name> is the binlog that
# the slave IO thread is currently reading from.
#
# ==== Usage ====
#
# [let $master_connection= <connection>;]
# source include/show_rpl_debug_info.inc;
#
# If $master_connection is set, debug info will be retrieved from the
# connection named $master_connection. Otherwise, it will be
# retrieved from the 'master' connection if the current connection is
# 'slave'.
let $_con= $CURRENT_CONNECTION;
--echo
--echo [on $_con]
--echo
--echo **** SHOW SLAVE STATUS on $_con ****
query_vertical SHOW SLAVE STATUS;
--echo
--echo **** SHOW PROCESSLIST on $_con ****
SHOW PROCESSLIST;
--echo
--echo **** SHOW BINLOG EVENTS on $_con ****
let $binlog_name= query_get_value("SHOW MASTER STATUS", File, 1);
eval SHOW BINLOG EVENTS IN '$binlog_name';
let $_master_con= $master_connection;
if (`SELECT '$_master_con' = ''`)
{
if (`SELECT '$_con' = 'slave'`)
{
let $_master_con= master;
}
if (`SELECT '$_master_con' = ''`)
{
--echo Unable to determine master connection. No debug info printed for master.
--echo Please fix the test case by setting $master_connection before sourcing
--echo show_rpl_debug_info.inc.
}
}
if (`SELECT '$_master_con' != ''`)
{
let $master_binlog_name_io= query_get_value("SHOW SLAVE STATUS", Master_Log_File, 1);
let $master_binlog_name_sql= query_get_value("SHOW SLAVE STATUS", Relay_Master_Log_File, 1);
--echo
--echo [on $_master_con]
connection $_master_con;
--echo
--echo **** SHOW MASTER STATUS on $_master_con ****
query_vertical SHOW MASTER STATUS;
--echo
--echo **** SHOW PROCESSLIST on $_master_con ****
SHOW PROCESSLIST;
--echo
--echo **** SHOW BINLOG EVENTS on $_master_con ****
eval SHOW BINLOG EVENTS IN '$master_binlog_name_sql';
if (`SELECT '$master_binlog_name_io' != '$master_binlog_name_sql'`)
{
eval SHOW BINLOG EVENTS IN '$master_binlog_name_io';
}
connection $_con;
}

View File

@ -0,0 +1,21 @@
# ==== Purpose ====
#
# Issues START SLAVE on the current connection. Then waits until both
# the IO and SQL threads have started, or until a timeout is reached.
#
# Please use this instead of 'START SLAVE', to reduce the risk of test
# case bugs.
#
# ==== Usage ====
#
# source include/wait_for_slave_to_start.inc;
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
--disable_query_log
START SLAVE;
--enable_query_log
--echo include/start_slave.inc
source include/wait_for_slave_to_start.inc;

View File

@ -0,0 +1,21 @@
# ==== Purpose ====
#
# Issues STOP SLAVE on the current connection. Then waits until both
# the IO and SQL threads have stopped, or until a timeout is reached.
#
# Please use this instead of 'STOP SLAVE', to reduce the risk of test
# case bugs.
#
# ==== Usage ====
#
# source include/wait_for_slave_to_start.inc;
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
--disable_query_log
STOP SLAVE;
--enable_query_log
--echo include/stop_slave.inc
source include/wait_for_slave_to_stop.inc;

View File

@ -0,0 +1,36 @@
# ==== Purpose ====
#
# Waits until the slave IO thread has been synced, i.e., all events
# have been copied over to slave. Does not care if the SQL thread is
# in sync.
#
#
# ==== Usage ====
#
# source include/sync_slave_io_with_master.inc;
#
# Syncs to the current position on master, as found by SHOW MASTER
# STATUS.
#
# Must be called on the master. Will change connection to the slave.
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
let $_master_file= query_get_value("SHOW MASTER STATUS", File, 1);
let $_master_pos= query_get_value("SHOW MASTER STATUS", Position, 1);
connection slave;
let $slave_error_message= Failed while waiting for slave IO thread to sync;
let $slave_param= Master_Log_File;
let $slave_param_value= $_master_file;
source include/wait_for_slave_param.inc;
let $slave_param= Read_Master_Log_Pos;
let $slave_param_value= $_master_pos;
source include/wait_for_slave_param.inc;
let $slave_error_message= ;

View File

@ -19,12 +19,6 @@
# #
###################################################################
--disable_query_log
eval set @USE_RUNNING_SERVER= '$USE_RUNNING_SERVER';
--require r/testdb_only.require
SELECT 'use extern server'
AS "Variable_name ",
IF(@USE_RUNNING_SERVER= '1','YES',
IF(@USE_RUNNING_SERVER= '0','NO','UNEXPECTED'))
AS "Value" ;
--enable_query_log
if ($USE_RUNNING_SERVER){
skip Not with extern server;
}

View File

@ -0,0 +1,19 @@
# ==== Purpose ====
#
# Waits until the IO thread of the current connection has started and
# connected to the master (i.e., until SHOW SLAVE STATUS returns Yes
# in the Slave_IO_Running field), or until a timeout is reached.
#
# ==== Usage ====
#
# source include/wait_for_slave_io_to_start.inc;
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
let $slave_param= Slave_IO_Running;
let $slave_param_value= Yes;
let $slave_error_message= Failed while waiting for slave IO thread to start;
source include/wait_for_slave_param.inc;
let $slave_error_message= ;

View File

@ -1,33 +1,24 @@
###################################################
#Author: Jeb
#Date: 2007-06-11
#Purpose: used for io errors on the slave. If Slave gets an io
# error, the io trhead should stop
#Details:
# 1) Fill in and setup variables
# 2) loop through looking for
# sql threads to stop
# 3) If loops too long die.
####################################################
connection slave;
let $my_show= SHOW SLAVE STATUS;
let $sql_running= Slave_IO_Running;
let $row_number= 1;
let $run= 1;
let $counter= 300;
# ==== Purpose ====
#
# Waits until the IO thread of the current connection has stopped, or
# until a timeout is reached.
#
# ==== Usage ====
#
# source include/wait_for_slave_io_to_stop.inc;
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
while ($run)
# if server has not used CHANGE MASTER to initiate slave, SHOW SLAVE
# STATUS will return an empty set.
let $_slave_io_running= query_get_value("SHOW SLAVE STATUS", Slave_IO_Running, 1);
if (`SELECT '$_slave_io_running' != 'No such row'`)
{
let $io_result= query_get_value("SHOW SLAVE STATUS", Slave_IO_Running, $row_number);
if (`SELECT '$io_result' = 'No'`){
let $run= 0;
}
sleep 0.1;
if (!$counter){
--echo "Failed while waiting for slave IO thread to stop"
query_vertical SHOW SLAVE STATUS;
exit;
}
dec $counter;
let $slave_param= Slave_IO_Running;
let $slave_param_value= No;
let $slave_error_message= Failed while waiting for slave IO thread to stop;
source include/wait_for_slave_param.inc;
let $slave_error_message= ;
}

View File

@ -1,26 +1,82 @@
# include/wait_for_slave_param.inc
# ==== Purpose ====
#
# SUMMARY
# Waits until SHOW SLAVE STATUS has returned a specified value, or
# until a timeout is reached.
#
# Waits until SHOW SLAVE STATUS has returned a spicified value.
# ==== Usage ====
#
# USAGE
# let $slave_param= Slave_SQL_Running;
# let $slave_param_value= No;
# source include/slave_wait_param.inc;
#
# let $slave_param= Slave_SQL_Running;
# let $slave_param_value= No;
# --source include/slave_wait_param.inc
# Parameters:
#
# $slave_param, $slave_param_value
# This macro will wait until the column of the output of SHOW SLAVE
# STATUS named $slave_param gets the value $slave_param_value. See
# the example above.
#
# $slave_param_comparison
# By default, this file waits until $slave_param becomes equal to
# $slave_param_value. If you want to wait until $slave_param
# becomes *unequal* to $slave_param_value, set this parameter to the
# string '!=', like this:
# let $slave_param_comparison= !=;
#
# $slave_timeout
# The default timeout is 5 minutes. You can change the timeout by
# setting $slave_timeout. The unit is tenths of seconds.
#
# $master_connection
# If the timeout is reached, debug info is given by calling SHOW
# SLAVE STATUS, SHOW PROCESSLIST, and SHOW BINLOG EVENTS. Then, a
# 'connection master' is then issued, and more debug info is given
# by calling SHOW MASTER STATUS, SHOW PROCESSLIST, and SHOW BINLOG
# EVENTS. If $master_connection is set, the latter three commands
# will be issued on $master_connection instead of on the host named
# 'master'. See also show_rpl_debug_info.inc
#
# $slave_error_message
# If set, this is printed when a timeout occurs. This is primarily
# intended to be used by other wait_for_slave_* macros, to indicate
# what the purpose of the wait was. (A very similar error message is
# given by default, but the wait_for_slave_* macros use this to give
# an error message identical to that in previous versions, so that
# errors are easier searchable in the pushbuild history.)
let $slave_wait_param_counter= 300;
let $slave_value= query_get_value("SHOW SLAVE STATUS", $slave_param, 1);
while (`select "$slave_value" != "$slave_param_value"`)
let $_slave_timeout_counter= $slave_timeout;
if (!$_slave_timeout_counter)
{
dec $slave_wait_param_counter;
if (!$slave_wait_param_counter)
{
--echo ERROR: failed while waiting for slave parameter $slave_param: $slave_param_value
query_vertical show slave status;
exit;
}
sleep 0.1;
let $slave_value= query_get_value("SHOW SLAVE STATUS", $slave_param, 1);
let $_slave_timeout_counter= 3000;
}
let $_slave_param_comparison= $slave_param_comparison;
if (`SELECT '$_slave_param_comparison' = ''`)
{
let $_slave_param_comparison= =;
}
let $_show_slave_status_value= query_get_value("SHOW SLAVE STATUS", $slave_param, 1);
while (`SELECT NOT('$_show_slave_status_value' $_slave_param_comparison '$slave_param_value') AND $_slave_timeout_counter > 0`)
{
dec $_slave_timeout_counter;
if ($_slave_timeout_counter)
{
sleep 0.1;
let $_show_slave_status_value= query_get_value("SHOW SLAVE STATUS", $slave_param, 1);
}
}
# This has to be outside the loop until BUG#41913 has been fixed
if (!$_slave_timeout_counter)
{
--echo **** ERROR: timeout after $slave_timeout seconds while waiting for slave parameter $slave_param $_slave_param_comparison $slave_param_value ****
if (`SELECT '$slave_error_message' != ''`)
{
--echo Message: $slave_error_message
}
--echo Current connection is '$CURRENT_CONNECTION'
echo Note: the following output may have changed since the failure was detected;
source include/show_rpl_debug_info.inc;
exit;
}

View File

@ -1,33 +1,39 @@
###################################################
#Author: Sven
#Date: 2007-10-09
#Purpose: Wait until the slave has an error in the
# sql thread, as indicated by
# "SHOW SLAVE STATUS", or at most 30
# seconds.
#Details:
# 1) Fill in and setup variables
# 2) loop, looking for sql error on slave
# 3) If it loops too long, die.
####################################################
connection slave;
let $row_number= 1;
let $run= 1;
let $counter= 300;
# ==== Purpose ====
#
# Waits until the SQL thread of the current connection has got an
# error, or until a timeout is reached. Also waits until the SQL
# thread has completely stopped.
#
# ==== Usage ====
#
# source include/wait_for_slave_sql_error.inc;
#
# Parameters:
#
# $slave_sql_errno
# The expected SQL error number. This is required.
# (After BUG#41956 has been fixed, this will be required to be a
# symbolic name instead of a number.)
#
# $slave_timeout
# See wait_for_slave_param.inc for description.
#
# $master_connection
# See wait_for_slave_param.inc for description.
while ($run)
{
let $sql_result= query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, $row_number);
let $run= `SELECT '$sql_result' = '0'`;
if ($run) {
real_sleep 0.1;
if (!$counter){
--echo "Failed while waiting for slave to produce an error in its sql thread"
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
query_vertical SHOW SLAVE STATUS;
exit;
}
dec $counter;
}
if (`SELECT '$slave_sql_errno' = ''`) {
--echo !!!ERROR IN TEST: you must set \$slave_sql_errno before sourcing wait_fro_slave_sql_error.inc
exit;
}
let $slave_param= Slave_SQL_Running;
let $slave_param_value= No;
let $slave_error_message= Failed while waiting for slave to stop the SQL thread (expecting error in the SQL thread);
source include/wait_for_slave_param.inc;
let $_error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
if (`SELECT '$_error' != '$slave_sql_errno'`) {
--echo Slave stopped with wrong error code: $_error (expected $slave_sql_errno)
source include/show_rpl_debug_info.inc;
exit;
}

View File

@ -5,8 +5,23 @@
#
# ==== Usage ====
#
# let show_sql_error=0|1;
# let $slave_sql_error= <ERRNO>;
# source include/wait_for_slave_sql_error_and_skip.inc;
#
# Parameters:
#
# $slave_sql_errno
# The error number to wait for. This is required. (See
# wait_for_slave_sql_error.inc)
#
# $show_sql_error
# If set, will print the error to the query log.
#
# $slave_timeout
# See wait_for_slave_param.inc for description.
#
# $master_connection
# See wait_for_slave_param.inc for description.
echo --source include/wait_for_slave_sql_error_and_skip.inc;
connection slave;
@ -17,11 +32,7 @@ if ($show_sql_error)
echo Last_SQL_Error = $error;
}
# wait for SQL thread to stop after the error
source include/wait_for_slave_sql_to_stop.inc;
# skip the erroneous statement
set global sql_slave_skip_counter=1;
start slave;
source include/wait_for_slave_to_start.inc;
source include/start_slave.inc;
connection master;

View File

@ -1,31 +1,17 @@
###################################################
#Author: Mats (based on file written by Jeb)
#Date: 2008-05-06
#Purpose: To wait for slave SQL thread to start
#Details:
# 1) Fill in and setup variables
# 2) loop through looking for both
# io and sql threads to start
# 3) If loops too long die.
####################################################
connection slave;
let $row_number= 1;
let $run= 1;
let $counter= 300;
while ($run)
{
let $sql_result= query_get_value("SHOW SLAVE STATUS", Slave_SQL_Running, $row_number);
if (`SELECT '$sql_result' = 'Yes'`){
let $run= 0;
}
sleep 0.1;
if (!$counter){
--echo "Failed while waiting for slave SQL to start"
query_vertical SHOW SLAVE STATUS;
exit;
}
dec $counter;
}
# ==== Purpose ====
#
# Waits the SQL thread of the current connection has started, or until
# a timeout is reached.
#
# ==== Usage ====
#
# source include/wait_for_slave_sql_to_start.inc;
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
let $slave_param= Slave_SQL_Running;
let $slave_param_value= Yes;
let $slave_error_message= Failed while waiting for slave SQL to start;
source include/wait_for_slave_param.inc;

View File

@ -1,33 +1,24 @@
###################################################
#Author: Jeb
#Date: 2007-06-11
#Purpose: used for SQL errors on the slave. If Slave gets a sql
# error, the SQL trhead should stop
#Details:
# 1) Fill in and setup variables
# 2) loop through looking for
# sql threads to stop
# 3) If loops too long die.
####################################################
if (!$keep_connection)
{
connection slave;
}
let $row_number= 1;
let $run= 1;
let $counter= 300;
# ==== Purpose ====
#
# Waits the SQL thread of the current connection has stopped, or until
# a timeout is reached.
#
# ==== Usage ====
#
# source include/wait_for_slave_sql_to_stop.inc;
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
while ($run)
# if server has not used CHANGE MASTER to initiate slave, SHOW SLAVE
# STATUS will return an empty set.
let $_slave_io_running= query_get_value("SHOW SLAVE STATUS", Slave_IO_Running, 1);
if (`SELECT '$_slave_io_running' != 'No such row'`)
{
let $sql_result= query_get_value("SHOW SLAVE STATUS", Slave_SQL_Running, $row_number);
if (`SELECT '$sql_result' = 'No'`){
let $run= 0;
}
sleep 0.1;
if (!$counter){
--echo "Failed while waiting for slave SQL thread to stop"
query_vertical SHOW SLAVE STATUS;
exit;
}
dec $counter;
let $slave_param= Slave_SQL_Running;
let $slave_param_value= No;
let $slave_error_message= Failed while waiting for slave SQL thread to stop;
source include/wait_for_slave_param.inc;
let $slave_error_message= ;
}

View File

@ -1,35 +1,24 @@
###################################################
#Author: Jeb
#Date: 2007-06-11
#Purpose: To wait a brief time for slave to start
#Details:
# 1) Fill in and setup variables
# 2) loop through looking for both
# io and sql threads to start
# 3) If loops too long die.
####################################################
connection slave;
let $row_number= 1;
let $run= 1;
let $counter= 300;
# ==== Purpose ====
#
# Waits until both the IO and SQL threads of the current connection
# have started, or until a timeout is reached.
#
# ==== Usage ====
#
# source include/wait_for_slave_to_start.inc;
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
while ($run)
{
let $io_result= query_get_value("SHOW SLAVE STATUS", Slave_IO_Running, $row_number);
if (`SELECT '$io_result' = 'Yes'`){
let $slave_error_message= Failed while waiting for slave to start;
let $sql_result= query_get_value("SHOW SLAVE STATUS", Slave_SQL_Running, $row_number);
if (`SELECT '$sql_result' = 'Yes'`){
let $run= 0;
}
}
sleep 0.1;
if (!$counter){
--echo "Failed while waiting for slave to start"
query_vertical SHOW SLAVE STATUS;
exit;
}
dec $counter;
}
let $slave_param= Slave_IO_Running;
let $slave_param_value= Yes;
source include/wait_for_slave_param.inc;
let $slave_param= Slave_SQL_Running;
let $slave_param_value= Yes;
source include/wait_for_slave_param.inc;
let $slave_error_message= ;

View File

@ -1,39 +1,30 @@
###################################################
#Author: Jeb
#Date: 2007-06-11
#Purpose: To replace the mysqltest.c executable
# wait_for_slave_to_stop function and
# return this to the test language.
#Details:
# 1) Fill in and setup variables
# 2) loop through looking for both
# io and sql threads to stop
# 3) If loops too long die.
####################################################
connection slave;
let $row_number= 1;
let $run= 1;
let $counter= 300;
# ==== Purpose ====
#
# Waits until both the IO and SQL threads of the current connection
# have stopped, or until a timeout is reached.
#
# ==== Usage ====
#
# source include/wait_for_slave_to_stop.inc;
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
while ($run)
# if server has not used CHANGE MASTER to initiate slave, SHOW SLAVE
# STATUS will return an empty set.
let $_slave_io_running= query_get_value("SHOW SLAVE STATUS", Slave_IO_Running, 1);
if (`SELECT '$_slave_io_running' != 'No such row'`)
{
let $io_result= query_get_value("SHOW SLAVE STATUS", Slave_IO_Running, $row_number);
if (`SELECT '$io_result' = 'No'`){
let $slave_error_message= Failed while waiting for slave to stop;
let $sql_result= query_get_value("SHOW SLAVE STATUS", Slave_SQL_Running, $row_number);
if (`SELECT '$sql_result' = 'No'`){
let $run= 0;
}
}
sleep 0.1;
if (!$counter){
--echo "Failed while waiting for slave to stop"
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
query_vertical SHOW SLAVE STATUS;
exit;
}
dec $counter;
let $slave_param= Slave_IO_Running;
let $slave_param_value= No;
source include/wait_for_slave_param.inc;
let $slave_param= Slave_SQL_Running;
let $slave_param_value= No;
source include/wait_for_slave_param.inc;
let $slave_error_message= ;
}

View File

@ -1,51 +0,0 @@
# include/wait_show_pattern.inc
#
# SUMMARY
#
# Waits until output produced by SHOW statement which particular type is
# specified as parameter matches certain pattern or maximum time reached.
#
# NOTES
#
# Only the first row produced by the parameter statement is checked.
#
# USAGE
#
# let $show_type= <Tail of SHOW statement>;
# let $show_pattern= 'Pattern to be used for LIKE matching';
# --source wait_show_pattern.inc
#
# EXAMPLES
#
# alter_table-big.test, wait_slave_status.inc
#
# SEE ALSO
#
# wait_slave_status.inc, wait_condition.inc (>=5.1)
#
###############################################################################
--disable_query_log
# We accept to wait maximum 30 seconds (0.2 sec/loop).
let $wait_counter= 150;
while ($wait_counter)
{
let $result= `SHOW $show_type`;
let $success= `SELECT '$result' LIKE $show_pattern`;
if ($success)
{
let $wait_counter= 0;
}
if (!$success)
{
real_sleep 0.2;
dec $wait_counter;
}
}
if (!$success)
{
echo Timeout in wait_show_pattern.inc \$show_type= $show_type \$show_pattern= $show_pattern (\$result= '$result');
}
--enable_query_log

View File

@ -1,129 +0,0 @@
# include/wait_slave_status.inc
#
# Created by Matthias Leich
#
# SUMMARY
#
# Waits until slave has reached certain state or maximum time reached.
#
# (This script will not work, when the SHOW command delivers more than one
# result record, because only the first record will be caught.)
#
# USAGE
#
# Set $result_pattern in test file and source this file:
#
# let $result_pattern= <pattern used for LIKE on the result of
# SHOW STATUS SLAVE>
# --include wait_slave_status.inc
#
# EXAMPLE
#
# The script rpl_until.test:
# ...
# --replace_result $MASTER_MYPORT MASTER_MYPORT
# --replace_column 1 # 9 # 23 # 33 #
# --vertical_results show slave status;
#
# outputs
# show slave status;
# Slave_IO_State #
# Master_Host 127.0.0.1
# Master_User root
# Master_Port MASTER_MYPORT
# Connect_Retry 1
# Master_Log_File master-bin.000001
# Read_Master_Log_Pos 776
# Relay_Log_File slave-relay-bin.000004
# Relay_Log_Pos #
# Relay_Master_Log_File master-bin.000001
# Slave_IO_Running Yes
# Slave_SQL_Running No
# Replicate_Do_DB
# Replicate_Ignore_DB
# Replicate_Do_Table
# Replicate_Ignore_Table
# Replicate_Wild_Do_Table
# Replicate_Wild_Ignore_Table
# Last_Errno 0
# Last_Error
# Skip_Counter 0
# Exec_Master_Log_Pos 319
# Relay_Log_Space #
# Until_Condition Master
# Until_Log_File master-bin.000001
# Until_Log_Pos 319
# Master_SSL_Allowed No
# Master_SSL_CA_File
# Master_SSL_CA_Path
# Master_SSL_Cert
# Master_SSL_Cipher
# Master_SSL_Key
# Seconds_Behind_Master #
#
# The main problem with the "show slave status;" in rpl_until is, that
# depending on the total test engine power and the current load caused by
# other processes, the expected slave status might be not reached though
# it will happen in maybe some seconds.
#
# The typical problem with rpl_until is that Slave_IO_Running is "No"
# instead of "Yes".
#
# The expected result follows the LIKE pattern:
#
# let $result_pattern= '%127.0.0.1%root%1%master-bin.000001%776%slave-relay-bin.000004%master-bin.000001%Yes%No%0%0%319%Master%master-bin.000001%319%No%';
#
# The Slave_IO_Running value is the "Yes" just after the "master-bin.000001".
#
# How to get this pattern ?
#
# Any lines "--replace_result ..." and "--replace_colum ..." just before
# the SHOW TABLE STATUS and of course the expected result itself
# show us columns where the content must be unified, because it is non
# deterministic or it depends on the current test environment.
#
# Unfortunately "--replace_result ..." and "--replace_colum ..." do not
# affect the result of our assignment let $my_val= `SHOW SLAVE STATUS`;
# Therefore such content must be covered by '%'.
#
# Please be careful. A more simple pattern might be dangerous, because we
# might get "wrong" matches. Example: There might be several "Yes" and "No"
# within one result row.
#
###############################################################################
# We do not want to print the auxiliary commands, because they are not of
# interest and their amount will vary depending how fast we get the
# desired state.
--disable_query_log
# The protocol should show
# - the setting of $result_pattern and
# - that this file is sourced ,
# because this increases the chance to use the protocol as replay script.
eval SELECT "let \$result_pattern= $result_pattern ;" AS "";
SELECT '--source include/wait_slave_status.inc' AS "";
let $show_type= SLAVE STATUS;
let $show_pattern= $result_pattern;
--enable_query_log
--source include/wait_show_pattern.inc
if (!$success)
{
let $message= ! Attention: Timeout in wait_slave_status.inc.
| Possible reasons with decreasing probability:
| - The LIKE pattern is wrong, because the
| testcase was altered or the layout of the
| SHOW SLAVE STATUS result set changed.
| - There is a new bug within the replication.
| - We met an extreme testing environment and timeout is
| too small.;
--source include/show_msg80.inc
--echo DEBUG INFO START (wait_slave_status.inc):
--echo $result_pattern
--vertical_results
show slave status;
--echo DEBUG INFO END
}

View File

@ -4,9 +4,13 @@
--disable_result_log
--disable_query_log
let $counter= 500;
let $mysql_errno= 9999;
while ($mysql_errno)
{
--error 0,2002,2003,2006,2013
# Strangely enough, the server might return "Too many connections"
# while being shutdown, thus 1040 is an "allowed" error
# See BUG#36228
--error 0,1040,1053,2002,2003,2006,2013
show status;
dec $counter;

View File

@ -0,0 +1,21 @@
#
# Include this script to wait until the connection to the
# server has been dropped
--disable_result_log
--disable_query_log
let $counter= 500;
let $mysql_errno= 0;
while (!$mysql_errno)
{
--error 0,1053,2002,2006,2013
show status;
dec $counter;
if (!$counter)
{
--die Server failed to dissapear
}
--sleep 0.1
}
--enable_query_log
--enable_result_log

View File

@ -1,115 +0,0 @@
#!/bin/sh
# Copyright (C) 1997-2006 MySQL AB
#
# 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
# This scripts creates the privilege tables db, host, user, tables_priv,
# columns_priv in the mysql database, as well as the func table.
if [ x$1 = x"--bin" ]; then
shift 1
BINARY_DIST=1
bindir=../bin
scriptdir=bin
libexecdir=../libexec
# Check if it's a binary distribution or a 'make install'
if test -x ../libexec/mysqld
then
execdir=../libexec
elif test -x ../../sbin/mysqld # RPM installation
then
execdir=../../sbin
bindir=../../bin
scriptdir=../bin
libexecdir=../../libexec
else
execdir=../bin
fi
fix_bin=mysql-test
else
execdir=../sql
bindir=../client
fix_bin=.
scriptdir=scripts
libexecdir=../libexec
fi
vardir=var
logdir=$vardir/log
if [ x$1 = x"-slave" ]
then
shift 1
data=var/slave-data
else
if [ x$1 = x"-1" ]
then
data=var/master-data1
else
data=var/master-data
fi
fi
ldata=$fix_bin/$data
mdata=$data/mysql
EXTRA_ARG=""
mysqld=
if test -x $execdir/mysqld
then
mysqld=$execdir/mysqld
else
if test ! -x $libexecdir/mysqld
then
echo "mysqld is missing - looked in $execdir and in $libexecdir"
exit 1
else
mysqld=$libexecdir/mysqld
fi
fi
# On IRIX hostname is in /usr/bsd so add this to the path
PATH=$PATH:/usr/bsd
hostname=`hostname` # Install this too in the user table
hostname="$hostname%" # Fix if not fully qualified hostname
#create the directories
[ -d $vardir ] || mkdir $vardir
[ -d $logdir ] || mkdir $logdir
# Create database directories mysql & test
if [ -d $data ] ; then rm -rf $data ; fi
mkdir $data $data/mysql $data/test
#for error messages
if [ x$BINARY_DIST = x1 ] ; then
basedir=..
else
basedir=.
EXTRA_ARG="--windows"
fi
INSTALL_CMD="$scriptdir/mysql_install_db --no-defaults $EXTRA_ARG --basedir=$basedir --datadir=mysql-test/$ldata --srcdir=."
echo "running $INSTALL_CMD"
cd ..
if $INSTALL_CMD
then
exit 0
else
echo "Error executing mysqld --bootstrap"
exit 1
fi

View File

@ -4,6 +4,7 @@ package My::Config::Option;
use strict;
use warnings;
use Carp;
sub new {
@ -26,12 +27,22 @@ sub value {
return $self->{value};
}
sub option {
my ($self)= @_;
my $name= $self->{name};
my $value= $self->{value};
my $opt= $name;
$opt= "$name=$value" if ($value);
$opt= "--$opt" unless ($opt =~ /^--/);
return $opt;
}
package My::Config::Group;
use strict;
use warnings;
use Carp;
sub new {
my ($class, $group_name)= @_;
@ -68,7 +79,7 @@ sub remove {
return undef unless defined $option;
# Remove from the hash
delete($self->{options_by_name}->{$option_name}) or die;
delete($self->{options_by_name}->{$option_name}) or croak;
# Remove from the array
@{$self->{options}}= grep { $_->name ne $option_name } @{$self->{options}};
@ -88,6 +99,33 @@ sub name {
return $self->{name};
}
sub suffix {
my ($self)= @_;
# Everything in name from the last .
my @parts= split(/\./, $self->{name});
my $suffix= pop(@parts);
return ".$suffix";
}
sub after {
my ($self, $prefix)= @_;
die unless defined $prefix;
# everything after $prefix
my $name= $self->{name};
if ($name =~ /^\Q$prefix\E(.*)$/)
{
return $1;
}
die "Failed to extract the value after '$prefix' in $name";
}
sub split {
my ($self)= @_;
# Return an array with name parts
return split(/\./, $self->{name});
}
#
# Return a specific option in the group
@ -100,23 +138,37 @@ sub option {
#
# Return a specific value for an option in the group
# Return value for an option in the group, fail if it does not exist
#
sub value {
my ($self, $option_name)= @_;
my $option= $self->option($option_name);
die "No option named '$option_name' in this group"
croak "No option named '$option_name' in group '$self->{name}'"
if ! defined($option);
return $option->value();
}
#
# Return value for an option if it exist
#
sub if_exist {
my ($self, $option_name)= @_;
my $option= $self->option($option_name);
return undef if ! defined($option);
return $option->value();
}
package My::Config;
use strict;
use warnings;
use Carp;
use IO::File;
use File::Basename;
@ -132,13 +184,13 @@ sub new {
my $self= bless { groups => [] }, $class;
my $F= IO::File->new($path, "<")
or die "Could not open '$path': $!";
or croak "Could not open '$path': $!";
while ( my $line= <$F> ) {
chomp($line);
# [group]
if ( $line =~ /\[(.*)\]/ ) {
if ( $line =~ /^\[(.*)\]/ ) {
# New group found
$group_name= $1;
#print "group: $group_name\n";
@ -149,7 +201,7 @@ sub new {
# Magic #! comments
elsif ( $line =~ /^#\!/) {
my $magic= $line;
die "Found magic comment '$magic' outside of group"
croak "Found magic comment '$magic' outside of group"
unless $group_name;
#print "$magic\n";
@ -171,8 +223,13 @@ sub new {
# !include <filename>
elsif ( $line =~ /^\!include\s*(.*?)\s*$/ ) {
my $include_file_name= dirname($path)."/".$1;
# Check that the file exists
die "The include file '$include_file_name' does not exist"
# Check that the file exists relative to path of first config file
if (! -f $include_file_name){
# Try to include file relativ to current dir
$include_file_name= $1;
}
croak "The include file '$include_file_name' does not exist"
unless -f $include_file_name;
$self->append(My::Config->new($include_file_name));
@ -182,7 +239,7 @@ sub new {
elsif ( $line =~ /^([\@\w-]+)\s*$/ ) {
my $option= $1;
die "Found option '$option' outside of group"
croak "Found option '$option' outside of group"
unless $group_name;
#print "$option\n";
@ -194,13 +251,13 @@ sub new {
my $option= $1;
my $value= $2;
die "Found option '$option=$value' outside of group"
croak "Found option '$option=$value' outside of group"
unless $group_name;
#print "$option=$value\n";
$self->insert($group_name, $option, $value);
} else {
die "Unexpected line '$line' found in '$path'";
croak "Unexpected line '$line' found in '$path'";
}
}
@ -231,6 +288,7 @@ sub insert {
# Add the option to the group
$group->insert($option, $value, $if_not_exist);
}
return $group;
}
#
@ -240,11 +298,11 @@ sub remove {
my ($self, $group_name, $option_name)= @_;
my $group= $self->group($group_name);
die "group '$group_name' does not exist"
croak "group '$group_name' does not exist"
unless defined($group);
$group->remove($option_name) or
die "option '$option_name' does not exist";
croak "option '$option_name' does not exist";
}
@ -267,10 +325,10 @@ sub group_exists {
#
sub _group_insert {
my ($self, $group_name)= @_;
caller eq __PACKAGE__ or die;
caller eq __PACKAGE__ or croak;
# Check that group does not already exist
die "Group already exists" if $self->group_exists($group_name);
croak "Group already exists" if $self->group_exists($group_name);
my $group= My::Config::Group->new($group_name);
push(@{$self->{groups}}, $group);
@ -354,11 +412,11 @@ sub value {
my ($self, $group_name, $option_name)= @_;
my $group= $self->group($group_name);
die "group '$group_name' does not exist"
croak "group '$group_name' does not exist"
unless defined($group);
my $option= $group->option($option_name);
die "option '$option_name' does not exist"
croak "option '$option_name' does not exist"
unless defined($option);
return $option->value();
@ -372,7 +430,7 @@ sub exists {
my ($self, $group_name, $option_name)= @_;
my $group= $self->group($group_name);
die "group '$group_name' does not exist"
croak "group '$group_name' does not exist"
unless defined($group);
my $option= $group->option($option_name);
@ -412,11 +470,11 @@ sub stringify {
# Save the config to named file
#
sub save {
my ($self, $path)= @_;
my $F= IO::File->new($path, ">")
or die "Could not open '$path': $!";
print $F $self;
undef $F; # Close the file
my ($self, $path)= @_;
my $F= IO::File->new($path, ">")
or croak "Could not open '$path': $!";
print $F $self;
undef $F; # Close the file
}
1;

View File

@ -0,0 +1,655 @@
# -*- cperl -*-
package My::ConfigFactory;
use strict;
use warnings;
use Carp;
use My::Config;
use My::Find;
use File::Basename;
#
# Rules to run first of all
#
my @pre_rules=
(
);
my @share_locations= ("share/mysql", "sql/share", "share");
sub get_basedir {
my ($self, $group)= @_;
my $basedir= $group->if_exist('basedir') ||
$self->{ARGS}->{basedir};
return $basedir;
}
sub fix_charset_dir {
my ($self, $config, $group_name, $group)= @_;
return my_find_dir($self->get_basedir($group),
\@share_locations, "charsets");
}
sub fix_language {
my ($self, $config, $group_name, $group)= @_;
return my_find_dir($self->get_basedir($group),
\@share_locations, "english");
}
sub fix_datadir {
my ($self, $config, $group_name)= @_;
my $vardir= $self->{ARGS}->{vardir};
return "$vardir/$group_name/data";
}
sub fix_pidfile {
my ($self, $config, $group_name, $group)= @_;
my $vardir= $self->{ARGS}->{vardir};
return "$vardir/run/$group_name.pid";
}
sub fix_port {
my ($self, $config, $group_name, $group)= @_;
my $hostname= $group->value('#host');
return $self->{HOSTS}->{$hostname}++;
}
sub fix_host {
my ($self)= @_;
# Get next host from HOSTS array
my @hosts= keys(%{$self->{HOSTS}});;
my $host_no= $self->{NEXT_HOST}++ % @hosts;
return $hosts[$host_no];
}
sub is_unique {
my ($config, $name, $value)= @_;
foreach my $group ( $config->groups() ) {
if ($group->option($name)) {
if ($group->value($name) eq $value){
return 0;
}
}
}
return 1;
}
sub fix_server_id {
my ($self, $config, $group_name, $group)= @_;
#define in the order that mysqlds are listed in my.cnf
my $server_id= $group->if_exist('server-id');
if (defined $server_id){
if (!is_unique($config, 'server-id', $server_id)) {
croak "The server-id($server_id) for '$group_name' is not unique";
}
return $server_id;
}
do {
$server_id= $self->{SERVER_ID}++;
} while(!is_unique($config, 'server-id', $server_id));
#print "$group_name: server_id: $server_id\n";
return $server_id;
}
sub fix_socket {
my ($self, $config, $group_name, $group)= @_;
# Put socket file in tmpdir
my $dir= $self->{ARGS}->{tmpdir};
return "$dir/$group_name.sock";
}
sub fix_tmpdir {
my ($self, $config, $group_name, $group)= @_;
my $dir= $self->{ARGS}->{tmpdir};
return "$dir/$group_name";
}
sub fix_log_error {
my ($self, $config, $group_name, $group)= @_;
my $dir= dirname($group->value('datadir'));
return "$dir/mysqld.err";
}
sub fix_log {
my ($self, $config, $group_name, $group)= @_;
my $dir= dirname($group->value('datadir'));
return "$dir/mysqld.log";
}
sub fix_log_slow_queries {
my ($self, $config, $group_name, $group)= @_;
my $dir= dirname($group->value('datadir'));
return "$dir/mysqld-slow.log";
}
sub fix_secure_file_priv {
my ($self)= @_;
my $vardir= $self->{ARGS}->{vardir};
# By default, prevent the started mysqld to access files outside of vardir
return $vardir;
}
sub fix_std_data {
my ($self, $config, $group_name, $group)= @_;
my $basedir= $self->get_basedir($group);
return "$basedir/mysql-test/std_data";
}
sub ssl_supported {
my ($self)= @_;
return $self->{ARGS}->{ssl};
}
sub fix_skip_ssl {
return if !ssl_supported(@_);
# Add skip-ssl if ssl is supported to avoid
# that mysqltest connects with SSL by default
return 1;
}
sub fix_ssl_ca {
return if !ssl_supported(@_);
my $std_data= fix_std_data(@_);
return "$std_data/cacert.pem"
}
sub fix_ssl_server_cert {
return if !ssl_supported(@_);
my $std_data= fix_std_data(@_);
return "$std_data/server-cert.pem"
}
sub fix_ssl_client_cert {
return if !ssl_supported(@_);
my $std_data= fix_std_data(@_);
return "$std_data/client-cert.pem"
}
sub fix_ssl_server_key {
return if !ssl_supported(@_);
my $std_data= fix_std_data(@_);
return "$std_data/server-key.pem"
}
sub fix_ssl_client_key {
return if !ssl_supported(@_);
my $std_data= fix_std_data(@_);
return "$std_data/client-key.pem"
}
#
# Rules to run for each mysqld in the config
# - will be run in order listed here
#
my @mysqld_rules=
(
{ 'basedir' => sub { return shift->{ARGS}->{basedir}; } },
{ 'tmpdir' => \&fix_tmpdir },
{ 'character-sets-dir' => \&fix_charset_dir },
{ 'language' => \&fix_language },
{ 'datadir' => \&fix_datadir },
{ 'pid-file' => \&fix_pidfile },
{ '#host' => \&fix_host },
{ 'port' => \&fix_port },
{ 'socket' => \&fix_socket },
{ 'log-error' => \&fix_log_error },
{ 'log' => \&fix_log },
{ 'log-slow-queries' => \&fix_log_slow_queries },
{ '#user' => sub { return shift->{ARGS}->{user} || ""; } },
{ '#password' => sub { return shift->{ARGS}->{password} || ""; } },
{ 'server-id' => \&fix_server_id, },
# By default, prevent the started mysqld to access files outside of vardir
{ 'secure-file-priv' => sub { return shift->{ARGS}->{vardir}; } },
{ 'ssl-ca' => \&fix_ssl_ca },
{ 'ssl-cert' => \&fix_ssl_server_cert },
{ 'ssl-key' => \&fix_ssl_server_key },
);
sub fix_ndb_mgmd_port {
my ($self, $config, $group_name, $group)= @_;
my $hostname= $group->value('HostName');
return $self->{HOSTS}->{$hostname}++;
}
sub fix_cluster_dir {
my ($self, $config, $group_name, $group)= @_;
my $vardir= $self->{ARGS}->{vardir};
my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
return "$vardir/mysql_cluster.$suffix/$process_type.$idx";
}
sub fix_cluster_backup_dir {
my ($self, $config, $group_name, $group)= @_;
my $vardir= $self->{ARGS}->{vardir};
my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
return "$vardir/mysql_cluster.$suffix/";
}
#
# Rules to run for each ndb_mgmd in the config
# - will be run in order listed here
#
my @ndb_mgmd_rules=
(
{ 'PortNumber' => \&fix_ndb_mgmd_port },
{ 'DataDir' => \&fix_cluster_dir },
);
#
# Rules to run for each ndbd in the config
# - will be run in order listed here
#
my @ndbd_rules=
(
{ 'HostName' => \&fix_host },
{ 'DataDir' => \&fix_cluster_dir },
{ 'BackupDataDir' => \&fix_cluster_backup_dir },
);
#
# Rules to run for each cluster_config section
# - will be run in order listed here
#
my @cluster_config_rules=
(
{ 'ndb_mgmd' => \&fix_host },
{ 'ndbd' => \&fix_host },
{ 'mysqld' => \&fix_host },
{ 'ndbapi' => \&fix_host },
);
#
# Rules to run for [client] section
# - will be run in order listed here
#
my @client_rules=
(
);
#
# Rules to run for [mysqltest] section
# - will be run in order listed here
#
my @mysqltest_rules=
(
{ 'ssl-ca' => \&fix_ssl_ca },
{ 'ssl-cert' => \&fix_ssl_client_cert },
{ 'ssl-key' => \&fix_ssl_client_key },
{ 'skip-ssl' => \&fix_skip_ssl },
);
#
# Rules to run for [mysqlbinlog] section
# - will be run in order listed here
#
my @mysqlbinlog_rules=
(
{ 'character-sets-dir' => \&fix_charset_dir },
);
#
# Rules to run for [mysql_upgrade] section
# - will be run in order listed here
#
my @mysql_upgrade_rules=
(
{ 'tmpdir' => sub { return shift->{ARGS}->{tmpdir}; } },
);
#
# Generate a [client.<suffix>] group to be
# used for connecting to [mysqld.<suffix>]
#
sub post_check_client_group {
my ($self, $config, $client_group_name, $mysqld_group_name)= @_;
# Settings needed for client, copied from its "mysqld"
my %client_needs=
(
port => 'port',
socket => 'socket',
host => '#host',
user => '#user',
password => '#password',
);
my $group_to_copy_from= $config->group($mysqld_group_name);
while (my ($name_to, $name_from)= each( %client_needs )) {
my $option= $group_to_copy_from->option($name_from);
if (! defined $option){
#print $config;
croak "Could not get value for '$name_from'";
}
$config->insert($client_group_name, $name_to, $option->value())
}
}
sub post_check_client_groups {
my ($self, $config)= @_;
my $first_mysqld= $config->first_like('mysqld.');
return unless $first_mysqld;
# Always generate [client] pointing to the first
# [mysqld.<suffix>]
$self->post_check_client_group($config,
'client',
$first_mysqld->name());
# Then generate [client.<suffix>] for each [mysqld.<suffix>]
foreach my $mysqld ( $config->like('mysqld.') ) {
$self->post_check_client_group($config,
'client'.$mysqld->after('mysqld'),
$mysqld->name())
}
}
#
# Generate [embedded] by copying the values
# needed from the default [mysqld] section
# and from first [mysqld.<suffix>]
#
sub post_check_embedded_group {
my ($self, $config)= @_;
return unless $self->{ARGS}->{embedded};
my $mysqld= $config->group('mysqld') or
croak "Can't run with embedded, config has no default mysqld section";
my $first_mysqld= $config->first_like('mysqld.') or
croak "Can't run with embedded, config has no mysqld";
my @no_copy =
(
'log-error', # Embedded server writes stderr to mysqltest's log file
'slave-net-timeout', # Embedded server are not build with replication
);
foreach my $option ( $mysqld->options(), $first_mysqld->options() ) {
# Don't copy options whose name is in "no_copy" list
next if grep ( $option->name() eq $_, @no_copy);
$config->insert('embedded', $option->name(), $option->value())
}
}
sub resolve_at_variable {
my ($self, $config, $group, $option)= @_;
# Split the options value on last .
my @parts= split(/\./, $option->value());
my $option_name= pop(@parts);
my $group_name= join('.', @parts);
$group_name =~ s/^\@//; # Remove at
my $from_group= $config->group($group_name)
or croak "There is no group named '$group_name' that ",
"can be used to resolve '$option_name'";
my $from= $from_group->value($option_name);
$config->insert($group->name(), $option->name(), $from)
}
sub post_fix_resolve_at_variables {
my ($self, $config)= @_;
foreach my $group ( $config->groups() ) {
foreach my $option ( $group->options()) {
next unless defined $option->value();
$self->resolve_at_variable($config, $group, $option)
if ($option->value() =~ /^\@/);
}
}
}
sub post_fix_mysql_cluster_section {
my ($self, $config)= @_;
# Add a [mysl_cluster.<suffix>] section for each
# defined [cluster_config.<suffix>] section
foreach my $group ( $config->like('cluster_config\.\w*$') )
{
my @urls;
# Generate ndb_connectstring for this cluster
foreach my $ndb_mgmd ( $config->like('cluster_config.ndb_mgmd.')) {
if ($ndb_mgmd->suffix() eq $group->suffix()) {
my $host= $ndb_mgmd->value('HostName');
my $port= $ndb_mgmd->value('PortNumber');
push(@urls, "$host:$port");
}
}
croak "Could not generate valid ndb_connectstring for '$group'"
unless @urls > 0;
my $ndb_connectstring= join(";", @urls);
# Add ndb_connectstring to [mysql_cluster.<suffix>]
$config->insert('mysql_cluster'.$group->suffix(),
'ndb_connectstring', $ndb_connectstring);
# Add ndb_connectstring to each mysqld connected to this
# cluster
foreach my $mysqld ( $config->like('cluster_config.mysqld.')) {
if ($mysqld->suffix() eq $group->suffix()) {
my $after= $mysqld->after('cluster_config.mysqld');
$config->insert("mysqld$after",
'ndb_connectstring', $ndb_connectstring);
}
}
}
}
#
# Rules to run last of all
#
my @post_rules=
(
\&post_check_client_groups,
\&post_fix_mysql_cluster_section,
\&post_fix_resolve_at_variables,
\&post_check_embedded_group,
);
sub run_rules_for_group {
my ($self, $config, $group, @rules)= @_;
foreach my $hash ( @rules ) {
while (my ($option, $rule)= each( %{$hash} )) {
# Only run this rule if the value is not already defined
if (!$config->exists($group->name(), $option)) {
my $value;
if (ref $rule eq "CODE") {
# Call the rule function
$value= &$rule($self, $config, $group->name(),
$config->group($group->name()));
} else {
$value= $rule;
}
if (defined $value) {
$config->insert($group->name(), $option, $value, 1);
}
}
}
}
}
sub run_section_rules {
my ($self, $config, $name, @rules)= @_;
foreach my $group ( $config->like($name) ) {
$self->run_rules_for_group($config, $group, @rules);
}
}
sub run_generate_sections_from_cluster_config {
my ($self, $config)= @_;
my @options= ('ndb_mgmd', 'ndbd',
'mysqld', 'ndbapi');
foreach my $group ( $config->like('cluster_config\.\w*$') ) {
# Keep track of current index per process type
my %idxes;
map { $idxes{$_}= 1; } @options;
foreach my $option_name ( @options ) {
my $value= $group->value($option_name);
my @hosts= split(/,/, $value, -1); # -1 => return also empty strings
# Add at least one host
push(@hosts, undef) unless scalar(@hosts);
# Assign hosts unless already fixed
@hosts= map { $self->fix_host() unless $_; } @hosts;
# Write the hosts value back
$group->insert($option_name, join(",", @hosts));
# Generate sections for each host
foreach my $host ( @hosts ){
my $idx= $idxes{$option_name}++;
my $suffix= $group->suffix();
# Generate a section for ndb_mgmd to read
$config->insert("cluster_config.$option_name.$idx$suffix",
"HostName", $host);
if ($option_name eq 'mysqld'){
my $datadir=
$self->fix_cluster_dir($config,
"cluster_config.mysqld.$idx$suffix",
$group);
$config->insert("mysqld.$idx$suffix",
'datadir', "$datadir/data");
}
}
}
}
}
sub new_config {
my ($class, $args)= @_;
my @required_args= ('basedir', 'baseport', 'vardir', 'template_path');
foreach my $required ( @required_args ) {
croak "you must pass '$required'" unless defined $args->{$required};
}
# Fill in hosts/port hash
my $hosts= {};
my $baseport= $args->{baseport};
$args->{hosts}= [ 'localhost' ] unless exists($args->{hosts});
foreach my $host ( @{$args->{hosts}} ) {
$hosts->{$host}= $baseport;
}
# Open the config template
my $config= My::Config->new($args->{'template_path'});
my $extra_template_path= $args->{'extra_template_path'};
if ($extra_template_path){
$config->append(My::Config->new($extra_template_path));
}
my $self= bless {
CONFIG => $config,
ARGS => $args,
HOSTS => $hosts,
NEXT_HOST => 0,
SERVER_ID => 1,
}, $class;
{
# Run pre rules
foreach my $rule ( @pre_rules ) {
&$rule($self, $config);
}
}
$self->run_section_rules($config,
'cluster_config\.\w*$',
@cluster_config_rules);
$self->run_generate_sections_from_cluster_config($config);
$self->run_section_rules($config,
'cluster_config.ndb_mgmd.',
@ndb_mgmd_rules);
$self->run_section_rules($config,
'cluster_config.ndbd',
@ndbd_rules);
$self->run_section_rules($config,
'mysqld.',
@mysqld_rules);
# [mysqlbinlog] need additional settings
$self->run_rules_for_group($config,
$config->insert('mysqlbinlog'),
@mysqlbinlog_rules);
# [mysql_upgrade] need additional settings
$self->run_rules_for_group($config,
$config->insert('mysql_upgrade'),
@mysql_upgrade_rules);
# Additional rules required for [client]
$self->run_rules_for_group($config,
$config->insert('client'),
@client_rules);
# Additional rules required for [mysqltest]
$self->run_rules_for_group($config,
$config->insert('mysqltest'),
@mysqltest_rules);
{
# Run post rules
foreach my $rule ( @post_rules ) {
&$rule($self, $config);
}
}
return $config;
}
1;

View File

@ -0,0 +1,131 @@
# -*- cperl -*-
# Copyright (C) 2004-2006 MySQL AB
#
# 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
package My::CoreDump;
use strict;
use Carp;
use My::Platform;
use File::Temp qw/ tempfile tempdir /;
sub _gdb {
my ($core_name)= @_;
print "\nTrying 'gdb' to get a backtrace\n";
return unless -f $core_name;
# Find out name of binary that generated core
`gdb -c '$core_name' --batch 2>&1` =~
/Core was generated by `([^\s\'\`]+)/;
my $binary= $1 or return;
print "Core generated by '$binary'\n";
# Create tempfile containing gdb commands
my ($tmp, $tmp_name) = tempfile();
print $tmp
"bt\n",
"thread apply all bt\n",
"quit\n";
close $tmp or die "Error closing $tmp_name: $!";
# Run gdb
my $gdb_output=
`gdb '$binary' -c '$core_name' -x '$tmp_name' --batch 2>&1`;
unlink $tmp_name or die "Error removing $tmp_name: $!";
return if $? >> 8;
return unless $gdb_output;
print <<EOF, $gdb_output, "\n";
Output from gdb follows. The first stack trace is from the failing thread.
The following stack traces are from all threads (so the failing one is
duplicated).
--------------------------
EOF
return 1;
}
sub _dbx {
my ($core_name)= @_;
print "\nTrying 'dbx' to get a backtrace\n";
return unless -f $core_name;
# Find out name of binary that generated core
`echo | dbx - '$core_name' 2>&1` =~
/Corefile specified executable: "([^"]+)"/;
my $binary= $1 or return;
print "Core generated by '$binary'\n";
# Find all threads
my @thr_ids = `echo threads | dbx '$binary' '$core_name' 2>&1` =~ /t@\d+/g;
# Create tempfile containing dbx commands
my ($tmp, $tmp_name) = tempfile();
foreach my $thread (@thr_ids) {
print $tmp "where $thread\n";
}
print $tmp "exit\n";
close $tmp or die "Error closing $tmp_name: $!";
# Run dbx
my $dbx_output=
`cat '$tmp_name' | dbx '$binary' '$core_name' 2>&1`;
unlink $tmp_name or die "Error removing $tmp_name: $!";
return if $? >> 8;
return unless $dbx_output;
print <<EOF, $dbx_output, "\n";
Output from dbx follows. Stack trace is printed for all threads in order,
above this you should see info about which thread was the failing one.
----------------------------
EOF
return 1;
}
sub show {
my ($class, $core_name)= @_;
# We try dbx first; gdb itself may coredump if run on a Sun Studio
# compiled binary on Solaris.
my @debuggers =
(
\&_dbx,
\&_gdb,
# TODO...
);
# Try debuggers until one succeeds
foreach my $debugger (@debuggers){
if ($debugger->($core_name)){
return;
}
}
return;
}
1;

View File

@ -0,0 +1,177 @@
# -*- cperl -*-
package My::File::Path;
use strict;
#
# File::Path::rmtree has a problem with deleting files
# and directories where it hasn't got read permission
#
# Patch this by installing a 'rmtree' function in local
# scope that first chmod all files to 0777 before calling
# the original rmtree function.
#
# This is almost gone in version 1.08 of File::Path -
# but unfortunately some hosts still suffers
# from this also in 1.08
#
use Exporter;
use base "Exporter";
our @EXPORT= qw / rmtree mkpath copytree /;
use File::Find;
use File::Copy;
use File::Spec;
use Carp;
use My::Handles;
use My::Platform;
sub rmtree {
my ($dir)= @_;
find( {
bydepth => 1,
no_chdir => 1,
wanted => sub {
my $name= $_;
if (!-l $name && -d _){
return if (rmdir($name) == 1);
chmod(0777, $name) or carp("couldn't chmod(0777, $name): $!");
return if (rmdir($name) == 1);
# Failed to remove the directory, analyze
carp("Couldn't remove directory '$name': $!");
My::Handles::show_handles($name);
} else {
return if (unlink($name) == 1);
chmod(0777, $name) or carp("couldn't chmod(0777, $name): $!");
return if (unlink($name) == 1);
carp("Couldn't delete file '$name': $!");
My::Handles::show_handles($name);
}
}
}, $dir );
};
use File::Basename;
sub _mkpath_debug {
my ($message, $path, $dir, $err)= @_;
print "=" x 40, "\n";
print $message, "\n";
print "err: '$err'\n";
print "path: '$path'\n";
print "dir: '$dir'\n";
print "-" x 40, "\n";
my $dirname= dirname($path);
print "ls -l $dirname\n";
print `ls -l $dirname`, "\n";
print "-" x 40, "\n";
print "dir $dirname\n";
print `dir $dirname`, "\n";
print "-" x 40, "\n";
my $dirname2= dirname($dirname);
print "ls -l $dirname2\n";
print `ls -l $dirname2`, "\n";
print "-" x 40, "\n";
print "dir $dirname2\n";
print `dir $dirname2`, "\n";
print "-" x 40, "\n";
print "file exists\n" if (-e $path);
print "file is a plain file\n" if (-f $path);
print "file is a directory\n" if (-d $path);
print "-" x 40, "\n";
print "showing handles for $path\n";
My::Handles::show_handles($path);
print "=" x 40, "\n";
}
sub mkpath {
my $path;
die "Usage: mkpath(<path>)" unless @_ == 1;
foreach my $dir ( File::Spec->splitdir( @_ ) ) {
#print "dir: $dir\n";
if ($dir =~ /^[a-z]:/i){
# Found volume ie. C:
$path= $dir;
next;
}
$path= File::Spec->catdir($path, $dir);
#print "path: $path\n";
next if -d $path; # Path already exists and is a directory
croak("File already exists but is not a directory: '$path'") if -e $path;
next if mkdir($path);
_mkpath_debug("mkdir failed", $path, $dir, $!);
# mkdir failed, try one more time
next if mkdir($path);
_mkpath_debug("mkdir failed, second time", $path, $dir, $!);
# mkdir failed again, try two more time after sleep(s)
sleep(1);
next if mkdir($path);
_mkpath_debug("mkdir failed, third time", $path, $dir, $!);
sleep(1);
next if mkdir($path);
_mkpath_debug("mkdir failed, fourth time", $path, $dir, $!);
# Report failure and die
croak("Couldn't create directory '$path' ",
" after 4 attempts and 2 sleep(1): $!");
}
};
sub copytree {
my ($from_dir, $to_dir, $use_umask) = @_;
die "Usage: copytree(<fromdir>, <todir>, [<umask>])"
unless @_ == 2 or @_ == 3;
my $orig_umask;
if ($use_umask){
# Set new umask and remember the original
$orig_umask= umask(oct($use_umask));
}
mkpath("$to_dir");
opendir(DIR, "$from_dir")
or croak("Can't find $from_dir$!");
for(readdir(DIR)) {
next if "$_" eq "." or "$_" eq "..";
# Skip SCCS/ directories
next if "$_" eq "SCCS";
if ( -d "$from_dir/$_" )
{
copytree("$from_dir/$_", "$to_dir/$_");
next;
}
copy("$from_dir/$_", "$to_dir/$_");
}
closedir(DIR);
if ($orig_umask){
# Set the original umask
umask($orig_umask);
}
}
1;

245
mysql-test/lib/My/Find.pm Normal file
View File

@ -0,0 +1,245 @@
# -*- cperl -*-
# Copyright (C) 2004-2006 MySQL AB
#
# 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
package My::Find;
#
# Utility functions to find files in a MySQL source or bindist
#
use strict;
use Carp;
use My::Platform;
use base qw(Exporter);
our @EXPORT= qw(my_find_bin my_find_dir my_find_file NOT_REQUIRED);
our $vs_config_dir;
my $bin_extension= ".exe" if IS_WINDOWS;
# Helper function to be used for fourth parameter to find functions
sub NOT_REQUIRED { return 0; }
#
# my_find_bin - find an executable with "name_1...name_n" in
# paths "path_1...path_n" and return the full path
#
# Example:
# my $mysqld_exe= my_find_bin($basedir.
# ["sql", "bin"],
# ["mysqld", "mysqld-debug"]);
# my $mysql_exe= my_find_bin($basedir,
# ["client", "bin"],
# "mysql");
#
#
# To check if something exists, use the required parameter
# set to 0, the function will return an empty string if the
# binary is not found
# my $mysql_exe= my_find_bin($basedir,
# ["client", "bin"],
# "mysql", NOT_REQUIRED);
#
# NOTE: The function honours MTR_VS_CONFIG environment variable
#
#
sub my_find_bin {
my ($base, $paths, $names, $required)= @_;
croak "usage: my_find_bin(<base>, <paths>, <names>, [<required>])"
unless @_ == 4 or @_ == 3;
# -------------------------------------------------------
# Find and return the first executable
# -------------------------------------------------------
foreach my $path (my_find_paths($base, $paths, $names, $bin_extension)) {
return $path if ( -x $path or (IS_WINDOWS and -f $path) );
}
if (defined $required and $required == NOT_REQUIRED){
# Return empty string to indicate not found
return "";
}
find_error($base, $paths, $names);
}
#
# my_find_file - find a file with "name_1...name_n" in
# paths "path_1...path_n" and return the full path
#
# Example:
# my $mysqld_exe= my_find_file($basedir.
# ["sql", "bin"],
# "filename");
#
#
# Also supports NOT_REQUIRED flag
#
# NOTE: The function honours MTR_VS_CONFIG environment variable
#
#
sub my_find_file {
my ($base, $paths, $names, $required)= @_;
croak "usage: my_find_file(<base>, <paths>, <names>, [<required>])"
unless @_ == 4 or @_ == 3;
# -------------------------------------------------------
# Find and return the first executable
# -------------------------------------------------------
foreach my $path (my_find_paths($base, $paths, $names, $bin_extension)) {
return $path if ( -f $path );
}
if (defined $required and $required == NOT_REQUIRED){
# Return empty string to indicate not found
return "";
}
find_error($base, $paths, $names);
}
#
# my_find_dir - find the first existing directory in one of
# the given paths
#
# Example:
# my $charset_set= my_find_dir($basedir,
# ["mysql/share","sql/share", "share"],
# ["charset"]);
# or
# my $charset_set= my_find_dir($basedir,
# ['client_release', 'client_debug',
# 'client', 'bin']);
#
# NOTE: The function honours MTR_VS_CONFIG environment variable
#
#
sub my_find_dir {
my ($base, $paths, $dirs, $required)= @_;
croak "usage: my_find_dir(<base>, <paths>[, <dirs>])"
unless (@_ == 3 or @_ == 2);
# -------------------------------------------------------
# Find and return the first directory
# -------------------------------------------------------
foreach my $path (my_find_paths($base, $paths, $dirs)) {
return $path if ( -d $path );
}
find_error($base, $paths, $dirs);
}
sub my_find_paths {
my ($base, $paths, $names, $extension)= @_;
# Convert the arguments into two normal arrays to ease
# further mappings
my (@names, @paths);
push(@names, ref $names eq "ARRAY" ? @$names : $names);
push(@paths, ref $paths eq "ARRAY" ? @$paths : $paths);
#print "base: $base\n";
#print "names: @names\n";
#print "paths: @paths\n";
# User can select to look in a special build dir
# which is a subdirectory of any of the paths
my @extra_dirs;
my $build_dir= $vs_config_dir || $ENV{MTR_VS_CONFIG} || $ENV{MTR_BUILD_DIR};
push(@extra_dirs, $build_dir) if defined $build_dir;
if (defined $extension){
# Append extension to names, if name does not already have extension
map { $_.=$extension unless /\.(.*)+$/ } @names;
}
# -------------------------------------------------------
# Windows specific
# -------------------------------------------------------
if (IS_WINDOWS) {
# Add the default extra build dirs unless a specific one has
# already been selected
push(@extra_dirs,
("release",
"relwithdebinfo",
"debug")) if @extra_dirs == 0;
}
#print "extra_build_dir: @extra_dirs\n";
# -------------------------------------------------------
# Build cross product of "paths * extra_build_dirs"
# -------------------------------------------------------
push(@paths, map { my $path= $_;
map { "$path/$_" } @extra_dirs
} @paths);
#print "paths: @paths\n";
# -------------------------------------------------------
# Build cross product of "paths * names"
# -------------------------------------------------------
@paths= map { my $path= $_;
map { "$path/$_" } @names
} @paths;
#print "paths: @paths\n";
# -------------------------------------------------------
# Prepend base to all paths
# -------------------------------------------------------
@paths= map { "$base/$_" } @paths;
#print "paths: @paths\n";
# -------------------------------------------------------
# Glob all paths to expand wildcards
# -------------------------------------------------------
@paths= map { glob("$_") } @paths;
#print "paths: @paths\n";
# -------------------------------------------------------
# Return the list of paths
# -------------------------------------------------------
return @paths;
}
sub commify {
return
(@_ == 0) ? '' :
(@_ == 1) ? $_[0] :
(@_ == 2) ? join(" or ", @_) :
join(", ", @_[0..($#_-1)], "or $_[-1]");
}
sub fnuttify {
return map('\''.$_.'\'', @_);
}
sub find_error {
my ($base, $paths, $names)= @_;
my (@names, @paths);
push(@names, ref $names eq "ARRAY" ? @$names : $names);
push(@paths, ref $paths eq "ARRAY" ? @$paths : $paths);
croak "** ERROR: Could not find ",
commify(fnuttify(@names)), " in ",
commify(fnuttify(my_find_paths($base, $paths, $names))), "\n";
}
1;

69
mysql-test/lib/My/Handles.pm Executable file
View File

@ -0,0 +1,69 @@
# -*- cperl -*-
# Copyright (C) 2008 MySQL AB
#
# 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
package My::Handles;
use strict;
use Carp;
use My::Platform;
my $handle_exe;
if (IS_WINDOWS){
# Check if handle.exe is available
# Pass switch to accept the EULA to avoid hanging
# if the program hasn't been run before.
my $list= `handle.exe -? -accepteula 2>&1`;
foreach my $line (split('\n', $list))
{
$handle_exe= "$1.$2"
if ($line =~ /Handle v([0-9]*)\.([0-9]*)/);
}
if ($handle_exe){
print "Found handle.exe version $handle_exe\n";
}
}
sub show_handles
{
my ($dir)= @_;
return unless $handle_exe;
return unless $dir;
$dir= native_path($dir);
# Get a list of open handles in a particular directory
my $list= `handle.exe "$dir" 2>&1` or return;
foreach my $line (split('\n', $list))
{
return if ($line =~ /No matching handles found/);
}
print "\n";
print "=" x 50, "\n";
print "Open handles in '$dir':\n";
print "$list\n";
print "=" x 50, "\n\n";
return;
}
1;

View File

@ -0,0 +1,199 @@
# -*- cperl -*-
# Copyright (C) 2004-2006 MySQL AB
#
# 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
package My::Options;
#
# Utility functions to work with list of options
#
use strict;
sub same($$) {
my $l1= shift;
my $l2= shift;
return compare($l1,$l2) == 0;
}
sub compare ($$) {
my $l1= shift;
my $l2= shift;
my @l1= @$l1;
my @l2= @$l2;
return -1 if @l1 < @l2;
return 1 if @l1 > @l2;
while ( @l1 ) # Same length
{
my $e1= shift @l1;
my $e2= shift @l2;
my $cmp= ($e1 cmp $e2);
return $cmp if $cmp != 0;
}
return 0; # They are the same
}
sub _split_option {
my ($option)= @_;
if ($option=~ /^--(.*)=(.*)$/){
return ($1, $2);
}
elsif ($option=~ /^--(.*)$/){
return ($1, undef)
}
elsif ($option=~ /^\$(.*)$/){ # $VAR
return ($1, undef)
}
elsif ($option=~ /^(.*)=(.*)$/){
return ($1, $2)
}
elsif ($option=~ /^-O$/){
return (undef, undef);
}
die "Unknown option format '$option'";
}
sub _build_option {
my ($name, $value)= @_;
if ($name =~ /^O, /){
return "-".$name."=".$value;
}
elsif ($value){
return "--".$name."=".$value;
}
return "--".$name;
}
#
# Compare two list of options and return what would need
# to be done to get the server running with the new settings
#
sub diff {
my ($from_opts, $to_opts)= @_;
my %from;
foreach my $from (@$from_opts)
{
my ($opt, $value)= _split_option($from);
next unless defined($opt);
$from{$opt}= $value;
}
#print "from: ", %from, "\n";
my %to;
foreach my $to (@$to_opts)
{
my ($opt, $value)= _split_option($to);
next unless defined($opt);
$to{$opt}= $value;
}
#print "to: ", %to, "\n";
# Remove the ones that are in both lists
foreach my $name (keys %from){
if (exists $to{$name} and $to{$name} eq $from{$name}){
#print "removing '$name' from both lists\n";
delete $to{$name};
delete $from{$name};
}
}
#print "from: ", %from, "\n";
#print "to: ", %to, "\n";
# Add all keys in "to" to result
my @result;
foreach my $name (keys %to){
push(@result, _build_option($name, $to{$name}));
}
# Add all keys in "from" that are not in "to"
# to result as "set to default"
foreach my $name (keys %from){
if (not exists $to{$name}) {
push(@result, _build_option($name, "default"));
}
}
return @result;
}
sub is_set {
my ($opts, $set_opts)= @_;
foreach my $opt (@$opts){
my ($opt_name1, $value1)= _split_option($opt);
foreach my $set_opt (@$set_opts){
my ($opt_name2, $value2)= _split_option($set_opt);
if ($opt_name1 eq $opt_name2){
# Option already set
return 1;
}
}
}
return 0;
}
sub toSQL {
my (@options)= @_;
my @sql;
foreach my $option (@options) {
my ($name, $value)= _split_option($option);
#print "name: $name\n";
#print "value: $value\n";
if ($name =~ /^O, (.*)/){
push(@sql, "SET GLOBAL $1=$value");
}
elsif ($name =~ /^set-variable=(.*)/){
push(@sql, "SET GLOBAL $1=$value");
}
else {
my $sql_name= $name;
$sql_name=~ s/-/_/g;
push(@sql, "SET GLOBAL $sql_name=$value");
}
}
return join("; ", @sql);
}
sub toStr {
my $name= shift;
return "$name: ",
"['", join("', '", @_), "']\n";
}
1;

View File

@ -0,0 +1,156 @@
# -*- cperl -*-
# Copyright (C) 2004-2006 MySQL AB
#
# 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
package My::Platform;
use strict;
use File::Basename;
use File::Path;
use base qw(Exporter);
our @EXPORT= qw(IS_CYGWIN IS_WINDOWS IS_WIN32PERL
native_path posix_path mixed_path
check_socket_path_length process_alive);
BEGIN {
if ($^O eq "cygwin") {
# Make sure cygpath works
if ((system("cygpath > /dev/null 2>&1") >> 8) != 1){
die "Could not execute 'cygpath': $!";
}
eval 'sub IS_CYGWIN { 1 }';
}
else {
eval 'sub IS_CYGWIN { 0 }';
}
if ($^O eq "MSWin32") {
eval 'sub IS_WIN32PERL { 1 }';
}
else {
eval 'sub IS_WIN32PERL { 0 }';
}
}
BEGIN {
if (IS_CYGWIN or IS_WIN32PERL) {
eval 'sub IS_WINDOWS { 1 }';
}
else {
eval 'sub IS_WINDOWS { 0 }';
}
}
#
# native_path
# Convert from path format used by perl to the underlying
# operating systems format
#
# NOTE
# Used when running windows binaries (that expect windows paths)
# in cygwin perl (that uses unix paths)
#
use Memoize;
if (!IS_WIN32PERL){
memoize('mixed_path');
memoize('native_path');
memoize('posix_path');
}
sub mixed_path {
my ($path)= @_;
if (IS_CYGWIN){
return unless defined $path;
my $cmd= "cygpath -m $path";
$path= `$cmd` or
print "Failed to run: '$cmd', $!\n";
chomp $path;
}
return $path;
}
sub native_path {
my ($path)= @_;
$path=~ s/\//\\/g
if (IS_CYGWIN or IS_WIN32PERL);
return $path;
}
sub posix_path {
my ($path)= @_;
if (IS_CYGWIN){
return unless defined $path;
$path= `cygpath $path`;
chomp $path;
}
return $path;
}
use File::Temp qw /tempdir/;
sub check_socket_path_length {
my ($path)= @_;
return 0 if IS_WINDOWS;
require IO::Socket::UNIX;
my $truncated= 1; # Be negative
# Create a tempfile name with same length as "path"
my $tmpdir = tempdir( CLEANUP => 0);
my $len = length($path) - length($tmpdir);
my $testfile = $tmpdir . "x" x ($len > 0 ? $len : 1);
my $sock;
eval {
$sock= new IO::Socket::UNIX
(
Local => $testfile,
Listen => 1,
);
die "Could not create UNIX domain socket: $!"
unless defined $sock;
die "UNIX domain socket patch was truncated"
unless ($testfile eq $sock->hostpath());
$truncated= 0; # Yes, it worked!
};
#print "check_socket_path_length, failed: ", $@, '\n' if ($@);
$sock= undef; # Close socket
unlink($testfile); # Remove the physical file
rmdir($tmpdir); # Remove the tempdir
return $truncated;
}
sub process_alive {
my ($pid)= @_;
die "usage: process_alive(pid)" unless $pid;
return kill(0, $pid) unless IS_WINDOWS;
my @list= split(/,/, `tasklist /FI "PID eq $pid" /NH /FO CSV`);
my $ret_pid= eval($list[1]);
return ($ret_pid == $pid);
}
1;

View File

@ -0,0 +1,580 @@
# -*- cperl -*-
# Copyright (C) 2004-2006 MySQL AB
#
# 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
package My::SafeProcess;
#
# Class that encapsulates process creation, monitoring and cleanup
#
# Spawns a monitor process which spawns a new process locally or
# remote using subclasses My::Process::Local or My::Process::Remote etc.
#
# The monitor process runs a simple event loop more or less just
# waiting for a reason to zap the process it monitors. Thus the user
# of this class does not need to care about process cleanup, it's
# handled automatically.
#
# The monitor process wait for:
# - the parent process to close the pipe, in that case it
# will zap the "monitored process" and exit
# - the "monitored process" to exit, in which case it will exit
# itself with same exit code as the "monitored process"
# - the parent process to send the "shutdown" signal in wich case
# monitor will kill the "monitored process" hard and exit
#
#
# When used it will look something like this:
# $> ps
# [script.pl]
# - [monitor for `mysqld`]
# - [mysqld]
# - [monitor for `mysqld`]
# - [mysqld]
# - [monitor for `mysqld`]
# - [mysqld]
#
#
use strict;
use Carp;
use POSIX qw(WNOHANG);
use My::SafeProcess::Base;
use base 'My::SafeProcess::Base';
use My::Find;
use My::Platform;
my %running;
my $_verbose= 0;
END {
# Kill any children still running
for my $proc (values %running){
if ( $proc->is_child($$) ){
#print "Killing: $proc\n";
if ($proc->wait_one(0)){
$proc->kill();
}
}
}
}
sub is_child {
my ($self, $parent_pid)= @_;
croak "usage: \$safe_proc->is_child()" unless (@_ == 2 and ref $self);
return ($self->{PARENT} == $parent_pid);
}
# Find the safe process binary or script
my @safe_process_cmd;
my $safe_kill;
if (IS_WIN32PERL or IS_CYGWIN){
# Use my_safe_process.exe
my $exe= my_find_bin(".", ["lib/My/SafeProcess", "My/SafeProcess"],
"my_safe_process");
push(@safe_process_cmd, $exe);
# Use my_safe_kill.exe
$safe_kill= my_find_bin(".", "lib/My/SafeProcess", "my_safe_kill");
}
else
{
# Use my_safe_process
my $exe= my_find_bin(".", ["lib/My/SafeProcess", "My/SafeProcess"],
"my_safe_process");
push(@safe_process_cmd, $exe);
}
sub new {
my $class= shift;
my %opts=
(
verbose => 0,
@_
);
my $path = delete($opts{'path'}) or croak "path required @_";
my $args = delete($opts{'args'}) or croak "args required @_";
my $input = delete($opts{'input'});
my $output = delete($opts{'output'});
my $error = delete($opts{'error'});
my $verbose = delete($opts{'verbose'});
my $host = delete($opts{'host'});
my $shutdown = delete($opts{'shutdown'});
my $user_data= delete($opts{'user_data'});
# if (defined $host) {
# $safe_script= "lib/My/SafeProcess/safe_process_cpcd.pl";
# }
if (IS_CYGWIN){
$path= mixed_path($path);
$input= mixed_path($input);
$output= mixed_path($output);
$error= mixed_path($error);
}
my @safe_args;
my ($safe_path, $safe_script)= @safe_process_cmd;
push(@safe_args, $safe_script) if defined $safe_script;
push(@safe_args, "--verbose") if $verbose > 0;
# Point the safe_process at the right parent if running on cygwin
push(@safe_args, "--parent-pid=".Cygwin::pid_to_winpid($$)) if IS_CYGWIN;
push(@safe_args, "--");
push(@safe_args, $path); # The program safe_process should execute
push(@safe_args, @$$args);
print "### safe_path: ", $safe_path, " ", join(" ", @safe_args), "\n"
if $verbose > 1;
my $pid= create_process(
path => $safe_path,
input => $input,
output => $output,
error => $error,
append => $opts{append},
args => \@safe_args,
);
my $name = delete($opts{'name'}) || "SafeProcess$pid";
my $proc= bless
({
SAFE_PID => $pid,
SAFE_WINPID => $pid, # Inidicates this is always a real process
SAFE_NAME => $name,
SAFE_SHUTDOWN => $shutdown,
PARENT => $$,
SAFE_USER_DATA => $user_data,
}, $class);
# Put the new process in list of running
$running{$pid}= $proc;
return $proc;
}
sub run {
my $proc= new(@_);
$proc->wait_one();
return $proc->exit_status();
}
#
# Start a process that returns after "duration" seconds
# or when it's parent process does not exist anymore
#
sub timer {
my $class= shift;
my $duration= shift or croak "duration required";
my $parent_pid= $$;
my $pid= My::SafeProcess::Base::_safe_fork();
if ($pid){
# Parent
my $proc= bless
({
SAFE_PID => $pid,
SAFE_NAME => "timer",
PARENT => $$,
}, $class);
# Put the new process in list of running
$running{$pid}= $proc;
return $proc;
}
# Child, install signal handlers and sleep for "duration"
$SIG{INT}= 'IGNORE';
$SIG{TERM}= sub {
#print STDERR "timer $$: woken up, exiting!\n";
exit(0);
};
$0= "safe_timer($duration)";
if (IS_WIN32PERL){
# Just a thread in same process
sleep($duration);
print STDERR "timer $$: expired after $duration seconds\n";
exit(0);
}
my $count_down= $duration;
while($count_down--){
# Check that parent is still alive
if (kill(0, $parent_pid) == 0){
#print STDERR "timer $$: parent gone, exiting!\n";
exit(0);
}
sleep(1);
}
print STDERR "timer $$: expired after $duration seconds\n";
exit(0);
}
#
# Shutdown process nicely, and wait for shutdown_timeout seconds
# If processes hasn't shutdown, kill them hard and wait for return
#
sub shutdown {
my $shutdown_timeout= shift;
my @processes= @_;
_verbose("shutdown, timeout: $shutdown_timeout, @processes");
return if (@processes == 0);
# Call shutdown function if process has one, else
# use kill
foreach my $proc (@processes){
_verbose(" proc: $proc");
my $shutdown= $proc->{SAFE_SHUTDOWN};
if ($shutdown_timeout > 0 and defined $shutdown){
$shutdown->();
$proc->{WAS_SHUTDOWN}= 1;
}
else {
$proc->start_kill();
}
}
my @kill_processes= ();
# Wait max shutdown_timeout seconds for those process
# that has been shutdown
foreach my $proc (@processes){
next unless $proc->{WAS_SHUTDOWN};
my $ret= $proc->wait_one($shutdown_timeout);
if ($ret != 0) {
push(@kill_processes, $proc);
}
# Only wait for the first process with shutdown timeout
$shutdown_timeout= 0;
}
# Wait infinitely for those process
# that has been killed
foreach my $proc (@processes){
next if $proc->{WAS_SHUTDOWN};
my $ret= $proc->wait_one(undef);
if ($ret != 0) {
warn "Wait for killed process failed!";
push(@kill_processes, $proc);
# Try one more time, best option...
}
}
# Return if all servers has exited
return if (@kill_processes == 0);
foreach my $proc (@kill_processes){
$proc->start_kill();
}
foreach my $proc (@kill_processes){
$proc->wait_one(undef);
}
return;
}
sub _winpid ($) {
my ($pid)= @_;
# In win32 perl, the pid is already the winpid
return $pid unless IS_CYGWIN;
# In cygwin, the pid is the pseudo process ->
# get the real winpid of my_safe_process
return Cygwin::pid_to_winpid($pid);
}
#
# Tell the process to die as fast as possible
#
sub start_kill {
my ($self)= @_;
croak "usage: \$safe_proc->start_kill()" unless (@_ == 1 and ref $self);
_verbose("start_kill: $self");
my $ret= 1;
my $pid= $self->{SAFE_PID};
die "INTERNAL ERROR: no pid" unless defined $pid;
if (IS_WINDOWS and defined $self->{SAFE_WINPID})
{
die "INTERNAL ERROR: no safe_kill" unless defined $safe_kill;
my $winpid= _winpid($pid);
$ret= system($safe_kill, $winpid) >> 8;
if ($ret == 3){
print "Couldn't open the winpid: $winpid ",
"for pid: $pid, try one more time\n";
sleep(1);
$winpid= _winpid($pid);
$ret= system($safe_kill, $winpid) >> 8;
print "Couldn't open the winpid: $winpid ",
"for pid: $pid, continue and see what happens...\n";
}
}
else
{
$pid= $self->{SAFE_PID};
die "Can't kill not started process" unless defined $pid;
$ret= kill("TERM", $pid);
}
return $ret;
}
sub dump_core {
my ($self)= @_;
return if IS_WINDOWS;
my $pid= $self->{SAFE_PID};
die "Can't cet core from not started process" unless defined $pid;
_verbose("Sending ABRT to $self");
kill ("ABRT", $pid);
return 1;
}
#
# Kill the process as fast as possible
# and wait for it to return
#
sub kill {
my ($self)= @_;
croak "usage: \$safe_proc->kill()" unless (@_ == 1 and ref $self);
$self->start_kill();
$self->wait_one();
return 1;
}
sub _collect {
my ($self)= @_;
$self->{EXIT_STATUS}= $?;
_verbose("_collect: $self");
# Take the process out of running list
my $pid= $self->{SAFE_PID};
die unless delete($running{$pid});
}
# Wait for process to exit
# optionally with a timeout
#
# timeout
# undef -> wait blocking infinitely
# 0 -> just poll with WNOHANG
# >0 -> wait blocking for max timeout seconds
#
# RETURN VALUES
# 0 Not running
# 1 Still running
#
sub wait_one {
my ($self, $timeout)= @_;
croak "usage: \$safe_proc->wait_one([timeout])" unless ref $self;
_verbose("wait_one $self, $timeout");
if ( ! defined($self->{SAFE_PID}) ) {
# No pid => not running
_verbose("No pid => not running");
return 0;
}
if ( defined $self->{EXIT_STATUS} ) {
# Exit status already set => not running
_verbose("Exit status already set => not running");
return 0;
}
my $pid= $self->{SAFE_PID};
my $use_alarm;
my $blocking;
if (defined $timeout)
{
if ($timeout == 0)
{
# 0 -> just poll with WNOHANG
$blocking= 0;
$use_alarm= 0;
}
else
{
# >0 -> wait blocking for max timeout seconds
$blocking= 1;
$use_alarm= 1;
}
}
else
{
# undef -> wait blocking infinitely
$blocking= 1;
$use_alarm= 0;
}
#_verbose("blocking: $blocking, use_alarm: $use_alarm");
my $retpid;
eval
{
# alarm should break the wait
local $SIG{ALRM}= sub { die "waitpid timeout"; };
alarm($timeout) if $use_alarm;
$retpid= waitpid($pid, $blocking ? 0 : &WNOHANG);
alarm(0) if $use_alarm;
};
if ($@)
{
die "Got unexpected: $@" if ($@ !~ /waitpid timeout/);
if (!defined $retpid) {
# Got timeout
_verbose("Got timeout");
return 1;
}
# Got pid _and_ alarm, continue
_verbose("Got pid and alarm, continue");
}
if ( $retpid == 0 ) {
# 0 => still running
_verbose("0 => still running");
return 1;
}
if ( not $blocking and $retpid == -1 ) {
# still running
_verbose("still running");
return 1;
}
#warn "wait_one: expected pid $pid but got $retpid"
# unless( $retpid == $pid );
$self->_collect();
return 0;
}
#
# Wait for any process to exit
#
# Returns a reference to the SafeProcess that
# exited or undefined
#
sub wait_any {
my $ret_pid;
if (IS_WIN32PERL) {
# Can't wait for -1 => use a polling loop
do {
Win32::Sleep(10); # 10 milli seconds
foreach my $pid (keys %running){
$ret_pid= waitpid($pid, &WNOHANG);
last if $pid == $ret_pid;
}
} while ($ret_pid == 0);
}
else
{
$ret_pid= waitpid(-1, 0);
if ($ret_pid <= 0){
# No more processes to wait for
print STDERR "wait_any, got invalid pid: $ret_pid\n";
return undef;
}
}
# Look it up in "running" table
my $proc= $running{$ret_pid};
unless (defined $proc){
print STDERR "Could not find pid: $ret_pid in running list\n";
print STDERR "running: ". join(", ", keys(%running)). "\n";
return undef;
}
$proc->_collect;
return $proc;
}
#
# Overload string operator
# and fallback to default functions if no
# overloaded function is found
#
use overload
'""' => \&self2str,
fallback => 1;
#
# Return the process as a nicely formatted string
#
sub self2str {
my ($self)= @_;
my $pid= $self->{SAFE_PID};
my $winpid= $self->{SAFE_WINPID};
my $name= $self->{SAFE_NAME};
my $exit_status= $self->{EXIT_STATUS};
my $str= "[$name - pid: $pid";
$str.= ", winpid: $winpid" if defined $winpid;
$str.= ", exit: $exit_status" if defined $exit_status;
$str.= "]";
}
sub _verbose {
return unless $_verbose;
print STDERR " ## ", @_, "\n";
}
sub pid {
my ($self)= @_;
return $self->{SAFE_PID};
}
sub user_data {
my ($self)= @_;
return $self->{SAFE_USER_DATA};
}
1;

View File

@ -0,0 +1,212 @@
# -*- cperl -*-
# Copyright (C) 2004-2006 MySQL AB
#
# 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
# 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;
package My::SafeProcess::Base;
#
# Utility functions for Process management
#
use Carp;
use IO::Pipe;
use base qw(Exporter);
our @EXPORT= qw(create_process);
#
# safe_fork
# Retry a couple of times if fork returns EAGAIN
#
sub _safe_fork {
my $retries= 5;
my $pid;
FORK:
{
$pid= fork;
if ( not defined($pid)) {
croak("fork failed after: $!") if (!$retries--);
warn("fork failed sleep 1 second and redo: $!");
sleep(1);
redo FORK;
}
}
return $pid;
};
#
# Decode exit status
#
sub exit_status {
my $self= shift;
my $raw= $self->{EXIT_STATUS};
croak("Can't call exit_status before process has died")
unless defined $raw;
if ($raw & 127)
{
# Killed by signal
my $signal_num= $raw & 127;
my $dumped_core= $raw & 128;
return 1; # Return error code
}
else
{
# Normal process exit
return $raw >> 8;
};
}
#
# Create a new process
# Return pid of the new process
#
sub create_process {
my %opts=
(
@_
);
my $path = delete($opts{'path'}) or die "path required";
my $args = delete($opts{'args'}) or die "args required";
my $input = delete($opts{'input'});
my $output = delete($opts{'output'});
my $error = delete($opts{'error'});
my $open_mode= $opts{append} ? ">>" : ">";
if ($^O eq "MSWin32"){
#printf STDERR "stdin %d, stdout %d, stderr %d\n",
# fileno STDIN, fileno STDOUT, fileno STDERR;
# input output redirect
my ($oldin, $oldout, $olderr);
open $oldin, '<&', \*STDIN or die "Failed to save old stdin: $!";
open $oldout, '>&', \*STDOUT or die "Failed to save old stdout: $!";
open $olderr, '>&', \*STDERR or die "Failed to save old stderr: $!";
if ( $input ) {
if ( ! open(STDIN, "<", $input) ) {
croak("can't redirect STDIN to '$input': $!");
}
}
if ( $output ) {
if ( ! open(STDOUT, $open_mode, $output) ) {
croak("can't redirect STDOUT to '$output': $!");
}
}
if ( $error ) {
if ( $output eq $error ) {
if ( ! open(STDERR, ">&STDOUT") ) {
croak("can't dup STDOUT: $!");
}
}
elsif ( ! open(STDERR, $open_mode, $error) ) {
croak("can't redirect STDERR to '$error': $!");
}
}
# Magic use of 'system(1, @args)' to spawn a process
# and get a proper Win32 pid
unshift (@$args, $path);
my $pid= system(1, @$args);
if ( $pid == 0 ){
print $olderr "create_process failed: $^E\n";
die "create_process failed: $^E";
}
# Retore IO redirects
open STDERR, '>&', $olderr
or croak("unable to reestablish STDERR");
open STDOUT, '>&', $oldout
or croak("unable to reestablish STDOUT");
open STDIN, '<&', $oldin
or croak("unable to reestablish STDIN");
#printf STDERR "stdin %d, stdout %d, stderr %d\n",
# fileno STDIN, fileno STDOUT, fileno STDERR;
return $pid;
}
local $SIG{PIPE}= sub { print STDERR "Got signal $@\n"; };
my $pipe= IO::Pipe->new();
my $pid= _safe_fork();
if ($pid){
# Parent
$pipe->reader();
my $line= <$pipe>; # Wait for child to say it's ready
return $pid;
}
$SIG{INT}= 'DEFAULT';
# Make this process it's own process group to be able to kill
# it and any childs(that hasn't changed group themself)
setpgrp(0,0) if $opts{setpgrp};
if ( $output and !open(STDOUT, $open_mode, $output) ) {
croak("can't redirect STDOUT to '$output': $!");
}
if ( $error ) {
if ( defined $output and $output eq $error ) {
if ( ! open(STDERR, ">&STDOUT") ) {
croak("can't dup STDOUT: $!");
}
}
elsif ( ! open(STDERR, $open_mode, $error) ) {
croak("can't redirect STDERR to '$error': $!");
}
}
if ( $input ) {
if ( ! open(STDIN, "<", $input) ) {
croak("can't redirect STDIN to '$input': $!");
}
}
# Tell parent to continue
$pipe->writer();
print $pipe "ready\n";
if ( !exec($path, @$args) ){
croak("Failed to exec '$path': $!");
}
croak("Should never come here");
}
1;

View File

@ -0,0 +1,17 @@
# Copyright (C) 2006 MySQL AB
#
# 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
ADD_EXECUTABLE(my_safe_process safe_process_win.cc)
ADD_EXECUTABLE(my_safe_kill safe_kill_win.cc)

View File

@ -0,0 +1,28 @@
# Copyright (C) 2000-2006 MySQL AB
#
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
safedir = $(prefix)/mysql-test/lib/My/SafeProcess
#nobase_bin_PROGRAMS = ...
safe_PROGRAMS = my_safe_process
my_safe_process_SOURCES = safe_process.cc
EXTRA_DIST = safe_kill_win.cc \
safe_process_win.cc \
CMakeLists.txt
# Don't update the files from bitkeeper
%::SCCS/s.%

View File

@ -0,0 +1,85 @@
/* Copyright (C) 2004 MySQL AB
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Utility program used to signal a safe_process it's time to shutdown
Usage:
safe_kill <pid>
*/
#include <windows.h>
#include <stdio.h>
#include <signal.h>
int main(int argc, const char** argv )
{
DWORD pid= -1;
HANDLE shutdown_event;
char safe_process_name[32]= {0};
int retry_open_event= 100;
/* Ignore any signals */
signal(SIGINT, SIG_IGN);
signal(SIGBREAK, SIG_IGN);
signal(SIGTERM, SIG_IGN);
if (argc != 2) {
fprintf(stderr, "safe_kill <pid>\n");
exit(2);
}
pid= atoi(argv[1]);
_snprintf(safe_process_name, sizeof(safe_process_name),
"safe_process[%d]", pid);
/* Open the event to signal */
while ((shutdown_event=
OpenEvent(EVENT_MODIFY_STATE, FALSE, safe_process_name)) == NULL)
{
/*
Check if the process is alive, otherwise there is really
no idea to retry the open of the event
*/
HANDLE process;
if ((process= OpenProcess(SYNCHRONIZE, FALSE, pid)) == NULL)
{
fprintf(stderr, "Could not open event or process %d, error: %d\n",
pid, GetLastError());
exit(3);
}
CloseHandle(process);
if (retry_open_event--)
Sleep(100);
else
{
fprintf(stderr, "Failed to open shutdown_event '%s', error: %d\n",
safe_process_name, GetLastError());
exit(3);
}
}
if(SetEvent(shutdown_event) == 0)
{
fprintf(stderr, "Failed to signal shutdown_event '%s', error: %d\n",
safe_process_name, GetLastError());
CloseHandle(shutdown_event);
exit(4);
}
CloseHandle(shutdown_event);
exit(0);
}

View File

@ -0,0 +1,277 @@
/* Copyright (C) 2008 MySQL AB
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Utility program that encapsulates process creation, monitoring
and bulletproof process cleanup
Usage:
safe_process [options to safe_process] -- progname arg1 ... argn
To safeguard mysqld you would invoke safe_process with a few options
for safe_process itself followed by a double dash to indicate start
of the command line for the program you really want to start
$> safe_process --output=output.log -- mysqld --datadir=var/data1 ...
This would redirect output to output.log and then start mysqld,
once it has done that it will continue to monitor the child as well
as the parent.
The safe_process then checks the follwing things:
1. Child exits, propagate the childs return code to the parent
by exiting with the same return code as the child.
2. Parent dies, immediately kill the child and exit, thus the
parent does not need to properly cleanup any child, it is handled
automatically.
3. Signal's recieced by the process will trigger same action as 2)
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
int verbose= 0;
int terminated= 0;
pid_t child_pid= -1;
char safe_process_name[32]= {0};
static void message(const char* fmt, ...)
{
if (!verbose)
return;
va_list args;
fprintf(stderr, "%s: ", safe_process_name);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
fflush(stderr);
}
static void die(const char* fmt, ...)
{
va_list args;
fprintf(stderr, "%s: FATAL ERROR, ", safe_process_name);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
if (int last_err= errno)
fprintf(stderr, "error: %d, %s\n", last_err, strerror(last_err));
exit(1);
}
static void kill_child (void)
{
int status= 0;
message("Killing child: %d", child_pid);
// Terminate whole process group
kill(-child_pid, SIGKILL);
pid_t ret_pid= waitpid(child_pid, &status, 0);
if (ret_pid == child_pid)
{
int exit_code= 1;
if (WIFEXITED(status))
{
// Process has exited, collect return status
exit_code= WEXITSTATUS(status);
message("Child exit: %d", exit_code);
// Exit with exit status of the child
exit(exit_code);
}
if (WIFSIGNALED(status))
message("Child killed by signal: %d", WTERMSIG(status));
exit(exit_code);
}
exit(1);
}
static void handle_abort (int sig)
{
message("Got signal %d, child_pid: %d, sending ABRT", sig, child_pid);
if (child_pid > 0) {
kill (-child_pid, SIGABRT); // Don't wait for it to terminate
}
}
static void handle_signal (int sig)
{
message("Got signal %d, child_pid: %d", sig, child_pid);
terminated= 1;
if (child_pid > 0)
kill_child();
// Ignore further signals
signal(SIGTERM, SIG_IGN);
signal(SIGINT, SIG_IGN);
// Continune execution, allow the child to be started and
// finally terminated by monitor loop
}
int main(int argc, char* const argv[] )
{
char* const* child_argv= 0;
pid_t own_pid= getpid();
pid_t parent_pid= getppid();
/* Install signal handlers */
signal(SIGTERM, handle_signal);
signal(SIGINT, handle_signal);
signal(SIGCHLD, handle_signal);
signal(SIGABRT, handle_abort);
sprintf(safe_process_name, "safe_process[%d]", own_pid);
message("Started");
/* Parse arguments */
for (int i= 1; i < argc; i++) {
const char* arg= argv[i];
if (strcmp(arg, "--") == 0 && strlen(arg) == 2) {
/* Got the "--" delimiter */
if (i >= argc)
die("No real args -> nothing to do");
child_argv= &argv[i+1];
break;
} else {
if ( strcmp(arg, "--verbose") == 0 )
verbose++;
else if ( strncmp(arg, "--parent-pid", 10) == 0 )
{
/* Override parent_pid with a value provided by user */
const char* start;
if ((start= strstr(arg, "=")) == NULL)
die("Could not find start of option value in '%s'", arg);
start++; /* Step past = */
if ((parent_pid= atoi(start)) == 0)
die("Invalid value '%s' passed to --parent-id", start);
}
else
die("Unknown option: %s", arg);
}
}
if (!child_argv || *child_argv == 0)
die("nothing to do");
message("parent_pid: %d", parent_pid);
if (parent_pid == own_pid)
die("parent_pid is equal to own pid!");
char buf;
int pfd[2];
if (pipe(pfd) == -1)
die("Failed to create pipe");
/* Create the child process */
while((child_pid= fork()) == -1)
{
message("fork failed");
sleep(1);
}
if (child_pid == 0)
{
close(pfd[0]); // Close unused read end
// Use default signal handlers in child
signal(SIGTERM, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
// Make this process it's own process group to be able to kill
// it and any childs(that hasn't changed group themself)
setpgid(0, 0);
// Signal that child is ready
buf= 37;
write(pfd[1], &buf, 1);
// Close write end
close(pfd[1]);
if (execvp(child_argv[0], child_argv) < 0)
die("Failed to exec child");
}
close(pfd[1]); // Close unused write end
// Wait for child to signal it's ready
read(pfd[0], &buf, 1);
if(buf != 37)
die("Didn't get 37 from pipe");
close(pfd[0]); // Close read end
/* Monitor loop */
message("Started child %d, terminated: %d", child_pid, terminated);
while(!terminated)
{
// Check if parent is still alive
if (kill(parent_pid, 0) != 0){
message("Parent is not alive anymore");
break;
}
// Check if child has exited, normally this will be
// detected immediately with SIGCHLD handler
int status= 0;
pid_t ret_pid= waitpid(child_pid, &status, WNOHANG);
if (ret_pid == child_pid)
{
int ret_code= 2;
if (WIFEXITED(status))
{
// Process has exited, collect return status
int ret_code= WEXITSTATUS(status);
message("Child exit: %d", ret_code);
// Exit with exit status of the child
exit(ret_code);
}
if (WIFSIGNALED(status))
message("Child killed by signal: %d", WTERMSIG(status));
exit(ret_code);
}
sleep(1);
}
kill_child();
exit(1);
}

View File

@ -0,0 +1,151 @@
#!/usr/bin/perl
# -*- cperl -*-
use strict;
use warnings;
use lib 'lib';
use My::SafeProcess::Base;
use POSIX qw(WNOHANG);
###########################################################################
# Util functions
###########################################################################
#
#Print message to stderr
#
my $verbose= 0;
sub message {
if ($verbose > 0){
use Time::localtime;
my $tm= localtime();
my $timestamp= sprintf("%02d%02d%02d %2d:%02d:%02d",
$tm->year % 100, $tm->mon+1, $tm->mday,
$tm->hour, $tm->min, $tm->sec);
print STDERR $timestamp, " monitor[$$]: ", @_, "\n";
}
}
###########################################################################
# Main program
###########################################################################
my $terminated= 0;
# Protect against being killed in the middle
# of child creation, just set the terminated flag
# to make sure the child will be killed off
# when program is ready to do that
$SIG{TERM}= sub { message("!Got signal @_"); $terminated= 1; };
$SIG{INT}= sub { message("!Got signal @_"); $terminated= 1; };
my $parent_pid= getppid();
my $found_double_dash= 0;
while (my $arg= shift(@ARGV)){
if ($arg =~ /^--$/){
$found_double_dash= 1;
last;
}
elsif ($arg =~ /^--verbose$/){
$verbose= 1;
}
else {
die "Unknown option: $arg";
}
}
my $path= shift(@ARGV); # Executable
die "usage:\n" .
" safe_process.pl [opts] -- <path> [<args> [...<args_n>]]"
unless defined $path || $found_double_dash;
message("started");
#message("path: '$path'");
message("parent: $parent_pid");
# Start process to monitor
my $child_pid=
create_process(
path => $path,
args => \@ARGV,
setpgrp => 1,
);
message("Started child $child_pid");
eval {
sub handle_signal {
$terminated= 1;
message("Got signal @_");
# Ignore all signals
foreach my $name (keys %SIG){
$SIG{$name}= 'IGNORE';
}
die "signaled\n";
};
local $SIG{TERM}= \&handle_signal;
local $SIG{INT}= \&handle_signal;
local $SIG{CHLD}= sub {
message("Got signal @_");
kill(9, -$child_pid);
my $ret= waitpid($child_pid, 0);
if ($? & 127){
exit(65); # Killed by signal
}
exit($? >> 8);
};
# Monitoring loop
while(!$terminated) {
# Check if parent is still alive
if (kill(0, $parent_pid) < 1){
message("Parent is not alive anymore");
last;
}
# Wait for child to terminate but wakeup every
# second to also check that parent is still alive
my $ret_pid;
$ret_pid= waitpid($child_pid, &WNOHANG);
if ($ret_pid == $child_pid) {
# Process has exited, collect return status
my $ret_code= $? >> 8;
message("Child exit: $ret_code");
# Exit with exit status of the child
exit ($ret_code);
}
sleep(1);
}
};
if ( $@ ) {
# The monitoring loop should have been
# broken by handle_signal
warn "Unexpected: $@" unless ( $@ =~ /signaled/ );
}
# Use negative pid in order to kill the whole
# process group
#
my $ret= kill(9, -$child_pid);
message("Killed child: $child_pid, ret: $ret");
if ($ret > 0) {
message("Killed child: $child_pid");
# Wait blocking for the child to return
my $ret_pid= waitpid($child_pid, 0);
if ($ret_pid != $child_pid){
message("unexpected pid $ret_pid returned from waitpid($child_pid)");
}
}
message("DONE!");
exit (1);

Some files were not shown because too many files have changed in this diff Show More