1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
# ==== Purpose ====
#
# Test that slave behaves well in some conflict situations. The
# following are tested:
#
# - The slave SQL thread sees an 'INSERT' of a row with a key that
# already exists in the table;
#
# - The slave SQL thread sees a 'DELETE' of a row that does not
# exist in the table.
#
# In statement-logging mode, the first conflict type causes the slave
# to stop with an error and the second conflict is ignored.
#
# In row-logging mode, the slave behavior depends the value of
# @@slave_exec_mode on the slave: if @@slave_exec_mode is IDEMPOTENT,
# the slave should ignore the conflicting statement and continue
# normally. If @@slave_exec_mode is STRICT, the slave should stop
# with an error.
#
# This test was previously named rpl_stm_mystery22/rpl_row_mystery22.
#
#
# ==== Method ====
#
# Create a table on master and slave, insert a row on slave, and
# insert the same row on master.
#
# Create a table on master and slave, insert a row on master with
# binlogging turned off, and remove the row on master with binlogging
# turned on.
#
#
# ==== Related bugs ====
#
# BUG#31552: Replication breaks when deleting rows from out-of-sync table without PK
# BUG#31609: Not all RBR slave errors reported as errors
#
# Bug in this test case:
# BUG#37718: rpl.rpl_stm_mystery22 fails sporadically on pushbuild
#
#
# ==== Usage ====
#
# This file assumes the following:
#
# - The test language variable $slave_is_idempotent is set to 1 if the
# slave is expected to stop on duplicate key errors (i.e., if the
# binlog is in statement mode or
# @@global.slave_exec_mode=STRICT). It is set to 0 otherwise.
#
# - Replication has been initialized by include/master-slave.inc
#
# - The test adds a suppression for the following warning:
# Slave: Can't find record in 't1' error.* 1032
--echo ==== Initialize ====
--echo [on master]
connection master;
CREATE TABLE t1(a INT PRIMARY KEY);
--echo [on slave]
sync_slave_with_master;
--echo ==== Test: SQL thread sees 'INSERT' of existing key ====
--echo ---- Prepare slave so that it will get duplicate key error ----
# This row will be in the way of the row inserted by master.
INSERT INTO t1 VALUES (1);
--echo ---- Insert rows on master ----
--echo [on master]
connection master;
# Insert the same row on master
INSERT INTO t1 VALUES (1);
save_master_pos;
SELECT * FROM t1;
--echo [on slave]
connection slave;
# If we are statement-logging or if slave_exec_mode=STRICT, we now
# expect to see an error on the slave. Otherwise (i.e., we are
# row-logging and slave_exec_mode=IDEMPOTENT), we expect that the
# duplicate row is ignored by the slave and replication continues.
if (`SELECT @@global.binlog_format != 'ROW' OR @@global.slave_exec_mode = 'STRICT'`) {
--echo ---- Wait until slave stops with an error ----
# Wait until the slave tries to run the query, fails with duplicate
# key error, and stops the SQL thread.
let $slave_sql_errno= 1062; # ER_DUP_ENTRY
source include/wait_for_slave_sql_error.inc;
--let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1)
--replace_regex /end_log_pos [0-9]+/end_log_pos END_LOG_POS/
--disable_query_log
--eval SELECT "$err" as 'Last_SQL_Error (expected "duplicate key" error)'
--enable_query_log
call mtr.add_suppression("Slave SQL.*Duplicate entry .1. for key .PRIMARY.* error.* 1062");
SELECT * FROM t1;
--echo ---- Resolve the conflict on the slave and restart SQL thread ----
DELETE FROM t1 WHERE a = 1;
START SLAVE SQL_THREAD;
source include/wait_for_slave_sql_to_start.inc;
}
--echo ---- Sync slave and verify that there is no error ----
sync_with_master;
let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
--echo Last_SQL_Error = '$err' (expected no error)
SELECT * FROM t1;
--echo ==== Test: SQL thread sees 'DELETE' of non-existing row ====
--echo ---- On master, insert two rows, the second with binlogging off ----
--echo [on master]
connection master;
DELETE FROM t1;
INSERT INTO t1 VALUES (1);
--echo [on slave]
sync_slave_with_master;
DELETE FROM t1 WHERE a = 1;
--echo ---- On master, remove the row that does not exist on slave ----
--echo [on master]
connection master;
DELETE FROM t1 WHERE a = 1;
SELECT * FROM t1;
save_master_pos;
--echo [on slave]
connection slave;
# If we are row-logging and slave_exec_mode is STRICT, we now expect
# an error since the row to delete does not exist on slave. Otherwise
# (i.e., either we are statement-logging or slave_exec_mode is
# IDEMPOTENT), the absence of the row to delete is ignored and
# replication continues.
if (`SELECT @@global.binlog_format = 'ROW' AND @@global.slave_exec_mode = 'STRICT'`) {
--echo ---- Wait until slave stops with an error ----
call mtr.add_suppression("Slave SQL.*Can.t find record in .t1., error.* 1032");
let $slave_sql_errno= 1032; # ER_KEY_NOT_FOUND
source include/wait_for_slave_sql_error.inc;
--let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1)
--replace_regex /end_log_pos [0-9]+/end_log_pos END_LOG_POS/
--disable_query_log
--eval SELECT "$err" as 'Last_SQL_Error (expected "duplicate key" error)'
--enable_query_log
SELECT * FROM t1;
--echo ---- Resolve the conflict on the slave and restart SQL thread ----
INSERT INTO t1 VALUES (1);
START SLAVE SQL_THREAD;
source include/wait_for_slave_sql_to_start.inc;
}
--echo ---- Sync slave and verify that there is no error ----
# The slave should sync ok, and SHOW SLAVE STATUS should give no
# error.
sync_with_master;
let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
--echo Last_SQL_Error = $err (expected no error)
SELECT * FROM t1;
--echo ==== Clean up ====
--echo [on master]
connection master;
DROP TABLE t1;
--echo [on slave]
--sync_slave_with_master
|