diff options
-rw-r--r-- | mysql-test/lib/mtr_process.pl | 17 | ||||
-rwxr-xr-x | mysql-test/mysql-test-run.pl | 54 | ||||
-rw-r--r-- | mysql-test/r/im_daemon_life_cycle.result | 1 | ||||
-rw-r--r-- | mysql-test/r/im_life_cycle.result | 30 | ||||
-rw-r--r-- | mysql-test/r/im_utils.result | 3 | ||||
-rw-r--r-- | mysql-test/r/insert.result | 32 | ||||
-rw-r--r-- | mysql-test/r/trigger.result | 32 | ||||
-rw-r--r-- | mysql-test/t/im_daemon_life_cycle.imtest | 17 | ||||
-rw-r--r-- | mysql-test/t/im_life_cycle.imtest | 55 | ||||
-rw-r--r-- | mysql-test/t/im_utils.imtest | 16 | ||||
-rw-r--r-- | mysql-test/t/insert.test | 33 | ||||
-rwxr-xr-x | mysql-test/t/kill_n_check.sh | 109 | ||||
-rw-r--r-- | mysql-test/t/trigger.test | 40 | ||||
-rwxr-xr-x | mysql-test/t/wait_for_process.sh | 66 | ||||
-rw-r--r-- | server-tools/instance-manager/instance_map.cc | 2 | ||||
-rw-r--r-- | server-tools/instance-manager/manager.cc | 43 | ||||
-rw-r--r-- | sql/sql_insert.cc | 43 |
17 files changed, 423 insertions, 170 deletions
diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index d6fb9382b90..1b2ce17a689 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -880,19 +880,28 @@ sub mtr_kill_processes ($) { sub mtr_kill_process ($$$$) { my $pid= shift; my $signal= shift; - my $retries= shift; + my $total_retries= shift; my $timeout= shift; - while (1) + for (my $cur_attempt= 1; $cur_attempt <= $total_retries; ++$cur_attempt) { + mtr_debug("Sending $signal to $pid..."); + kill($signal, $pid); - last unless kill (0, $pid) and $retries--; + unless (kill (0, $pid)) + { + mtr_debug("Process $pid died."); + return; + } - mtr_debug("Sleep $timeout second waiting for processes to die"); + mtr_debug("Sleeping $timeout second(s) waiting for processes to die..."); sleep($timeout); } + + mtr_debug("Process $pid is still alive after $total_retries " . + "of sending signal $signal."); } ############################################################################## diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 811dd004246..ca2eb6641cd 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3120,22 +3120,58 @@ sub im_stop($) { # Try graceful shutdown. + mtr_debug("IM-main pid: $instance_manager->{'pid'}"); + mtr_debug("Stopping IM-main..."); + mtr_kill_process($instance_manager->{'pid'}, 'TERM', 10, 1); + # If necessary, wait for angel process to die. + + if (defined $instance_manager->{'angel_pid'}) + { + mtr_debug("IM-angel pid: $instance_manager->{'angel_pid'}"); + mtr_debug("Waiting for IM-angel to die..."); + + my $total_attempts= 10; + + for (my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt) + { + unless (kill (0, $instance_manager->{'angel_pid'})) + { + mtr_debug("IM-angel died."); + last; + } + + sleep(1); + } + } + # Check that all processes died. my $clean_shutdown= 0; while (1) { - last if kill (0, $instance_manager->{'pid'}); + if (kill (0, $instance_manager->{'pid'})) + { + mtr_debug("IM-main is still alive."); + last; + } - last if (defined $instance_manager->{'angel_pid'}) && - kill (0, $instance_manager->{'angel_pid'}); + if (defined $instance_manager->{'angel_pid'} && + kill (0, $instance_manager->{'angel_pid'})) + { + mtr_debug("IM-angel is still alive."); + last; + } foreach my $pid (@mysqld_pids) { - last if kill (0, $pid); + if (kill (0, $pid)) + { + mtr_debug("Guarded mysqld ($pid) is still alive."); + last; + } } $clean_shutdown= 1; @@ -3146,15 +3182,21 @@ sub im_stop($) { unless ($clean_shutdown) { - mtr_kill_process($instance_manager->{'angel_pid'}, 'KILL', 10, 1) - if defined $instance_manager->{'angel_pid'}; + + if (defined $instance_manager->{'angel_pid'}) + { + mtr_debug("Killing IM-angel..."); + mtr_kill_process($instance_manager->{'angel_pid'}, 'KILL', 10, 1) + } + mtr_debug("Killing IM-main..."); mtr_kill_process($instance_manager->{'pid'}, 'KILL', 10, 1); # Shutdown managed mysqld-processes. Some of them may be nonguarded, so IM # will not stop them on shutdown. So, we should firstly try to end them # legally. + mtr_debug("Killing guarded mysqld(s)..."); mtr_kill_processes(\@mysqld_pids); # Complain in error log so that a warning will be shown. diff --git a/mysql-test/r/im_daemon_life_cycle.result b/mysql-test/r/im_daemon_life_cycle.result index 29c9ea2047d..a5526a31384 100644 --- a/mysql-test/r/im_daemon_life_cycle.result +++ b/mysql-test/r/im_daemon_life_cycle.result @@ -1,3 +1,4 @@ +Success: the process has been started. SHOW INSTANCES; instance_name state mysqld1 online diff --git a/mysql-test/r/im_life_cycle.result b/mysql-test/r/im_life_cycle.result index 876fbb38eee..aa26b355aff 100644 --- a/mysql-test/r/im_life_cycle.result +++ b/mysql-test/r/im_life_cycle.result @@ -2,6 +2,7 @@ -------------------------------------------------------------------- -- 1.1.1. -------------------------------------------------------------------- +Success: the process has been started. SHOW INSTANCES; instance_name state mysqld1 online @@ -11,10 +12,7 @@ mysqld2 offline -- 1.1.2. -------------------------------------------------------------------- START INSTANCE mysqld2; -SHOW INSTANCES; -instance_name state -mysqld1 online -mysqld2 online +Success: the process has been started. SHOW VARIABLES LIKE 'port'; Variable_name Value port IM_MYSQLD2_PORT @@ -23,16 +21,7 @@ port IM_MYSQLD2_PORT -- 1.1.3. -------------------------------------------------------------------- STOP INSTANCE mysqld2; -SHOW INSTANCES; -instance_name state -mysqld1 online -mysqld2 offline -SHOW INSTANCE STATUS mysqld1; -instance_name state version_number version mysqld_compatible -mysqld1 online VERSION_NUMBER VERSION no -SHOW INSTANCE STATUS mysqld2; -instance_name state version_number version mysqld_compatible -mysqld2 offline VERSION_NUMBER VERSION no +Success: the process has been stopped. -------------------------------------------------------------------- -- 1.1.4. @@ -66,18 +55,15 @@ SHOW INSTANCES; instance_name state mysqld1 online mysqld2 offline + +-------------------------------------------------------------------- +-- 1.1.7. +-------------------------------------------------------------------- START INSTANCE mysqld2; -SHOW INSTANCES; -instance_name state -mysqld1 online -mysqld2 online +Success: the process has been started. Killing the process... Sleeping... Success: the process was killed. -SHOW INSTANCES; -instance_name state -mysqld1 online -mysqld2 offline -------------------------------------------------------------------- -- 1.1.8. diff --git a/mysql-test/r/im_utils.result b/mysql-test/r/im_utils.result index ae8e03bf8ea..df20a7fb5c7 100644 --- a/mysql-test/r/im_utils.result +++ b/mysql-test/r/im_utils.result @@ -1,3 +1,4 @@ +Success: the process has been started. SHOW INSTANCES; instance_name state mysqld1 online @@ -42,7 +43,9 @@ skip-ndbcluster VALUE nonguarded VALUE log-output VALUE START INSTANCE mysqld2; +Success: the process has been started. STOP INSTANCE mysqld2; +Success: the process has been stopped. SHOW mysqld1 LOG FILES; Logfile Path File size ERROR LOG PATH FILE_SIZE diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 18bd6d7e796..235c3f61fe9 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -321,3 +321,35 @@ ERROR 42000: Column 'b' specified twice INSERT INTO t1 (b,b) SELECT 0,0 ON DUPLICATE KEY UPDATE a = a + VALUES (a); ERROR 42000: Column 'b' specified twice drop table t1; +create table t1 (n int); +create view v1 as select * from t1; +insert delayed into v1 values (1); +ERROR HY000: 'test.v1' is not BASE TABLE +drop table t1; +drop view v1; +create table t1 (id int primary key, data int); +insert into t1 values (1, 1), (2, 2), (3, 3); +select row_count(); +row_count() +3 +insert ignore into t1 values (1, 1); +select row_count(); +row_count() +0 +replace into t1 values (1, 11); +select row_count(); +row_count() +2 +replace into t1 values (4, 4); +select row_count(); +row_count() +1 +insert into t1 values (2, 2) on duplicate key update data= data + 10; +select row_count(); +row_count() +2 +insert into t1 values (5, 5) on duplicate key update data= data + 10; +select row_count(); +row_count() +1 +drop table t1; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 24675f2cd66..145579201a9 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -169,21 +169,22 @@ select @log; @log (BEFORE_INSERT: new=(id=1, data=2)) set @log:= ""; -replace t1 values (1, 3), (2, 2); +insert into t1 (id, data) values (1, 3), (2, 2) on duplicate key update data= data + 1; select @log; @log -(BEFORE_INSERT: new=(id=1, data=3))(BEFORE_UPDATE: old=(id=1, data=1) new=(id=1, data=3))(AFTER_UPDATE: old=(id=1, data=1) new=(id=1, data=3))(BEFORE_INSERT: new=(id=2, data=2))(AFTER_INSERT: new=(id=2, data=2)) -alter table t1 add ts timestamp default now(); +(BEFORE_INSERT: new=(id=1, data=3))(BEFORE_UPDATE: old=(id=1, data=1) new=(id=1, data=2))(AFTER_UPDATE: old=(id=1, data=1) new=(id=1, data=2))(BEFORE_INSERT: new=(id=2, data=2))(AFTER_INSERT: new=(id=2, data=2)) set @log:= ""; -replace t1 (id, data) values (1, 4); +replace t1 values (1, 4), (3, 3); select @log; @log -(BEFORE_INSERT: new=(id=1, data=4))(BEFORE_DELETE: old=(id=1, data=3))(AFTER_DELETE: old=(id=1, data=3))(AFTER_INSERT: new=(id=1, data=4)) +(BEFORE_INSERT: new=(id=1, data=4))(BEFORE_DELETE: old=(id=1, data=2))(AFTER_DELETE: old=(id=1, data=2))(AFTER_INSERT: new=(id=1, data=4))(BEFORE_INSERT: new=(id=3, data=3))(AFTER_INSERT: new=(id=3, data=3)) +drop trigger t1_bd; +drop trigger t1_ad; set @log:= ""; -insert into t1 (id, data) values (1, 5), (3, 3) on duplicate key update data= data + 2; +replace t1 values (1, 5); select @log; @log -(BEFORE_INSERT: new=(id=1, data=5))(BEFORE_UPDATE: old=(id=1, data=4) new=(id=1, data=6))(AFTER_UPDATE: old=(id=1, data=4) new=(id=1, data=6))(BEFORE_INSERT: new=(id=3, data=3))(AFTER_INSERT: new=(id=3, data=3)) +(BEFORE_INSERT: new=(id=1, data=5))(AFTER_INSERT: new=(id=1, data=5)) drop table t1; create table t1 (id int primary key, data varchar(10), fk int); create table t2 (event varchar(100)); @@ -493,15 +494,9 @@ select * from t1; i k 3 13 replace into t1 values (3, 3); -ERROR 42S22: Unknown column 'at' in 'NEW' -select * from t1; -i k -3 3 -alter table t1 add ts timestamp default now(); -replace into t1 (i, k) values (3, 13); ERROR 42S22: Unknown column 'at' in 'OLD' select * from t1; -i k ts +i k drop table t1, t2; create table t1 (i int, bt int, k int, key(k)) engine=myisam; create table t2 (i int); @@ -574,18 +569,11 @@ i k 1 1 2 2 replace into t1 values (2, 4); -ERROR 42S22: Unknown column 'bt' in 'NEW' +ERROR 42S22: Unknown column 'bt' in 'OLD' select * from t1; i k 1 1 2 2 -alter table t1 add ts timestamp default now(); -replace into t1 (i, k) values (2, 11); -ERROR 42S22: Unknown column 'bt' in 'OLD' -select * from t1; -i k ts -1 1 0000-00-00 00:00:00 -2 2 0000-00-00 00:00:00 drop table t1, t2; drop function if exists bug5893; create table t1 (col1 int, col2 int); diff --git a/mysql-test/t/im_daemon_life_cycle.imtest b/mysql-test/t/im_daemon_life_cycle.imtest index d173ce2a6e2..3afc36935f8 100644 --- a/mysql-test/t/im_daemon_life_cycle.imtest +++ b/mysql-test/t/im_daemon_life_cycle.imtest @@ -10,9 +10,22 @@ ########################################################################### +# Wait for mysqld1 (guarded instance) to start. + +--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD1_PATH_PID 30 started + +# Let IM detect that mysqld1 is online. This delay should be longer than +# monitoring interval. + --sleep 3 -# should be longer than monitoring interval and enough to start instance. + +# Check that start conditions are as expected. SHOW INSTANCES; ---exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted +########################################################################### + +# Kill the IM main process and check that the IM Angel will restart the main +# process. + +--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted 30 diff --git a/mysql-test/t/im_life_cycle.imtest b/mysql-test/t/im_life_cycle.imtest index d71cdc86624..2cbe53a7b28 100644 --- a/mysql-test/t/im_life_cycle.imtest +++ b/mysql-test/t/im_life_cycle.imtest @@ -22,8 +22,16 @@ --echo -- 1.1.1. --echo -------------------------------------------------------------------- +# Wait for mysqld1 (guarded instance) to start. + +--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD1_PATH_PID 30 started + +# Let IM detect that mysqld1 is online. This delay should be longer than +# monitoring interval. + --sleep 3 -# should be longer than monitoring interval and enough to start instance. + +# Check that start conditions are as expected. SHOW INSTANCES; @@ -44,10 +52,12 @@ SHOW INSTANCES; START INSTANCE mysqld2; # FIXME: START INSTANCE should be synchronous. ---sleep 3 -# should be longer than monitoring interval and enough to start instance. +--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started -SHOW INSTANCES; +# FIXME: SHOW INSTANCES is not deterministic unless START INSTANCE is +# synchronous. Even waiting for mysqld to start by looking at its pid file is +# not enough, because IM may not detect that mysqld has started. +# SHOW INSTANCES; --connect (mysql_con,localhost,root,,mysql,$IM_MYSQLD2_PORT,$IM_MYSQLD2_SOCK) --connection mysql_con @@ -74,14 +84,12 @@ SHOW VARIABLES LIKE 'port'; STOP INSTANCE mysqld2; # FIXME: STOP INSTANCE should be synchronous. ---sleep 3 -# should be longer than monitoring interval and enough to stop instance. +--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 stopped -SHOW INSTANCES; ---replace_column 3 VERSION_NUMBER 4 VERSION -SHOW INSTANCE STATUS mysqld1; ---replace_column 3 VERSION_NUMBER 4 VERSION -SHOW INSTANCE STATUS mysqld2; +# FIXME: SHOW INSTANCES is not deterministic unless START INSTANCE is +# synchronous. Even waiting for mysqld to start by looking at its pid file is +# not enough, because IM may not detect that mysqld has started. +# SHOW INSTANCES; ########################################################################### # @@ -140,10 +148,14 @@ STOP INSTANCE mysqld3; SHOW INSTANCES; ---exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD1_PATH_PID restarted +--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD1_PATH_PID restarted 30 + +# Give some time to IM to detect that mysqld was restarted. It should be longer +# than monitoring interval. --sleep 3 -# should be longer than monitoring interval and enough to start instance. + +SHOW INSTANCES; ########################################################################### # @@ -156,18 +168,21 @@ SHOW INSTANCES; --echo -- 1.1.7. --echo -------------------------------------------------------------------- -SHOW INSTANCES; - START INSTANCE mysqld2; # FIXME: START INSTANCE should be synchronous. ---sleep 3 -# should be longer than monitoring interval and enough to start instance. +--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started -SHOW INSTANCES; +# FIXME: SHOW INSTANCES is not deterministic unless START INSTANCE is +# synchronous. Even waiting for mysqld to start by looking at its pid file is +# not enough, because IM may not detect that mysqld has started. +# SHOW INSTANCES; ---exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD2_PATH_PID killed +--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD2_PATH_PID killed 10 -SHOW INSTANCES; +# FIXME: SHOW INSTANCES is not deterministic unless START INSTANCE is +# synchronous. Even waiting for mysqld to start by looking at its pid file is +# not enough, because IM may not detect that mysqld has started. +# SHOW INSTANCES; ########################################################################### # diff --git a/mysql-test/t/im_utils.imtest b/mysql-test/t/im_utils.imtest index 8e8d475cfee..47902eeba52 100644 --- a/mysql-test/t/im_utils.imtest +++ b/mysql-test/t/im_utils.imtest @@ -17,8 +17,16 @@ # - the second instance is offline; # +# Wait for mysqld1 (guarded instance) to start. + +--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD1_PATH_PID 30 started + +# Let IM detect that mysqld1 is online. This delay should be longer than +# monitoring interval. + --sleep 3 -# should be longer than monitoring interval and enough to start instance. + +# Check that start conditions are as expected. SHOW INSTANCES; @@ -43,12 +51,10 @@ SHOW INSTANCE OPTIONS mysqld2; # START INSTANCE mysqld2; - -# FIXME: START INSTANCE should be synchronous. ---sleep 3 -# should be longer than monitoring interval and enough to start instance. +--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started STOP INSTANCE mysqld2; +--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 stopped # # Check 'SHOW LOG FILES' command: diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index e2514083ea7..3711e2986ed 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -201,3 +201,36 @@ insert into t1 (b,b) select 1,2; --error 1110 INSERT INTO t1 (b,b) SELECT 0,0 ON DUPLICATE KEY UPDATE a = a + VALUES (a); drop table t1; +# Test for INSERT DELAYED INTO a <view> +# BUG#13683: INSERT DELAYED into a view creates an infinite loop +# + +create table t1 (n int); +create view v1 as select * from t1; +--error 1347 +insert delayed into v1 values (1); +drop table t1; +drop view v1; + +# +# Test for values returned by ROW_COUNT() function +# (and thus for values returned by mysql_affected_rows()) +# for various forms of INSERT +# +create table t1 (id int primary key, data int); +insert into t1 values (1, 1), (2, 2), (3, 3); +select row_count(); +insert ignore into t1 values (1, 1); +select row_count(); +# Reports that 2 rows are affected (1 deleted + 1 inserted) +replace into t1 values (1, 11); +select row_count(); +replace into t1 values (4, 4); +select row_count(); +# Reports that 2 rows are affected. This conforms to documentation. +# (Useful for differentiating inserts from updates). +insert into t1 values (2, 2) on duplicate key update data= data + 10; +select row_count(); +insert into t1 values (5, 5) on duplicate key update data= data + 10; +select row_count(); +drop table t1; diff --git a/mysql-test/t/kill_n_check.sh b/mysql-test/t/kill_n_check.sh index e722b3a180d..64cc869d1ec 100755 --- a/mysql-test/t/kill_n_check.sh +++ b/mysql-test/t/kill_n_check.sh @@ -1,66 +1,115 @@ #!/bin/sh -if [ $# -ne 2 ]; then - echo "Usage: kill_n_check.sh <pid file path> killed|restarted" +########################################################################### + +# NOTE: this script returns 0 (success) even in case of failure. This is +# because this script is executed under mysql-test-run[.pl] and it's better to +# examine particular problem in log file, than just having said that the test +# case has failed. + +########################################################################### + +check_restart() +{ + if [ ! -r "$pid_path" ]; then + user_msg='the process was killed' + return 1 + fi + + new_pid=`cat "$pid_path" 2>/dev/null` + + if [ $? -eq 0 -a "$original_pid" = "$new_pid" ]; then + user_msg='the process was not restarted' + return 1 + fi + + user_msg='the process was restarted' + return 0 +} + +########################################################################### + +if [ $# -ne 3 ]; then + echo "Usage: kill_n_check.sh <pid file path> killed|restarted <timeout>" exit 0 fi pid_path="$1" expected_result="$2" +total_timeout="$3" -if [ -z "$pid_path" -o ! -r "$pid_path" ]; then - echo "Error: invalid PID path ($pid_path) or PID file does not exist." +if [ "$expected_result" != 'killed' -a \ + "$expected_result" != 'restarted' ]; then + echo "Error: invalid second argument ('killed' or 'restarted' expected)." exit 0 fi -if [ "$expected_result" != "killed" -a \ - "$expected_result" != "restarted" ]; then - echo "Error: expected result must be either 'killed' or 'restarted'." +if [ -z "$pid_path" ]; then + echo "Error: invalid PID path ($pid_path)." exit 0 fi -# echo "PID path: '$pid_path'" +if [ $expected_result = 'killed' -a ! -r "$pid_path" ]; then + echo "Error: PID file ($pid_path) does not exist." + exit 0 +fi -original_pid=`cat "$pid_path"` +if [ -z "$total_timeout" ]; then + echo "Error: timeout is not specified." + exit 0 +fi -# echo "Original PID: $original_pid" +########################################################################### + +original_pid=`cat "$pid_path"` echo "Killing the process..." kill -9 $original_pid +########################################################################### + echo "Sleeping..." -sleep 3 +if [ "$expected_result" = "restarted" ]; then -new_pid="" + # Wait for the process to restart. -[ -r "$pid_path" ] && new_pid=`cat "$pid_path"` + cur_attempt=1 -# echo "New PID: $new_pid" + while true; do -if [ "$expected_result" = "restarted" ]; then + if check_restart; then + echo "Success: $user_msg." + exit 0 + fi - if [ -z "$new_pid" ]; then - echo "Error: the process was killed." - exit 0 - fi + [ $cur_attempt -ge $total_timeout ] && break - if [ "$original_pid" -eq "$new_pid" ]; then - echo "Error: the process was not restarted." - exit 0 - fi - - echo "Success: the process was restarted." + sleep 1 + + cur_attempt=`expr $cur_attempt + 1` + + done + + echo "Error: $user_msg." exit 0 - -else # $expected_result = killed - + +else # $expected_result == killed + + # Here we have to sleep for some long time to ensure that the process will + # not be restarted. + + sleep $total_timeout + + new_pid=`cat "$pid_path" 2>/dev/null` + if [ "$new_pid" -a "$new_pid" -ne "$original_pid" ]; then echo "Error: the process was restarted." - exit 0 + else + echo "Success: the process was killed." fi - echo "Success: the process was killed." exit 0 + fi diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index a87f289e94e..58adffc6e87 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -185,24 +185,26 @@ select @log; set @log:= ""; insert ignore t1 values (1, 2); select @log; -# REPLACE: before insert trigger should be called for both records, -# but then for first one update will be executed (and both update -# triggers should fire). For second after insert trigger will be -# called as for usual insert +# INSERT ... ON DUPLICATE KEY UPDATE ... set @log:= ""; -replace t1 values (1, 3), (2, 2); +insert into t1 (id, data) values (1, 3), (2, 2) on duplicate key update data= data + 1; select @log; -# Now let us change table in such way that REPLACE on won't be executed -# using update. -alter table t1 add ts timestamp default now(); +# REPLACE (also test for bug#13479 "REPLACE activates UPDATE trigger, +# not the DELETE and INSERT triggers") +# We define REPLACE as INSERT which DELETEs old rows which conflict with +# row being inserted. So for the first record in statement below we will +# call before insert trigger, then delete will be executed (and both delete +# triggers should fire). Finally after insert trigger will be called. +# For the second record we will just call both on insert triggers. set @log:= ""; -# This REPLACE should be executed via DELETE and INSERT so proper -# triggers should be invoked. -replace t1 (id, data) values (1, 4); +replace t1 values (1, 4), (3, 3); select @log; -# Finally let us test INSERT ... ON DUPLICATE KEY UPDATE ... +# Now we will drop ON DELETE triggers to test REPLACE which is internally +# executed via update +drop trigger t1_bd; +drop trigger t1_ad; set @log:= ""; -insert into t1 (id, data) values (1, 5), (3, 3) on duplicate key update data= data + 2; +replace t1 values (1, 5); select @log; # This also drops associated triggers @@ -531,14 +533,11 @@ alter table t1 add primary key (i); --error 1054 insert into t1 values (3, 4) on duplicate key update k= k + 10; select * from t1; +# The following statement will delete old row and won't +# insert new one since after delete trigger will fail. --error 1054 replace into t1 values (3, 3); select * from t1; -# Change table in such way that REPLACE will delete row -alter table t1 add ts timestamp default now(); ---error 1054 -replace into t1 (i, k) values (3, 13); -select * from t1; # Also drops all triggers drop table t1, t2; @@ -594,11 +593,6 @@ select * from t1; --error 1054 replace into t1 values (2, 4); select * from t1; -# Change table in such way that REPLACE will delete row -alter table t1 add ts timestamp default now(); ---error 1054 -replace into t1 (i, k) values (2, 11); -select * from t1; # Also drops all triggers drop table t1, t2; diff --git a/mysql-test/t/wait_for_process.sh b/mysql-test/t/wait_for_process.sh new file mode 100755 index 00000000000..df0f4a17e3a --- /dev/null +++ b/mysql-test/t/wait_for_process.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +########################################################################### + +pid_path="$1" +total_attempts="$2" +event="$3" + +case "$3" in + started) + check_fn='check_started'; + ;; + + stopped) + check_fn='check_stopped'; + ;; + + *) + echo "Error: invalid third argument ('started' or 'stopped' expected)." + exit 0 +esac + +########################################################################### + +check_started() +{ + [ ! -r "$pid_path" ] && return 1 + + new_pid=`cat "$pid_path" 2>/dev/null` + + [ $? -eq 0 -a "$original_pid" = "$new_pid" ] && return 1 + + return 0 +} + +########################################################################### + +check_stopped() +{ + [ -r "$pid_path" ] && return 1 + + return 0 +} + +########################################################################### + +cur_attempt=1 + +while true; do + + if ( eval $check_fn ); then + echo "Success: the process has been $event." + exit 0 + fi + + [ $cur_attempt -ge $total_attempts ] && break + + sleep 1 + + cur_attempt=`expr $cur_attempt + 1` + +done + +echo "Error: the process has not been $event in $total_attempts secs." +exit 0 + diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc index c9608fa7c14..ec73fb7d73a 100644 --- a/server-tools/instance-manager/instance_map.cc +++ b/server-tools/instance-manager/instance_map.cc @@ -293,7 +293,7 @@ int Instance_map::flush_instances() get_instance_key, delete_instance, 0); rc= load(); - guardian->init(); + guardian->init(); // TODO: check error status. return rc; } diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc index 599131089ed..d2d498eebf1 100644 --- a/server-tools/instance-manager/manager.cc +++ b/server-tools/instance-manager/manager.cc @@ -198,6 +198,25 @@ void manager() if (create_pid_file(Options::Main::pid_file_name, manager_pid)) return; /* necessary logging has been already done. */ + /* + Initialize signals and alarm-infrastructure. + + NOTE: To work nicely with LinuxThreads, the signal thread is the first + thread in the process. + + NOTE: + After init_thr_alarm() call it's possible to call thr_alarm() (from + different threads), that results in sending ALARM signal to the alarm + thread (which can be the main thread). That signal can interrupt + blocking calls. + + In other words, a blocking call can be interrupted in the main thread + after init_thr_alarm(). + */ + + sigset_t mask; + set_signals(&mask); + /* create guardian thread */ { pthread_t guardian_thd_id; @@ -205,9 +224,16 @@ void manager() int rc; /* - NOTE: Guardian should be shutdown first. Only then all other threads - need to be stopped. This should be done, as guardian is responsible for - shutting down the instances, and this is a long operation. + NOTE: Guardian should be shutdown first. Only then all other threads + need to be stopped. This should be done, as guardian is responsible + for shutting down the instances, and this is a long operation. + + NOTE: Guardian uses thr_alarm() when detects current state of + instances (is_running()), but it is not interfere with + flush_instances() later in the code, because until flush_instances() + complete in the main thread, Guardian thread is not permitted to + process instances. And before flush_instances() there is no instances + to proceed. */ pthread_attr_init(&guardian_thd_attr); @@ -223,10 +249,8 @@ void manager() } - /* - To work nicely with LinuxThreads, the signal thread is the first thread - in the process. - */ + /* Load instances. */ + { instance_map.guardian->lock(); @@ -246,11 +270,6 @@ void manager() } } - /* Initialize signals and alarm-infrastructure. */ - - sigset_t mask; - set_signals(&mask); - /* create the listener */ { pthread_t listener_thd_id; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f1f97400283..ecf4f4a545b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1083,16 +1083,19 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) to convert the latter operation internally to an UPDATE. We also should not perform this conversion if we have timestamp field with ON UPDATE which is different from DEFAULT. + Another case when conversion should not be performed is when + we have ON DELETE trigger on table so user may notice that + we cheat here. Note that it is ok to do such conversion for + tables which have ON UPDATE but have no ON DELETE triggers, + we just should not expose this fact to users by invoking + ON UPDATE triggers. */ if (last_uniq_key(table,key_nr) && !table->file->referenced_by_foreign_key() && (table->timestamp_field_type == TIMESTAMP_NO_AUTO_SET || - table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH)) + table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH) && + (!table->triggers || !table->triggers->has_delete_triggers())) { - if (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, - TRG_ACTION_BEFORE, TRUE)) - goto before_trg_err; if (thd->clear_next_insert_id) { /* Reset auto-increment cacheing if we do an update */ @@ -1103,13 +1106,11 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) table->record[0]))) goto err; info->deleted++; - trg_error= (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, - TRG_ACTION_AFTER, - TRUE)); - /* Update logfile and count */ - info->copied++; - goto ok_or_after_trg_err; + /* + Since we pretend that we have done insert we should call + its after triggers. + */ + goto after_trg_n_copied_inc; } else { @@ -1133,10 +1134,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } } } - info->copied++; - trg_error= (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_INSERT, - TRG_ACTION_AFTER, TRUE)); /* Restore column maps if they where replaced during an duplicate key problem. @@ -1151,14 +1148,14 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)) goto err; table->file->restore_auto_increment(); + goto ok_or_after_trg_err; } - else - { - info->copied++; - trg_error= (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_INSERT, - TRG_ACTION_AFTER, TRUE)); - } + +after_trg_n_copied_inc: + info->copied++; + trg_error= (table->triggers && + table->triggers->process_triggers(thd, TRG_EVENT_INSERT, + TRG_ACTION_AFTER, TRUE)); ok_or_after_trg_err: if (key) |