polardbxengine/mysql-test/suite/rpl/t/rpl_row_jsondiff_error.test

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