mirror of
https://github.com/MariaDB/server.git
synced 2025-04-02 05:15:33 +02:00
merged 5.1 main to 5.1-rpl
manually resolved conflicts: Text conflict in client/mysqltest.c Contents conflict in mysql-test/include/have_bug25714.inc Text conflict in mysql-test/include/have_ndbapi_examples.inc Text conflict in mysql-test/mysql-test-run.pl Text conflict in mysql-test/suite/parts/inc/partition_check_drop.inc Text conflict in mysql-test/suite/parts/inc/partition_layout.inc Text conflict in mysql-test/suite/parts/inc/partition_layout_check1.inc Text conflict in mysql-test/suite/parts/inc/partition_layout_check2.inc Text conflict in mysql-test/suite/parts/r/partition_alter1_1_2_myisam.result Text conflict in mysql-test/suite/parts/r/partition_alter1_1_myisam.result Text conflict in mysql-test/suite/parts/r/partition_alter1_2_myisam.result Text conflict in mysql-test/suite/parts/r/partition_alter2_myisam.result Text conflict in mysql-test/suite/parts/r/partition_alter3_innodb.result Text conflict in mysql-test/suite/parts/r/partition_alter3_myisam.result Text conflict in mysql-test/suite/parts/r/partition_basic_innodb.result Text conflict in mysql-test/suite/parts/r/partition_basic_myisam.result Text conflict in mysql-test/suite/parts/r/partition_basic_symlink_myisam.result Text conflict in mysql-test/suite/parts/r/partition_engine_myisam.result Text conflict in mysql-test/suite/parts/r/partition_syntax_myisam.result Text conflict in mysql-test/suite/rpl_ndb/t/disabled.def Text conflict in mysql-test/t/disabled.def
This commit is contained in:
commit
4cf30d44ef
505 changed files with 15814 additions and 16274 deletions
.bzrignoreCMakeLists.txt
client
configure.inmysql-test
Makefile.amcreate-test-resultfix-result
extra
binlog_tests
rpl_tests
include
check-testcase.testcheck-warnings.testcircular_rpl_for_4_hosts_init.inccircular_rpl_for_4_hosts_sync.inccommit.incdefault_my.cnfdefault_mysqld.cnfdefault_ndbd.cnffederated.inchave_blackhole.inchave_bug25714.inchave_federated_db.inchave_log_bin.inchave_ndbapi_examples.incloaddata_autocom.incmaster-slave-reset.incmix1.incmtr_check.sqlmtr_warnings.sqlndb_backup.incndb_master-slave_2ch.incndb_not_readonly.incndb_restore_master.incndb_restore_slave_eoption.increset_master_and_slave.increstart_mysqld.incrpl_events.incstart_slave.incstop_slave.incsync_slave_io_with_master.inctestdb_only.incwait_for_slave_io_to_start.incwait_for_slave_io_to_stop.incwait_for_slave_param.incwait_for_slave_sql_error.incwait_for_slave_sql_to_start.incwait_for_slave_sql_to_stop.incwait_for_slave_to_start.incwait_for_slave_to_stop.incwait_show_pattern.incwait_slave_status.incwait_until_connected_again.incwait_until_disconnected.inc
install_test_db.shlib
|
@ -1286,6 +1286,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
|
||||
|
@ -2094,10 +2095,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/*
|
||||
|
|
|
@ -257,3 +257,4 @@ IF(WITH_EMBEDDED_SERVER)
|
|||
ADD_SUBDIRECTORY(libmysqld)
|
||||
ADD_SUBDIRECTORY(libmysqld/examples)
|
||||
ENDIF(WITH_EMBEDDED_SERVER)
|
||||
ADD_SUBDIRECTORY(mysql-test/lib/My/SafeProcess)
|
||||
|
|
|
@ -278,8 +278,9 @@ enum enum_commands {
|
|||
Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST,
|
||||
Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP,
|
||||
Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES,
|
||||
Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR, Q_LIST_FILES,
|
||||
Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
|
||||
Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
|
||||
Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
|
||||
Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER,
|
||||
|
||||
Q_UNKNOWN, /* Unknown command. */
|
||||
Q_COMMENT, /* Comments, ignored. */
|
||||
|
@ -374,6 +375,8 @@ const char *command_names[]=
|
|||
"list_files",
|
||||
"list_files_write_file",
|
||||
"list_files_append_file",
|
||||
"send_shutdown",
|
||||
"shutdown_server",
|
||||
|
||||
0
|
||||
};
|
||||
|
@ -456,6 +459,8 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query,
|
|||
void str_to_file(const char *fname, char *str, int size);
|
||||
void str_to_file2(const char *fname, char *str, int size, my_bool append);
|
||||
|
||||
void fix_win_paths(const char *val, int len);
|
||||
|
||||
#ifdef __WIN__
|
||||
void free_tmp_sh_file();
|
||||
void free_win_path_patterns();
|
||||
|
@ -623,6 +628,9 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query,
|
|||
break;
|
||||
}
|
||||
}
|
||||
#ifdef __WIN__
|
||||
fix_win_paths(query_eval->str, query_eval->length);
|
||||
#endif
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -1345,6 +1353,7 @@ void show_diff(DYNAMIC_STRING* ds,
|
|||
const char* filename1, const char* filename2)
|
||||
{
|
||||
|
||||
const char* diff_failed= 0;
|
||||
DYNAMIC_STRING ds_tmp;
|
||||
|
||||
if (init_dynamic_string(&ds_tmp, "", 256, 256))
|
||||
|
@ -1370,17 +1379,36 @@ void show_diff(DYNAMIC_STRING* ds,
|
|||
"2>&1",
|
||||
NULL) > 1) /* Most "diff" tools return >1 if error */
|
||||
{
|
||||
/*
|
||||
Fallback to dump both files to result file and inform
|
||||
about installing "diff"
|
||||
*/
|
||||
dynstr_set(&ds_tmp, "");
|
||||
|
||||
dynstr_append(&ds_tmp,
|
||||
/* Fallback to plain "diff" */
|
||||
if (run_tool("diff",
|
||||
&ds_tmp, /* Get output from diff in ds_tmp */
|
||||
filename1,
|
||||
filename2,
|
||||
"2>&1",
|
||||
NULL) > 1) /* Most "diff" tools return >1 if error */
|
||||
{
|
||||
dynstr_set(&ds_tmp, "");
|
||||
|
||||
diff_failed= "Could not execute 'diff -u', 'diff -c' or 'diff'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (diff_failed)
|
||||
{
|
||||
/*
|
||||
Fallback to dump both files to result file and inform
|
||||
about installing "diff"
|
||||
*/
|
||||
dynstr_append(&ds_tmp, "\n");
|
||||
dynstr_append(&ds_tmp, diff_failed);
|
||||
dynstr_append(&ds_tmp,
|
||||
"\n"
|
||||
"The two files differ but it was not possible to execute 'diff' in\n"
|
||||
"order to show only the difference, tried both 'diff -u' or 'diff -c'.\n"
|
||||
"Instead the whole content of the two files was shown for you to diff manually. ;)\n\n"
|
||||
"order to show only the difference. Instead the whole content of the\n"
|
||||
"two files was shown for you to diff manually.\n\n"
|
||||
"To get a better report you should install 'diff' on your system, which you\n"
|
||||
"for example can get from http://www.gnu.org/software/diffutils/diffutils.html\n"
|
||||
#ifdef __WIN__
|
||||
|
@ -1388,16 +1416,15 @@ void show_diff(DYNAMIC_STRING* ds,
|
|||
#endif
|
||||
"\n");
|
||||
|
||||
dynstr_append(&ds_tmp, " --- ");
|
||||
dynstr_append(&ds_tmp, filename1);
|
||||
dynstr_append(&ds_tmp, " >>>\n");
|
||||
cat_file(&ds_tmp, filename1);
|
||||
dynstr_append(&ds_tmp, "<<<\n --- ");
|
||||
dynstr_append(&ds_tmp, filename1);
|
||||
dynstr_append(&ds_tmp, " >>>\n");
|
||||
cat_file(&ds_tmp, filename2);
|
||||
dynstr_append(&ds_tmp, "<<<<\n");
|
||||
}
|
||||
dynstr_append(&ds_tmp, " --- ");
|
||||
dynstr_append(&ds_tmp, filename1);
|
||||
dynstr_append(&ds_tmp, " >>>\n");
|
||||
cat_file(&ds_tmp, filename1);
|
||||
dynstr_append(&ds_tmp, "<<<\n --- ");
|
||||
dynstr_append(&ds_tmp, filename1);
|
||||
dynstr_append(&ds_tmp, " >>>\n");
|
||||
cat_file(&ds_tmp, filename2);
|
||||
dynstr_append(&ds_tmp, "<<<<\n");
|
||||
}
|
||||
|
||||
if (ds)
|
||||
|
@ -2041,9 +2068,9 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
|
|||
static DYNAMIC_STRING ds_col;
|
||||
static DYNAMIC_STRING ds_row;
|
||||
const struct command_arg query_get_value_args[] = {
|
||||
"query", ARG_STRING, TRUE, &ds_query, "Query to run",
|
||||
"column name", ARG_STRING, TRUE, &ds_col, "Name of column",
|
||||
"row number", ARG_STRING, TRUE, &ds_row, "Number for row"
|
||||
{"query", ARG_STRING, TRUE, &ds_query, "Query to run"},
|
||||
{"column name", ARG_STRING, TRUE, &ds_col, "Name of column"},
|
||||
{"row number", ARG_STRING, TRUE, &ds_row, "Number for row"}
|
||||
};
|
||||
|
||||
DBUG_ENTER("var_set_query_get_value");
|
||||
|
@ -2218,8 +2245,19 @@ void eval_expr(VAR *v, const char *p, const char **p_end)
|
|||
int open_file(const char *name)
|
||||
{
|
||||
char buff[FN_REFLEN];
|
||||
size_t length;
|
||||
DBUG_ENTER("open_file");
|
||||
DBUG_PRINT("enter", ("name: %s", name));
|
||||
|
||||
/* Extract path from current file and try it as base first */
|
||||
if (dirname_part(buff, cur_file->file_name, &length))
|
||||
{
|
||||
strxmov(buff, buff, name, NullS);
|
||||
if (access(buff, F_OK) == 0){
|
||||
DBUG_PRINT("info", ("The file exists"));
|
||||
name= buff;
|
||||
}
|
||||
}
|
||||
if (!test_if_hard_path(name))
|
||||
{
|
||||
strxmov(buff, opt_basedir, name, NullS);
|
||||
|
@ -2789,7 +2827,7 @@ void do_mkdir(struct st_command *command)
|
|||
int error;
|
||||
static DYNAMIC_STRING ds_dirname;
|
||||
const struct command_arg mkdir_args[] = {
|
||||
"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to create"
|
||||
{"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to create"}
|
||||
};
|
||||
DBUG_ENTER("do_mkdir");
|
||||
|
||||
|
@ -2819,7 +2857,7 @@ void do_rmdir(struct st_command *command)
|
|||
int error;
|
||||
static DYNAMIC_STRING ds_dirname;
|
||||
const struct command_arg rmdir_args[] = {
|
||||
"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove"
|
||||
{"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove"}
|
||||
};
|
||||
DBUG_ENTER("do_rmdir");
|
||||
|
||||
|
@ -3897,6 +3935,145 @@ void do_set_charset(struct st_command *command)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Run query and return one field in the result set from the
|
||||
first row and <column>
|
||||
*/
|
||||
|
||||
int query_get_string(MYSQL* mysql, const char* query,
|
||||
int column, DYNAMIC_STRING* ds)
|
||||
{
|
||||
MYSQL_RES *res= NULL;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (mysql_query(mysql, query))
|
||||
die("'%s' failed: %d %s", query,
|
||||
mysql_errno(mysql), mysql_error(mysql));
|
||||
if ((res= mysql_store_result(mysql)) == NULL)
|
||||
die("Failed to store result: %d %s",
|
||||
mysql_errno(mysql), mysql_error(mysql));
|
||||
|
||||
if ((row= mysql_fetch_row(res)) == NULL)
|
||||
{
|
||||
mysql_free_result(res);
|
||||
ds= 0;
|
||||
return 1;
|
||||
}
|
||||
init_dynamic_string(ds, (row[column] ? row[column] : "NULL"), ~0, 32);
|
||||
mysql_free_result(res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int my_kill(int pid, int sig)
|
||||
{
|
||||
#ifdef __WIN__
|
||||
HANDLE proc;
|
||||
if ((proc= OpenProcess(PROCESS_TERMINATE, FALSE, pid)) == NULL)
|
||||
return -1;
|
||||
if (sig == 0)
|
||||
{
|
||||
CloseHandle(proc);
|
||||
return 0;
|
||||
}
|
||||
(void)TerminateProcess(proc, 201);
|
||||
CloseHandle(proc);
|
||||
return 1;
|
||||
#else
|
||||
return kill(pid, sig);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Shutdown the server of current connection and
|
||||
make sure it goes away within <timeout> seconds
|
||||
|
||||
NOTE! Currently only works with local server
|
||||
|
||||
SYNOPSIS
|
||||
do_shutdown_server()
|
||||
command called command
|
||||
|
||||
DESCRIPTION
|
||||
shutdown [<timeout>]
|
||||
|
||||
*/
|
||||
|
||||
void do_shutdown_server(struct st_command *command)
|
||||
{
|
||||
int timeout=60, pid;
|
||||
DYNAMIC_STRING ds_pidfile_name;
|
||||
MYSQL* mysql = &cur_con->mysql;
|
||||
static DYNAMIC_STRING ds_timeout;
|
||||
const struct command_arg shutdown_args[] = {
|
||||
{"timeout", ARG_STRING, FALSE, &ds_timeout, "Timeout before killing server"}
|
||||
};
|
||||
DBUG_ENTER("do_shutdown_server");
|
||||
|
||||
check_command_args(command, command->first_argument, shutdown_args,
|
||||
sizeof(shutdown_args)/sizeof(struct command_arg),
|
||||
' ');
|
||||
|
||||
if (ds_timeout.length)
|
||||
{
|
||||
timeout= atoi(ds_timeout.str);
|
||||
if (timeout == 0)
|
||||
die("Illegal argument for timeout: '%s'", ds_timeout.str);
|
||||
}
|
||||
dynstr_free(&ds_timeout);
|
||||
|
||||
/* Get the servers pid_file name and use it to read pid */
|
||||
if (query_get_string(mysql, "SHOW VARIABLES LIKE 'pid_file'", 1,
|
||||
&ds_pidfile_name))
|
||||
die("Failed to get pid_file from server");
|
||||
|
||||
/* Read the pid from the file */
|
||||
{
|
||||
int fd;
|
||||
char buff[32];
|
||||
|
||||
if ((fd= my_open(ds_pidfile_name.str, O_RDONLY, MYF(0))) < 0)
|
||||
die("Failed to open file '%s'", ds_pidfile_name.str);
|
||||
dynstr_free(&ds_pidfile_name);
|
||||
|
||||
if (my_read(fd, (uchar*)&buff,
|
||||
sizeof(buff), MYF(0)) <= 0){
|
||||
my_close(fd, MYF(0));
|
||||
die("pid file was empty");
|
||||
}
|
||||
my_close(fd, MYF(0));
|
||||
|
||||
pid= atoi(buff);
|
||||
if (pid == 0)
|
||||
die("Pidfile didn't contain a valid number");
|
||||
}
|
||||
DBUG_PRINT("info", ("Got pid %d", pid));
|
||||
|
||||
/* Tell server to shutdown if timeout > 0*/
|
||||
if (timeout && mysql_shutdown(mysql, SHUTDOWN_DEFAULT))
|
||||
die("mysql_shutdown failed");
|
||||
|
||||
/* Check that server dies */
|
||||
while(timeout--){
|
||||
if (my_kill(0, pid) < 0){
|
||||
DBUG_PRINT("info", ("Sleeping, timeout: %d", timeout));
|
||||
break;
|
||||
}
|
||||
DBUG_PRINT("info", ("Sleeping, timeout: %d", timeout));
|
||||
my_sleep(1);
|
||||
}
|
||||
|
||||
/* Kill the server */
|
||||
DBUG_PRINT("info", ("Killing server, pid: %d", pid));
|
||||
(void)my_kill(9, pid);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if MYSQL_VERSION_ID >= 50000
|
||||
/* List of error names to error codes, available from 5.0 */
|
||||
typedef struct
|
||||
|
@ -7481,8 +7658,16 @@ int main(int argc, char **argv)
|
|||
command->last_argument= command->end;
|
||||
break;
|
||||
case Q_PING:
|
||||
(void) mysql_ping(&cur_con->mysql);
|
||||
break;
|
||||
handle_command_error(command, mysql_ping(&cur_con->mysql));
|
||||
break;
|
||||
case Q_SEND_SHUTDOWN:
|
||||
handle_command_error(command,
|
||||
mysql_shutdown(&cur_con->mysql,
|
||||
SHUTDOWN_DEFAULT));
|
||||
break;
|
||||
case Q_SHUTDOWN_SERVER:
|
||||
do_shutdown_server(command);
|
||||
break;
|
||||
case Q_EXEC:
|
||||
do_exec(command);
|
||||
command_executed++;
|
||||
|
@ -7812,6 +7997,9 @@ void do_get_replace(struct st_command *command)
|
|||
if (!*from)
|
||||
die("Wrong number of arguments to replace_result in '%s'",
|
||||
command->query);
|
||||
#ifdef __WIN__
|
||||
fix_win_paths(to, from - to);
|
||||
#endif
|
||||
insert_pointer_name(&from_array,to);
|
||||
to= get_string(&buff, &from, command);
|
||||
insert_pointer_name(&to_array,to);
|
||||
|
|
|
@ -2789,8 +2789,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)
|
||||
|
|
|
@ -17,130 +17,90 @@
|
|||
|
||||
## 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/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.pl \
|
||||
lib/My/ConfigFactory.pm \
|
||||
lib/My/Config.pm \
|
||||
lib/My/Find.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/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/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/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)
|
||||
|
@ -155,31 +115,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.%
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */;
|
||||
|
|
|
@ -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 */;
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
|
||||
eval create table t1 (a int) engine=$engine_type;
|
||||
flush tables;
|
||||
system rm $MYSQLTEST_VARDIR/master-data/test/t1.MYI ;
|
||||
let $MYSQLD_DATADIR= `select @@datadir`;
|
||||
system rm $MYSQLD_DATADIR/test/t1.MYI ;
|
||||
drop table if exists t1;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 #
|
||||
|
|
|
@ -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,7 +141,7 @@ 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;
|
||||
|
@ -155,7 +155,7 @@ drop table t1;
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
reset master;
|
||||
reset slave;
|
||||
# We are going to read the slave's binlog which contains file_id (for some LOAD
|
||||
|
@ -32,8 +30,13 @@ reset 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 #
|
||||
|
@ -76,17 +79,14 @@ 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).
|
||||
start slave;
|
||||
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
|
||||
source include/start_slave.inc;
|
||||
|
||||
sync_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/stop_slave.inc;
|
||||
source include/start_slave.inc;
|
||||
connection master;
|
||||
|
||||
# Create some entries for second log
|
||||
|
@ -99,10 +99,7 @@ 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_with_master;
|
||||
sync_slave_with_master;
|
||||
show binary logs;
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT $VERSION VERSION
|
||||
--replace_column 2 # 5 #
|
||||
|
|
|
@ -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;
|
||||
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
#
|
||||
# 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
|
||||
|
||||
|
||||
|
||||
|
|
12
mysql-test/include/check-warnings.test
Normal file
12
mysql-test/include/check-warnings.test
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
#
|
||||
# This test is executed once after each test to check the servers
|
||||
# for unexpected warnings found in the servers error log
|
||||
#
|
||||
--disable_query_log
|
||||
call mtr.check_warnings(@result);
|
||||
if (`select @result = 0`){
|
||||
skip OK;
|
||||
}
|
||||
echo Found warnings;
|
||||
--enable_query_log
|
130
mysql-test/include/circular_rpl_for_4_hosts_init.inc
Normal file
130
mysql-test/include/circular_rpl_for_4_hosts_init.inc
Normal 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
|
||||
|
23
mysql-test/include/circular_rpl_for_4_hosts_sync.inc
Normal file
23
mysql-test/include/circular_rpl_for_4_hosts_sync.inc
Normal 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
|
|
@ -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;
|
||||
|
|
25
mysql-test/include/default_my.cnf
Normal file
25
mysql-test/include/default_my.cnf
Normal 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
|
21
mysql-test/include/default_mysqld.cnf
Normal file
21
mysql-test/include/default_mysqld.cnf
Normal 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
|
||||
|
27
mysql-test/include/default_ndbd.cnf
Normal file
27
mysql-test/include/default_ndbd.cnf
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
[cluster_config]
|
||||
MaxNoOfSavedMessages= 1000
|
||||
MaxNoOfConcurrentTransactions= 64
|
||||
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
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
59
mysql-test/include/mtr_check.sql
Normal file
59
mysql-test/include/mtr_check.sql
Normal 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||
|
306
mysql-test/include/mtr_warnings.sql
Normal file
306
mysql-test/include/mtr_warnings.sql
Normal file
|
@ -0,0 +1,306 @@
|
|||
delimiter ||;
|
||||
|
||||
use mtr||
|
||||
|
||||
--
|
||||
-- Load table with the patterns that are considered
|
||||
-- as suspicious and should be examined further
|
||||
--
|
||||
CREATE TABLE suspicious_patterns (
|
||||
pattern VARCHAR(255)
|
||||
)||
|
||||
|
||||
|
||||
--
|
||||
-- Declare a trigger that makes sure
|
||||
-- no invalid patterns can be inserted
|
||||
-- into suspicious_patterns
|
||||
--
|
||||
/*!50002
|
||||
CREATE DEFINER=root@localhost TRIGGER sp_insert
|
||||
BEFORE INSERT ON suspicious_patterns
|
||||
FOR EACH ROW BEGIN
|
||||
DECLARE dummy INT;
|
||||
SELECT "" REGEXP NEW.pattern INTO dummy;
|
||||
END
|
||||
*/||
|
||||
|
||||
|
||||
--
|
||||
-- Insert patterns for the lines we should check
|
||||
--
|
||||
INSERT INTO suspicious_patterns VALUES
|
||||
("^Warning:|mysqld: Warning|\\[Warning\\]"),
|
||||
("^Error:|\\[ERROR\\]"),
|
||||
("^==.* at 0x"),
|
||||
("InnoDB: Warning"),
|
||||
("^safe_mutex:|allocated at line"),
|
||||
("missing DBUG_RETURN"),
|
||||
("Attempting backtrace"),
|
||||
("Assertion .* failed")||
|
||||
|
||||
|
||||
--
|
||||
-- Create table where testcases can insert patterns to
|
||||
-- be supressed
|
||||
--
|
||||
CREATE TABLE test_supressions (
|
||||
pattern VARCHAR(255)
|
||||
)||
|
||||
|
||||
|
||||
--
|
||||
-- Declare a trigger that makes sure
|
||||
-- no invalid patterns can be inserted
|
||||
-- into test_supressions
|
||||
--
|
||||
/*!50002
|
||||
CREATE DEFINER=root@localhost TRIGGER ts_insert
|
||||
BEFORE INSERT ON test_supressions
|
||||
FOR EACH ROW BEGIN
|
||||
DECLARE dummy INT;
|
||||
SELECT "" REGEXP NEW.pattern INTO dummy;
|
||||
END
|
||||
*/||
|
||||
|
||||
|
||||
--
|
||||
-- Load table with patterns that will be supressed globally(always)
|
||||
--
|
||||
CREATE TABLE global_supressions (
|
||||
pattern VARCHAR(255)
|
||||
)||
|
||||
|
||||
|
||||
-- Declare a trigger that makes sure
|
||||
-- no invalid patterns can be inserted
|
||||
-- into global_supressions
|
||||
--
|
||||
/*!50002
|
||||
CREATE DEFINER=root@localhost TRIGGER gs_insert
|
||||
BEFORE INSERT ON global_supressions
|
||||
FOR EACH ROW BEGIN
|
||||
DECLARE dummy INT;
|
||||
SELECT "" REGEXP NEW.pattern INTO dummy;
|
||||
END
|
||||
*/||
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Insert patterns that should always be supressed
|
||||
--
|
||||
INSERT INTO global_supressions 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"),
|
||||
|
||||
/*
|
||||
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 .*Deadlock found"),
|
||||
("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
|
||||
|
||||
-- Don't write these queries to binlog
|
||||
SET SQL_LOG_BIN=0;
|
||||
--
|
||||
-- Load the server .err file into "error_log" table
|
||||
--
|
||||
CREATE TEMPORARY TABLE error_log (
|
||||
row INT AUTO_INCREMENT PRIMARY KEY,
|
||||
line mediumtext NULL
|
||||
);
|
||||
|
||||
SELECT variable_value INTO @log_error
|
||||
FROM information_schema.global_variables
|
||||
WHERE variable_name='LOG_ERROR';
|
||||
|
||||
SET @@session.max_allowed_packet= 1024*1024*1024;
|
||||
SET @text= load_file(@log_error);
|
||||
-- select @text;
|
||||
|
||||
WHILE LOCATE('\n', @text) DO
|
||||
INSERT error_log (line)
|
||||
VALUES (
|
||||
SUBSTR(@text, 1, LOCATE('\n', @text)-1)
|
||||
);
|
||||
SET @text= SUBSTR(@text FROM LOCATE('\n', @text)+1);
|
||||
END WHILE;
|
||||
|
||||
-- select * from error_log;
|
||||
|
||||
--
|
||||
-- Remove all lines belonging to previous tests
|
||||
--
|
||||
SELECT COALESCE(MAX(row),0) INTO @max_row
|
||||
FROM error_log
|
||||
WHERE line REGEXP "^CURRENT_TEST:";
|
||||
DELETE FROM error_log WHERE row < @max_row;
|
||||
|
||||
CREATE TEMPORARY TABLE suspect_lines AS
|
||||
SELECT DISTINCT el.line, 0 as "supressed"
|
||||
FROM error_log el, suspicious_patterns ep
|
||||
WHERE el.line REGEXP ep.pattern;
|
||||
|
||||
-- Mark lines that are supressed by global supressions
|
||||
UPDATE suspect_lines sl, global_supressions gs
|
||||
SET supressed=1
|
||||
WHERE sl.line REGEXP gs.pattern;
|
||||
|
||||
-- Mark lines that are supressed by test specific supressions
|
||||
UPDATE suspect_lines sl, test_supressions ts
|
||||
SET supressed=2
|
||||
WHERE sl.line REGEXP ts.pattern;
|
||||
|
||||
SELECT COUNT(*) INTO @num_warnings FROM suspect_lines
|
||||
WHERE supressed=0;
|
||||
|
||||
IF @num_warnings > 0 THEN
|
||||
SELECT @log_error;
|
||||
SELECT line as log_error
|
||||
FROM suspect_lines WHERE supressed=0;
|
||||
SELECT * FROM test_supressions;
|
||||
-- Return 2 -> check failed
|
||||
SELECT 2 INTO result;
|
||||
ELSE
|
||||
-- Return 0 -> OK
|
||||
SELECT 0 INTO RESULT;
|
||||
END IF;
|
||||
|
||||
-- Cleanup for next test
|
||||
TRUNCATE test_supressions;
|
||||
|
||||
END||
|
||||
|
||||
--
|
||||
-- Declare a procedure testcases can use to insert test
|
||||
-- specific supressions
|
||||
--
|
||||
/*!50001
|
||||
CREATE DEFINER=root@localhost
|
||||
PROCEDURE add_supression(pattern VARCHAR(255))
|
||||
BEGIN
|
||||
INSERT INTO test_supressions (pattern) VALUES (pattern);
|
||||
END
|
||||
*/||
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
136
mysql-test/include/ndb_master-slave_2ch.inc
Normal file
136
mysql-test/include/ndb_master-slave_2ch.inc
Normal 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;
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
20
mysql-test/include/restart_mysqld.inc
Normal file
20
mysql-test/include/restart_mysqld.inc
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
# Write file to make mysql-test-run.pl expect crash and restart
|
||||
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
|
||||
restart
|
||||
EOF
|
||||
|
||||
# Send shutdown to the connected server and give
|
||||
# it 10 seconds to die before zapping it
|
||||
shutdown_server 10;
|
||||
|
||||
|
||||
# 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
|
||||
|
|
@ -62,7 +62,9 @@ SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name
|
|||
DROP EVENT IF EXISTS test.slave_once;
|
||||
--enable_warnings
|
||||
|
||||
CREATE EVENT test.slave_once ON SCHEDULE EVERY 5 MINUTE DO
|
||||
# Create an event on slave and check its state. An event shouldn't be executed
|
||||
# so set start time in 1 hour.
|
||||
CREATE EVENT test.slave_once ON SCHEDULE EVERY 5 MINUTE STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO
|
||||
INSERT IGNORE INTO t1(id, c) VALUES (3, 'from slave_once');
|
||||
|
||||
--echo "Checking event status on the slave for originator value = slave's server_id"
|
||||
|
@ -81,8 +83,11 @@ connection master;
|
|||
DROP EVENT IF EXISTS test.justonce;
|
||||
--enable_warnings
|
||||
|
||||
# Create an event on master and check its state on slave. An event shouldn't be executed
|
||||
# so set start time in 1 hour. Check that changes of event statement replicated to slave
|
||||
|
||||
--echo "Creating event test.er on the master"
|
||||
CREATE EVENT test.er ON SCHEDULE EVERY 3 SECOND DO
|
||||
CREATE EVENT test.er ON SCHEDULE EVERY 3 SECOND STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO
|
||||
INSERT IGNORE INTO t1(id, c) VALUES (4, 'from er');
|
||||
|
||||
--echo "Checking event status on the master"
|
||||
|
@ -95,7 +100,7 @@ SELECT db, name, status, originator, body FROM mysql.event WHERE db = 'test' AND
|
|||
|
||||
connection master;
|
||||
--echo "Altering event test.er on the master"
|
||||
ALTER EVENT test.er ON SCHEDULE EVERY 5 SECOND DO
|
||||
ALTER EVENT test.er ON SCHEDULE EVERY 5 SECOND STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO
|
||||
INSERT IGNORE INTO t1(id, c) VALUES (5, 'from alter er');
|
||||
|
||||
--echo "Checking event status on the master"
|
||||
|
@ -123,8 +128,11 @@ SELECT db, name, status, originator FROM mysql.event WHERE db = 'test';
|
|||
# test the DISABLE ON SLAVE for setting event SLAVESIDE_DISABLED as status
|
||||
# on CREATE EVENT
|
||||
|
||||
# Create an event on slave and check its status. An event shouldn't be executed
|
||||
# so set start time in 1 hour.
|
||||
|
||||
--echo "Creating event test.slave_terminate on the slave"
|
||||
CREATE EVENT test.slave_terminate ON SCHEDULE EVERY 3 SECOND DO
|
||||
CREATE EVENT test.slave_terminate ON SCHEDULE EVERY 3 SECOND STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO
|
||||
INSERT IGNORE INTO t1(id, c) VALUES (6, 'from slave_terminate');
|
||||
|
||||
--echo "Checking event status on the slave"
|
||||
|
|
21
mysql-test/include/start_slave.inc
Normal file
21
mysql-test/include/start_slave.inc
Normal 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
|
||||
# $slave_keep_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;
|
21
mysql-test/include/stop_slave.inc
Normal file
21
mysql-test/include/stop_slave.inc
Normal 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
|
||||
# $slave_keep_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;
|
36
mysql-test/include/sync_slave_io_with_master.inc
Normal file
36
mysql-test/include/sync_slave_io_with_master.inc
Normal 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
|
||||
# $slave_keep_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= ;
|
|
@ -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;
|
||||
}
|
||||
|
|
19
mysql-test/include/wait_for_slave_io_to_start.inc
Normal file
19
mysql-test/include/wait_for_slave_io_to_start.inc
Normal 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
|
||||
# $slave_keep_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= ;
|
|
@ -1,33 +1,18 @@
|
|||
###################################################
|
||||
#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;
|
||||
|
||||
while ($run)
|
||||
{
|
||||
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;
|
||||
}
|
||||
# ==== 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
|
||||
# $slave_keep_connection. See wait_for_slave_param.inc for
|
||||
# descriptions.
|
||||
|
||||
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= ;
|
||||
|
|
|
@ -1,26 +1,94 @@
|
|||
# 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.
|
||||
#
|
||||
# $slave_keep_connection
|
||||
# If the timeout is reached, debug info is given by calling SHOW
|
||||
# SLAVE STATUS, SHOW PROCESSLIST, and SHOW BINLOG EVENTS. By
|
||||
# default (assuming the current connection is slave), a 'connection
|
||||
# master' is then issued, and the same information is printed again
|
||||
# on the master host. You can avoid switching to master (and thus
|
||||
# suppress debug info on master too) by setting
|
||||
# $slave_keep_connection to 1.
|
||||
#
|
||||
# $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)
|
||||
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')`)
|
||||
{
|
||||
if (!$_slave_timeout_counter)
|
||||
{
|
||||
--echo ERROR: failed while waiting for slave parameter $slave_param: $slave_param_value
|
||||
query_vertical show slave status;
|
||||
--echo **** ERROR: failed while waiting for slave parameter $slave_param $_slave_param_comparison $slave_param_value ****
|
||||
if (`SELECT '$slave_error_message' != ''`)
|
||||
{
|
||||
--echo Message: $slave_error_message
|
||||
}
|
||||
--echo Note: the following output may have changed since the failure was detected
|
||||
--echo **** Showing SLAVE STATUS, PROCESSLIST, and BINLOG EVENTS on slave ****
|
||||
query_vertical SHOW SLAVE STATUS;
|
||||
SHOW PROCESSLIST;
|
||||
let $binlog_name= query_get_value("SHOW MASTER STATUS", File, 1);
|
||||
eval SHOW BINLOG EVENTS IN '$binlog_name';
|
||||
if (!$slave_keep_connection) {
|
||||
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 **** Showing MASTER STATUS, PROCESSLIST, and BINLOG EVENTS on master ****
|
||||
--echo [on master]
|
||||
connection master;
|
||||
query_vertical SHOW MASTER STATUS;
|
||||
SHOW PROCESSLIST;
|
||||
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';
|
||||
}
|
||||
}
|
||||
exit;
|
||||
}
|
||||
dec $_slave_timeout_counter;
|
||||
sleep 0.1;
|
||||
let $slave_value= query_get_value("SHOW SLAVE STATUS", $slave_param, 1);
|
||||
let $_show_slave_status_value= query_get_value("SHOW SLAVE STATUS", $slave_param, 1);
|
||||
}
|
||||
|
|
|
@ -1,33 +1,23 @@
|
|||
###################################################
|
||||
#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.
|
||||
#
|
||||
# ==== Usage ====
|
||||
#
|
||||
# source include/wait_for_slave_sql_error.inc;
|
||||
#
|
||||
# Parameters to this macro are $slave_timeout and
|
||||
# $slave_keep_connection. See wait_for_slave_param.inc for
|
||||
# descriptions.
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
let $old_slave_param_comparison= $slave_param_comparison;
|
||||
|
||||
let $slave_param= Last_SQL_Errno;
|
||||
let $slave_param_comparison= !=;
|
||||
let $slave_param_value= 0;
|
||||
let $slave_error_message= Failed while waiting for slave to produce an error in its sql thread;
|
||||
source include/wait_for_slave_param.inc;
|
||||
let $slave_error_message= ;
|
||||
|
||||
let $slave_param_comparison= $old_slave_param_comparison;
|
||||
|
|
|
@ -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
|
||||
# $slave_keep_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;
|
||||
|
|
|
@ -1,33 +1,18 @@
|
|||
###################################################
|
||||
#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
|
||||
# $slave_keep_connection. See wait_for_slave_param.inc for
|
||||
# descriptions.
|
||||
|
||||
while ($run)
|
||||
{
|
||||
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= ;
|
||||
|
|
|
@ -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
|
||||
# $slave_keep_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= ;
|
||||
|
|
|
@ -1,39 +1,24 @@
|
|||
###################################################
|
||||
#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
|
||||
# $slave_keep_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' = '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= ;
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -4,9 +4,13 @@
|
|||
--disable_result_log
|
||||
--disable_query_log
|
||||
let $counter= 500;
|
||||
let $mysql_errno= 9999;
|
||||
while ($mysql_errno)
|
||||
{
|
||||
--error 0,2002,2006
|
||||
# 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;
|
||||
|
|
21
mysql-test/include/wait_until_disconnected.inc
Normal file
21
mysql-test/include/wait_until_disconnected.inc
Normal 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= 9999;
|
||||
while (!$mysql_errno)
|
||||
{
|
||||
--error 0,1053,2002,2006
|
||||
show status;
|
||||
|
||||
dec $counter;
|
||||
if (!$counter)
|
||||
{
|
||||
--die Server failed to dissapear
|
||||
}
|
||||
--sleep 0.1
|
||||
}
|
||||
--enable_query_log
|
||||
--enable_result_log
|
|
@ -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
|
|
@ -4,6 +4,7 @@ package My::Config::Option;
|
|||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Carp;
|
||||
|
||||
|
||||
sub new {
|
||||
|
@ -31,7 +32,7 @@ package My::Config::Group;
|
|||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Carp;
|
||||
|
||||
sub new {
|
||||
my ($class, $group_name)= @_;
|
||||
|
@ -68,7 +69,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 +89,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 +128,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 +174,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 +191,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 +213,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 +229,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 +241,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 +278,7 @@ sub insert {
|
|||
# Add the option to the group
|
||||
$group->insert($option, $value, $if_not_exist);
|
||||
}
|
||||
return $group;
|
||||
}
|
||||
|
||||
#
|
||||
|
@ -240,11 +288,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 +315,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 +402,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 +420,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 +460,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;
|
||||
|
|
647
mysql-test/lib/My/ConfigFactory.pm
Normal file
647
mysql-test/lib/My/ConfigFactory.pm
Normal file
|
@ -0,0 +1,647 @@
|
|||
# -*- 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_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 },
|
||||
);
|
||||
|
||||
|
||||
#
|
||||
# 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;
|
||||
|
83
mysql-test/lib/My/File/Path.pm
Normal file
83
mysql-test/lib/My/File/Path.pm
Normal file
|
@ -0,0 +1,83 @@
|
|||
# -*- 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::Path;
|
||||
use File::Copy;
|
||||
use Carp;
|
||||
|
||||
no warnings 'redefine';
|
||||
|
||||
sub rmtree {
|
||||
my ($dir)= @_;
|
||||
|
||||
#
|
||||
# chmod all files to 0777 before calling rmtree
|
||||
#
|
||||
find( {
|
||||
no_chdir => 1,
|
||||
wanted => sub {
|
||||
chmod(0777, $_)
|
||||
or warn("couldn't chmod(0777, $_): $!");
|
||||
}
|
||||
},
|
||||
$dir
|
||||
);
|
||||
|
||||
|
||||
# Call rmtree from File::Path
|
||||
goto &File::Path::rmtree;
|
||||
};
|
||||
|
||||
|
||||
sub mkpath {
|
||||
goto &File::Path::mkpath;
|
||||
};
|
||||
|
||||
|
||||
sub copytree {
|
||||
my ($from_dir, $to_dir) = @_;
|
||||
|
||||
die "Usage: copytree(<fromdir>, <todir>" unless @_ == 2;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
1;
|
211
mysql-test/lib/My/Find.pm
Normal file
211
mysql-test/lib/My/Find.pm
Normal file
|
@ -0,0 +1,211 @@
|
|||
# -*- 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 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", 0);
|
||||
#
|
||||
# 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_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;
|
199
mysql-test/lib/My/Options.pm
Normal file
199
mysql-test/lib/My/Options.pm
Normal 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;
|
||||
|
126
mysql-test/lib/My/Platform.pm
Normal file
126
mysql-test/lib/My/Platform.pm
Normal file
|
@ -0,0 +1,126 @@
|
|||
# -*- 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 base qw(Exporter);
|
||||
our @EXPORT= qw(IS_CYGWIN IS_WINDOWS IS_WIN32PERL
|
||||
native_path posix_path mixed_path
|
||||
check_socket_path_length);
|
||||
|
||||
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)
|
||||
#
|
||||
|
||||
sub mixed_path {
|
||||
my ($path)= @_;
|
||||
if (IS_CYGWIN){
|
||||
return unless defined $path;
|
||||
$path= `cygpath -m $path`;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
sub check_socket_path_length {
|
||||
my ($path)= @_;
|
||||
my $truncated= 0;
|
||||
|
||||
return 0 if IS_WINDOWS;
|
||||
|
||||
require IO::Socket::UNIX;
|
||||
|
||||
my $sock = new IO::Socket::UNIX
|
||||
(
|
||||
Local => $path,
|
||||
Listen => 1,
|
||||
);
|
||||
if (!defined $sock){
|
||||
# Could not create a UNIX domain socket
|
||||
return 0; # Ok, will not be used by mysqld either
|
||||
}
|
||||
if ($path ne $sock->hostpath()){
|
||||
# Path was truncated
|
||||
$truncated= 1;
|
||||
# Output diagnostic messages
|
||||
print "path: '$path', length: ", length($path) ,"\n";
|
||||
print "hostpath: '", $sock->hostpath(),
|
||||
"', length: ", length($sock->hostpath()), "\n";
|
||||
}
|
||||
$sock= undef; # Close socket
|
||||
unlink($path); # Remove the physical file
|
||||
return $truncated;
|
||||
}
|
||||
|
||||
|
||||
1;
|
563
mysql-test/lib/My/SafeProcess.pm
Normal file
563
mysql-test/lib/My/SafeProcess.pm
Normal file
|
@ -0,0 +1,563 @@
|
|||
# -*- 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";
|
||||
$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 _process_alive {
|
||||
my ($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);
|
||||
}
|
||||
|
||||
|
||||
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, $winpid)= 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 => $winpid,
|
||||
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)";
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# 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;
|
||||
if (IS_WINDOWS and defined $self->{SAFE_WINPID})
|
||||
{
|
||||
die "INTERNAL ERROR: no safe_kill" unless defined $safe_kill;
|
||||
die "INTERNAL ERROR: no winpid" unless defined $self->{SAFE_WINPID};
|
||||
|
||||
# Use my_safe_kill to tell my_safe_process
|
||||
# it's time to kill it's child and return
|
||||
$pid= $self->{SAFE_WINPID};
|
||||
$ret= system($safe_kill, $pid) >> 8;
|
||||
if (IS_CYGWIN and $ret == 3)
|
||||
{
|
||||
print "safe_process is gone, kickstart the fake process\n";
|
||||
if (kill(15, $self->{SAFE_PID}) != 1){
|
||||
print STDERR "Failed to kickstart the fake process\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$pid= $self->{SAFE_PID};
|
||||
die "Can't kill not started process" unless defined $pid;
|
||||
$ret= kill(15, $pid);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# 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);
|
||||
|
||||
# Special processig of return code
|
||||
# since negative pids are valid
|
||||
if ($ret_pid == 0 or $ret_pid == -1) {
|
||||
print STDERR "wait_any, got invalid pid: $ret_pid\n";
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
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 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;
|
236
mysql-test/lib/My/SafeProcess/Base.pm
Normal file
236
mysql-test/lib/My/SafeProcess/Base.pm
Normal file
|
@ -0,0 +1,236 @@
|
|||
# -*- 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);
|
||||
|
||||
|
||||
sub winpid {
|
||||
my ($pid)= @_;
|
||||
|
||||
return undef unless $^O eq "cygwin";
|
||||
|
||||
# The child get a new winpid when the exec takes
|
||||
# place, wait for that to happen
|
||||
my $winpid;
|
||||
my $delay= 0;
|
||||
do
|
||||
{
|
||||
# Yield to the child
|
||||
select(undef, undef, undef, $delay);
|
||||
# Increase the delay slightly for each loop
|
||||
$delay += 0.000001;
|
||||
|
||||
$winpid= Cygwin::pid_to_winpid($pid);
|
||||
|
||||
} until ($winpid != $pid);
|
||||
|
||||
return $winpid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# 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 wantarray ? ($pid, $pid) : $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 wantarray ? ($pid, winpid($pid)) : $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;
|
||||
|
17
mysql-test/lib/My/SafeProcess/CMakeLists.txt
Normal file
17
mysql-test/lib/My/SafeProcess/CMakeLists.txt
Normal 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)
|
28
mysql-test/lib/My/SafeProcess/Makefile.am
Normal file
28
mysql-test/lib/My/SafeProcess/Makefile.am
Normal 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.%
|
72
mysql-test/lib/My/SafeProcess/safe_kill_win.cc
Executable file
72
mysql-test/lib/My/SafeProcess/safe_kill_win.cc
Executable file
|
@ -0,0 +1,72 @@
|
|||
/* 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
266
mysql-test/lib/My/SafeProcess/safe_process.cc
Normal file
266
mysql-test/lib/My/SafeProcess/safe_process.cc
Normal file
|
@ -0,0 +1,266 @@
|
|||
/* 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_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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
151
mysql-test/lib/My/SafeProcess/safe_process.pl
Normal file
151
mysql-test/lib/My/SafeProcess/safe_process.pl
Normal 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);
|
||||
|
||||
|
316
mysql-test/lib/My/SafeProcess/safe_process_win.cc
Executable file
316
mysql-test/lib/My/SafeProcess/safe_process_win.cc
Executable file
|
@ -0,0 +1,316 @@
|
|||
/* 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 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)
|
||||
|
||||
4. The named event "safe_process[pid]" can be signaled and will
|
||||
trigger same action as 2)
|
||||
|
||||
WARNING! Be careful when using ProcessExplorer, since it will open
|
||||
a handle to each process(and maybe also the Job), the process
|
||||
spawned by safe_process will not be closed off when safe_process
|
||||
is killed.
|
||||
*/
|
||||
|
||||
/* Requires Windows 2000 or higher */
|
||||
#define _WIN32_WINNT 0x0500
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <signal.h>
|
||||
|
||||
static int verbose= 0;
|
||||
static 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= GetLastError())
|
||||
fprintf(stderr, "error: %d, %s\n", last_err, strerror(last_err));
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
DWORD get_parent_pid(DWORD pid)
|
||||
{
|
||||
HANDLE snapshot;
|
||||
DWORD parent_pid= -1;
|
||||
PROCESSENTRY32 pe32;
|
||||
pe32.dwSize= sizeof(PROCESSENTRY32);
|
||||
|
||||
snapshot= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (snapshot == INVALID_HANDLE_VALUE)
|
||||
die("CreateToolhelp32Snapshot failed");
|
||||
|
||||
if (!Process32First(snapshot, &pe32))
|
||||
{
|
||||
CloseHandle(snapshot);
|
||||
die("Process32First failed");
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (pe32.th32ProcessID == pid)
|
||||
parent_pid= pe32.th32ParentProcessID;
|
||||
} while(Process32Next( snapshot, &pe32));
|
||||
CloseHandle(snapshot);
|
||||
|
||||
if (parent_pid == -1)
|
||||
die("Could not find parent pid");
|
||||
|
||||
return parent_pid;
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
PARENT,
|
||||
CHILD,
|
||||
EVENT,
|
||||
NUM_HANDLES
|
||||
};
|
||||
|
||||
|
||||
HANDLE shutdown_event;
|
||||
void handle_signal (int signal)
|
||||
{
|
||||
message("Got signal: %d", signal);
|
||||
if(SetEvent(shutdown_event) == 0) {
|
||||
/* exit safe_process and (hopefully) kill off the child */
|
||||
die("Failed to SetEvent");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char** argv )
|
||||
{
|
||||
char child_args[4096]= {0};
|
||||
DWORD pid= GetCurrentProcessId();
|
||||
DWORD parent_pid= get_parent_pid(pid);
|
||||
HANDLE job_handle;
|
||||
HANDLE wait_handles[NUM_HANDLES]= {0};
|
||||
PROCESS_INFORMATION process_info= {0};
|
||||
|
||||
sprintf(safe_process_name, "safe_process[%d]", pid);
|
||||
|
||||
/* Create an event for the signal handler */
|
||||
if ((shutdown_event=
|
||||
CreateEvent(NULL, TRUE, FALSE, safe_process_name)) == NULL)
|
||||
die("Failed to create shutdown_event");
|
||||
wait_handles[EVENT]= shutdown_event;
|
||||
|
||||
signal(SIGINT, handle_signal);
|
||||
signal(SIGBREAK, handle_signal);
|
||||
signal(SIGTERM, handle_signal);
|
||||
|
||||
message("Started");
|
||||
|
||||
/* Parse arguments */
|
||||
for (int i= 1; i < argc; i++) {
|
||||
const char* arg= argv[i];
|
||||
char* to= child_args;
|
||||
if (strcmp(arg, "--") == 0 && strlen(arg) == 2) {
|
||||
/* Got the "--" delimiter */
|
||||
if (i >= argc)
|
||||
die("No real args -> nothing to do");
|
||||
/* Copy the remaining args to child_arg */
|
||||
for (int j= i+1; j < argc; j++) {
|
||||
to+= _snprintf(to, child_args + sizeof(child_args) - to, "%s ", argv[j]);
|
||||
}
|
||||
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_args == '\0')
|
||||
die("nothing to do");
|
||||
|
||||
/* Open a handle to the parent process */
|
||||
message("parent_pid: %d", parent_pid);
|
||||
if (parent_pid == pid)
|
||||
die("parent_pid is equal to own pid!");
|
||||
|
||||
if ((wait_handles[PARENT]=
|
||||
OpenProcess(SYNCHRONIZE, FALSE, parent_pid)) == NULL)
|
||||
die("Failed to open parent process with pid: %d", parent_pid);
|
||||
|
||||
/* Create the child process in a job */
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
|
||||
STARTUPINFO si = { 0 };
|
||||
si.cb = sizeof(si);
|
||||
|
||||
/*
|
||||
Create the job object to make it possible to kill the process
|
||||
and all of it's children in one go
|
||||
*/
|
||||
if ((job_handle= CreateJobObject(NULL, NULL)) == NULL)
|
||||
die("CreateJobObject failed");
|
||||
|
||||
/*
|
||||
Make all processes associated with the job terminate when the
|
||||
last handle to the job is closed.
|
||||
*/
|
||||
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
if (SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation,
|
||||
&jeli, sizeof(jeli)) == 0)
|
||||
message("SetInformationJobObject failed, continue anyway...");
|
||||
|
||||
#if 0
|
||||
/* Setup stdin, stdout and stderr redirect */
|
||||
si.dwFlags= STARTF_USESTDHANDLES;
|
||||
si.hStdInput= GetStdHandle(STD_INPUT_HANDLE);
|
||||
si.hStdOutput= GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
si.hStdError= GetStdHandle(STD_ERROR_HANDLE);
|
||||
#endif
|
||||
|
||||
/*
|
||||
Create the process suspended to make sure it's assigned to the
|
||||
Job before it creates any process of it's own
|
||||
*/
|
||||
if (CreateProcess(NULL, (LPSTR)child_args,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE, /* inherit handles */
|
||||
CREATE_SUSPENDED,
|
||||
NULL,
|
||||
NULL,
|
||||
&si,
|
||||
&process_info) == 0)
|
||||
die("CreateProcess failed");
|
||||
|
||||
if (AssignProcessToJobObject(job_handle, process_info.hProcess) == 0)
|
||||
{
|
||||
TerminateProcess(process_info.hProcess, 200);
|
||||
die("AssignProcessToJobObject failed");
|
||||
}
|
||||
ResumeThread(process_info.hThread);
|
||||
CloseHandle(process_info.hThread);
|
||||
|
||||
wait_handles[CHILD]= process_info.hProcess;
|
||||
|
||||
message("Started child %d", process_info.dwProcessId);
|
||||
|
||||
/* Monitor loop */
|
||||
DWORD child_exit_code= 1;
|
||||
DWORD wait_res= WaitForMultipleObjects(NUM_HANDLES, wait_handles,
|
||||
FALSE, INFINITE);
|
||||
switch (wait_res)
|
||||
{
|
||||
case WAIT_OBJECT_0 + PARENT:
|
||||
message("Parent exit");
|
||||
break;
|
||||
case WAIT_OBJECT_0 + CHILD:
|
||||
if (GetExitCodeProcess(wait_handles[CHILD], &child_exit_code) == 0)
|
||||
message("Child exit: could not get exit_code");
|
||||
else
|
||||
message("Child exit: exit_code: %d", child_exit_code);
|
||||
break;
|
||||
case WAIT_OBJECT_0 + EVENT:
|
||||
message("Wake up from shutdown_event");
|
||||
break;
|
||||
|
||||
default:
|
||||
message("Unexpected result %d from WaitForMultipleObjects", wait_res);
|
||||
break;
|
||||
}
|
||||
message("Exiting, child: %d", process_info.dwProcessId);
|
||||
|
||||
if (TerminateJobObject(job_handle, 201) == 0)
|
||||
message("TerminateJobObject failed");
|
||||
CloseHandle(job_handle);
|
||||
message("Job terminated and closed");
|
||||
if (wait_res != WAIT_OBJECT_0 + CHILD)
|
||||
{
|
||||
/* The child has not yet returned, wait for it */
|
||||
message("waiting for child to exit");
|
||||
if ((wait_res= WaitForSingleObject(wait_handles[CHILD], INFINITE))
|
||||
!= WAIT_OBJECT_0)
|
||||
{
|
||||
message("child wait failed: %d", wait_res);
|
||||
}
|
||||
else
|
||||
{
|
||||
message("child wait succeeded");
|
||||
}
|
||||
/* Child's exit code should now be 201, no need to get it */
|
||||
}
|
||||
|
||||
message("Closing handles");
|
||||
for (int i= 0; i < NUM_HANDLES; i++)
|
||||
CloseHandle(wait_handles[i]);
|
||||
|
||||
message("Exiting, exit_code: %d", child_exit_code);
|
||||
exit(child_exit_code);
|
||||
}
|
||||
|
196
mysql-test/lib/My/SysInfo.pm
Normal file
196
mysql-test/lib/My/SysInfo.pm
Normal file
|
@ -0,0 +1,196 @@
|
|||
# -*- 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::SysInfo;
|
||||
|
||||
use strict;
|
||||
use Carp;
|
||||
use My::Platform;
|
||||
|
||||
use constant DEFAULT_BOGO_MIPS => 2000;
|
||||
|
||||
sub _cpuinfo {
|
||||
my ($self)= @_;
|
||||
|
||||
my $info_file= "/proc/cpuinfo";
|
||||
if ( !( -e $info_file and -f $info_file) ) {
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $F= IO::File->new($info_file) or return undef;
|
||||
|
||||
# Set input separator to blank line
|
||||
local $/ = '';
|
||||
|
||||
while ( my $cpu_chunk= <$F>) {
|
||||
chomp($cpu_chunk);
|
||||
|
||||
my $cpuinfo = {};
|
||||
|
||||
foreach my $cpuline ( split(/\n/, $cpu_chunk) ) {
|
||||
my ( $attribute, $value ) = split(/\s*:\s*/, $cpuline);
|
||||
|
||||
$attribute =~ s/\s+/_/;
|
||||
$attribute = lc($attribute);
|
||||
|
||||
if ( $value =~ /^(no|not available|yes)$/ ) {
|
||||
$value = $value eq 'yes' ? 1 : 0;
|
||||
}
|
||||
|
||||
if ( $attribute eq 'flags' ) {
|
||||
@{ $cpuinfo->{flags} } = split / /, $value;
|
||||
} else {
|
||||
$cpuinfo->{$attribute} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
# Make sure bogomips is set to some value
|
||||
$cpuinfo->{bogomips} |= DEFAULT_BOGO_MIPS;
|
||||
|
||||
# Cpus reported once, but with 'cpu_count' set to the actual number
|
||||
my $cpu_count= $cpuinfo->{cpu_count} || 1;
|
||||
for(1..$cpu_count){
|
||||
push(@{$self->{cpus}}, $cpuinfo);
|
||||
}
|
||||
}
|
||||
$F= undef; # Close file
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub _kstat {
|
||||
my ($self)= @_;
|
||||
while (1){
|
||||
my $instance_num= $self->{cpus} ? @{$self->{cpus}} : 0;
|
||||
my $list= `kstat -p -m cpu_info -i $instance_num`;
|
||||
my @lines= split('\n', $list) or last; # Break loop
|
||||
|
||||
my $cpuinfo= {};
|
||||
foreach my $line (@lines)
|
||||
{
|
||||
my ($module, $instance, $name, $statistic, $value)=
|
||||
$line=~ /(\w*):(\w*):(\w*):(\w*)\t(.*)/;
|
||||
|
||||
$cpuinfo->{$statistic}= $value;
|
||||
}
|
||||
|
||||
# Default value, the actual cpu values can be used to decrease this
|
||||
# on slower cpus
|
||||
$cpuinfo->{bogomips}= DEFAULT_BOGO_MIPS;
|
||||
|
||||
push(@{$self->{cpus}}, $cpuinfo);
|
||||
}
|
||||
|
||||
# At least one cpu should have been found
|
||||
# if this method worked
|
||||
if ( $self->{cpus} ) {
|
||||
return $self;
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
sub _unamex {
|
||||
my ($self)= @_;
|
||||
# TODO
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
sub new {
|
||||
my ($class)= @_;
|
||||
|
||||
|
||||
my $self= bless {
|
||||
cpus => (),
|
||||
}, $class;
|
||||
|
||||
my @info_methods =
|
||||
(
|
||||
\&_cpuinfo,
|
||||
\&_kstat,
|
||||
\&_unamex,
|
||||
);
|
||||
|
||||
foreach my $method (@info_methods){
|
||||
if ($method->($self)){
|
||||
return $self;
|
||||
}
|
||||
}
|
||||
|
||||
# Push a dummy cpu
|
||||
push(@{$self->{cpus}},
|
||||
{
|
||||
bogomips => DEFAULT_BOGO_MIPS,
|
||||
model_name => "unknown",
|
||||
});
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
# Return the list of cpus found
|
||||
sub cpus {
|
||||
my ($self)= @_;
|
||||
return @{$self->{cpus}} or
|
||||
confess "INTERNAL ERROR: No cpus in list";
|
||||
}
|
||||
|
||||
|
||||
# Return the number of cpus found
|
||||
sub num_cpus {
|
||||
my ($self)= @_;
|
||||
return int(@{$self->{cpus}}) or
|
||||
confess "INTERNAL ERROR: No cpus in list";
|
||||
}
|
||||
|
||||
|
||||
# Return the smallest bogomips value amongst the processors
|
||||
sub min_bogomips {
|
||||
my ($self)= @_;
|
||||
|
||||
my $bogomips;
|
||||
|
||||
foreach my $cpu (@{$self->{cpus}}) {
|
||||
if (!defined $bogomips or $bogomips > $cpu->{bogomips}) {
|
||||
$bogomips= $cpu->{bogomips};
|
||||
}
|
||||
}
|
||||
|
||||
return $bogomips;
|
||||
}
|
||||
|
||||
|
||||
# Prit the cpuinfo
|
||||
sub print_info {
|
||||
my ($self)= @_;
|
||||
|
||||
foreach my $cpu (@{$self->{cpus}}) {
|
||||
while ((my ($key, $value)) = each(%$cpu)) {
|
||||
print " ", $key, "= ";
|
||||
if (ref $value eq "ARRAY") {
|
||||
print "[", join(", ", @$value), "]";
|
||||
} else {
|
||||
print $value;
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
122
mysql-test/lib/My/Test.pm
Normal file
122
mysql-test/lib/My/Test.pm
Normal file
|
@ -0,0 +1,122 @@
|
|||
# -*- cperl -*-
|
||||
|
||||
|
||||
#
|
||||
# One test
|
||||
#
|
||||
package My::Test;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Carp;
|
||||
|
||||
|
||||
sub new {
|
||||
my $class= shift;
|
||||
my $self= bless {
|
||||
@_,
|
||||
}, $class;
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Return a unique key that can be used to
|
||||
# identify this test in a hash
|
||||
#
|
||||
sub key {
|
||||
my ($self)= @_;
|
||||
my $key= $self->{name};
|
||||
$key.= "+".$self->{combination} if $self->{combination};
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
||||
sub _encode {
|
||||
my ($value)= @_;
|
||||
$value =~ s/([|\\\x{0a}\x{0d}])/sprintf('\%02X', ord($1))/eg;
|
||||
return $value;
|
||||
}
|
||||
|
||||
sub _decode {
|
||||
my ($value)= @_;
|
||||
$value =~ s/\\([0-9a-fA-F]{2})/chr(hex($1))/ge;
|
||||
return $value;
|
||||
}
|
||||
|
||||
sub is_failed {
|
||||
my ($self)= @_;
|
||||
my $result= $self->{result};
|
||||
croak "'is_failed' can't be called until test has been run!"
|
||||
unless defined $result;
|
||||
|
||||
return ($result eq 'MTR_RES_FAILED');
|
||||
}
|
||||
|
||||
|
||||
sub write_test {
|
||||
my ($test, $sock, $header)= @_;
|
||||
|
||||
print $sock $header, "\n";
|
||||
while ((my ($key, $value)) = each(%$test)) {
|
||||
print $sock $key, "= ";
|
||||
if (ref $value eq "ARRAY") {
|
||||
print $sock "[", _encode(join(", ", @$value)), "]";
|
||||
} else {
|
||||
print $sock _encode($value);
|
||||
}
|
||||
print $sock "\n";
|
||||
}
|
||||
print $sock "\n";
|
||||
}
|
||||
|
||||
|
||||
sub read_test {
|
||||
my ($sock)= @_;
|
||||
my $test= My::Test->new();
|
||||
# Read the : separated key value pairs until a
|
||||
# single newline on it's own line
|
||||
my $line;
|
||||
while (defined($line= <$sock>)) {
|
||||
# List is terminated by newline on it's own
|
||||
if ($line eq "\n") {
|
||||
# Correctly terminated reply
|
||||
# print "Got newline\n";
|
||||
last;
|
||||
}
|
||||
chomp($line);
|
||||
|
||||
# Split key/value on the first "="
|
||||
my ($key, $value)= split("= ", $line, 2);
|
||||
|
||||
if ($value =~ /^\[(.*)\]/){
|
||||
my @values= split(", ", _decode($1));
|
||||
push(@{$test->{$key}}, @values);
|
||||
}
|
||||
else
|
||||
{
|
||||
$test->{$key}= _decode($value);
|
||||
}
|
||||
}
|
||||
return $test;
|
||||
}
|
||||
|
||||
|
||||
sub print_test {
|
||||
my ($self)= @_;
|
||||
|
||||
print "[", $self->{name}, "]", "\n";
|
||||
while ((my ($key, $value)) = each(%$self)) {
|
||||
print " ", $key, "= ";
|
||||
if (ref $value eq "ARRAY") {
|
||||
print "[", join(", ", @$value), "]";
|
||||
} else {
|
||||
print $value;
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
|
||||
1;
|
|
@ -1,969 +0,0 @@
|
|||
# -*- cperl -*-
|
||||
# Copyright (C) 2005-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 File::Basename;
|
||||
use IO::File();
|
||||
use strict;
|
||||
|
||||
use My::Config;
|
||||
|
||||
sub collect_test_cases ($);
|
||||
sub collect_one_suite ($);
|
||||
sub collect_one_test_case ($$$$$$$$$);
|
||||
|
||||
sub mtr_options_from_test_file($$);
|
||||
|
||||
my $do_test;
|
||||
my $skip_test;
|
||||
|
||||
sub init_pattern {
|
||||
my ($from, $what)= @_;
|
||||
if ( $from =~ /^[a-z0-9]$/ ) {
|
||||
# Does not contain any regex, make the pattern match
|
||||
# beginning of string
|
||||
$from= "^$from";
|
||||
}
|
||||
# Check that pattern is a valid regex
|
||||
eval { "" =~/$from/; 1 } or
|
||||
mtr_error("Invalid regex '$from' passed to $what\nPerl says: $@");
|
||||
return $from;
|
||||
}
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Collect information about test cases we are to run
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
sub collect_test_cases ($) {
|
||||
$do_test= init_pattern($::opt_do_test, "--do-test");
|
||||
$skip_test= init_pattern($::opt_skip_test, "--skip-test");
|
||||
|
||||
my $suites= shift; # Semicolon separated list of test suites
|
||||
my $cases = []; # Array of hash
|
||||
|
||||
foreach my $suite (split(",", $suites))
|
||||
{
|
||||
push(@$cases, collect_one_suite($suite));
|
||||
}
|
||||
|
||||
|
||||
if ( @::opt_cases )
|
||||
{
|
||||
# Check that the tests specified was found
|
||||
# in at least one suite
|
||||
foreach my $test_name_spec ( @::opt_cases )
|
||||
{
|
||||
my $found= 0;
|
||||
my ($sname, $tname, $extension)= split_testname($test_name_spec);
|
||||
foreach my $test ( @$cases )
|
||||
{
|
||||
# test->{name} is always in suite.name format
|
||||
if ( $test->{name} =~ /.*\.$tname/ )
|
||||
{
|
||||
$found= 1;
|
||||
}
|
||||
}
|
||||
if ( not $found )
|
||||
{
|
||||
mtr_error("Could not find $tname in any suite");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $::opt_reorder )
|
||||
{
|
||||
# Reorder the test cases in an order that will make them faster to run
|
||||
my %sort_criteria;
|
||||
|
||||
# Make a mapping of test name to a string that represents how that test
|
||||
# should be sorted among the other tests. Put the most important criterion
|
||||
# first, then a sub-criterion, then sub-sub-criterion, et c.
|
||||
foreach my $tinfo (@$cases)
|
||||
{
|
||||
my @criteria = ();
|
||||
|
||||
# Look for tests that muct be in run in a defined order
|
||||
# that is defined by test having the same name except for
|
||||
# the ending digit
|
||||
|
||||
# Put variables into hash
|
||||
my $test_name= $tinfo->{'name'};
|
||||
my $depend_on_test_name;
|
||||
if ( $test_name =~ /^([\D]+)([0-9]{1})$/ )
|
||||
{
|
||||
my $base_name= $1;
|
||||
my $idx= $2;
|
||||
mtr_verbose("$test_name => $base_name idx=$idx");
|
||||
if ( $idx > 1 )
|
||||
{
|
||||
$idx-= 1;
|
||||
$base_name= "$base_name$idx";
|
||||
mtr_verbose("New basename $base_name");
|
||||
}
|
||||
|
||||
foreach my $tinfo2 (@$cases)
|
||||
{
|
||||
if ( $tinfo2->{'name'} eq $base_name )
|
||||
{
|
||||
mtr_verbose("found dependent test $tinfo2->{'name'}");
|
||||
$depend_on_test_name=$base_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( defined $depend_on_test_name )
|
||||
{
|
||||
mtr_verbose("Giving $test_name same critera as $depend_on_test_name");
|
||||
$sort_criteria{$test_name} = $sort_criteria{$depend_on_test_name};
|
||||
}
|
||||
else
|
||||
{
|
||||
#
|
||||
# Append the criteria for sorting, in order of importance.
|
||||
#
|
||||
push(@criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0"));
|
||||
# Group test with equal options together.
|
||||
# Ending with "~" makes empty sort later than filled
|
||||
push(@criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~");
|
||||
|
||||
$sort_criteria{$test_name} = join(" ", @criteria);
|
||||
}
|
||||
}
|
||||
|
||||
@$cases = sort {
|
||||
$sort_criteria{$a->{'name'}} . $a->{'name'} cmp
|
||||
$sort_criteria{$b->{'name'}} . $b->{'name'}; } @$cases;
|
||||
|
||||
if ( $::opt_script_debug )
|
||||
{
|
||||
# For debugging the sort-order
|
||||
foreach my $tinfo (@$cases)
|
||||
{
|
||||
print("$sort_criteria{$tinfo->{'name'}} -> \t$tinfo->{'name'}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $cases;
|
||||
|
||||
}
|
||||
|
||||
# Valid extensions and their corresonding component id
|
||||
my %exts = ( 'test' => 'mysqld',
|
||||
'imtest' => 'im'
|
||||
);
|
||||
|
||||
|
||||
# Returns (suitename, testname, extension)
|
||||
sub split_testname {
|
||||
my ($test_name)= @_;
|
||||
|
||||
# Get rid of directory part and split name on .'s
|
||||
my @parts= split(/\./, basename($test_name));
|
||||
|
||||
if (@parts == 1){
|
||||
# Only testname given, ex: alias
|
||||
return (undef , $parts[0], undef);
|
||||
} elsif (@parts == 2) {
|
||||
# Either testname.test or suite.testname given
|
||||
# Ex. main.alias or alias.test
|
||||
|
||||
if (defined $exts{$parts[1]})
|
||||
{
|
||||
return (undef , $parts[0], $parts[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ($parts[0], $parts[1], undef);
|
||||
}
|
||||
|
||||
} elsif (@parts == 3) {
|
||||
# Fully specified suitename.testname.test
|
||||
# ex main.alias.test
|
||||
return ( $parts[0], $parts[1], $parts[2]);
|
||||
}
|
||||
|
||||
mtr_error("Illegal format of test name: $test_name");
|
||||
}
|
||||
|
||||
|
||||
sub collect_one_suite($)
|
||||
{
|
||||
my $suite= shift; # Test suite name
|
||||
my @cases; # Array of hash
|
||||
|
||||
mtr_verbose("Collecting: $suite");
|
||||
|
||||
my $suitedir= "$::glob_mysql_test_dir"; # Default
|
||||
if ( $suite ne "main" )
|
||||
{
|
||||
$suitedir= mtr_path_exists("$suitedir/suite/$suite",
|
||||
"$suitedir/$suite");
|
||||
mtr_verbose("suitedir: $suitedir");
|
||||
}
|
||||
|
||||
my $testdir= "$suitedir/t";
|
||||
my $resdir= "$suitedir/r";
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Build a hash of disabled testcases for this suite
|
||||
# ----------------------------------------------------------------------
|
||||
my %disabled;
|
||||
if ( open(DISABLED, "$testdir/disabled.def" ) )
|
||||
{
|
||||
while ( <DISABLED> )
|
||||
{
|
||||
chomp;
|
||||
if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ )
|
||||
{
|
||||
$disabled{$1}= $2;
|
||||
}
|
||||
}
|
||||
close DISABLED;
|
||||
}
|
||||
|
||||
# Read suite.opt file
|
||||
my $suite_opt_file= "$testdir/suite.opt";
|
||||
my $suite_opts= [];
|
||||
if ( -f $suite_opt_file )
|
||||
{
|
||||
$suite_opts= mtr_get_opts_from_file($suite_opt_file);
|
||||
}
|
||||
|
||||
if ( @::opt_cases )
|
||||
{
|
||||
# Collect in specified order
|
||||
foreach my $test_name_spec ( @::opt_cases )
|
||||
{
|
||||
my ($sname, $tname, $extension)= split_testname($test_name_spec);
|
||||
|
||||
# The test name parts have now been defined
|
||||
#print " suite_name: $sname\n";
|
||||
#print " tname: $tname\n";
|
||||
#print " extension: $extension\n";
|
||||
|
||||
# Check cirrect suite if suitename is defined
|
||||
next if (defined $sname and $suite ne $sname);
|
||||
|
||||
my $component_id;
|
||||
if ( defined $extension )
|
||||
{
|
||||
my $full_name= "$testdir/$tname.$extension";
|
||||
# Extension was specified, check if the test exists
|
||||
if ( ! -f $full_name)
|
||||
{
|
||||
# This is only an error if suite was specified, otherwise it
|
||||
# could exist in another suite
|
||||
mtr_error("Test '$full_name' was not found in suite '$sname'")
|
||||
if $sname;
|
||||
|
||||
next;
|
||||
}
|
||||
$component_id= $exts{$extension};
|
||||
}
|
||||
else
|
||||
{
|
||||
# No extension was specified
|
||||
my ($ext, $component);
|
||||
while (($ext, $component)= each %exts) {
|
||||
my $full_name= "$testdir/$tname.$ext";
|
||||
|
||||
if ( ! -f $full_name ) {
|
||||
next;
|
||||
}
|
||||
$component_id= $component;
|
||||
$extension= $ext;
|
||||
}
|
||||
# Test not found here, could exist in other suite
|
||||
next unless $component_id;
|
||||
}
|
||||
|
||||
collect_one_test_case($testdir,$resdir,$suite,$tname,
|
||||
"$tname.$extension",\@cases,\%disabled,
|
||||
$component_id,$suite_opts);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
opendir(TESTDIR, $testdir) or mtr_error("Can't open dir \"$testdir\": $!");
|
||||
|
||||
foreach my $elem ( sort readdir(TESTDIR) )
|
||||
{
|
||||
my $component_id= undef;
|
||||
my $tname= undef;
|
||||
|
||||
if ($tname= mtr_match_extension($elem, 'test'))
|
||||
{
|
||||
$component_id = 'mysqld';
|
||||
}
|
||||
elsif ($tname= mtr_match_extension($elem, 'imtest'))
|
||||
{
|
||||
$component_id = 'im';
|
||||
}
|
||||
else
|
||||
{
|
||||
next;
|
||||
}
|
||||
|
||||
# Skip tests that does not match the --do-test= filter
|
||||
next if ($do_test and not $tname =~ /$do_test/o);
|
||||
|
||||
collect_one_test_case($testdir,$resdir,$suite,$tname,
|
||||
$elem,\@cases,\%disabled,$component_id,
|
||||
$suite_opts);
|
||||
}
|
||||
closedir TESTDIR;
|
||||
}
|
||||
|
||||
|
||||
# Return empty list if no testcases found
|
||||
return if (@cases == 0);
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Read combinations for this suite and build testcases x combinations
|
||||
# if any combinations exists
|
||||
# ----------------------------------------------------------------------
|
||||
if ( ! $::opt_skip_combination )
|
||||
{
|
||||
my @combinations;
|
||||
my $combination_file= "$suitedir/combinations";
|
||||
#print "combination_file: $combination_file\n";
|
||||
if (@::opt_combinations)
|
||||
{
|
||||
# take the combination from command-line
|
||||
mtr_verbose("Take the combination from command line");
|
||||
foreach my $combination (@::opt_combinations) {
|
||||
my $comb= {};
|
||||
$comb->{name}= $combination;
|
||||
push(@{$comb->{comb_opt}}, $combination);
|
||||
push(@combinations, $comb);
|
||||
}
|
||||
}
|
||||
elsif (-f $combination_file )
|
||||
{
|
||||
# Read combinations file in my.cnf format
|
||||
mtr_verbose("Read combinations file");
|
||||
my $config= My::Config->new($combination_file);
|
||||
|
||||
foreach my $group ($config->groups()) {
|
||||
my $comb= {};
|
||||
$comb->{name}= $group->name();
|
||||
foreach my $option ( $group->options() ) {
|
||||
push(@{$comb->{comb_opt}}, $option->name()."=".$option->value());
|
||||
}
|
||||
push(@combinations, $comb);
|
||||
}
|
||||
}
|
||||
|
||||
if (@combinations)
|
||||
{
|
||||
print " - adding combinations\n";
|
||||
#print_testcases(@cases);
|
||||
|
||||
my @new_cases;
|
||||
foreach my $comb (@combinations)
|
||||
{
|
||||
foreach my $test (@cases)
|
||||
{
|
||||
#print $test->{name}, " ", $comb, "\n";
|
||||
my $new_test= {};
|
||||
|
||||
while (my ($key, $value) = each(%$test)) {
|
||||
if (ref $value eq "ARRAY") {
|
||||
push(@{$new_test->{$key}}, @$value);
|
||||
} else {
|
||||
$new_test->{$key}= $value;
|
||||
}
|
||||
}
|
||||
|
||||
# Append the combination options to master_opt and slave_opt
|
||||
push(@{$new_test->{master_opt}}, @{$comb->{comb_opt}});
|
||||
push(@{$new_test->{slave_opt}}, @{$comb->{comb_opt}});
|
||||
|
||||
# Add combination name shrt name
|
||||
$new_test->{combination}= $comb->{name};
|
||||
|
||||
# Add the new test to new test cases list
|
||||
push(@new_cases, $new_test);
|
||||
}
|
||||
}
|
||||
#print_testcases(@new_cases);
|
||||
@cases= @new_cases;
|
||||
#print_testcases(@cases);
|
||||
}
|
||||
}
|
||||
|
||||
optimize_cases(\@cases);
|
||||
#print_testcases(@cases);
|
||||
|
||||
return @cases;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Loop through all test cases
|
||||
# - optimize which test to run by skipping unnecessary ones
|
||||
# - update settings if necessary
|
||||
#
|
||||
sub optimize_cases {
|
||||
my ($cases)= @_;
|
||||
|
||||
foreach my $tinfo ( @$cases )
|
||||
{
|
||||
# Skip processing if already marked as skipped
|
||||
next if $tinfo->{skip};
|
||||
|
||||
# Replication test needs an adjustment of binlog format
|
||||
if (mtr_match_prefix($tinfo->{'name'}, "rpl"))
|
||||
{
|
||||
|
||||
# =======================================================
|
||||
# Get binlog-format used by this test from master_opt
|
||||
# =======================================================
|
||||
my $test_binlog_format;
|
||||
foreach my $opt ( @{$tinfo->{master_opt}} ) {
|
||||
$test_binlog_format= $test_binlog_format ||
|
||||
mtr_match_prefix($opt, "--binlog-format=");
|
||||
}
|
||||
# print $tinfo->{name}." uses ".$test_binlog_format."\n";
|
||||
|
||||
# =======================================================
|
||||
# If a special binlog format was selected with
|
||||
# --mysqld=--binlog-format=x, skip all test with different
|
||||
# binlog-format
|
||||
# =======================================================
|
||||
if (defined $::used_binlog_format and
|
||||
$test_binlog_format and
|
||||
$::used_binlog_format ne $test_binlog_format)
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "Requires --binlog-format='$test_binlog_format'";
|
||||
next;
|
||||
}
|
||||
|
||||
# =======================================================
|
||||
# Check that testcase supports the designated binlog-format
|
||||
# =======================================================
|
||||
if ($test_binlog_format and defined $tinfo->{'sup_binlog_formats'} )
|
||||
{
|
||||
my $supported=
|
||||
grep { $_ eq $test_binlog_format } @{$tinfo->{'sup_binlog_formats'}};
|
||||
if ( !$supported )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}=
|
||||
"Doesn't support --binlog-format='$test_binlog_format'";
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
# =======================================================
|
||||
# Use dynamic switching of binlog-format if mtr started
|
||||
# w/o --mysqld=--binlog-format=xxx and combinations.
|
||||
# =======================================================
|
||||
if (!defined $tinfo->{'combination'} and
|
||||
!defined $::used_binlog_format)
|
||||
{
|
||||
$test_binlog_format= $tinfo->{'sup_binlog_formats'}->[0];
|
||||
}
|
||||
|
||||
# Save binlog format for dynamic switching
|
||||
$tinfo->{binlog_format}= $test_binlog_format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Collect information about a single test case
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
sub collect_one_test_case($$$$$$$$$) {
|
||||
my $testdir= shift;
|
||||
my $resdir= shift;
|
||||
my $suite= shift;
|
||||
my $tname= shift;
|
||||
my $elem= shift;
|
||||
my $cases= shift;
|
||||
my $disabled=shift;
|
||||
my $component_id= shift;
|
||||
my $suite_opts= shift;
|
||||
|
||||
my $path= "$testdir/$elem";
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Skip some tests silently
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
if ( $::opt_start_from and $tname lt $::opt_start_from )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
my $tinfo= {};
|
||||
$tinfo->{'name'}= basename($suite) . ".$tname";
|
||||
$tinfo->{'result_file'}= "$resdir/$tname.result";
|
||||
$tinfo->{'component_id'} = $component_id;
|
||||
push(@$cases, $tinfo);
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Skip some tests but include in list, just mark them to skip
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
if ( $skip_test and $tname =~ /$skip_test/o )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Collect information about test case
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
$tinfo->{'path'}= $path;
|
||||
$tinfo->{'timezone'}= "GMT-3"; # for UNIX_TIMESTAMP tests to work
|
||||
|
||||
$tinfo->{'slave_num'}= 0; # Default, no slave
|
||||
$tinfo->{'master_num'}= 1; # Default, 1 master
|
||||
if ( defined mtr_match_prefix($tname,"rpl") )
|
||||
{
|
||||
if ( $::opt_skip_rpl )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "No replication tests(--skip-rpl)";
|
||||
return;
|
||||
}
|
||||
|
||||
$tinfo->{'slave_num'}= 1; # Default for rpl* tests, use one slave
|
||||
|
||||
}
|
||||
|
||||
if ( defined mtr_match_prefix($tname,"federated") )
|
||||
{
|
||||
# Default, federated uses the first slave as it's federated database
|
||||
$tinfo->{'slave_num'}= 1;
|
||||
}
|
||||
|
||||
my $master_opt_file= "$testdir/$tname-master.opt";
|
||||
my $slave_opt_file= "$testdir/$tname-slave.opt";
|
||||
my $slave_mi_file= "$testdir/$tname.slave-mi";
|
||||
my $master_sh= "$testdir/$tname-master.sh";
|
||||
my $slave_sh= "$testdir/$tname-slave.sh";
|
||||
my $disabled_file= "$testdir/$tname.disabled";
|
||||
my $im_opt_file= "$testdir/$tname-im.opt";
|
||||
|
||||
$tinfo->{'master_opt'}= [];
|
||||
$tinfo->{'slave_opt'}= [];
|
||||
$tinfo->{'slave_mi'}= [];
|
||||
|
||||
|
||||
# Add suite opts
|
||||
foreach my $opt ( @$suite_opts )
|
||||
{
|
||||
mtr_verbose($opt);
|
||||
push(@{$tinfo->{'master_opt'}}, $opt);
|
||||
push(@{$tinfo->{'slave_opt'}}, $opt);
|
||||
}
|
||||
|
||||
# Add master opts
|
||||
if ( -f $master_opt_file )
|
||||
{
|
||||
|
||||
my $master_opt= mtr_get_opts_from_file($master_opt_file);
|
||||
|
||||
foreach my $opt ( @$master_opt )
|
||||
{
|
||||
my $value;
|
||||
|
||||
# The opt file is used both to send special options to the mysqld
|
||||
# as well as pass special test case specific options to this
|
||||
# script
|
||||
|
||||
$value= mtr_match_prefix($opt, "--timezone=");
|
||||
if ( defined $value )
|
||||
{
|
||||
$tinfo->{'timezone'}= $value;
|
||||
next;
|
||||
}
|
||||
|
||||
$value= mtr_match_prefix($opt, "--slave-num=");
|
||||
if ( defined $value )
|
||||
{
|
||||
$tinfo->{'slave_num'}= $value;
|
||||
next;
|
||||
}
|
||||
|
||||
$value= mtr_match_prefix($opt, "--result-file=");
|
||||
if ( defined $value )
|
||||
{
|
||||
# Specifies the file mysqltest should compare
|
||||
# output against
|
||||
$tinfo->{'result_file'}= "r/$value.result";
|
||||
next;
|
||||
}
|
||||
|
||||
# If we set default time zone, remove the one we have
|
||||
$value= mtr_match_prefix($opt, "--default-time-zone=");
|
||||
if ( defined $value )
|
||||
{
|
||||
# Set timezone for this test case to something different
|
||||
$tinfo->{'timezone'}= "GMT-8";
|
||||
# Fallthrough, add the --default-time-zone option
|
||||
}
|
||||
|
||||
# The --restart option forces a restart even if no special
|
||||
# option is set. If the options are the same as next testcase
|
||||
# there is no need to restart after the testcase
|
||||
# has completed
|
||||
if ( $opt eq "--force-restart" )
|
||||
{
|
||||
$tinfo->{'force_restart'}= 1;
|
||||
next;
|
||||
}
|
||||
|
||||
# Ok, this was a real option, add it
|
||||
push(@{$tinfo->{'master_opt'}}, $opt);
|
||||
}
|
||||
}
|
||||
|
||||
# Add slave opts
|
||||
if ( -f $slave_opt_file )
|
||||
{
|
||||
my $slave_opt= mtr_get_opts_from_file($slave_opt_file);
|
||||
|
||||
foreach my $opt ( @$slave_opt )
|
||||
{
|
||||
# If we set default time zone, remove the one we have
|
||||
my $value= mtr_match_prefix($opt, "--default-time-zone=");
|
||||
$tinfo->{'slave_opt'}= [] if defined $value;
|
||||
}
|
||||
push(@{$tinfo->{'slave_opt'}}, @$slave_opt);
|
||||
}
|
||||
|
||||
if ( -f $slave_mi_file )
|
||||
{
|
||||
$tinfo->{'slave_mi'}= mtr_get_opts_from_file($slave_mi_file);
|
||||
}
|
||||
|
||||
if ( -f $master_sh )
|
||||
{
|
||||
if ( $::glob_win32_perl )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "No tests with sh scripts on Windows";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
$tinfo->{'master_sh'}= $master_sh;
|
||||
}
|
||||
}
|
||||
|
||||
if ( -f $slave_sh )
|
||||
{
|
||||
if ( $::glob_win32_perl )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "No tests with sh scripts on Windows";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
$tinfo->{'slave_sh'}= $slave_sh;
|
||||
}
|
||||
}
|
||||
|
||||
if ( -f $im_opt_file )
|
||||
{
|
||||
$tinfo->{'im_opts'} = mtr_get_opts_from_file($im_opt_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
$tinfo->{'im_opts'} = [];
|
||||
}
|
||||
|
||||
# FIXME why this late?
|
||||
my $marked_as_disabled= 0;
|
||||
if ( $disabled->{$tname} )
|
||||
{
|
||||
$marked_as_disabled= 1;
|
||||
$tinfo->{'comment'}= $disabled->{$tname};
|
||||
}
|
||||
|
||||
if ( -f $disabled_file )
|
||||
{
|
||||
$marked_as_disabled= 1;
|
||||
$tinfo->{'comment'}= mtr_fromfile($disabled_file);
|
||||
}
|
||||
|
||||
# If test was marked as disabled, either opt_enable_disabled is off and then
|
||||
# we skip this test, or it is on and then we run this test but warn
|
||||
|
||||
if ( $marked_as_disabled )
|
||||
{
|
||||
if ( $::opt_enable_disabled )
|
||||
{
|
||||
$tinfo->{'dont_skip_though_disabled'}= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'disable'}= 1; # Sub type of 'skip'
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $component_id eq 'im' )
|
||||
{
|
||||
if ( $::glob_use_embedded_server )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "No IM with embedded server";
|
||||
return;
|
||||
}
|
||||
elsif ( $::opt_ps_protocol )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "No IM with --ps-protocol";
|
||||
return;
|
||||
}
|
||||
elsif ( $::opt_skip_im )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "No IM tests(--skip-im)";
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_options_from_test_file($tinfo,"$testdir/${tname}.test");
|
||||
|
||||
if ( defined $::used_default_engine )
|
||||
{
|
||||
# Different default engine is used
|
||||
# tag test to require that engine
|
||||
$tinfo->{'ndb_test'}= 1
|
||||
if ( $::used_default_engine =~ /^ndb/i );
|
||||
|
||||
$tinfo->{'innodb_test'}= 1
|
||||
if ( $::used_default_engine =~ /^innodb/i );
|
||||
}
|
||||
|
||||
#enable federated for this test
|
||||
if ($tinfo->{'federated_test'})
|
||||
{
|
||||
push(@{$tinfo->{'master_opt'}}, "--loose-federated");
|
||||
push(@{$tinfo->{'slave_opt'}}, "--loose-federated");
|
||||
}
|
||||
|
||||
if ( $tinfo->{'big_test'} and ! $::opt_big_test )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "Test need 'big-test' option";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $tinfo->{'ndb_extra'} and ! $::opt_ndb_extra_test )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "Test need 'ndb_extra' option";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $tinfo->{'require_manager'} )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "Test need the _old_ manager(to be removed)";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $tinfo->{'need_debug'} && ! $::debug_compiled_binaries )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "Test need debug binaries";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $tinfo->{'ndb_test'} )
|
||||
{
|
||||
# This is a NDB test
|
||||
if ( ! $::glob_ndbcluster_supported )
|
||||
{
|
||||
# Ndb is not supported, skip it
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "No ndbcluster support";
|
||||
return;
|
||||
}
|
||||
elsif ( $::opt_skip_ndbcluster )
|
||||
{
|
||||
# All ndb test's should be skipped
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "No ndbcluster tests(--skip-ndbcluster)";
|
||||
return;
|
||||
}
|
||||
# Ndb tests run with two mysqld masters
|
||||
$tinfo->{'master_num'}= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
# This is not a ndb test
|
||||
if ( $::opt_with_ndbcluster_only )
|
||||
{
|
||||
# Only the ndb test should be run, all other should be skipped
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "Only ndbcluster tests(--with-ndbcluster-only)";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $tinfo->{'innodb_test'} )
|
||||
{
|
||||
# This is a test that need innodb
|
||||
if ( $::mysqld_variables{'innodb'} ne "TRUE" )
|
||||
{
|
||||
# innodb is not supported, skip it
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "No innodb support";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $tinfo->{'need_binlog'} )
|
||||
{
|
||||
if (grep(/^--skip-log-bin/, @::opt_extra_mysqld_opt) )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "Test need binlog";
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $::mysql_version_id >= 50100 )
|
||||
{
|
||||
# Test does not need binlog, add --skip-binlog to
|
||||
# the options used when starting it
|
||||
push(@{$tinfo->{'master_opt'}}, "--skip-log-bin");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# List of tags in the .test files that if found should set
|
||||
# the specified value in "tinfo"
|
||||
our @tags=
|
||||
(
|
||||
["include/have_innodb.inc", "innodb_test", 1],
|
||||
["include/have_binlog_format_row.inc", "sup_binlog_formats", ["row"]],
|
||||
["include/have_log_bin.inc", "need_binlog", 1],
|
||||
["include/have_binlog_format_statement.inc",
|
||||
"sup_binlog_formats", ["statement"]],
|
||||
["include/have_binlog_format_mixed.inc", "sup_binlog_formats", ["mixed"]],
|
||||
["include/have_binlog_format_mixed_or_row.inc",
|
||||
"sup_binlog_formats", ["mixed","row"]],
|
||||
["include/have_binlog_format_mixed_or_statement.inc",
|
||||
"sup_binlog_formats", ["mixed","statement"]],
|
||||
["include/have_binlog_format_row_or_statement.inc",
|
||||
"sup_binlog_formats", ["row","statement"]],
|
||||
["include/big_test.inc", "big_test", 1],
|
||||
["include/have_debug.inc", "need_debug", 1],
|
||||
["include/have_ndb.inc", "ndb_test", 1],
|
||||
["include/have_multi_ndb.inc", "ndb_test", 1],
|
||||
["include/have_ndb_extra.inc", "ndb_extra", 1],
|
||||
["include/ndb_master-slave.inc", "ndb_test", 1],
|
||||
["require_manager", "require_manager", 1],
|
||||
["include/federated.inc", "federated_test", 1],
|
||||
["include/have_federated_db.inc", "federated_test", 1],
|
||||
);
|
||||
|
||||
sub mtr_options_from_test_file($$) {
|
||||
my $tinfo= shift;
|
||||
my $file= shift;
|
||||
#mtr_verbose("$file");
|
||||
my $F= IO::File->new($file) or mtr_error("can't open file \"$file\": $!");
|
||||
|
||||
while ( my $line= <$F> )
|
||||
{
|
||||
|
||||
# Skip line if it start's with #
|
||||
next if ( $line =~ /^#/ );
|
||||
|
||||
# Match this line against tag in "tags" array
|
||||
foreach my $tag (@tags)
|
||||
{
|
||||
if ( index($line, $tag->[0]) >= 0 )
|
||||
{
|
||||
# Tag matched, assign value to "tinfo"
|
||||
$tinfo->{"$tag->[1]"}= $tag->[2];
|
||||
}
|
||||
}
|
||||
|
||||
# If test sources another file, open it as well
|
||||
if ( $line =~ /^\-\-([[:space:]]*)source(.*)$/ or
|
||||
$line =~ /^([[:space:]]*)source(.*);$/ )
|
||||
{
|
||||
my $value= $2;
|
||||
$value =~ s/^\s+//; # Remove leading space
|
||||
$value =~ s/[[:space:]]+$//; # Remove ending space
|
||||
|
||||
my $sourced_file= "$::glob_mysql_test_dir/$value";
|
||||
if ( -f $sourced_file )
|
||||
{
|
||||
# Only source the file if it exists, we may get
|
||||
# false positives in the regexes above if someone
|
||||
# writes "source nnnn;" in a test case(such as mysqltest.test)
|
||||
mtr_options_from_test_file($tinfo, $sourced_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub print_testcases {
|
||||
my (@cases)= @_;
|
||||
|
||||
print "=" x 60, "\n";
|
||||
foreach my $test (@cases){
|
||||
print "[", $test->{name}, "]", "\n";
|
||||
while ((my ($key, $value)) = each(%$test)) {
|
||||
print " ", $key, "=";
|
||||
if (ref $value eq "ARRAY") {
|
||||
print join(", ", @$value);
|
||||
} else {
|
||||
print $value;
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
print "=" x 60, "\n";
|
||||
}
|
||||
|
||||
|
||||
1;
|
1113
mysql-test/lib/mtr_cases.pm
Normal file
1113
mysql-test/lib/mtr_cases.pm
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,297 +0,0 @@
|
|||
# -*- cperl -*-
|
||||
# Copyright (C) 2005 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 Data::Dumper;
|
||||
use strict;
|
||||
|
||||
# $Data::Dumper::Indent= 1;
|
||||
|
||||
sub mtr_diff($$);
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# This is a simplified unified diff, with some special handling
|
||||
# of unsorted result sets
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# FIXME replace die with mtr_error
|
||||
|
||||
#require "mtr_report.pl";
|
||||
#mtr_diff("a.txt","b.txt");
|
||||
|
||||
sub mtr_diff ($$) {
|
||||
my $file1 = shift;
|
||||
my $file2 = shift;
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# We read in all of the files at once
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
unless ( open(FILE1, $file1) )
|
||||
{
|
||||
mtr_warning("can't open \"$file1\": $!");
|
||||
return;
|
||||
}
|
||||
|
||||
unless ( open(FILE2, $file2) )
|
||||
{
|
||||
mtr_warning("can't open \"$file2\": $!");
|
||||
return;
|
||||
}
|
||||
|
||||
my $lines1= collect_lines(<FILE1>);
|
||||
my $lines2= collect_lines(<FILE2>);
|
||||
close FILE1;
|
||||
close FILE2;
|
||||
|
||||
# print Dumper($lines1);
|
||||
# print Dumper($lines2);
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# We compare line by line, but don't shift off elements until we know
|
||||
# what to do. This way we use the "restart" method, do simple change
|
||||
# and restart by entering the diff loop from the beginning again.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
my @context;
|
||||
my @info; # Collect information, and output later
|
||||
my $lno1= 1;
|
||||
my $lno2= 1;
|
||||
|
||||
while ( @$lines1 or @$lines2 )
|
||||
{
|
||||
unless ( @$lines1 )
|
||||
{
|
||||
push(@info, map {['+',$lno1,$lno2++,$_]} @$lines2);
|
||||
last;
|
||||
}
|
||||
unless ( @$lines2 )
|
||||
{
|
||||
push(@info, map {['-',$lno1++,$lno2,$_]} @$lines1);
|
||||
last;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# We know both have lines
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
if ( $lines1->[0] eq $lines2->[0] )
|
||||
{
|
||||
# Simple case, first line match and all is well
|
||||
push(@info, ['',$lno1++,$lno2++,$lines1->[0]]);
|
||||
shift @$lines1;
|
||||
shift @$lines2;
|
||||
next;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Now, we know they differ
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# How far in the other one, is there a match?
|
||||
|
||||
my $idx2= find_next_match($lines1->[0], $lines2);
|
||||
my $idx1= find_next_match($lines2->[0], $lines1);
|
||||
|
||||
# Here we could test "if ( !defined $idx2 or !defined $idx1 )" and
|
||||
# use a more complicated diff algorithm in the case both contains
|
||||
# each others lines, just dislocated. But for this application, there
|
||||
# should be no need.
|
||||
|
||||
if ( !defined $idx2 )
|
||||
{
|
||||
push(@info, ['-',$lno1++,$lno2,$lines1->[0]]);
|
||||
shift @$lines1;
|
||||
}
|
||||
else
|
||||
{
|
||||
push(@info, ['+',$lno1,$lno2++,$lines2->[0]]);
|
||||
shift @$lines2;
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Try to output nicely
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# print Dumper(\@info);
|
||||
|
||||
# We divide into "chunks" to output
|
||||
# We want at least three lines of context
|
||||
|
||||
my @chunks;
|
||||
my @chunk;
|
||||
my $state= 'pre'; # 'pre', 'in' and 'post' difference
|
||||
my $post_count= 0;
|
||||
|
||||
foreach my $info ( @info )
|
||||
{
|
||||
if ( $info->[0] eq '' and $state eq 'pre' )
|
||||
{
|
||||
# Collect no more than three lines of context before diff
|
||||
push(@chunk, $info);
|
||||
shift(@chunk) if @chunk > 3;
|
||||
next;
|
||||
}
|
||||
|
||||
if ( $info->[0] =~ /(\+|\-)/ and $state =~ /(pre|in)/ )
|
||||
{
|
||||
# Start/continue collecting diff
|
||||
$state= 'in';
|
||||
push(@chunk, $info);
|
||||
next;
|
||||
}
|
||||
|
||||
if ( $info->[0] eq '' and $state eq 'in' )
|
||||
{
|
||||
# Stop collecting diff, and collect context after diff
|
||||
$state= 'post';
|
||||
$post_count= 1;
|
||||
push(@chunk, $info);
|
||||
next;
|
||||
}
|
||||
|
||||
if ( $info->[0] eq '' and $state eq 'post' and $post_count < 6 )
|
||||
{
|
||||
# We might find a new diff sequence soon, continue to collect
|
||||
# non diffs but five up on 6.
|
||||
$post_count++;
|
||||
push(@chunk, $info);
|
||||
next;
|
||||
}
|
||||
|
||||
if ( $info->[0] eq '' and $state eq 'post' )
|
||||
{
|
||||
# We put an end to this, giving three non diff lines to
|
||||
# the old chunk, and three to the new one.
|
||||
my @left= splice(@chunk, -3, 3);
|
||||
push(@chunks, [@chunk]);
|
||||
$state= 'pre';
|
||||
$post_count= 0;
|
||||
@chunk= @left;
|
||||
next;
|
||||
}
|
||||
|
||||
if ( $info->[0] =~ /(\+|\-)/ and $state eq 'post' )
|
||||
{
|
||||
# We didn't split, continue collect diff
|
||||
$state= 'in';
|
||||
push(@chunk, $info);
|
||||
next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( $post_count > 3 )
|
||||
{
|
||||
$post_count -= 3;
|
||||
splice(@chunk, -$post_count, $post_count);
|
||||
}
|
||||
push(@chunks, [@chunk]) if @chunk and $state ne 'pre';
|
||||
|
||||
foreach my $chunk ( @chunks )
|
||||
{
|
||||
my $from_file_start= $chunk->[0]->[1];
|
||||
my $to_file_start= $chunk->[0]->[2];
|
||||
my $from_file_offset= $chunk->[$#$chunk]->[1] - $from_file_start;
|
||||
my $to_file_offset= $chunk->[$#$chunk]->[2] - $to_file_start;
|
||||
print "\@\@ -$from_file_start,$from_file_offset ",
|
||||
"+$to_file_start,$to_file_offset \@\@\n";
|
||||
|
||||
foreach my $info ( @$chunk )
|
||||
{
|
||||
if ( $info->[0] eq '' )
|
||||
{
|
||||
print " $info->[3]\n";
|
||||
}
|
||||
elsif ( $info->[0] eq '-' )
|
||||
{
|
||||
print "- $info->[3]\n";
|
||||
}
|
||||
elsif ( $info->[0] eq '+' )
|
||||
{
|
||||
print "+ $info->[3]\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# print Dumper(\@chunks);
|
||||
|
||||
}
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Find if the string is found in the array, return the index if found,
|
||||
# if not found, return "undef"
|
||||
##############################################################################
|
||||
|
||||
sub find_next_match {
|
||||
my $line= shift;
|
||||
my $lines= shift;
|
||||
|
||||
for ( my $idx= 0; $idx < @$lines; $idx++ )
|
||||
{
|
||||
return $idx if $lines->[$idx] eq $line;
|
||||
}
|
||||
|
||||
return undef; # No match found
|
||||
}
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Just read the lines, but handle "sets" of lines that are unordered
|
||||
##############################################################################
|
||||
|
||||
sub collect_lines {
|
||||
|
||||
my @recordset;
|
||||
my @lines;
|
||||
|
||||
while (@_)
|
||||
{
|
||||
my $line= shift @_;
|
||||
chomp($line);
|
||||
|
||||
if ( $line =~ /^\Q%unordered%\E\t/ )
|
||||
{
|
||||
push(@recordset, $line);
|
||||
}
|
||||
elsif ( @recordset )
|
||||
{
|
||||
push(@lines, sort @recordset);
|
||||
@recordset= (); # Clear it
|
||||
}
|
||||
else
|
||||
{
|
||||
push(@lines, $line);
|
||||
}
|
||||
}
|
||||
|
||||
if ( @recordset )
|
||||
{
|
||||
push(@lines, sort @recordset);
|
||||
@recordset= (); # Clear it
|
||||
}
|
||||
|
||||
return \@lines;
|
||||
}
|
||||
|
||||
1;
|
|
@ -1,775 +0,0 @@
|
|||
# -*- cperl -*-
|
||||
# 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
|
||||
|
||||
# This is a library file used by the Perl version of mysql-test-run,
|
||||
# and is part of the translation of the Bourne shell script with the
|
||||
# same name.
|
||||
|
||||
use strict;
|
||||
|
||||
# Private IM-related operations.
|
||||
|
||||
sub mtr_im_kill_process ($$$$);
|
||||
sub mtr_im_load_pids ($);
|
||||
sub mtr_im_terminate ($);
|
||||
sub mtr_im_check_alive ($);
|
||||
sub mtr_im_check_main_alive ($);
|
||||
sub mtr_im_check_angel_alive ($);
|
||||
sub mtr_im_check_mysqlds_alive ($);
|
||||
sub mtr_im_check_mysqld_alive ($);
|
||||
sub mtr_im_cleanup ($);
|
||||
sub mtr_im_rm_file ($);
|
||||
sub mtr_im_errlog ($);
|
||||
sub mtr_im_kill ($);
|
||||
sub mtr_im_wait_for_connection ($$$);
|
||||
sub mtr_im_wait_for_mysqld($$$);
|
||||
|
||||
# Public IM-related operations.
|
||||
|
||||
sub mtr_im_start ($$);
|
||||
sub mtr_im_stop ($);
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Private operations.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
sub mtr_im_kill_process ($$$$) {
|
||||
my $pid_lst= shift;
|
||||
my $signal= shift;
|
||||
my $total_retries= shift;
|
||||
my $timeout= shift;
|
||||
|
||||
my %pids;
|
||||
|
||||
foreach my $pid ( @{$pid_lst} )
|
||||
{
|
||||
$pids{$pid}= 1;
|
||||
}
|
||||
|
||||
for ( my $cur_attempt= 1; $cur_attempt <= $total_retries; ++$cur_attempt )
|
||||
{
|
||||
foreach my $pid ( keys %pids )
|
||||
{
|
||||
mtr_debug("Sending $signal to $pid...");
|
||||
|
||||
kill($signal, $pid);
|
||||
|
||||
unless ( kill (0, $pid) )
|
||||
{
|
||||
mtr_debug("Process $pid died.");
|
||||
delete $pids{$pid};
|
||||
}
|
||||
}
|
||||
|
||||
return if scalar keys %pids == 0;
|
||||
|
||||
mtr_debug("Sleeping $timeout second(s) waiting for processes to die...");
|
||||
|
||||
sleep($timeout);
|
||||
}
|
||||
|
||||
mtr_debug("Process(es) " .
|
||||
join(' ', keys %pids) .
|
||||
" is still alive after $total_retries " .
|
||||
"of sending signal $signal.");
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_load_pids($) {
|
||||
my $im= shift;
|
||||
|
||||
mtr_debug("Loading PID files...");
|
||||
|
||||
# Obtain mysqld-process pids.
|
||||
|
||||
my $instances = $im->{'instances'};
|
||||
|
||||
for ( my $idx= 0; $idx < 2; ++$idx )
|
||||
{
|
||||
mtr_debug("IM-guarded mysqld[$idx] PID file: '" .
|
||||
$instances->[$idx]->{'path_pid'} . "'.");
|
||||
|
||||
my $mysqld_pid;
|
||||
|
||||
if ( -r $instances->[$idx]->{'path_pid'} )
|
||||
{
|
||||
$mysqld_pid= mtr_get_pid_from_file($instances->[$idx]->{'path_pid'});
|
||||
mtr_debug("IM-guarded mysqld[$idx] PID: $mysqld_pid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
$mysqld_pid= undef;
|
||||
mtr_debug("IM-guarded mysqld[$idx]: no PID file.");
|
||||
}
|
||||
|
||||
$instances->[$idx]->{'pid'}= $mysqld_pid;
|
||||
}
|
||||
|
||||
# Re-read Instance Manager PIDs from the file, since during tests Instance
|
||||
# Manager could have been restarted, so its PIDs could have been changed.
|
||||
|
||||
# - IM-main
|
||||
|
||||
mtr_debug("IM-main PID file: '$im->{path_pid}'.");
|
||||
|
||||
if ( -f $im->{'path_pid'} )
|
||||
{
|
||||
$im->{'pid'} =
|
||||
mtr_get_pid_from_file($im->{'path_pid'});
|
||||
|
||||
mtr_debug("IM-main PID: $im->{pid}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("IM-main: no PID file.");
|
||||
$im->{'pid'}= undef;
|
||||
}
|
||||
|
||||
# - IM-angel
|
||||
|
||||
mtr_debug("IM-angel PID file: '$im->{path_angel_pid}'.");
|
||||
|
||||
if ( -f $im->{'path_angel_pid'} )
|
||||
{
|
||||
$im->{'angel_pid'} =
|
||||
mtr_get_pid_from_file($im->{'path_angel_pid'});
|
||||
|
||||
mtr_debug("IM-angel PID: $im->{'angel_pid'}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("IM-angel: no PID file.");
|
||||
$im->{'angel_pid'} = undef;
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_terminate($) {
|
||||
my $im= shift;
|
||||
|
||||
# Load pids from pid-files. We should do it first of all, because IM deletes
|
||||
# them on shutdown.
|
||||
|
||||
mtr_im_load_pids($im);
|
||||
|
||||
mtr_debug("Shutting Instance Manager down...");
|
||||
|
||||
# Ignoring SIGCHLD so that all children could rest in peace.
|
||||
|
||||
start_reap_all();
|
||||
|
||||
# Send SIGTERM to IM-main.
|
||||
|
||||
if ( defined $im->{'pid'} )
|
||||
{
|
||||
mtr_debug("IM-main pid: $im->{pid}.");
|
||||
mtr_debug("Stopping IM-main...");
|
||||
|
||||
mtr_im_kill_process([ $im->{'pid'} ], 'TERM', 10, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("IM-main pid: n/a.");
|
||||
}
|
||||
|
||||
# If IM-angel was alive, wait for it to die.
|
||||
|
||||
if ( defined $im->{'angel_pid'} )
|
||||
{
|
||||
mtr_debug("IM-angel pid: $im->{'angel_pid'}.");
|
||||
mtr_debug("Waiting for IM-angel to die...");
|
||||
|
||||
my $total_attempts= 10;
|
||||
|
||||
for ( my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt )
|
||||
{
|
||||
unless ( kill (0, $im->{'angel_pid'}) )
|
||||
{
|
||||
mtr_debug("IM-angel died.");
|
||||
last;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("IM-angel pid: n/a.");
|
||||
}
|
||||
|
||||
stop_reap_all();
|
||||
|
||||
# Re-load PIDs.
|
||||
|
||||
mtr_im_load_pids($im);
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_check_alive($) {
|
||||
my $im= shift;
|
||||
|
||||
mtr_debug("Checking whether IM-components are alive...");
|
||||
|
||||
return 1 if mtr_im_check_main_alive($im);
|
||||
|
||||
return 1 if mtr_im_check_angel_alive($im);
|
||||
|
||||
return 1 if mtr_im_check_mysqlds_alive($im);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_check_main_alive($) {
|
||||
my $im= shift;
|
||||
|
||||
# Check that the process, that we know to be IM's, is dead.
|
||||
|
||||
if ( defined $im->{'pid'} )
|
||||
{
|
||||
if ( kill (0, $im->{'pid'}) )
|
||||
{
|
||||
mtr_debug("IM-main (PID: $im->{pid}) is alive.");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("IM-main (PID: $im->{pid}) is dead.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("No PID file for IM-main.");
|
||||
}
|
||||
|
||||
# Check that IM does not accept client connections.
|
||||
|
||||
if ( mtr_ping_port($im->{'port'}) )
|
||||
{
|
||||
mtr_debug("IM-main (port: $im->{port}) " .
|
||||
"is accepting connections.");
|
||||
|
||||
mtr_im_errlog("IM-main is accepting connections on port " .
|
||||
"$im->{port}, but there is no " .
|
||||
"process information.");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("IM-main (port: $im->{port}) " .
|
||||
"does not accept connections.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_check_angel_alive($) {
|
||||
my $im= shift;
|
||||
|
||||
# Check that the process, that we know to be the Angel, is dead.
|
||||
|
||||
if ( defined $im->{'angel_pid'} )
|
||||
{
|
||||
if ( kill (0, $im->{'angel_pid'}) )
|
||||
{
|
||||
mtr_debug("IM-angel (PID: $im->{angel_pid}) is alive.");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("IM-angel (PID: $im->{angel_pid}) is dead.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("No PID file for IM-angel.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_check_mysqlds_alive($) {
|
||||
my $im= shift;
|
||||
|
||||
mtr_debug("Checking for IM-guarded mysqld instances...");
|
||||
|
||||
my $instances = $im->{'instances'};
|
||||
|
||||
for ( my $idx= 0; $idx < 2; ++$idx )
|
||||
{
|
||||
mtr_debug("Checking mysqld[$idx]...");
|
||||
|
||||
return 1
|
||||
if mtr_im_check_mysqld_alive($instances->[$idx]);
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_check_mysqld_alive($) {
|
||||
my $mysqld_instance= shift;
|
||||
|
||||
# Check that the process is dead.
|
||||
|
||||
if ( defined $mysqld_instance->{'pid'} )
|
||||
{
|
||||
if ( kill (0, $mysqld_instance->{'pid'}) )
|
||||
{
|
||||
mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is alive.");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is dead.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("No PID file for mysqld instance.");
|
||||
}
|
||||
|
||||
# Check that mysqld does not accept client connections.
|
||||
|
||||
if ( mtr_ping_port($mysqld_instance->{'port'}) )
|
||||
{
|
||||
mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " .
|
||||
"is accepting connections.");
|
||||
|
||||
mtr_im_errlog("Mysqld is accepting connections on port " .
|
||||
"$mysqld_instance->{port}, but there is no " .
|
||||
"process information.");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " .
|
||||
"does not accept connections.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_cleanup($) {
|
||||
my $im= shift;
|
||||
|
||||
mtr_im_rm_file($im->{'path_pid'});
|
||||
mtr_im_rm_file($im->{'path_sock'});
|
||||
|
||||
mtr_im_rm_file($im->{'path_angel_pid'});
|
||||
|
||||
for ( my $idx= 0; $idx < 2; ++$idx )
|
||||
{
|
||||
mtr_im_rm_file($im->{'instances'}->[$idx]->{'path_pid'});
|
||||
mtr_im_rm_file($im->{'instances'}->[$idx]->{'path_sock'});
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_rm_file($)
|
||||
{
|
||||
my $file_path= shift;
|
||||
|
||||
if ( -f $file_path )
|
||||
{
|
||||
mtr_debug("Removing '$file_path'...");
|
||||
|
||||
unless ( unlink($file_path) )
|
||||
{
|
||||
mtr_warning("Can not remove '$file_path'.")
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("File '$file_path' does not exist already.");
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_errlog($) {
|
||||
my $msg= shift;
|
||||
|
||||
# Complain in error log so that a warning will be shown.
|
||||
#
|
||||
# TODO: unless BUG#20761 is fixed, we will print the warning to stdout, so
|
||||
# that it can be seen on console and does not produce pushbuild error.
|
||||
|
||||
# my $errlog= "$opt_vardir/log/mysql-test-run.pl.err";
|
||||
#
|
||||
# open (ERRLOG, ">>$errlog") ||
|
||||
# mtr_error("Can not open error log ($errlog)");
|
||||
#
|
||||
# my $ts= localtime();
|
||||
# print ERRLOG
|
||||
# "Warning: [$ts] $msg\n";
|
||||
#
|
||||
# close ERRLOG;
|
||||
|
||||
my $ts= localtime();
|
||||
print "Warning: [$ts] $msg\n";
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
sub mtr_im_kill($) {
|
||||
my $im= shift;
|
||||
|
||||
# Re-load PIDs. That can be useful because some processes could have been
|
||||
# restarted.
|
||||
|
||||
mtr_im_load_pids($im);
|
||||
|
||||
# Ignoring SIGCHLD so that all children could rest in peace.
|
||||
|
||||
start_reap_all();
|
||||
|
||||
# Kill IM-angel first of all.
|
||||
|
||||
if ( defined $im->{'angel_pid'} )
|
||||
{
|
||||
mtr_debug("Killing IM-angel (PID: $im->{angel_pid})...");
|
||||
mtr_im_kill_process([ $im->{'angel_pid'} ], 'KILL', 10, 1)
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("IM-angel is dead.");
|
||||
}
|
||||
|
||||
# Re-load PIDs again.
|
||||
|
||||
mtr_im_load_pids($im);
|
||||
|
||||
# Kill IM-main.
|
||||
|
||||
if ( defined $im->{'pid'} )
|
||||
{
|
||||
mtr_debug("Killing IM-main (PID: $im->pid})...");
|
||||
mtr_im_kill_process([ $im->{'pid'} ], 'KILL', 10, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_debug("IM-main is dead.");
|
||||
}
|
||||
|
||||
# Re-load PIDs again.
|
||||
|
||||
mtr_im_load_pids($im);
|
||||
|
||||
# Kill guarded mysqld instances.
|
||||
|
||||
my @mysqld_pids;
|
||||
|
||||
mtr_debug("Collecting PIDs of mysqld instances to kill...");
|
||||
|
||||
for ( my $idx= 0; $idx < 2; ++$idx )
|
||||
{
|
||||
my $pid= $im->{'instances'}->[$idx]->{'pid'};
|
||||
|
||||
unless ( defined $pid )
|
||||
{
|
||||
next;
|
||||
}
|
||||
|
||||
mtr_debug(" - IM-guarded mysqld[$idx] PID: $pid.");
|
||||
|
||||
push (@mysqld_pids, $pid);
|
||||
}
|
||||
|
||||
if ( scalar @mysqld_pids > 0 )
|
||||
{
|
||||
mtr_debug("Killing IM-guarded mysqld instances...");
|
||||
mtr_im_kill_process(\@mysqld_pids, 'KILL', 10, 1);
|
||||
}
|
||||
|
||||
# That's all.
|
||||
|
||||
stop_reap_all();
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
|
||||
sub mtr_im_wait_for_connection($$$) {
|
||||
my $im= shift;
|
||||
my $total_attempts= shift;
|
||||
my $connect_timeout= shift;
|
||||
|
||||
mtr_debug("Waiting for IM on port $im->{port} " .
|
||||
"to start accepting connections...");
|
||||
|
||||
for ( my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt )
|
||||
{
|
||||
mtr_debug("Trying to connect to IM ($cur_attempt of $total_attempts)...");
|
||||
|
||||
if ( mtr_ping_port($im->{'port'}) )
|
||||
{
|
||||
mtr_debug("IM is accepting connections " .
|
||||
"on port $im->{port}.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
mtr_debug("Sleeping $connect_timeout...");
|
||||
sleep($connect_timeout);
|
||||
}
|
||||
|
||||
mtr_debug("IM does not accept connections " .
|
||||
"on port $im->{port} after " .
|
||||
($total_attempts * $connect_timeout) . " seconds.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
|
||||
sub mtr_im_wait_for_mysqld($$$) {
|
||||
my $mysqld= shift;
|
||||
my $total_attempts= shift;
|
||||
my $connect_timeout= shift;
|
||||
|
||||
mtr_debug("Waiting for IM-guarded mysqld on port $mysqld->{port} " .
|
||||
"to start accepting connections...");
|
||||
|
||||
for ( my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt )
|
||||
{
|
||||
mtr_debug("Trying to connect to mysqld " .
|
||||
"($cur_attempt of $total_attempts)...");
|
||||
|
||||
if ( mtr_ping_port($mysqld->{'port'}) )
|
||||
{
|
||||
mtr_debug("Mysqld is accepting connections " .
|
||||
"on port $mysqld->{port}.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
mtr_debug("Sleeping $connect_timeout...");
|
||||
sleep($connect_timeout);
|
||||
}
|
||||
|
||||
mtr_debug("Mysqld does not accept connections " .
|
||||
"on port $mysqld->{port} after " .
|
||||
($total_attempts * $connect_timeout) . " seconds.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Public operations.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
sub mtr_im_start($$) {
|
||||
my $im = shift;
|
||||
my $opts = shift;
|
||||
|
||||
mtr_debug("Starting Instance Manager...");
|
||||
|
||||
my $args;
|
||||
mtr_init_args(\$args);
|
||||
mtr_add_arg($args, "--defaults-file=%s", $im->{'defaults_file'});
|
||||
|
||||
foreach my $opt ( @{$opts} )
|
||||
{
|
||||
mtr_add_arg($args, $opt);
|
||||
}
|
||||
|
||||
$im->{'spawner_pid'} =
|
||||
mtr_spawn(
|
||||
$::exe_im, # path to the executable
|
||||
$args, # cmd-line args
|
||||
'', # stdin
|
||||
$im->{'path_log'}, # stdout
|
||||
$im->{'path_err'}, # stderr
|
||||
'', # pid file path (not used)
|
||||
{ append_log_file => 1 } # append log files
|
||||
);
|
||||
|
||||
unless ( $im->{'spawner_pid'} )
|
||||
{
|
||||
mtr_error('Could not start Instance Manager.')
|
||||
}
|
||||
|
||||
# Instance Manager can be run in daemon mode. In this case, it creates
|
||||
# several processes and the parent process, created by mtr_spawn(), exits just
|
||||
# after start. So, we have to obtain Instance Manager PID from the PID file.
|
||||
|
||||
mtr_debug("Waiting for IM to create PID file (" .
|
||||
"path: '$im->{path_pid}'; " .
|
||||
"timeout: $im->{start_timeout})...");
|
||||
|
||||
unless ( sleep_until_file_created($im->{'path_pid'},
|
||||
$im->{'start_timeout'},
|
||||
-1) ) # real PID is still unknown
|
||||
{
|
||||
mtr_debug("IM has not created PID file in $im->{start_timeout} secs.");
|
||||
mtr_debug("Aborting test suite...");
|
||||
|
||||
mtr_kill_leftovers();
|
||||
|
||||
mtr_report("IM has not created PID file in $im->{start_timeout} secs.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
$im->{'pid'}= mtr_get_pid_from_file($im->{'path_pid'});
|
||||
|
||||
mtr_debug("Instance Manager started. PID: $im->{pid}.");
|
||||
|
||||
# Wait until we can connect to IM.
|
||||
|
||||
my $IM_CONNECT_TIMEOUT= 30;
|
||||
|
||||
unless ( mtr_im_wait_for_connection($im,
|
||||
$IM_CONNECT_TIMEOUT, 1) )
|
||||
{
|
||||
mtr_debug("Can not connect to Instance Manager " .
|
||||
"in $IM_CONNECT_TIMEOUT seconds after start.");
|
||||
mtr_debug("Aborting test suite...");
|
||||
|
||||
mtr_kill_leftovers();
|
||||
|
||||
mtr_report("Can not connect to Instance Manager " .
|
||||
"in $IM_CONNECT_TIMEOUT seconds after start.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Wait for IM to start guarded instances:
|
||||
# - wait for PID files;
|
||||
|
||||
mtr_debug("Waiting for guarded mysqlds instances to create PID files...");
|
||||
|
||||
for ( my $idx= 0; $idx < 2; ++$idx )
|
||||
{
|
||||
my $mysqld= $im->{'instances'}->[$idx];
|
||||
|
||||
if ( exists $mysqld->{'nonguarded'} )
|
||||
{
|
||||
next;
|
||||
}
|
||||
|
||||
mtr_debug("Waiting for mysqld[$idx] to create PID file (" .
|
||||
"path: '$mysqld->{path_pid}'; " .
|
||||
"timeout: $mysqld->{start_timeout})...");
|
||||
|
||||
unless ( sleep_until_file_created($mysqld->{'path_pid'},
|
||||
$mysqld->{'start_timeout'},
|
||||
-1) ) # real PID is still unknown
|
||||
{
|
||||
mtr_debug("mysqld[$idx] has not created PID file in " .
|
||||
"$mysqld->{start_timeout} secs.");
|
||||
mtr_debug("Aborting test suite...");
|
||||
|
||||
mtr_kill_leftovers();
|
||||
|
||||
mtr_report("mysqld[$idx] has not created PID file in " .
|
||||
"$mysqld->{start_timeout} secs.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mtr_debug("PID file for mysqld[$idx] ($mysqld->{path_pid} created.");
|
||||
}
|
||||
|
||||
# Wait until we can connect to guarded mysqld-instances
|
||||
# (in other words -- wait for IM to start guarded instances).
|
||||
|
||||
mtr_debug("Waiting for guarded mysqlds to start accepting connections...");
|
||||
|
||||
for ( my $idx= 0; $idx < 2; ++$idx )
|
||||
{
|
||||
my $mysqld= $im->{'instances'}->[$idx];
|
||||
|
||||
if ( exists $mysqld->{'nonguarded'} )
|
||||
{
|
||||
next;
|
||||
}
|
||||
|
||||
mtr_debug("Waiting for mysqld[$idx] to accept connection...");
|
||||
|
||||
unless ( mtr_im_wait_for_mysqld($mysqld, 30, 1) )
|
||||
{
|
||||
mtr_debug("Can not connect to mysqld[$idx] " .
|
||||
"in $IM_CONNECT_TIMEOUT seconds after start.");
|
||||
mtr_debug("Aborting test suite...");
|
||||
|
||||
mtr_kill_leftovers();
|
||||
|
||||
mtr_report("Can not connect to mysqld[$idx] " .
|
||||
"in $IM_CONNECT_TIMEOUT seconds after start.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mtr_debug("mysqld[$idx] started.");
|
||||
}
|
||||
|
||||
mtr_debug("Instance Manager and its components are up and running.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
|
||||
sub mtr_im_stop($) {
|
||||
my $im= shift;
|
||||
|
||||
mtr_debug("Stopping Instance Manager...");
|
||||
|
||||
# Try graceful shutdown.
|
||||
|
||||
mtr_im_terminate($im);
|
||||
|
||||
# Check that all processes died.
|
||||
|
||||
unless ( mtr_im_check_alive($im) )
|
||||
{
|
||||
mtr_debug("Instance Manager has been stopped successfully.");
|
||||
mtr_im_cleanup($im);
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Instance Manager don't want to die. We should kill it.
|
||||
|
||||
mtr_im_errlog("Instance Manager did not shutdown gracefully.");
|
||||
|
||||
mtr_im_kill($im);
|
||||
|
||||
# Check again that all IM-related processes have been killed.
|
||||
|
||||
my $im_is_alive= mtr_im_check_alive($im);
|
||||
|
||||
mtr_im_cleanup($im);
|
||||
|
||||
if ( $im_is_alive )
|
||||
{
|
||||
mtr_debug("Can not kill Instance Manager or its children.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mtr_debug("Instance Manager has been killed successfully.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
1;
|
|
@ -20,135 +20,14 @@
|
|||
|
||||
use strict;
|
||||
|
||||
sub mtr_get_pid_from_file ($);
|
||||
sub mtr_get_opts_from_file ($);
|
||||
sub mtr_fromfile ($);
|
||||
sub mtr_tofile ($@);
|
||||
sub mtr_tonewfile($@);
|
||||
sub mtr_lastlinefromfile($);
|
||||
sub mtr_appendfile_to_file ($$);
|
||||
sub mtr_grab_file($);
|
||||
sub mtr_printfile($);
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
sub mtr_get_pid_from_file ($) {
|
||||
my $pid_file_path= shift;
|
||||
my $TOTAL_ATTEMPTS= 30;
|
||||
my $timeout= 1;
|
||||
|
||||
# We should read from the file until we get correct pid. As it is
|
||||
# stated in BUG#21884, pid file can be empty at some moment. So, we should
|
||||
# read it until we get valid data.
|
||||
|
||||
for (my $cur_attempt= 1; $cur_attempt <= $TOTAL_ATTEMPTS; ++$cur_attempt)
|
||||
{
|
||||
mtr_debug("Reading pid file '$pid_file_path' " .
|
||||
"($cur_attempt of $TOTAL_ATTEMPTS)...");
|
||||
|
||||
open(FILE, '<', $pid_file_path)
|
||||
or mtr_error("can't open file \"$pid_file_path\": $!");
|
||||
|
||||
# Read pid number from file
|
||||
my $pid= <FILE>;
|
||||
chomp $pid;
|
||||
close FILE;
|
||||
|
||||
return $pid if $pid=~ /^(\d+)/;
|
||||
|
||||
mtr_debug("Pid file '$pid_file_path' does not yet contain pid number.\n" .
|
||||
"Sleeping $timeout second(s) more...");
|
||||
|
||||
sleep($timeout);
|
||||
}
|
||||
|
||||
mtr_error("Pid file '$pid_file_path' is corrupted. " .
|
||||
"Can not retrieve PID in " .
|
||||
($timeout * $TOTAL_ATTEMPTS) . " seconds.");
|
||||
}
|
||||
|
||||
sub mtr_get_opts_from_file ($) {
|
||||
my $file= shift;
|
||||
|
||||
open(FILE,"<",$file) or mtr_error("can't open file \"$file\": $!");
|
||||
my @args;
|
||||
while ( <FILE> )
|
||||
{
|
||||
chomp;
|
||||
|
||||
# --set-variable=init_connect=set @a='a\\0c'
|
||||
s/^\s+//; # Remove leading space
|
||||
s/\s+$//; # Remove ending space
|
||||
|
||||
# This is strange, but we need to fill whitespace inside
|
||||
# quotes with something, to remove later. We do this to
|
||||
# be able to split on space. Else, we have trouble with
|
||||
# options like
|
||||
#
|
||||
# --someopt="--insideopt1 --insideopt2"
|
||||
#
|
||||
# But still with this, we are not 100% sure it is right,
|
||||
# we need a shell to do it right.
|
||||
|
||||
# print STDERR "\n";
|
||||
# print STDERR "AAA: $_\n";
|
||||
|
||||
s/\'([^\'\"]*)\'/unspace($1,"\x0a")/ge;
|
||||
s/\"([^\'\"]*)\"/unspace($1,"\x0b")/ge;
|
||||
s/\'([^\'\"]*)\'/unspace($1,"\x0a")/ge;
|
||||
s/\"([^\'\"]*)\"/unspace($1,"\x0b")/ge;
|
||||
|
||||
# print STDERR "BBB: $_\n";
|
||||
|
||||
# foreach my $arg (/(--?\w.*?)(?=\s+--?\w|$)/)
|
||||
|
||||
# FIXME ENV vars should be expanded!!!!
|
||||
|
||||
foreach my $arg (split(/[ \t]+/))
|
||||
{
|
||||
$arg =~ tr/\x11\x0a\x0b/ \'\"/; # Put back real chars
|
||||
# The outermost quotes has to go
|
||||
$arg =~ s/^([^\'\"]*)\'(.*)\'([^\'\"]*)$/$1$2$3/
|
||||
or $arg =~ s/^([^\'\"]*)\"(.*)\"([^\'\"]*)$/$1$2$3/;
|
||||
$arg =~ s/\\\\/\\/g;
|
||||
|
||||
$arg =~ s/\$\{(\w+)\}/envsubst($1)/ge;
|
||||
$arg =~ s/\$(\w+)/envsubst($1)/ge;
|
||||
|
||||
# print STDERR "ARG: $arg\n";
|
||||
# Do not pass empty string since my_getopt is not capable to handle it.
|
||||
if (length($arg))
|
||||
{
|
||||
push(@args, $arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
close FILE;
|
||||
return \@args;
|
||||
}
|
||||
|
||||
sub envsubst {
|
||||
my $string= shift;
|
||||
|
||||
if ( ! defined $ENV{$string} )
|
||||
{
|
||||
mtr_error("opt file referense \$$string that is unknown");
|
||||
}
|
||||
|
||||
return $ENV{$string};
|
||||
}
|
||||
|
||||
sub unspace {
|
||||
my $string= shift;
|
||||
my $quote= shift;
|
||||
$string =~ s/[ \t]/\x11/g;
|
||||
return "$quote$string$quote";
|
||||
}
|
||||
|
||||
# Read a whole file, stripping leading and trailing whitespace.
|
||||
sub mtr_fromfile ($) {
|
||||
my $file= shift;
|
||||
|
@ -161,19 +40,6 @@ sub mtr_fromfile ($) {
|
|||
return $text;
|
||||
}
|
||||
|
||||
sub mtr_lastlinefromfile ($) {
|
||||
my $file= shift;
|
||||
my $text;
|
||||
|
||||
open(FILE,"<",$file) or mtr_error("can't open file \"$file\": $!");
|
||||
while (my $line= <FILE>)
|
||||
{
|
||||
$text= $line;
|
||||
}
|
||||
close FILE;
|
||||
return $text;
|
||||
}
|
||||
|
||||
|
||||
sub mtr_tofile ($@) {
|
||||
my $file= shift;
|
||||
|
@ -183,6 +49,7 @@ sub mtr_tofile ($@) {
|
|||
close FILE;
|
||||
}
|
||||
|
||||
|
||||
sub mtr_tonewfile ($@) {
|
||||
my $file= shift;
|
||||
|
||||
|
@ -191,6 +58,7 @@ sub mtr_tonewfile ($@) {
|
|||
close FILE;
|
||||
}
|
||||
|
||||
|
||||
sub mtr_appendfile_to_file ($$) {
|
||||
my $from_file= shift;
|
||||
my $to_file= shift;
|
||||
|
@ -203,6 +71,7 @@ sub mtr_appendfile_to_file ($$) {
|
|||
close TOFILE;
|
||||
}
|
||||
|
||||
|
||||
# Read a whole file verbatim.
|
||||
sub mtr_grab_file($) {
|
||||
my $file= shift;
|
||||
|
@ -215,4 +84,15 @@ sub mtr_grab_file($) {
|
|||
}
|
||||
|
||||
|
||||
# Print the file to STDOUT
|
||||
sub mtr_printfile($) {
|
||||
my $file= shift;
|
||||
open(FILE, '<', $file)
|
||||
or warn $!;
|
||||
print while(<FILE>);
|
||||
close FILE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
|
|
@ -18,20 +18,17 @@
|
|||
# and is part of the translation of the Bourne shell script with the
|
||||
# same name.
|
||||
|
||||
package mtr_match;
|
||||
use strict;
|
||||
|
||||
sub mtr_match_prefix ($$);
|
||||
sub mtr_match_extension ($$);
|
||||
sub mtr_match_any_exact ($$);
|
||||
use base qw(Exporter);
|
||||
our @EXPORT= qw(mtr_match_prefix
|
||||
mtr_match_extension
|
||||
mtr_match_substring);
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Match a prefix and return what is after the prefix
|
||||
|
||||
#
|
||||
sub mtr_match_prefix ($$) {
|
||||
my $string= shift;
|
||||
my $prefix= shift;
|
||||
|
@ -47,8 +44,9 @@ sub mtr_match_prefix ($$) {
|
|||
}
|
||||
|
||||
|
||||
#
|
||||
# Match extension and return the name without extension
|
||||
|
||||
#
|
||||
sub mtr_match_extension ($$) {
|
||||
my $file= shift;
|
||||
my $ext= shift;
|
||||
|
@ -64,8 +62,9 @@ sub mtr_match_extension ($$) {
|
|||
}
|
||||
|
||||
|
||||
#
|
||||
# Match a substring anywere in a string
|
||||
|
||||
#
|
||||
sub mtr_match_substring ($$) {
|
||||
my $string= shift;
|
||||
my $substring= shift;
|
|
@ -19,45 +19,25 @@
|
|||
# same name.
|
||||
|
||||
use strict;
|
||||
use File::Find;
|
||||
|
||||
sub mtr_native_path($);
|
||||
use My::Platform;
|
||||
|
||||
sub mtr_init_args ($);
|
||||
sub mtr_add_arg ($$@);
|
||||
sub mtr_args2str($@);
|
||||
sub mtr_path_exists(@);
|
||||
sub mtr_script_exists(@);
|
||||
sub mtr_file_exists(@);
|
||||
sub mtr_exe_exists(@);
|
||||
sub mtr_exe_maybe_exists(@);
|
||||
sub mtr_copy_dir($$);
|
||||
sub mtr_rmtree($);
|
||||
sub mtr_same_opts($$);
|
||||
sub mtr_cmp_opts($$);
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Misc
|
||||
# Args
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Convert path to OS native format
|
||||
sub mtr_native_path($)
|
||||
{
|
||||
my $path= shift;
|
||||
|
||||
# MySQL version before 5.0 still use cygwin, no need
|
||||
# to convert path
|
||||
return $path
|
||||
if ($::mysql_version_id < 50000);
|
||||
|
||||
$path=~ s/\//\\/g
|
||||
if ($::glob_win32);
|
||||
return $path;
|
||||
}
|
||||
|
||||
|
||||
# FIXME move to own lib
|
||||
|
||||
sub mtr_init_args ($) {
|
||||
my $args = shift;
|
||||
$$args = []; # Empty list
|
||||
|
@ -68,9 +48,18 @@ sub mtr_add_arg ($$@) {
|
|||
my $format= shift;
|
||||
my @fargs = @_;
|
||||
|
||||
# Quote args if args contain space
|
||||
$format= "\"$format\""
|
||||
if (IS_WINDOWS and grep(/\s/, @fargs));
|
||||
|
||||
push(@$args, sprintf($format, @fargs));
|
||||
}
|
||||
|
||||
sub mtr_args2str($@) {
|
||||
my $exe= shift or die;
|
||||
return join(" ", native_path($exe), @_);
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
|
||||
#
|
||||
|
@ -100,7 +89,7 @@ sub mtr_path_exists (@) {
|
|||
sub mtr_script_exists (@) {
|
||||
foreach my $path ( @_ )
|
||||
{
|
||||
if($::glob_win32)
|
||||
if(IS_WINDOWS)
|
||||
{
|
||||
return $path if -f $path;
|
||||
}
|
||||
|
@ -140,11 +129,10 @@ sub mtr_file_exists (@) {
|
|||
sub mtr_exe_maybe_exists (@) {
|
||||
my @path= @_;
|
||||
|
||||
map {$_.= ".exe"} @path if $::glob_win32;
|
||||
map {$_.= ".nlm"} @path if $::glob_netware;
|
||||
map {$_.= ".exe"} @path if IS_WINDOWS;
|
||||
foreach my $path ( @path )
|
||||
{
|
||||
if($::glob_win32)
|
||||
if(IS_WINDOWS)
|
||||
{
|
||||
return $path if -f $path;
|
||||
}
|
||||
|
@ -179,134 +167,11 @@ sub mtr_exe_exists (@) {
|
|||
}
|
||||
|
||||
|
||||
sub mtr_copy_dir($$) {
|
||||
my $from_dir= shift;
|
||||
my $to_dir= shift;
|
||||
sub mtr_milli_sleep {
|
||||
die "usage: mtr_milli_sleep(milliseconds)" unless @_ == 1;
|
||||
my ($millis)= @_;
|
||||
|
||||
# mtr_verbose("Copying from $from_dir to $to_dir");
|
||||
|
||||
mkpath("$to_dir");
|
||||
opendir(DIR, "$from_dir")
|
||||
or mtr_error("Can't find $from_dir$!");
|
||||
for(readdir(DIR)) {
|
||||
next if "$_" eq "." or "$_" eq "..";
|
||||
if ( -d "$from_dir/$_" )
|
||||
{
|
||||
mtr_copy_dir("$from_dir/$_", "$to_dir/$_");
|
||||
next;
|
||||
}
|
||||
copy("$from_dir/$_", "$to_dir/$_");
|
||||
}
|
||||
closedir(DIR);
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub mtr_rmtree($) {
|
||||
my ($dir)= @_;
|
||||
mtr_verbose("mtr_rmtree: $dir");
|
||||
|
||||
# Try to use File::Path::rmtree. Recent versions
|
||||
# handles removal of directories and files that don't
|
||||
# have full permissions, while older versions
|
||||
# may have a problem with that and we use our own version
|
||||
|
||||
eval { rmtree($dir); };
|
||||
if ( $@ ) {
|
||||
mtr_warning("rmtree($dir) failed, trying with File::Find...");
|
||||
|
||||
my $errors= 0;
|
||||
|
||||
# chmod
|
||||
find( {
|
||||
no_chdir => 1,
|
||||
wanted => sub {
|
||||
chmod(0777, $_)
|
||||
or mtr_warning("couldn't chmod(0777, $_): $!") and $errors++;
|
||||
}
|
||||
},
|
||||
$dir
|
||||
);
|
||||
|
||||
# rm
|
||||
finddepth( {
|
||||
no_chdir => 1,
|
||||
wanted => sub {
|
||||
my $file= $_;
|
||||
# Use special underscore (_) filehandle, caches stat info
|
||||
if (!-l $file and -d _ ) {
|
||||
rmdir($file) or
|
||||
mtr_warning("couldn't rmdir($file): $!") and $errors++;
|
||||
} else {
|
||||
unlink($file)
|
||||
or mtr_warning("couldn't unlink($file): $!") and $errors++;
|
||||
}
|
||||
}
|
||||
},
|
||||
$dir
|
||||
);
|
||||
|
||||
mtr_error("Failed to remove '$dir'") if $errors;
|
||||
|
||||
mtr_report("OK, that worked!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub mtr_same_opts ($$) {
|
||||
my $l1= shift;
|
||||
my $l2= shift;
|
||||
return mtr_cmp_opts($l1,$l2) == 0;
|
||||
}
|
||||
|
||||
sub mtr_cmp_opts ($$) {
|
||||
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
|
||||
}
|
||||
|
||||
#
|
||||
# Compare two arrays and put all unequal elements into a new one
|
||||
#
|
||||
sub mtr_diff_opts ($$) {
|
||||
my $l1= shift;
|
||||
my $l2= shift;
|
||||
my $f;
|
||||
my $l= [];
|
||||
foreach my $e1 (@$l1)
|
||||
{
|
||||
$f= undef;
|
||||
foreach my $e2 (@$l2)
|
||||
{
|
||||
$f= 1 unless ($e1 ne $e2);
|
||||
}
|
||||
push(@$l, $e1) unless (defined $f);
|
||||
}
|
||||
foreach my $e2 (@$l2)
|
||||
{
|
||||
$f= undef;
|
||||
foreach my $e1 (@$l1)
|
||||
{
|
||||
$f= 1 unless ($e1 ne $e2);
|
||||
}
|
||||
push(@$l, $e2) unless (defined $f);
|
||||
}
|
||||
return $l;
|
||||
select(undef, undef, undef, ($millis/1000));
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,588 +0,0 @@
|
|||
# -*- 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;
|
||||
use warnings;
|
||||
|
||||
sub mtr_report_test_name($);
|
||||
sub mtr_report_test_passed($);
|
||||
sub mtr_report_test_failed($);
|
||||
sub mtr_report_test_skipped($);
|
||||
sub mtr_report_test_not_skipped_though_disabled($);
|
||||
|
||||
sub mtr_report_stats ($);
|
||||
sub mtr_print_line ();
|
||||
sub mtr_print_thick_line ();
|
||||
sub mtr_print_header ();
|
||||
sub mtr_report (@);
|
||||
sub mtr_warning (@);
|
||||
sub mtr_error (@);
|
||||
sub mtr_child_error (@);
|
||||
sub mtr_debug (@);
|
||||
sub mtr_verbose (@);
|
||||
|
||||
my $tot_real_time= 0;
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
sub mtr_report_test_name ($) {
|
||||
my $tinfo= shift;
|
||||
my $tname= $tinfo->{name};
|
||||
|
||||
$tname.= " '$tinfo->{combination}'"
|
||||
if defined $tinfo->{combination};
|
||||
|
||||
_mtr_log($tname);
|
||||
printf "%-30s ", $tname;
|
||||
}
|
||||
|
||||
sub mtr_report_test_skipped ($) {
|
||||
my $tinfo= shift;
|
||||
|
||||
$tinfo->{'result'}= 'MTR_RES_SKIPPED';
|
||||
if ( $tinfo->{'disable'} )
|
||||
{
|
||||
mtr_report("[ disabled ] $tinfo->{'comment'}");
|
||||
}
|
||||
elsif ( $tinfo->{'comment'} )
|
||||
{
|
||||
mtr_report("[ skipped ] $tinfo->{'comment'}");
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_report("[ skipped ]");
|
||||
}
|
||||
}
|
||||
|
||||
sub mtr_report_tests_not_skipped_though_disabled ($) {
|
||||
my $tests= shift;
|
||||
|
||||
if ( $::opt_enable_disabled )
|
||||
{
|
||||
my @disabled_tests= grep {$_->{'dont_skip_though_disabled'}} @$tests;
|
||||
if ( @disabled_tests )
|
||||
{
|
||||
print "\nTest(s) which will be run though they are marked as disabled:\n";
|
||||
foreach my $tinfo ( sort {$a->{'name'} cmp $b->{'name'}} @disabled_tests )
|
||||
{
|
||||
printf " %-20s : %s\n", $tinfo->{'name'}, $tinfo->{'comment'};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub mtr_report_test_passed ($) {
|
||||
my $tinfo= shift;
|
||||
|
||||
my $timer= "";
|
||||
if ( $::opt_timer and -f "$::opt_vardir/log/timer" )
|
||||
{
|
||||
$timer= mtr_fromfile("$::opt_vardir/log/timer");
|
||||
$tot_real_time += ($timer/1000);
|
||||
$timer= sprintf "%12s", $timer;
|
||||
}
|
||||
$tinfo->{'result'}= 'MTR_RES_PASSED';
|
||||
mtr_report("[ pass ] $timer");
|
||||
}
|
||||
|
||||
sub mtr_report_test_failed ($) {
|
||||
my $tinfo= shift;
|
||||
|
||||
$tinfo->{'result'}= 'MTR_RES_FAILED';
|
||||
if ( defined $tinfo->{'timeout'} )
|
||||
{
|
||||
mtr_report("[ fail ] timeout");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_report("[ fail ]");
|
||||
}
|
||||
|
||||
if ( $tinfo->{'comment'} )
|
||||
{
|
||||
# The test failure has been detected by mysql-test-run.pl
|
||||
# when starting the servers or due to other error, the reason for
|
||||
# failing the test is saved in "comment"
|
||||
mtr_report("\nERROR: $tinfo->{'comment'}");
|
||||
}
|
||||
elsif ( -f $::path_timefile )
|
||||
{
|
||||
# Test failure was detected by test tool and it's report
|
||||
# about what failed has been saved to file. Display the report.
|
||||
print "\n";
|
||||
print mtr_fromfile($::path_timefile); # FIXME print_file() instead
|
||||
print "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
# Neither this script or the test tool has recorded info
|
||||
# about why the test has failed. Should be debugged.
|
||||
mtr_report("\nUnexpected termination, probably when starting mysqld");;
|
||||
}
|
||||
}
|
||||
|
||||
sub mtr_report_stats ($) {
|
||||
my $tests= shift;
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Find out how we where doing
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
my $tot_skiped= 0;
|
||||
my $tot_passed= 0;
|
||||
my $tot_failed= 0;
|
||||
my $tot_tests= 0;
|
||||
my $tot_restarts= 0;
|
||||
my $found_problems= 0; # Some warnings in the logfiles are errors...
|
||||
|
||||
foreach my $tinfo (@$tests)
|
||||
{
|
||||
if ( $tinfo->{'result'} eq 'MTR_RES_SKIPPED' )
|
||||
{
|
||||
$tot_skiped++;
|
||||
}
|
||||
elsif ( $tinfo->{'result'} eq 'MTR_RES_PASSED' )
|
||||
{
|
||||
$tot_tests++;
|
||||
$tot_passed++;
|
||||
}
|
||||
elsif ( $tinfo->{'result'} eq 'MTR_RES_FAILED' )
|
||||
{
|
||||
$tot_tests++;
|
||||
$tot_failed++;
|
||||
}
|
||||
if ( $tinfo->{'restarted'} )
|
||||
{
|
||||
$tot_restarts++;
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Print out a summary report to screen
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
if ( ! $tot_failed )
|
||||
{
|
||||
print "All $tot_tests tests were successful.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
my $ratio= $tot_passed * 100 / $tot_tests;
|
||||
print "Failed $tot_failed/$tot_tests tests, ";
|
||||
printf("%.2f", $ratio);
|
||||
print "\% were successful.\n\n";
|
||||
print
|
||||
"The log files in var/log may give you some hint\n",
|
||||
"of what went wrong.\n",
|
||||
"If you want to report this error, please read first ",
|
||||
"the documentation at\n",
|
||||
"http://dev.mysql.com/doc/mysql/en/mysql-test-suite.html\n";
|
||||
}
|
||||
if (!$::opt_extern)
|
||||
{
|
||||
print "The servers were restarted $tot_restarts times\n";
|
||||
}
|
||||
|
||||
if ( $::opt_timer )
|
||||
{
|
||||
use English;
|
||||
|
||||
mtr_report("Spent", sprintf("%.3f", $tot_real_time),"of",
|
||||
time - $BASETIME, "seconds executing testcases");
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# If a debug run, there might be interesting information inside
|
||||
# the "var/log/*.err" files. We save this info in "var/log/warnings"
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
if ( ! $::glob_use_running_server )
|
||||
{
|
||||
# Save and report if there was any fatal warnings/errors in err logs
|
||||
|
||||
my $warnlog= "$::opt_vardir/log/warnings";
|
||||
|
||||
unless ( open(WARN, ">$warnlog") )
|
||||
{
|
||||
mtr_warning("can't write to the file \"$warnlog\": $!");
|
||||
}
|
||||
else
|
||||
{
|
||||
# We report different types of problems in order
|
||||
foreach my $pattern ( "^Warning:",
|
||||
"\\[Warning\\]",
|
||||
"\\[ERROR\\]",
|
||||
"^Error:", "^==.* at 0x",
|
||||
"InnoDB: Warning",
|
||||
"InnoDB: Error",
|
||||
"^safe_mutex:",
|
||||
"missing DBUG_RETURN",
|
||||
"mysqld: Warning",
|
||||
"allocated at line",
|
||||
"Attempting backtrace", "Assertion .* failed" )
|
||||
{
|
||||
foreach my $errlog ( sort glob("$::opt_vardir/log/*.err") )
|
||||
{
|
||||
my $testname= "";
|
||||
unless ( open(ERR, $errlog) )
|
||||
{
|
||||
mtr_warning("can't read $errlog");
|
||||
next;
|
||||
}
|
||||
my $leak_reports_expected= undef;
|
||||
while ( <ERR> )
|
||||
{
|
||||
# There is a test case that purposely provokes a
|
||||
# SAFEMALLOC leak report, even though there is no actual
|
||||
# leak. We need to detect this, and ignore the warning in
|
||||
# that case.
|
||||
if (/Begin safemalloc memory dump:/) {
|
||||
$leak_reports_expected= 1;
|
||||
} elsif (/End safemalloc memory dump./) {
|
||||
$leak_reports_expected= undef;
|
||||
}
|
||||
|
||||
# Skip some non fatal warnings from the log files
|
||||
if (
|
||||
/\"SELECT UNIX_TIMESTAMP\(\)\" failed on master/ or
|
||||
/Aborted connection/ or
|
||||
/Client requested master to start replication from impossible position/ or
|
||||
/Could not find first log file name in binary log/ or
|
||||
/Enabling keys got errno/ or
|
||||
/Error reading master configuration/ or
|
||||
/Error reading packet/ or
|
||||
/Event Scheduler/ or
|
||||
/Failed to open log/ or
|
||||
/Failed to open the existing master info file/ or
|
||||
/Forcing shutdown of [0-9]* plugins/ or
|
||||
/Can't open shared library .*\bha_example\b/ or
|
||||
/Couldn't load plugin .*\bha_example\b/ or
|
||||
|
||||
# Due to timing issues, it might be that this warning
|
||||
# is printed when the server shuts down and the
|
||||
# computer is loaded.
|
||||
/Forcing close of thread \d+ user: '.*?'/ or
|
||||
|
||||
/Got error [0-9]* when reading table/ or
|
||||
/Incorrect definition of table/ or
|
||||
/Incorrect information in file/ or
|
||||
/InnoDB: Warning: we did not need to do crash recovery/ or
|
||||
/Invalid \(old\?\) table or database name/ or
|
||||
/Lock wait timeout exceeded/ or
|
||||
/Log entry on master is longer than max_allowed_packet/ or
|
||||
/unknown option '--loose-/ or
|
||||
/unknown variable 'loose-/ or
|
||||
/You have forced lower_case_table_names to 0 through a command-line option/ or
|
||||
/Setting lower_case_table_names=2/ or
|
||||
/NDB Binlog:/ or
|
||||
/NDB: failed to setup table/ or
|
||||
/NDB: only row based binary logging/ or
|
||||
/Neither --relay-log nor --relay-log-index were used/ or
|
||||
/Query partially completed/ or
|
||||
/Slave I.O thread aborted while waiting for relay log/ or
|
||||
/Slave SQL thread is stopped because UNTIL condition/ or
|
||||
/Slave SQL thread retried transaction/ or
|
||||
/Slave \(additional info\)/ or
|
||||
/Slave: .*Duplicate column name/ or
|
||||
/Slave: .*master may suffer from/ or
|
||||
/Slave: According to the master's version/ or
|
||||
/Slave: Column [0-9]* type mismatch/ or
|
||||
/Slave: Error .* doesn't exist/ or
|
||||
/Slave: Error .*Deadlock found/ or
|
||||
/Slave: Error .*Unknown table/ or
|
||||
/Slave: Error in Write_rows event: / or
|
||||
/Slave: Field .* of table .* has no default value/ or
|
||||
/Slave: Field .* doesn't have a default value/ or
|
||||
/Slave: Query caused different errors on master and slave/ or
|
||||
/Slave: Table .* doesn't exist/ or
|
||||
/Slave: Table width mismatch/ or
|
||||
/Slave: The incident LOST_EVENTS occured on the master/ or
|
||||
/Slave: Unknown error.* 1105/ or
|
||||
/Slave: Can't drop database.* database doesn't exist/ or
|
||||
/Slave SQL:.*(?:Error_code: \d+|Query:.*)/ or
|
||||
/Sort aborted/ or
|
||||
/Time-out in NDB/ or
|
||||
/One can only use the --user.*root/ or
|
||||
/Setting lower_case_table_names=2/ or
|
||||
/Table:.* on (delete|rename)/ or
|
||||
/You have an error in your SQL syntax/ or
|
||||
/deprecated/ or
|
||||
/description of time zone/ or
|
||||
/equal MySQL server ids/ or
|
||||
/error .*connecting to master/ or
|
||||
/error reading log entry/ or
|
||||
/lower_case_table_names is set/ or
|
||||
/skip-name-resolve mode/ or
|
||||
/slave SQL thread aborted/ or
|
||||
/Slave: .*Duplicate entry/ or
|
||||
# Special case for Bug #26402 in show_check.test
|
||||
# Question marks are not valid file name parts
|
||||
# on Windows platforms. Ignore this error message.
|
||||
/\QCan't find file: '.\test\????????.frm'\E/ or
|
||||
# Special case, made as specific as possible, for:
|
||||
# Bug #28436: Incorrect position in SHOW BINLOG EVENTS causes
|
||||
# server coredump
|
||||
/\QError in Log_event::read_log_event(): 'Sanity check failed', data_len: 258, event_type: 49\E/ or
|
||||
/Statement is not safe to log in statement format/ or
|
||||
|
||||
# test case for Bug#bug29807 copies a stray frm into database
|
||||
/InnoDB: Error: table `test`.`bug29807` does not exist in the InnoDB internal/ or
|
||||
/Cannot find or open table test\/bug29807 from/ or
|
||||
|
||||
# innodb foreign key tests that fail in ALTER or RENAME produce this
|
||||
/InnoDB: Error: in ALTER TABLE `test`.`t[12]`/ or
|
||||
/InnoDB: Error: in RENAME TABLE table `test`.`t1`/ or
|
||||
/InnoDB: Error: table `test`.`t[12]` does not exist in the InnoDB internal/ or
|
||||
|
||||
# Test case for Bug#14233 produces the following warnings:
|
||||
/Stored routine 'test'.'bug14233_1': invalid value in column mysql.proc/ or
|
||||
/Stored routine 'test'.'bug14233_2': invalid value in column mysql.proc/ or
|
||||
/Stored routine 'test'.'bug14233_3': invalid value in column mysql.proc/ or
|
||||
|
||||
# BUG#29839 - lowercase_table3.test: Cannot find table test/T1
|
||||
# from the internal data dictiona
|
||||
/Cannot find table test\/BUG29839 from the internal data dictionary/ or
|
||||
# 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'/ or
|
||||
|
||||
# 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/ or
|
||||
/Slave: Can't DROP 'c7'.* 1091/ or
|
||||
/Slave: Key column 'c6'.* 1072/ or
|
||||
|
||||
# rpl_idempotency.test produces warnings for the slave.
|
||||
($testname eq 'rpl.rpl_idempotency' and
|
||||
(/Slave: Can\'t find record in \'t1\' Error_code: 1032/ or
|
||||
/Slave: Cannot add or update a child row: a foreign key constraint fails .* Error_code: 1452/
|
||||
)) or
|
||||
|
||||
# These tests does "kill" on queries, causing sporadic errors when writing to logs
|
||||
(($testname eq 'rpl.rpl_skip_error' or
|
||||
$testname eq 'rpl.rpl_err_ignoredtable' or
|
||||
$testname eq 'binlog.binlog_killed_simulate' or
|
||||
$testname eq 'binlog.binlog_killed') and
|
||||
(/Failed to write to mysql\.\w+_log/
|
||||
)) or
|
||||
|
||||
# rpl_bug33931 has deliberate failures
|
||||
($testname eq 'rpl.rpl_bug33931' and
|
||||
(/Failed during slave.*thread initialization/
|
||||
)) or
|
||||
|
||||
# rpl_temporary has an error on slave that can be ignored
|
||||
($testname eq 'rpl.rpl_temporary' and
|
||||
(/Slave: Can\'t find record in \'user\' Error_code: 1032/
|
||||
)) or
|
||||
|
||||
# Test case for Bug#31590 produces the following error:
|
||||
/Out of sort memory; increase server sort buffer size/
|
||||
)
|
||||
{
|
||||
next; # Skip these lines
|
||||
}
|
||||
if ( /CURRENT_TEST: (.*)/ )
|
||||
{
|
||||
$testname= $1;
|
||||
}
|
||||
if ( /$pattern/ )
|
||||
{
|
||||
if ($leak_reports_expected) {
|
||||
next;
|
||||
}
|
||||
$found_problems= 1;
|
||||
print WARN basename($errlog) . ": $testname: $_";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $::opt_check_testcases )
|
||||
{
|
||||
# Look for warnings produced by mysqltest in testname.warnings
|
||||
foreach my $test_warning_file
|
||||
( glob("$::glob_mysql_test_dir/r/*.warnings") )
|
||||
{
|
||||
$found_problems= 1;
|
||||
print WARN "Check myqltest warnings in $test_warning_file\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( $found_problems )
|
||||
{
|
||||
mtr_warning("Got errors/warnings while running tests, please examine",
|
||||
"\"$warnlog\" for details.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "\n";
|
||||
|
||||
# Print a list of testcases that failed
|
||||
if ( $tot_failed != 0 )
|
||||
{
|
||||
my $test_mode= join(" ", @::glob_test_mode) || "default";
|
||||
print "mysql-test-run in $test_mode mode: *** Failing the test(s):";
|
||||
|
||||
foreach my $tinfo (@$tests)
|
||||
{
|
||||
if ( $tinfo->{'result'} eq 'MTR_RES_FAILED' )
|
||||
{
|
||||
print " $tinfo->{'name'}";
|
||||
}
|
||||
}
|
||||
print "\n";
|
||||
|
||||
}
|
||||
|
||||
# Print a list of check_testcases that failed(if any)
|
||||
if ( $::opt_check_testcases )
|
||||
{
|
||||
my @check_testcases= ();
|
||||
|
||||
foreach my $tinfo (@$tests)
|
||||
{
|
||||
if ( defined $tinfo->{'check_testcase_failed'} )
|
||||
{
|
||||
push(@check_testcases, $tinfo->{'name'});
|
||||
}
|
||||
}
|
||||
|
||||
if ( @check_testcases )
|
||||
{
|
||||
print "Check of testcase failed for: ";
|
||||
print join(" ", @check_testcases);
|
||||
print "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( $tot_failed != 0 || $found_problems)
|
||||
{
|
||||
mtr_error("there were failing test cases");
|
||||
}
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Text formatting
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
sub mtr_print_line () {
|
||||
print '-' x 55, "\n";
|
||||
}
|
||||
|
||||
sub mtr_print_thick_line () {
|
||||
print '=' x 55, "\n";
|
||||
}
|
||||
|
||||
sub mtr_print_header () {
|
||||
print "\n";
|
||||
if ( $::opt_timer )
|
||||
{
|
||||
print "TEST RESULT TIME (ms)\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print "TEST RESULT\n";
|
||||
}
|
||||
mtr_print_line();
|
||||
print "\n";
|
||||
}
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Log and reporting functions
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
use IO::File;
|
||||
|
||||
my $log_file_ref= undef;
|
||||
|
||||
sub mtr_log_init ($) {
|
||||
my ($filename)= @_;
|
||||
|
||||
mtr_error("Log is already open") if defined $log_file_ref;
|
||||
|
||||
$log_file_ref= IO::File->new($filename, "a") or
|
||||
mtr_warning("Could not create logfile $filename: $!");
|
||||
}
|
||||
|
||||
sub _mtr_log (@) {
|
||||
print $log_file_ref join(" ", @_),"\n"
|
||||
if defined $log_file_ref;
|
||||
}
|
||||
|
||||
sub mtr_report (@) {
|
||||
# Print message to screen and log
|
||||
_mtr_log(@_);
|
||||
print join(" ", @_),"\n";
|
||||
}
|
||||
|
||||
sub mtr_warning (@) {
|
||||
# Print message to screen and log
|
||||
_mtr_log("WARNING: ", @_);
|
||||
print STDERR "mysql-test-run: WARNING: ",join(" ", @_),"\n";
|
||||
}
|
||||
|
||||
sub mtr_error (@) {
|
||||
# Print message to screen and log
|
||||
_mtr_log("ERROR: ", @_);
|
||||
print STDERR "mysql-test-run: *** ERROR: ",join(" ", @_),"\n";
|
||||
mtr_exit(1);
|
||||
}
|
||||
|
||||
sub mtr_child_error (@) {
|
||||
# Print message to screen and log
|
||||
_mtr_log("ERROR(child): ", @_);
|
||||
print STDERR "mysql-test-run: *** ERROR(child): ",join(" ", @_),"\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sub mtr_debug (@) {
|
||||
# Only print if --script-debug is used
|
||||
if ( $::opt_script_debug )
|
||||
{
|
||||
_mtr_log("###: ", @_);
|
||||
print STDERR "####: ",join(" ", @_),"\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub mtr_verbose (@) {
|
||||
# Always print to log, print to screen only when --verbose is used
|
||||
_mtr_log("> ",@_);
|
||||
if ( $::opt_verbose )
|
||||
{
|
||||
print STDERR "> ",join(" ", @_),"\n";
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
451
mysql-test/lib/mtr_report.pm
Normal file
451
mysql-test/lib/mtr_report.pm
Normal file
|
@ -0,0 +1,451 @@
|
|||
# -*- 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.
|
||||
|
||||
package mtr_report;
|
||||
use strict;
|
||||
|
||||
use base qw(Exporter);
|
||||
our @EXPORT= qw(report_option mtr_print_line mtr_print_thick_line
|
||||
mtr_print_header mtr_report mtr_report_stats
|
||||
mtr_warning mtr_error mtr_debug mtr_verbose
|
||||
mtr_verbose_restart mtr_report_test_passed
|
||||
mtr_report_test_skipped mtr_print
|
||||
mtr_report_test);
|
||||
|
||||
use mtr_match;
|
||||
require "mtr_io.pl";
|
||||
|
||||
my $tot_real_time= 0;
|
||||
|
||||
our $timestamp= 0;
|
||||
our $timediff= 0;
|
||||
our $name;
|
||||
our $verbose;
|
||||
our $verbose_restart= 0;
|
||||
our $timer= 1;
|
||||
|
||||
sub report_option {
|
||||
my ($opt, $value)= @_;
|
||||
|
||||
# Convert - to _ in option name
|
||||
$opt =~ s/-/_/g;
|
||||
no strict 'refs';
|
||||
${$opt}= $value;
|
||||
|
||||
#print $name, " setting $opt to ", (defined $value? $value : "undef") ,"\n";
|
||||
}
|
||||
|
||||
sub _name {
|
||||
return $name ? $name." " : undef;
|
||||
}
|
||||
|
||||
sub _mtr_report_test_name ($) {
|
||||
my $tinfo= shift;
|
||||
my $tname= $tinfo->{name};
|
||||
|
||||
return unless defined $verbose;
|
||||
|
||||
# Add combination name if any
|
||||
$tname.= " '$tinfo->{combination}'"
|
||||
if defined $tinfo->{combination};
|
||||
|
||||
print _name(), _timestamp();
|
||||
printf "%-40s ", $tname;
|
||||
}
|
||||
|
||||
|
||||
sub mtr_report_test_skipped ($) {
|
||||
my ($tinfo)= @_;
|
||||
$tinfo->{'result'}= 'MTR_RES_SKIPPED';
|
||||
|
||||
mtr_report_test($tinfo);
|
||||
}
|
||||
|
||||
|
||||
sub mtr_report_test_passed ($) {
|
||||
my ($tinfo)= @_;
|
||||
|
||||
# Save the timer value
|
||||
my $timer_str= "";
|
||||
if ( $timer and -f "$::opt_vardir/log/timer" )
|
||||
{
|
||||
$timer_str= mtr_fromfile("$::opt_vardir/log/timer");
|
||||
$tinfo->{timer}= $timer_str;
|
||||
}
|
||||
|
||||
# Set as passed unless already set
|
||||
if ( not defined $tinfo->{'result'} ){
|
||||
$tinfo->{'result'}= 'MTR_RES_PASSED';
|
||||
}
|
||||
|
||||
mtr_report_test($tinfo);
|
||||
}
|
||||
|
||||
|
||||
sub mtr_report_test ($) {
|
||||
my ($tinfo)= @_;
|
||||
_mtr_report_test_name($tinfo);
|
||||
|
||||
if ($tinfo->{'result'} eq 'MTR_RES_FAILED'){
|
||||
|
||||
if ( defined $tinfo->{'warnings'} )
|
||||
{
|
||||
mtr_report("[ fail ] Found warnings in server log file!");
|
||||
mtr_report($tinfo->{'warnings'});
|
||||
return;
|
||||
}
|
||||
if ( defined $tinfo->{'timeout'} )
|
||||
{
|
||||
mtr_report("[ fail ] timeout");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_report("[ fail ]");
|
||||
}
|
||||
|
||||
if ( $tinfo->{'comment'} )
|
||||
{
|
||||
# The test failure has been detected by mysql-test-run.pl
|
||||
# when starting the servers or due to other error, the reason for
|
||||
# failing the test is saved in "comment"
|
||||
mtr_report("\nERROR: $tinfo->{'comment'}");
|
||||
}
|
||||
elsif ( $tinfo->{logfile} )
|
||||
{
|
||||
# Test failure was detected by test tool and its report
|
||||
# about what failed has been saved to file. Display the report.
|
||||
mtr_report("\n");
|
||||
mtr_report($tinfo->{logfile}, "\n");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
# Neither this script or the test tool has recorded info
|
||||
# about why the test has failed. Should be debugged.
|
||||
mtr_report("\nUnexpected termination, probably when starting mysqld");;
|
||||
}
|
||||
}
|
||||
elsif ($tinfo->{'result'} eq 'MTR_RES_SKIPPED')
|
||||
{
|
||||
if ( $tinfo->{'disable'} )
|
||||
{
|
||||
mtr_report("[ disabled ] $tinfo->{'comment'}");
|
||||
}
|
||||
elsif ( $tinfo->{'comment'} )
|
||||
{
|
||||
if ( $tinfo->{skip_detected_by_test} )
|
||||
{
|
||||
mtr_report("[ skip ]. $tinfo->{'comment'}");
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_report("[ skip ] $tinfo->{'comment'}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_report("[ skip ]");
|
||||
}
|
||||
}
|
||||
elsif ($tinfo->{'result'} eq 'MTR_RES_PASSED')
|
||||
{
|
||||
my $timer_str= $tinfo->{timer} || "";
|
||||
$tot_real_time += ($timer_str/1000);
|
||||
mtr_report("[ pass ] ", sprintf("%5s", $timer_str));
|
||||
|
||||
# Show any problems check-testcase found
|
||||
if ( defined $tinfo->{'check'} )
|
||||
{
|
||||
mtr_report($tinfo->{'check'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub mtr_report_stats ($) {
|
||||
my $tests= shift;
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Find out how we where doing
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
my $tot_skiped= 0;
|
||||
my $tot_passed= 0;
|
||||
my $tot_failed= 0;
|
||||
my $tot_tests= 0;
|
||||
my $tot_restarts= 0;
|
||||
my $found_problems= 0;
|
||||
|
||||
foreach my $tinfo (@$tests)
|
||||
{
|
||||
if ( $tinfo->{failures} )
|
||||
{
|
||||
# Test has failed at least one time
|
||||
$tot_tests++;
|
||||
$tot_failed++;
|
||||
}
|
||||
elsif ( $tinfo->{'result'} eq 'MTR_RES_SKIPPED' )
|
||||
{
|
||||
# Test was skipped
|
||||
$tot_skiped++;
|
||||
}
|
||||
elsif ( $tinfo->{'result'} eq 'MTR_RES_PASSED' )
|
||||
{
|
||||
# Test passed
|
||||
$tot_tests++;
|
||||
$tot_passed++;
|
||||
}
|
||||
|
||||
if ( $tinfo->{'restarted'} )
|
||||
{
|
||||
# Servers was restarted
|
||||
$tot_restarts++;
|
||||
}
|
||||
|
||||
# Look for warnings produced by mysqltest
|
||||
my $base_file= mtr_match_extension($tinfo->{'result_file'},
|
||||
"result"); # Trim extension
|
||||
my $warning_file= "$base_file.warnings";
|
||||
if ( -f $warning_file )
|
||||
{
|
||||
$found_problems= 1;
|
||||
mtr_warning("Check myqltest warnings in '$warning_file'");
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Print out a summary report to screen
|
||||
# ----------------------------------------------------------------------
|
||||
print "The servers were restarted $tot_restarts times\n";
|
||||
|
||||
if ( $timer )
|
||||
{
|
||||
use English;
|
||||
|
||||
mtr_report("Spent", sprintf("%.3f", $tot_real_time),"of",
|
||||
time - $BASETIME, "seconds executing testcases");
|
||||
}
|
||||
|
||||
|
||||
my $warnlog= "$::opt_vardir/log/warnings";
|
||||
if ( -f $warnlog )
|
||||
{
|
||||
mtr_warning("Got errors/warnings while running tests, please examine",
|
||||
"'$warnlog' for details.");
|
||||
}
|
||||
|
||||
print "\n";
|
||||
|
||||
# Print a list of check_testcases that failed(if any)
|
||||
if ( $::opt_check_testcases )
|
||||
{
|
||||
my %check_testcases;
|
||||
|
||||
foreach my $tinfo (@$tests)
|
||||
{
|
||||
if ( defined $tinfo->{'check_testcase_failed'} )
|
||||
{
|
||||
$check_testcases{$tinfo->{'name'}}= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( keys %check_testcases )
|
||||
{
|
||||
print "Check of testcase failed for: ";
|
||||
print join(" ", keys %check_testcases);
|
||||
print "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Print a list of testcases that failed
|
||||
if ( $tot_failed != 0 )
|
||||
{
|
||||
|
||||
# Print each failed test, again
|
||||
#foreach my $test ( @$tests ){
|
||||
# if ( $test->{failures} ) {
|
||||
# mtr_report_test($test);
|
||||
# }
|
||||
#}
|
||||
|
||||
my $ratio= $tot_passed * 100 / $tot_tests;
|
||||
print "Failed $tot_failed/$tot_tests tests, ";
|
||||
printf("%.2f", $ratio);
|
||||
print "\% were successful.\n\n";
|
||||
|
||||
# Print the list of test that failed in a format
|
||||
# that can be copy pasted to rerun only failing tests
|
||||
print "Failing test(s):";
|
||||
|
||||
my %seen= ();
|
||||
foreach my $tinfo (@$tests)
|
||||
{
|
||||
my $tname= $tinfo->{'name'};
|
||||
if ( $tinfo->{failures} and ! $seen{$tname})
|
||||
{
|
||||
print " $tname";
|
||||
$seen{$tname}= 1;
|
||||
}
|
||||
}
|
||||
print "\n\n";
|
||||
|
||||
# Print info about reporting the error
|
||||
print
|
||||
"The log files in var/log may give you some hint of what went wrong.\n\n",
|
||||
"If you want to report this error, please read first ",
|
||||
"the documentation\n",
|
||||
"at http://dev.mysql.com/doc/mysql/en/mysql-test-suite.html\n\n";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
print "All $tot_tests tests were successful.\n\n";
|
||||
}
|
||||
|
||||
if ( $tot_failed != 0 || $found_problems)
|
||||
{
|
||||
mtr_error("there were failing test cases");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Text formatting
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
sub mtr_print_line () {
|
||||
print '-' x 60, "\n";
|
||||
}
|
||||
|
||||
|
||||
sub mtr_print_thick_line {
|
||||
my $char= shift || '=';
|
||||
print $char x 60, "\n";
|
||||
}
|
||||
|
||||
|
||||
sub mtr_print_header () {
|
||||
print "\n";
|
||||
printf "TEST";
|
||||
print " " x 38;
|
||||
print "RESULT ";
|
||||
print "TIME (ms)" if $timer;
|
||||
print "\n";
|
||||
mtr_print_line();
|
||||
print "\n";
|
||||
}
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Log and reporting functions
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
use Time::localtime;
|
||||
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
my $t0= gettimeofday();
|
||||
|
||||
sub _timestamp {
|
||||
return "" unless $timestamp;
|
||||
|
||||
my $diff;
|
||||
if ($timediff){
|
||||
my $t1= gettimeofday();
|
||||
my $elapsed= $t1 - $t0;
|
||||
|
||||
$diff= sprintf(" +%02.3f", $elapsed);
|
||||
|
||||
# Save current time for next lap
|
||||
$t0= $t1;
|
||||
|
||||
}
|
||||
|
||||
my $tm= localtime();
|
||||
return sprintf("%02d%02d%02d %2d:%02d:%02d%s ",
|
||||
$tm->year % 100, $tm->mon+1, $tm->mday,
|
||||
$tm->hour, $tm->min, $tm->sec, $diff);
|
||||
}
|
||||
|
||||
# Always print message to screen
|
||||
sub mtr_print (@) {
|
||||
print _name(), join(" ", @_), "\n";
|
||||
}
|
||||
|
||||
|
||||
# Print message to screen if verbose is defined
|
||||
sub mtr_report (@) {
|
||||
if (defined $verbose)
|
||||
{
|
||||
print _name(), join(" ", @_), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Print warning to screen
|
||||
sub mtr_warning (@) {
|
||||
print STDERR _name(), _timestamp(),
|
||||
"mysql-test-run: WARNING: ", join(" ", @_), "\n";
|
||||
}
|
||||
|
||||
|
||||
# Print error to screen and then exit
|
||||
sub mtr_error (@) {
|
||||
print STDERR _name(), _timestamp(),
|
||||
"mysql-test-run: *** ERROR: ", join(" ", @_), "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
sub mtr_debug (@) {
|
||||
if ( $verbose > 2 )
|
||||
{
|
||||
print STDERR _name(),
|
||||
_timestamp(), "####: ", join(" ", @_), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub mtr_verbose (@) {
|
||||
if ( $verbose )
|
||||
{
|
||||
print STDERR _name(), _timestamp(),
|
||||
"> ",join(" ", @_),"\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub mtr_verbose_restart (@) {
|
||||
my ($server, @args)= @_;
|
||||
my $proc= $server->{proc};
|
||||
if ( $verbose_restart )
|
||||
{
|
||||
print STDERR _name(),_timestamp(),
|
||||
"> Restart $proc - ",join(" ", @args),"\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1;
|
|
@ -135,7 +135,7 @@ sub run_stress_test ()
|
|||
}
|
||||
|
||||
mtr_init_args(\$args);
|
||||
|
||||
mtr_add_args($args, "$::glob_mysql_test_dir/mysql-stress-test.pl");
|
||||
mtr_add_arg($args, "--server-socket=%s", $::master->[0]->{'path_sock'});
|
||||
mtr_add_arg($args, "--server-user=%s", $::opt_user);
|
||||
mtr_add_arg($args, "--server-database=%s", "test");
|
||||
|
@ -181,7 +181,13 @@ sub run_stress_test ()
|
|||
}
|
||||
|
||||
#Run stress test
|
||||
mtr_run("$::glob_mysql_test_dir/mysql-stress-test.pl", $args, "", "", "", "");
|
||||
My::SafeProcess->run
|
||||
(
|
||||
name => "stress test",
|
||||
path => $^X,
|
||||
args => \$args,
|
||||
);
|
||||
|
||||
if ( ! $::glob_use_embedded_server )
|
||||
{
|
||||
stop_all_servers();
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
# -*- cperl -*-
|
||||
# Copyright (C) 2005-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 Errno;
|
||||
use strict;
|
||||
|
||||
sub mtr_init_timers ();
|
||||
sub mtr_timer_start($$$);
|
||||
sub mtr_timer_stop($$);
|
||||
sub mtr_timer_stop_all($);
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Initiate the structure shared by all timers
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
sub mtr_init_timers () {
|
||||
my $timers = { timers => {}, pids => {}};
|
||||
return $timers;
|
||||
}
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Start, stop and poll a timer
|
||||
#
|
||||
# As alarm() isn't portable to Windows, we use separate processes to
|
||||
# implement timers.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
sub mtr_timer_start($$$) {
|
||||
my ($timers,$name,$duration)= @_;
|
||||
|
||||
if ( exists $timers->{'timers'}->{$name} )
|
||||
{
|
||||
# We have an old running timer, kill it
|
||||
mtr_warning("There is an old timer running");
|
||||
mtr_timer_stop($timers,$name);
|
||||
}
|
||||
|
||||
FORK:
|
||||
{
|
||||
my $tpid= fork();
|
||||
|
||||
if ( ! defined $tpid )
|
||||
{
|
||||
if ( $! == $!{EAGAIN} ) # See "perldoc Errno"
|
||||
{
|
||||
mtr_warning("Got EAGAIN from fork(), sleep 1 second and redo");
|
||||
sleep(1);
|
||||
redo FORK;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtr_error("can't fork timer, error: $!");
|
||||
}
|
||||
}
|
||||
|
||||
if ( $tpid )
|
||||
{
|
||||
# Parent, record the information
|
||||
mtr_verbose("Starting timer for '$name',",
|
||||
"duration: $duration, pid: $tpid");
|
||||
$timers->{'timers'}->{$name}->{'pid'}= $tpid;
|
||||
$timers->{'timers'}->{$name}->{'duration'}= $duration;
|
||||
$timers->{'pids'}->{$tpid}= $name;
|
||||
}
|
||||
else
|
||||
{
|
||||
# Child, install signal handlers and sleep for "duration"
|
||||
|
||||
# Don't do the ^C cleanup in the timeout child processes!
|
||||
# There is actually a race here, if we get ^C after fork(), but before
|
||||
# clearing the signal handler.
|
||||
$SIG{INT}= 'DEFAULT';
|
||||
|
||||
$SIG{TERM}= sub {
|
||||
mtr_verbose("timer $$ woke up, exiting!");
|
||||
exit(0);
|
||||
};
|
||||
|
||||
$0= "mtr_timer(timers,$name,$duration)";
|
||||
sleep($duration);
|
||||
mtr_verbose("timer $$ expired after $duration seconds");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub mtr_timer_stop ($$) {
|
||||
my ($timers,$name)= @_;
|
||||
|
||||
if ( exists $timers->{'timers'}->{$name} )
|
||||
{
|
||||
my $tpid= $timers->{'timers'}->{$name}->{'pid'};
|
||||
mtr_verbose("Stopping timer for '$name' with pid $tpid");
|
||||
|
||||
# FIXME as Cygwin reuses pids fast, maybe check that is
|
||||
# the expected process somehow?!
|
||||
kill(15, $tpid);
|
||||
|
||||
# As the timers are so simple programs, we trust them to terminate,
|
||||
# and use blocking wait for it. We wait just to avoid a zombie.
|
||||
waitpid($tpid,0);
|
||||
|
||||
delete $timers->{'timers'}->{$name}; # Remove the timer information
|
||||
delete $timers->{'pids'}->{$tpid}; # and PID reference
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
mtr_error("Asked to stop timer '$name' not started");
|
||||
}
|
||||
|
||||
|
||||
sub mtr_timer_stop_all ($) {
|
||||
my $timers= shift;
|
||||
|
||||
foreach my $name ( keys %{$timers->{'timers'}} )
|
||||
{
|
||||
mtr_timer_stop($timers, $name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
sub mtr_timer_timeout ($$) {
|
||||
my ($timers,$pid)= @_;
|
||||
|
||||
return "" unless exists $timers->{'pids'}->{$pid};
|
||||
|
||||
# Got a timeout(the process with $pid is recorded as being a timer)
|
||||
# return the name of the timer
|
||||
return $timers->{'pids'}->{$pid};
|
||||
}
|
||||
|
||||
1;
|
27
mysql-test/lib/t/Base.t
Normal file
27
mysql-test/lib/t/Base.t
Normal file
|
@ -0,0 +1,27 @@
|
|||
# -*- cperl -*-
|
||||
use Test::More qw(no_plan);
|
||||
use strict;
|
||||
|
||||
use_ok ("My::SafeProcess::Base");
|
||||
|
||||
|
||||
my $count= 0;
|
||||
for (1..100){
|
||||
my $pid= My::SafeProcess::Base::_safe_fork();
|
||||
exit unless $pid;
|
||||
(waitpid($pid, 0) == $pid) and $count++;
|
||||
}
|
||||
ok($count == 100, "safe_fork");
|
||||
|
||||
# A nice little forkbomb
|
||||
SKIP: {
|
||||
skip("forkbomb", 1);
|
||||
eval {
|
||||
while(1){
|
||||
my $pid= My::SafeProcess::Base::_safe_fork();
|
||||
exit unless $pid;
|
||||
}
|
||||
};
|
||||
ok($@, "forkbomb");
|
||||
}
|
||||
|
33
mysql-test/lib/t/Find.t
Normal file
33
mysql-test/lib/t/Find.t
Normal file
|
@ -0,0 +1,33 @@
|
|||
# -*- cperl -*-
|
||||
use Test::More qw(no_plan);
|
||||
use strict;
|
||||
|
||||
use_ok ("My::Find");
|
||||
my $basedir= "../..";
|
||||
|
||||
print "=" x 40, "\n";
|
||||
my $mysqld_exe= my_find_bin($basedir,
|
||||
["sql", "bin"],
|
||||
["mysqld", "mysqld-debug"]);
|
||||
print "mysqld_exe: $mysqld_exe\n";
|
||||
print "=" x 40, "\n";
|
||||
my $mysql_exe= my_find_bin($basedir,
|
||||
["client", "bin"],
|
||||
"mysql");
|
||||
print "mysql_exe: $mysql_exe\n";
|
||||
print "=" x 40, "\n";
|
||||
|
||||
my $mtr_build_dir= $ENV{MTR_BUILD_DIR};
|
||||
$ENV{MTR_BUILD_DIR}= "debug";
|
||||
my $mysql_exe= my_find_bin($basedir,
|
||||
["client", "bin"],
|
||||
"mysql");
|
||||
print "mysql_exe: $mysql_exe\n";
|
||||
$ENV{MTR_BUILD_DIR}= $mtr_build_dir;
|
||||
print "=" x 40, "\n";
|
||||
|
||||
my $charset_dir= my_find_dir($basedir,
|
||||
["share/mysql", "sql/share", "share"],
|
||||
"charsets");
|
||||
print "charset_dir: $charset_dir\n";
|
||||
print "=" x 40, "\n";
|
127
mysql-test/lib/t/Options.t
Normal file
127
mysql-test/lib/t/Options.t
Normal file
|
@ -0,0 +1,127 @@
|
|||
|
||||
# -*- cperl -*-
|
||||
use Test::More qw(no_plan);
|
||||
use strict;
|
||||
|
||||
use_ok("My::Options");
|
||||
|
||||
my @tests=
|
||||
(
|
||||
[
|
||||
['--binlog-format=row', '--loose-skip-innodb', '--binlog-format=ms'],
|
||||
['--binlog-format=row', '--loose-skip-innodb', '--binlog-format=statement'],
|
||||
['--binlog-format=statement']
|
||||
],
|
||||
|
||||
[
|
||||
['--binlog-format=row', '--loose-skip-innodb', '--binlog-format=statement'],
|
||||
['--binlog-format=row', '--loose-skip-innodb', '--binlog-format=mixed'],
|
||||
['--binlog-format=mixed']
|
||||
],
|
||||
|
||||
[
|
||||
['--binlog-format=row', '--loose-skip-innodb', '--binlog-format=mixed'],
|
||||
['--binlog-format=row', '--loose-skip-innodb', '--binlog-format=statement'],
|
||||
['--binlog-format=statement']
|
||||
],
|
||||
|
||||
[
|
||||
['--binlog-format=mixed', '--loose-skip-innodb', '--binlog-format=row'],
|
||||
['--binlog-format=statement', '--loose-skip-innodb', '--binlog-format=row'],
|
||||
[ ]
|
||||
],
|
||||
|
||||
[
|
||||
['--binlog-format=row'],
|
||||
[ ],
|
||||
['--binlog-format=default']
|
||||
],
|
||||
|
||||
[
|
||||
[ ],
|
||||
['--binlog-format=row'],
|
||||
['--binlog-format=row']
|
||||
],
|
||||
|
||||
[
|
||||
[ ],
|
||||
['-O', 'max_binlog_size=1' ],
|
||||
['--max_binlog_size=1' ]
|
||||
],
|
||||
|
||||
[
|
||||
['-O', 'max_binlog_size=1' ],
|
||||
['-O', 'max_binlog_size=1' ],
|
||||
[ ],
|
||||
],
|
||||
|
||||
[
|
||||
['-O', 'max_binlog_size=1' ],
|
||||
[ ],
|
||||
['--max_binlog_size=default' ]
|
||||
],
|
||||
|
||||
[
|
||||
[ ],
|
||||
['-O', 'max_binlog_size=1', '--binlog-format=row' ],
|
||||
['--max_binlog_size=1', '--binlog-format=row' ]
|
||||
],
|
||||
[
|
||||
['--binlog-format=statement' ],
|
||||
['-O', 'max_binlog_size=1', '--binlog-format=row' ],
|
||||
['--max_binlog_size=1', '--binlog-format=row']
|
||||
],
|
||||
|
||||
[
|
||||
[ '--binlog-format=statement' ],
|
||||
['-O', 'max_binlog_size=1', '--binlog-format=statement' ],
|
||||
['--max_binlog_size=1' ]
|
||||
],
|
||||
|
||||
[
|
||||
[ '--binlog-format=statement' ],
|
||||
['-O', 'max_binlog_size=1', '--binlog-format=statement' ],
|
||||
['--max_binlog_size=1' ]
|
||||
],
|
||||
|
||||
[
|
||||
[ '--binlog-format=statement' ],
|
||||
['--relay-log=/path/to/a/relay-log', '--binlog-format=row'],
|
||||
['--relay-log=/path/to/a/relay-log', '--binlog-format=row' ]
|
||||
],
|
||||
|
||||
|
||||
[
|
||||
[ '--binlog-format=statement' ],
|
||||
['--relay-log=/path/to/a/relay-log', '-O', 'max_binlog_size=1'],
|
||||
['--max_binlog_size=1', '--relay-log=/path/to/a/relay-log', '--binlog-format=default' ]
|
||||
],
|
||||
|
||||
[
|
||||
[ '--slow-query-log=0' ],
|
||||
[ '--slow-query-log' ],
|
||||
[ '--slow-query-log' ]
|
||||
],
|
||||
|
||||
|
||||
);
|
||||
|
||||
|
||||
my $test_no= 0;
|
||||
foreach my $test (@tests){
|
||||
print "test", $test_no++, "\n";
|
||||
foreach my $opts (@$test){
|
||||
print My::Options::toStr("", @$opts);
|
||||
}
|
||||
my $from= $test->[0];
|
||||
my $to= $test->[1];
|
||||
my @result= My::Options::diff($from, $to);
|
||||
ok(My::Options::same(\@result, $test->[2]));
|
||||
if (!My::Options::same(\@result, $test->[2])){
|
||||
print "failed\n";
|
||||
print My::Options::toStr("result", @result);
|
||||
print My::Options::toStr("expect", @{$test->[2]});
|
||||
}
|
||||
print My::Options::toSQL(@result), "\n";
|
||||
print "\n";
|
||||
}
|
18
mysql-test/lib/t/Platform.t
Normal file
18
mysql-test/lib/t/Platform.t
Normal file
|
@ -0,0 +1,18 @@
|
|||
# -*- cperl -*-
|
||||
use Test::More qw(no_plan);
|
||||
use strict;
|
||||
|
||||
use_ok ("My::Platform");
|
||||
use My::Platform;
|
||||
|
||||
use File::Temp qw / tempdir /;
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
|
||||
print "Running on Windows\n" if (IS_WINDOWS);
|
||||
print "Using ActiveState perl\n" if (IS_WIN32PERL);
|
||||
print "Using cygwin perl\n" if (IS_CYGWIN);
|
||||
|
||||
print "dir: '$dir'\n";
|
||||
print "native: '".native_path($dir)."'\n";
|
||||
print "mixed: '".mixed_path($dir)."'\n";
|
||||
print "posix: '".posix_path($dir)."'\n";
|
102
mysql-test/lib/t/SafeProcess.t
Normal file
102
mysql-test/lib/t/SafeProcess.t
Normal file
|
@ -0,0 +1,102 @@
|
|||
# -*- cperl -*-
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use IO::File;
|
||||
|
||||
use Test::More qw(no_plan);
|
||||
use_ok ("My::SafeProcess");
|
||||
|
||||
|
||||
my $perl_path= $^X;
|
||||
|
||||
{
|
||||
# Test exit codes
|
||||
my $count= 32;
|
||||
my $ok_count= 0;
|
||||
for my $code (0..$count-1) {
|
||||
|
||||
my $args= [ "$FindBin::Bin/test_child.pl", "--exit-code=$code" ];
|
||||
my $proc= My::SafeProcess->new
|
||||
(
|
||||
path => $perl_path,
|
||||
args => \$args,
|
||||
output => "/dev/null",
|
||||
error => "/dev/null",
|
||||
);
|
||||
# Wait max 10 seconds for the process to finish
|
||||
$ok_count++ if ($proc->wait_one(10) == 0 and
|
||||
$proc->exit_status() == $code);
|
||||
}
|
||||
ok($count == $ok_count, "check exit_status, $ok_count");
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
# spawn a number of concurrent processes
|
||||
my $count= 16;
|
||||
my $ok_count= 0;
|
||||
my %procs;
|
||||
for my $code (0..$count-1) {
|
||||
|
||||
my $args= [ "$FindBin::Bin/test_child.pl", "--exit-code=$code" ];
|
||||
$procs{$code}= My::SafeProcess->new
|
||||
(
|
||||
path => $perl_path,
|
||||
args => \$args,
|
||||
output => "/dev/null",
|
||||
error => "/dev/null",
|
||||
);
|
||||
}
|
||||
|
||||
for my $code (0..$count-1) {
|
||||
$ok_count++ if ($procs{$code}->wait_one(10) == 0 and
|
||||
$procs{$code}->exit_status() == $code);
|
||||
}
|
||||
ok($count == $ok_count, "concurrent, $ok_count");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Test stdout, stderr
|
||||
#
|
||||
{
|
||||
use File::Temp qw / tempdir /;
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
|
||||
my $args= [ "$FindBin::Bin/test_child.pl" ];
|
||||
my $proc= My::SafeProcess->new
|
||||
(
|
||||
path => $perl_path,
|
||||
args => \$args,
|
||||
output => "$dir/output.txt",
|
||||
error => "$dir/error.txt",
|
||||
);
|
||||
|
||||
$proc->wait_one(2); # Wait max 2 seconds for the process to finish
|
||||
|
||||
my $fh= IO::File->new("$dir/output.txt");
|
||||
my @text= <$fh>;
|
||||
ok(grep(/Hello stdout/, @text), "check stdout");
|
||||
$fh= IO::File->new("$dir/error.txt");
|
||||
my @text= <$fh>;
|
||||
ok(grep(/Hello stderr/, @text), "check stderr");
|
||||
|
||||
# To same file
|
||||
$proc= My::SafeProcess->new
|
||||
(
|
||||
path => $perl_path,
|
||||
args => \$args,
|
||||
output => "$dir/output.txt",
|
||||
error => "$dir/output.txt",
|
||||
debug => 1,
|
||||
);
|
||||
|
||||
$proc->wait_one(2); # Wait max 2 seconds for the process to finish
|
||||
|
||||
my $fh= IO::File->new("$dir/output.txt");
|
||||
my @text= <$fh>;
|
||||
ok((grep(/Hello stdout/, @text) and grep(/Hello stderr/, @text)),
|
||||
"check stdout and stderr");
|
||||
|
||||
}
|
149
mysql-test/lib/t/SafeProcessStress.pl
Executable file
149
mysql-test/lib/t/SafeProcessStress.pl
Executable file
|
@ -0,0 +1,149 @@
|
|||
#!/usr/bin/perl
|
||||
# -*- cperl -*-
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use My::SafeProcess;
|
||||
|
||||
#
|
||||
# Test longterm running of SafeProcess
|
||||
#
|
||||
|
||||
my $perl_path= $^X;
|
||||
my $verbose= 0;
|
||||
my $loops= 100;
|
||||
|
||||
print "kill one and wait for one\n";
|
||||
for (1...$loops){
|
||||
use File::Temp qw / tempdir /;
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
|
||||
my @procs;
|
||||
for (1..10){
|
||||
|
||||
my $args= [ "$FindBin::Bin/dummyd.pl", "--vardir=$dir" ];
|
||||
my $proc= My::SafeProcess->new
|
||||
(
|
||||
path => $perl_path,
|
||||
args => \$args,
|
||||
verbose => $verbose,
|
||||
);
|
||||
push(@procs, $proc);
|
||||
}
|
||||
|
||||
foreach my $proc (@procs) {
|
||||
$proc->kill();
|
||||
# dummyd will always be killed and thus
|
||||
# exit_status should have been set to 1
|
||||
die "oops, exit_status: ", $proc->exit_status()
|
||||
unless $proc->exit_status() == 1;
|
||||
}
|
||||
|
||||
print "=" x 60, "\n";
|
||||
}
|
||||
|
||||
|
||||
print "With 1 second sleep in dummyd\n";
|
||||
for (1...$loops){
|
||||
use File::Temp qw / tempdir /;
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
|
||||
my @procs;
|
||||
for (1..10){
|
||||
|
||||
my $args= [ "$FindBin::Bin/dummyd.pl",
|
||||
"--vardir=$dir",
|
||||
"--sleep=1" ];
|
||||
my $proc= My::SafeProcess->new
|
||||
(
|
||||
path => $perl_path,
|
||||
args => \$args,
|
||||
verbose => $verbose,
|
||||
);
|
||||
push(@procs, $proc);
|
||||
}
|
||||
|
||||
foreach my $proc (@procs) {
|
||||
$proc->kill();
|
||||
}
|
||||
|
||||
print "=" x 60, "\n";
|
||||
}
|
||||
|
||||
print "kill all and wait for one\n";
|
||||
for (1...$loops){
|
||||
use File::Temp qw / tempdir /;
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
|
||||
my @procs;
|
||||
for (1..10){
|
||||
|
||||
my $args= [ "$FindBin::Bin/dummyd.pl", "--vardir=$dir" ];
|
||||
my $proc= My::SafeProcess->new
|
||||
(
|
||||
path => $perl_path,
|
||||
args => \$args,
|
||||
verbose => $verbose,
|
||||
);
|
||||
push(@procs, $proc);
|
||||
}
|
||||
|
||||
foreach my $proc (@procs) {
|
||||
$proc->start_kill();
|
||||
}
|
||||
|
||||
foreach my $proc (@procs) {
|
||||
$proc->wait_one();
|
||||
}
|
||||
|
||||
print "=" x 60, "\n";
|
||||
}
|
||||
|
||||
print "kill all using shutdown without callback\n";
|
||||
for (1...$loops){
|
||||
use File::Temp qw / tempdir /;
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
|
||||
my @procs;
|
||||
for (1..10){
|
||||
|
||||
my $args= [ "$FindBin::Bin/dummyd.pl", "--vardir=$dir" ];
|
||||
my $proc= My::SafeProcess->new
|
||||
(
|
||||
path => $perl_path,
|
||||
args => \$args,
|
||||
verbose => $verbose,
|
||||
);
|
||||
push(@procs, $proc);
|
||||
}
|
||||
|
||||
My::SafeProcess::shutdown(2, @procs);
|
||||
|
||||
print "=" x 60, "\n";
|
||||
}
|
||||
|
||||
print "kill all using shutdown\n";
|
||||
for (1...$loops){
|
||||
use File::Temp qw / tempdir /;
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
|
||||
my @procs;
|
||||
for (1..10){
|
||||
|
||||
my $args= [ "$FindBin::Bin/dummyd.pl", "--vardir=$dir" ];
|
||||
my $proc= My::SafeProcess->new
|
||||
(
|
||||
path => $perl_path,
|
||||
args => \$args,
|
||||
verbose => $verbose,
|
||||
shutdown => sub { }, # Does nothing
|
||||
);
|
||||
push(@procs, $proc);
|
||||
}
|
||||
|
||||
My::SafeProcess::shutdown(2, @procs);
|
||||
|
||||
print "=" x 60, "\n";
|
||||
}
|
||||
|
||||
exit(0);
|
34
mysql-test/lib/t/copytree.t
Normal file
34
mysql-test/lib/t/copytree.t
Normal file
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/perl
|
||||
# -*- cperl -*-
|
||||
|
||||
use strict;
|
||||
|
||||
use My::File::Path;
|
||||
|
||||
use Test::Simple tests => 7;
|
||||
use File::Temp qw / tempdir /;
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
my $testdir="$dir/test";
|
||||
my $test_todir="$dir/to";
|
||||
|
||||
my $subdir= "$testdir/test1/test2/test3";
|
||||
|
||||
#
|
||||
# 1. Create, copy and remove a directory structure
|
||||
#
|
||||
mkpath($subdir);
|
||||
ok( -d $subdir, "Check '$subdir' is created");
|
||||
|
||||
copytree($testdir, $test_todir);
|
||||
ok( -d $test_todir, "Check '$test_todir' is created");
|
||||
ok( -d "$test_todir/test1", "Check 'test1' is created");
|
||||
ok( -d "$test_todir/test1/test2", "Check 'test2' is created");
|
||||
ok( -d "$test_todir/test1/test2/test3", "Check 'test3' is created");
|
||||
|
||||
|
||||
rmtree($testdir);
|
||||
ok( ! -d $testdir, "Check '$testdir' is gone");
|
||||
|
||||
rmtree($test_todir);
|
||||
ok( ! -d $test_todir, "Check '$test_todir' is gone");
|
||||
|
38
mysql-test/lib/t/dummyd.pl
Normal file
38
mysql-test/lib/t/dummyd.pl
Normal file
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/perl
|
||||
# -*- cperl -*-
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
use IO::File;
|
||||
|
||||
my $vardir;
|
||||
my $randie= 0;
|
||||
my $sleep= 0;
|
||||
GetOptions
|
||||
(
|
||||
# Directory where to write files
|
||||
'vardir=s' => \$vardir,
|
||||
'die-randomly' => \$randie,
|
||||
'sleep=i' => \$sleep,
|
||||
);
|
||||
|
||||
die("invalid vardir ") unless defined $vardir and -d $vardir;
|
||||
|
||||
my $pid= $$;
|
||||
while(1){
|
||||
for my $i (1..64){
|
||||
# Write to file
|
||||
my $name= "$vardir/$pid.$i.tmp";
|
||||
my $F= IO::File->new($name, "w")
|
||||
or warn "$$, Could not open $name: $!" and next;
|
||||
print $F rand($.) for (1..1000);
|
||||
$F->close();
|
||||
sleep($sleep);
|
||||
die "ooops!" if $randie and rand() < 0.0001
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exit (0);
|
||||
|
||||
|
52
mysql-test/lib/t/rmtree.t
Normal file
52
mysql-test/lib/t/rmtree.t
Normal file
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/perl
|
||||
# -*- cperl -*-
|
||||
|
||||
use strict;
|
||||
|
||||
use My::File::Path;
|
||||
|
||||
use Test::Simple tests => 8;
|
||||
use File::Temp qw / tempdir /;
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
my $testdir="$dir/test";
|
||||
|
||||
my $subdir= "$testdir/test1/test2/test3";
|
||||
|
||||
#
|
||||
# 1. Create and remove a directory structure
|
||||
#
|
||||
mkpath($subdir);
|
||||
ok( -d $subdir, "Check '$subdir' is created");
|
||||
|
||||
rmtree($testdir);
|
||||
ok( ! -d $testdir, "Check '$testdir' is gone");
|
||||
|
||||
#
|
||||
# 2. Create and remove a directory structure
|
||||
# where one directory is chmod to 0000
|
||||
#
|
||||
mkpath($subdir);
|
||||
ok( -d $subdir, "Check '$subdir' is created");
|
||||
|
||||
ok( chmod(0000, $subdir) == 1 , "Check one dir was chmoded");
|
||||
|
||||
rmtree($testdir);
|
||||
ok( ! -d $testdir, "Check '$testdir' is gone");
|
||||
|
||||
#
|
||||
# 3. Create and remove a directory structure
|
||||
# where one file is chmod to 0000
|
||||
#
|
||||
mkpath($subdir);
|
||||
ok( -d $subdir, "Check '$subdir' is created");
|
||||
|
||||
my $testfile= "$subdir/test.file";
|
||||
open(F, ">", $testfile) or die;
|
||||
print F "hello\n";
|
||||
close(F);
|
||||
|
||||
ok( chmod(0000, $testfile) == 1 , "Check one file was chmoded");
|
||||
|
||||
rmtree($testdir);
|
||||
ok( ! -d $testdir, "Check '$testdir' is gone");
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue