275 lines
10 KiB
Plaintext
275 lines
10 KiB
Plaintext
# ==== Requirements ====
|
|
#
|
|
# The following situations should result in errors:
|
|
#
|
|
# E1. A JSON path exists on the master but not on slave, and is
|
|
# updated/deleted on teh master.
|
|
#
|
|
# E2. A JSON path exists on the slave but not on the master, and is
|
|
# inserted on the master.
|
|
#
|
|
# E3. The slave has an extra column, which is generated and has a uniqueness
|
|
# constaint that gets violated by the update.
|
|
#
|
|
# E4. Both master and slave have a generated column, and the slave has an
|
|
# extra uniquness constraint that gets violated by the update.
|
|
#
|
|
# E5. Out of memory happens while applying a JSON diff.
|
|
#
|
|
# E6. The row event containing partial JSON is corrupted.
|
|
# - This includes a number of different ways to corrupt the event.
|
|
# See implementation of E6 below.
|
|
#
|
|
# The consequence of the error depends on the mode; there are three modes:
|
|
#
|
|
# M1. Normal mode, error causing slave to stop.
|
|
#
|
|
# M2. slave_skip_errors includes the error.
|
|
#
|
|
# M3. slave_exec_mode=IDEMPOTENT
|
|
#
|
|
# In addition, the consequence of corrupted events should be that
|
|
# mysqlbinlog -v prints an appropriate message when failing to decode
|
|
# the row event.
|
|
#
|
|
# The code paths to handle idempotent errors are different for each
|
|
# slave_rows_search_algorithms, hence we must run the test once for each
|
|
# algorithm.
|
|
#
|
|
# ==== Implementation ====
|
|
#
|
|
# Setup each scenario using
|
|
# extra/rpl_tests/rpl_row_jsondiff_error_scenario.inc
|
|
#
|
|
# Setup scenarios in a loop with three iterations, each iteration testing
|
|
# one of M1-M3.
|
|
#
|
|
# Use include/begin_replace_combination.inc to run with all different
|
|
# slave_rows_search_algorithms.
|
|
#
|
|
# ==== Related Worklog ====
|
|
#
|
|
# WL#2955 RBR replication of partial JSON updates
|
|
#
|
|
|
|
--source include/have_debug.inc
|
|
--source include/have_grep.inc
|
|
--source include/master-slave.inc
|
|
|
|
--echo ######## Configure ########
|
|
|
|
--let $dollar_func= CHAR(36)
|
|
--let $dollar= `SELECT $dollar_func`
|
|
|
|
--echo # Configure slave_rows_search_algorithms on master
|
|
--let $replace_combination_from= BOTH.BINLOG_FORMAT=ROW,MIXED,STATEMENT
|
|
--let $replace_combination_to= GLOBAL.SLAVE_ROWS_SEARCH_ALGORITHMS=INDEX_SCAN,HASH_SCAN,TABLE_SCAN
|
|
--source include/rpl_connection_master.inc
|
|
--source include/begin_replace_combination.inc
|
|
|
|
--echo # Configure partial JSON on master
|
|
--source include/rpl_connection_master.inc
|
|
SET @old_binlog_row_image= @@SESSION.BINLOG_ROW_IMAGE;
|
|
SET @old_binlog_row_value_options= @@SESSION.BINLOG_ROW_VALUE_OPTIONS;
|
|
SET @@SESSION.BINLOG_ROW_IMAGE = 'MINIMAL';
|
|
SET @@SESSION.BINLOG_ROW_VALUE_OPTIONS = 'PARTIAL_JSON';
|
|
|
|
--echo # Add error suppressions on slave
|
|
--source include/rpl_connection_slave.inc
|
|
call mtr.add_suppression("Could not execute Update_rows_partial event on table test.t");
|
|
call mtr.add_suppression("Can't find record in 't'");
|
|
# When mts is enabled
|
|
call mtr.add_suppression("The slave coordinator and worker threads are stopped, possibly leaving data in inconsistent state");
|
|
call mtr.add_suppression("Slave: Could not apply JSON diff");
|
|
call mtr.add_suppression("Slave: Corrupted JSON diff");
|
|
call mtr.add_suppression("Slave: Corrupted replication event was detected");
|
|
call mtr.add_suppression("Slave: Got error 1610 - ");
|
|
call mtr.add_suppression("Slave: Got error 3648 - ");
|
|
call mtr.add_suppression("Slave: Got error 3649 - ");
|
|
call mtr.add_suppression("Slave: Got error 5 - ");
|
|
|
|
--echo ######## Test ########
|
|
|
|
--let $clean_error= 1
|
|
|
|
--let $mode= 0
|
|
while ($mode < 3)
|
|
{
|
|
--source include/rpl_connection_slave.inc
|
|
|
|
if ($mode == 0)
|
|
{
|
|
--let $error_mode= FAIL
|
|
--source include/stop_slave.inc
|
|
}
|
|
if ($mode == 1)
|
|
{
|
|
--let $error_mode= SKIP
|
|
|
|
--let $rpl_server_number= 2
|
|
# Error ER_KEY_NOT_FOUND
|
|
--let $er_dup_entry= convert_error(ER_DUP_ENTRY)
|
|
--let $er_key_not_found= convert_error(ER_KEY_NOT_FOUND)
|
|
--let $er_could_not_apply_json_diff= convert_error(ER_COULD_NOT_APPLY_JSON_DIFF)
|
|
--let $er_corrupted_json_diff= convert_error(ER_CORRUPTED_JSON_DIFF)
|
|
--let $er_slave_corrupt_event= convert_error(ER_SLAVE_CORRUPT_EVENT)
|
|
--let $rpl_server_parameters= --slave_skip_errors=$er_dup_entry,$er_key_not_found,$er_could_not_apply_json_diff,$er_corrupted_json_diff,$er_slave_corrupt_event,5
|
|
--source include/rpl_restart_server.inc
|
|
--source include/rpl_connection_slave.inc
|
|
}
|
|
if ($mode == 2)
|
|
{
|
|
--let $error_mode= IDEMPOTENT
|
|
|
|
--let $rpl_server_number= 2
|
|
--let $rpl_server_parameters= --skip-slave-start
|
|
--source include/rpl_restart_server.inc
|
|
|
|
--source include/rpl_connection_slave.inc
|
|
SET GLOBAL SLAVE_EXEC_MODE = IDEMPOTENT;
|
|
}
|
|
|
|
--echo ******** ERROR MODE: $error_mode ********
|
|
|
|
--echo ---- Configure slave ----
|
|
# Configure slave options here and not before the loop, since we
|
|
# restart the server above.
|
|
|
|
--echo # Configure slave_rows_search_algorithms and binlog_format
|
|
--source include/rpl_connection_slave.inc
|
|
--source include/begin_replace_combination.inc
|
|
|
|
--echo # Configure partial JSON
|
|
SET @old_binlog_row_image= @@GLOBAL.BINLOG_ROW_IMAGE;
|
|
SET @old_binlog_row_value_options= @@GLOBAL.BINLOG_ROW_VALUE_OPTIONS;
|
|
SET @@GLOBAL.BINLOG_ROW_IMAGE = 'MINIMAL';
|
|
SET @@GLOBAL.BINLOG_ROW_VALUE_OPTIONS = 'PARTIAL_JSON';
|
|
|
|
--source include/start_slave.inc
|
|
|
|
# For show_rpl_debug_info
|
|
--let $extra_debug_table= test.t
|
|
|
|
--let $table= test.t
|
|
--let $column_def= i INT PRIMARY KEY, j JSON
|
|
--let $stmt_pre= UPDATE t SET j =
|
|
--let $stmt_post= WHERE i = 1
|
|
--let $insert_columns= (i, j)
|
|
|
|
--let $desc= E1. Path exists on master but not on slave, JSON_REMOVE
|
|
--let $rows= (1, '[1, {"m" : 1}]')
|
|
--let $rows_slave= (1, '[1, {"s" : 1}]')
|
|
--let $stmt= JSON_REMOVE(j, '$dollar[1].m')
|
|
--let $error= convert_error(ER_COULD_NOT_APPLY_JSON_DIFF)
|
|
--source extra/rpl_tests/rpl_row_jsondiff_error_scenario.inc
|
|
|
|
--let $desc= E1. Path exists on master but not on slave, JSON_SET
|
|
--let $rows= (1, '[1, {"m" : 1}]')
|
|
--let $rows_slave= (1, '[1, {"s" : 1}]')
|
|
--let $stmt= JSON_SET(j, '$dollar[1].m', 2)
|
|
--let $error= convert_error(ER_COULD_NOT_APPLY_JSON_DIFF)
|
|
--source extra/rpl_tests/rpl_row_jsondiff_error_scenario.inc
|
|
|
|
--let $desc= E2. Path exists on slave but not on master
|
|
--let $rows= (1, '[1, {"m" : 1}]')
|
|
--let $rows_slave= (1, '[1, {"s" : 1}]')
|
|
--let $stmt= JSON_SET(j, '$dollar[1].s', 2)
|
|
--let $error= convert_error(ER_COULD_NOT_APPLY_JSON_DIFF)
|
|
--source extra/rpl_tests/rpl_row_jsondiff_error_scenario.inc
|
|
|
|
# Disabled due to BUG#26630497
|
|
if (0) {
|
|
--let $desc= E3. Violation of uniqueness constraint in slave-only generated column
|
|
--let $column_def= i INT PRIMARY KEY, j JSON
|
|
--let $column_def_slave= $column_def, g INT GENERATED ALWAYS AS (j->"$dollar.id") VIRTUAL UNIQUE KEY
|
|
--let $rows_slave=
|
|
--let $rows= (1, '{"id": 1, "value": "x"}'), (2, '{"id": 2, "value": "y"}')
|
|
--let $stmt= JSON_SET(j, '$dollar.id', 2)
|
|
--let $error= convert_error(ER_DUP_ENTRY)
|
|
--source extra/rpl_tests/rpl_row_jsondiff_error_scenario.inc
|
|
}
|
|
|
|
--let $desc= E4. Violation of slave-only uniqueness constraint in generated column
|
|
--let $column_def= i INT PRIMARY KEY, j JSON, g INT GENERATED ALWAYS AS (j->"$dollar.id") VIRTUAL
|
|
--let $column_def_slave= $column_def UNIQUE KEY
|
|
--let $rows_slave=
|
|
--let $rows= (1, '{"id": 1, "value": "x"}'), (2, '{"id": 2, "value": "y"}')
|
|
--let $stmt= JSON_SET(j, '$dollar.id', 2)
|
|
--let $error= convert_error(ER_DUP_ENTRY)
|
|
--source extra/rpl_tests/rpl_row_jsondiff_error_scenario.inc
|
|
|
|
--let $desc= E5. Out of memory applying diff
|
|
--let $column_def= i INT PRIMARY KEY, j JSON
|
|
--let $column_def_slave=
|
|
--let $rows= (1, '{"id": 1, "value": "x"}')
|
|
--let $stmt= JSON_SET(j, '$dollar.id', REPEAT('a', 1024))
|
|
--let $slave_debug_symbol= simulate_oom_in_apply_json_diffs
|
|
--let $error= 5
|
|
--source include/rpl_connection_slave.inc
|
|
SET GLOBAL BINLOG_ROW_VALUE_OPTIONS = '';
|
|
--source include/stop_slave_sql.inc
|
|
--source include/start_slave_sql.inc
|
|
--source extra/rpl_tests/rpl_row_jsondiff_error_scenario.inc
|
|
--source include/rpl_connection_slave.inc
|
|
SET GLOBAL BINLOG_ROW_VALUE_OPTIONS = 'PARTIAL_JSON';
|
|
--source include/stop_slave_sql.inc
|
|
--source include/start_slave_sql.inc
|
|
--let $slave_debug_symbol=
|
|
|
|
--let $desc= E6. Corruption in event
|
|
--let $stmt= JSON_SET(j, '$dollar.id', '[1]')
|
|
# Use mysqlbinlog on corrupted events, in order to get coverage for
|
|
# error cases in mysqlbinlog
|
|
--let $use_mysqlbinlog= 1
|
|
# Make remove_debug_point not complain if the symbol was already removed.
|
|
--let $debug_if_exists= 1
|
|
|
|
# 1. Error cases where the format of a json diff is invalid in some
|
|
# way. The cases only differ on the suffix of the debug symbol,
|
|
# so we iterate over them in a loop to reduce copy-paste.
|
|
--let $error= convert_error(ER_CORRUPTED_JSON_DIFF)
|
|
--let $debug_symbol_list= bad_op,truncate_before_path_length,bad_path_length,truncate_before_path,bad_path_char,truncate_before_doc_length,bad_doc_length,truncate_before_doc,bad_doc_char
|
|
--let $debug_symbol_number= 1
|
|
while ($debug_symbol_number <= 9)
|
|
{
|
|
# Extract the Nth symbol from comma-separated list
|
|
--let $master_debug_symbol= `SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('$debug_symbol_list', ',', $debug_symbol_number), ',', -1)`
|
|
--let $master_debug_symbol= binlog_corrupt_json_diff_$master_debug_symbol
|
|
--source extra/rpl_tests/rpl_row_jsondiff_error_scenario.inc
|
|
|
|
--inc $debug_symbol_number
|
|
}
|
|
|
|
# 2. Other simulated error cases error.
|
|
# This uses a different error and a different debug symbol prefix,
|
|
# so execute outside the loop.
|
|
--let $error= convert_error(ER_SLAVE_CORRUPT_EVENT)
|
|
--let $master_debug_symbol= binlog_omit_last_column_from_table_map_event
|
|
--source extra/rpl_tests/rpl_row_jsondiff_error_scenario.inc
|
|
|
|
--let $debug_if_exists= 0
|
|
--let $use_mysqlbinlog= 0
|
|
--let $master_debug_symbol=
|
|
|
|
--echo ---- Clean up partial JSON on slave ----
|
|
--source include/rpl_connection_slave.inc
|
|
SET @@GLOBAL.BINLOG_ROW_VALUE_OPTIONS= @old_binlog_row_value_options;
|
|
SET @@GLOBAL.BINLOG_ROW_IMAGE= @old_binlog_row_image;
|
|
|
|
--inc $mode
|
|
}
|
|
|
|
--source include/rpl_connection_master.inc
|
|
SET @@SESSION.BINLOG_ROW_VALUE_OPTIONS= @old_binlog_row_value_options;
|
|
SET @@SESSION.BINLOG_ROW_IMAGE= @old_binlog_row_image;
|
|
--source include/end_replace_combination.inc
|
|
|
|
--source include/rpl_connection_slave.inc
|
|
# To avoid an error 'ER_RUNNING_APPLIER_PREVENTS_SWITCH_GLOBAL_BINLOG_FORMAT',
|
|
# which will be caused by the following include/end_replace_combination.inc
|
|
--source include/stop_slave_sql.inc
|
|
--source include/end_replace_combination.inc
|
|
|
|
--let $rpl_only_running_threads= 1
|
|
--source include/rpl_end.inc
|