diff options
-rw-r--r-- | mysql-test/std_data/rpl/master-bin-seq_10.3.36.000001 | bin | 0 -> 1245 bytes | |||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_parallel_seq.result | 46 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_parallel_seq.test | 81 | ||||
-rw-r--r-- | sql/ha_sequence.cc | 3 | ||||
-rw-r--r-- | sql/log_event.cc | 27 | ||||
-rw-r--r-- | sql/rpl_parallel.cc | 7 | ||||
-rw-r--r-- | sql/slave.cc | 36 | ||||
-rw-r--r-- | sql/slave.h | 3 |
8 files changed, 190 insertions, 13 deletions
diff --git a/mysql-test/std_data/rpl/master-bin-seq_10.3.36.000001 b/mysql-test/std_data/rpl/master-bin-seq_10.3.36.000001 Binary files differnew file mode 100644 index 00000000000..0fa163d0484 --- /dev/null +++ b/mysql-test/std_data/rpl/master-bin-seq_10.3.36.000001 diff --git a/mysql-test/suite/rpl/r/rpl_parallel_seq.result b/mysql-test/suite/rpl/r/rpl_parallel_seq.result new file mode 100644 index 00000000000..d3512d6cc53 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_parallel_seq.result @@ -0,0 +1,46 @@ +include/master-slave.inc +[connection master] +connection slave; +include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +# MDEV-29621 the sequence engine binlog_row_image-full events +# MDL-deadlock on the parallel slave. +connection master; +CREATE SEQUENCE s1; +SET @@session.binlog_row_image=FULL; +SET @@session.debug_dbug="+d,binlog_force_commit_id"; +SET @commit_id=7; +SET @@gtid_seq_no=100; +SELECT NEXT VALUE FOR s1; +NEXT VALUE FOR s1 +1 +INSERT INTO s1 VALUES(2, 1, 10, 1, 2, 1, 1, 0); +SET @@session.debug_dbug=""; +connection slave; +SET @@global.slave_parallel_threads=2; +SET @@global.slave_parallel_mode=optimistic; +SET @@global.debug_dbug="+d,hold_worker_on_schedule"; +include/start_slave.inc +SET DEBUG_SYNC = 'now SIGNAL continue_worker'; +connection master; +DROP SEQUENCE s1; +connection slave; +include/stop_slave.inc +# Simulate buggy 10.3.36 master to prove the parallel applier +# does not deadlock now at replaying the above master load. +connection master; +include/rpl_stop_server.inc [server_number=1] +include/rpl_start_server.inc [server_number=1] +connection slave; +RESET MASTER; +SET @@global.gtid_slave_pos=""; +CHANGE MASTER TO master_host='127.0.0.1', master_port=SERVER_MYPORT_1, master_user='root', master_use_gtid=slave_pos; +START SLAVE UNTIL MASTER_GTID_POS='0-1-102'; +SET DEBUG_SYNC = 'now SIGNAL continue_worker'; +include/wait_for_slave_to_stop.inc +SET debug_sync = RESET; +SET @@global.slave_parallel_threads= 0; +SET @@global.slave_parallel_mode= conservative; +SET @@global.debug_dbug = ""; +include/start_slave.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_seq.test b/mysql-test/suite/rpl/t/rpl_parallel_seq.test new file mode 100644 index 00000000000..e92c0f61746 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_seq.test @@ -0,0 +1,81 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; + +--echo # MDEV-29621 the sequence engine binlog_row_image-full events +--echo # MDL-deadlock on the parallel slave. +--connection master +CREATE SEQUENCE s1; +SET @@session.binlog_row_image=FULL; +SET @@session.debug_dbug="+d,binlog_force_commit_id"; +SET @commit_id=7; +SET @@gtid_seq_no=100; +SELECT NEXT VALUE FOR s1; +INSERT INTO s1 VALUES(2, 1, 10, 1, 2, 1, 1, 0); +SET @@session.debug_dbug=""; + +--connection slave +--let $slave_parallel_threads=`select @@global.slave_parallel_threads` +--let $slave_parallel_mode=`select @@global.slave_parallel_mode` +SET @@global.slave_parallel_threads=2; +SET @@global.slave_parallel_mode=optimistic; +SET @@global.debug_dbug="+d,hold_worker_on_schedule"; +--source include/start_slave.inc + +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to start commit before starting%" +--source include/wait_condition.inc +SET DEBUG_SYNC = 'now SIGNAL continue_worker'; + +--connection master +DROP SEQUENCE s1; +--sync_slave_with_master +--source include/stop_slave.inc + +--echo # Simulate buggy 10.3.36 master to prove the parallel applier +--echo # does not deadlock now at replaying the above master load. +--connection master +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master-bin.000001 +--copy_file $MYSQL_TEST_DIR/std_data/rpl/master-bin-seq_10.3.36.000001 $datadir/master-bin.000001 + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc +--save_master_pos + +--connection slave +RESET MASTER; +SET @@global.gtid_slave_pos=""; + +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1, master_user='root', master_use_gtid=slave_pos; + +START SLAVE UNTIL MASTER_GTID_POS='0-1-102'; + +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit" +--source include/wait_condition.inc +SET DEBUG_SYNC = 'now SIGNAL continue_worker'; + +# +# MDEV-29621 clean up. +# +--source include/wait_for_slave_to_stop.inc +SET debug_sync = RESET; +--eval SET @@global.slave_parallel_threads= $slave_parallel_threads +--eval SET @@global.slave_parallel_mode= $slave_parallel_mode + SET @@global.debug_dbug = ""; +--source include/start_slave.inc + + +--source include/rpl_end.inc diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index a0959f692cf..35e765188cb 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -235,8 +235,9 @@ int ha_sequence::write_row(uchar *buf) on master and slaves - Check that the new row is an accurate SEQUENCE object */ - THD *thd= table->in_use; + /* mark a full binlog image insert to force non-parallel slave */ + thd->transaction.stmt.mark_trans_did_ddl(); if (table->s->tmp_table == NO_TMP_TABLE && thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE, diff --git a/sql/log_event.cc b/sql/log_event.cc index b2b1adc1558..9eb10ce1a58 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -13713,8 +13713,14 @@ Rows_log_event::write_row(rpl_group_info *rgi, int Rows_log_event::update_sequence() { TABLE *table= m_table; // pointer to event's table + bool old_master= false; + int err= 0; - if (!bitmap_is_set(table->rpl_write_set, MIN_VALUE_FIELD_NO)) + if (!bitmap_is_set(table->rpl_write_set, MIN_VALUE_FIELD_NO) || + (!(table->in_use->rgi_slave->gtid_ev_flags2 & Gtid_log_event::FL_DDL) && + !(old_master= + rpl_master_has_bug(thd->rgi_slave->rli, + 29621, FALSE, FALSE, FALSE, TRUE)))) { /* This event come from a setval function executed on the master. Update the sequence next_number and round, like we do with setval() @@ -13727,12 +13733,27 @@ int Rows_log_event::update_sequence() return table->s->sequence->set_value(table, nextval, round, 0) > 0; } - + if (thd->rgi_slave->is_parallel_exec && old_master) + { + DBUG_ASSERT(thd->rgi_slave->parallel_entry); + /* + With parallel replication enabled, we can't execute alongside any other + transaction in which we may depend, so we force retry to release + the server layer table lock for possible prior in binlog order + same table transactions. + */ + if (thd->rgi_slave->parallel_entry->last_committed_sub_id < + thd->rgi_slave->wait_commit_sub_id) + { + err= ER_LOCK_DEADLOCK; + my_error(err, MYF(0)); + } + } /* Update all fields in table and update the active sequence, like with ALTER SEQUENCE */ - return table->file->ha_write_row(table->record[0]); + return err == 0 ? table->file->ha_write_row(table->record[0]) : err; } diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index dbe77c54230..7ec87e4aa62 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -2780,7 +2780,12 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, if (mode <= SLAVE_PARALLEL_MINIMAL || !(gtid_flags & Gtid_log_event::FL_GROUP_COMMIT_ID) || - e->last_commit_id != gtid_ev->commit_id) + e->last_commit_id != gtid_ev->commit_id || + /* + MULTI_BATCH is also set when the current gtid even being a member + of a commit group is flagged as DDL which disallows parallel. + */ + (gtid_flags & Gtid_log_event::FL_DDL)) flags|= group_commit_orderer::MULTI_BATCH; /* Make sure we do not attempt to run DDL in parallel speculatively. */ if (gtid_flags & Gtid_log_event::FL_DDL) diff --git a/sql/slave.cc b/sql/slave.cc index b64b9a64979..3f06c40e7c2 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -8028,14 +8028,15 @@ end: @return TRUE if master has the bug, FALSE if it does not. */ bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, - bool (*pred)(const void *), const void *param) + bool (*pred)(const void *), const void *param, + bool maria_master) { struct st_version_range_for_one_bug { uint bug_id; const uchar introduced_in[3]; // first version with bug const uchar fixed_in[3]; // first version with fix }; - static struct st_version_range_for_one_bug versions_for_all_bugs[]= + static struct st_version_range_for_one_bug versions_for_their_bugs[]= { {24432, { 5, 0, 24 }, { 5, 0, 38 } }, {24432, { 5, 1, 12 }, { 5, 1, 17 } }, @@ -8043,13 +8044,30 @@ bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, {33029, { 5, 1, 0 }, { 5, 1, 12 } }, {37426, { 5, 1, 0 }, { 5, 1, 26 } }, }; + static struct st_version_range_for_one_bug versions_for_our_bugs[]= + { + {29621, { 10, 3, 36 }, { 10, 3, 39 } }, + {29621, { 10, 4, 26 }, { 10, 4, 29 } }, + {29621, { 10, 5, 17 }, { 10, 5, 20 } }, + {29621, { 10, 6, 9 }, { 10, 6, 13 } }, + {29621, { 10, 7, 5 }, { 10, 7, 9 } }, + {29621, { 10, 8, 4 }, { 10, 8, 8 } }, + {29621, { 10, 9, 2 }, { 10, 9, 6 } }, + {29621, { 10, 10,1 }, { 10, 10,4 } }, + {29621, { 10, 11,1 }, { 10, 11,3 } }, + }; const uchar *master_ver= rli->relay_log.description_event_for_exec->server_version_split.ver; DBUG_ASSERT(sizeof(rli->relay_log.description_event_for_exec->server_version_split.ver) == 3); - for (uint i= 0; - i < sizeof(versions_for_all_bugs)/sizeof(*versions_for_all_bugs);i++) + struct st_version_range_for_one_bug* versions_for_all_bugs= maria_master ? + versions_for_our_bugs : versions_for_their_bugs; + uint all_size= maria_master ? + sizeof(versions_for_our_bugs)/sizeof(*versions_for_our_bugs) : + sizeof(versions_for_their_bugs)/sizeof(*versions_for_their_bugs); + + for (uint i= 0; i < all_size; i++) { const uchar *introduced_in= versions_for_all_bugs[i].introduced_in, *fixed_in= versions_for_all_bugs[i].fixed_in; @@ -8058,18 +8076,21 @@ bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, (memcmp(fixed_in, master_ver, 3) > 0) && (pred == NULL || (*pred)(param))) { + const char *bug_source= maria_master ? + "https://jira.mariadb.org/browse/MDEV-" : + "http://bugs.mysql.com/bug.php?id="; if (!report) return TRUE; // a short message for SHOW SLAVE STATUS (message length constraints) my_printf_error(ER_UNKNOWN_ERROR, "master may suffer from" - " http://bugs.mysql.com/bug.php?id=%u" + " %s%u" " so slave stops; check error log on slave" - " for more info", MYF(0), bug_id); + " for more info", MYF(0), bug_source, bug_id); // a verbose message for the error log rli->report(ERROR_LEVEL, ER_UNKNOWN_ERROR, NULL, "According to the master's version ('%s')," " it is probable that master suffers from this bug:" - " http://bugs.mysql.com/bug.php?id=%u" + " %s%u" " and thus replicating the current binary log event" " may make the slave's data become different from the" " master's data." @@ -8083,6 +8104,7 @@ bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, " equal to '%d.%d.%d'. Then replication can be" " restarted.", rli->relay_log.description_event_for_exec->server_version, + bug_source, bug_id, fixed_in[0], fixed_in[1], fixed_in[2]); return TRUE; diff --git a/sql/slave.h b/sql/slave.h index 8d3b4f6d2aa..aeea317a5ab 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -231,7 +231,8 @@ bool show_all_master_info(THD* thd); void show_binlog_info_get_fields(THD *thd, List<Item> *field_list); bool show_binlog_info(THD* thd); bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, - bool (*pred)(const void *), const void *param); + bool (*pred)(const void *), const void *param, + bool maria_master= false); bool rpl_master_erroneous_autoinc(THD* thd); const char *print_slave_db_safe(const char *db); |