commit 06d8f8e3dbb9796d998b1571e3ce9a30a04f67a9 Author: GAO Xiaoxin Date: Mon May 4 01:23:05 2020 +0800 Issue #99425 Semi-sync better to be aware of datacenter Description: It is a future request. MySQL semi-sync plugin has variable rpl_semi_sync_master_wait_for_slave_count, which can control the master to wait for at least number of slaves to response ack. For cross datacenter situation, such as two datacenter, we hope the semi-sync can ensure the master transaction has been received by the slave in the other datacenter. If only use rpl_semi_sync_master_wait_for_slave_count, we must cover all slaves in the datacenter of the master, which may lead master to wait too many slaves and has worse tolerance for net environment. How to repeat: Two datacenter and setup two mysqls for each datacenter. Suppose these four mysqls are m1, s1, s2, s3. m1 and s1 in datacenter1. s2 and s3 in datacenter2. The replication relationship is m1->s1, m1->s2, m1->s3. In order to ensure the transaction of m1 to replica to datacenter2, we should set rpl_semi_sync_master_wait_for_slave_count to be 2, actually we can finish the master commit if any of s2 or s3 response to master, no need to wait for s1. Suggested fix: It is better to introduce the available zoon for mysql, such as a datacenter is a available zoon, and mysql can config to wait at least number of available zoon slaves for master commit. For detail, each mysql has new options: 1. available_zoon_id, which indicate the available zoon of this mysql. It is a global variable and can not be dynamic changed. 2. rpl_semi_sync_master_wait_for_slave_az_count, which indicate the master only need to wait how many of available zoon slaves for commit. The master will maintain two ack_container, one for rpl_semi_sync_master_wait_for_slave_count, and one for rpl_semi_sync_master_wait_for_slave_az_count. Anyone ck_container satisfied can lead master to finish commit. For tow datacenter four mysqls situation mentioned above, we can set rpl_semi_sync_master_wait_for_slave_count to be 2 and set rpl_semi_sync_master_wait_for_slave_az_count to be 1. If s2 or s3 response fast than s1, the master can finish the commit more soon. diff --git a/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_wait_az_slave_count.result b/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_wait_az_slave_count.result new file mode 100644 index 0000000..eeace32 --- /dev/null +++ b/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_wait_az_slave_count.result @@ -0,0 +1,170 @@ +include/rpl_init.inc [topology=1->2, 1->3, 1->4, 1->5] +Warnings: +Note #### Sending passwords in plain text without SSL/TLS is extremely insecure. +Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information. +Warnings: +Note #### Sending passwords in plain text without SSL/TLS is extremely insecure. +Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information. +Warnings: +Note #### Sending passwords in plain text without SSL/TLS is extremely insecure. +Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information. +Warnings: +Note #### Sending passwords in plain text without SSL/TLS is extremely insecure. +Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information. +CREATE TABLE t1(c1 INT); +include/rpl_sync.inc +[connection server_1] +include/install_semisync_master.inc +[connection server_2] +include/install_semisync_slave.inc +[connection server_3] +include/install_semisync_slave.inc +[connection server_4] +include/install_semisync_slave.inc +[connection server_5] +include/install_semisync_slave.inc +[connection server_1] +SET GLOBAL rpl_semi_sync_master_trace_level= 255; +#################################################################### +# Test Case: az_count=0, slave_count has no enough slaves +#################################################################### +SET GLOBAL rpl_semi_sync_master_timeout=3000; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 20; +set global rpl_semi_sync_master_wait_for_slave_az_count=0; +INSERT INTO t1 VALUES(1); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 0 + 0] +include/assert.inc [rpl_semi_sync_master_no_tx should be 0 + 1] +################################################################### +# Test Case: az_count=0, slave_count has enough slaves +################################################################### +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 4; +INSERT INTO t1 VALUES(3); +INSERT INTO t1 VALUES(4); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 0 + 2] +include/assert.inc [rpl_semi_sync_master_no_tx should be 1 + 0] +######################################################################### +# Test Case: az_count=0, slave_count has more slaves +######################################################################### +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 2; +INSERT INTO t1 VALUES(10); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 2 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 1 + 0] +######################################################################### +# Test Case: az_count < slave_count, az_count has no enough slaves +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=10; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 20; +INSERT INTO t1 VALUES(11); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 3 + 0] +include/assert.inc [rpl_semi_sync_master_no_tx should be 1 + 1] +######################################################################### +# Test Case: az_count < slave_count, az_count has enough slaves +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=2; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 20; +INSERT INTO t1 VALUES(12); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 3 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 2 + 0] +######################################################################### +# Test Case: az_count < slave_count, az_count has more slaves, slave_count not enough +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=1; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 20; +INSERT INTO t1 VALUES(13); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 4 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 2 + 0] +######################################################################### +# Test Case: az_count < slave_count, az_count has more slaves, slave_count enough +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=1; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 4; +INSERT INTO t1 VALUES(14); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 5 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 2 + 0] +######################################################################### +# Test Case: az_count < slave_count, az_count has more slaves, slave_count more +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=1; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 1; +INSERT INTO t1 VALUES(15); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 6 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 2 + 0] +######################################################################### +# Test Case: az_count = slave_count, az_count has no enough slaves +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=10; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 10; +INSERT INTO t1 VALUES(16); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 7 + 0] +include/assert.inc [rpl_semi_sync_master_no_tx should be 2 + 1] +######################################################################### +# Test Case: az_count = slave_count, az_count has enough slaves +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=2; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 2; +INSERT INTO t1 VALUES(17); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 7 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 3 + 0] +######################################################################### +# Test Case: az_count > slave_count, slave_count has no enough slaves +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=20; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 10; +INSERT INTO t1 VALUES(18); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 8 + 0] +include/assert.inc [rpl_semi_sync_master_no_tx should be 3 + 1] +######################################################################### +# Test Case: az_count > slave_count, slave_count has enough slaves +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=20; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 4; +INSERT INTO t1 VALUES(19); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 8 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 4 + 0] +######################################################################### +# Test Case: az_count > slave_count, slave_count has more slaves +######################################################################### +set global rpl_semi_sync_master_wait_for_slave_az_count=20; +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 2; +INSERT INTO t1 VALUES(20); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 9 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 4 + 0] +#################################################################### +# Test Case: az_count=0, slave_count has no enough slaves +#################################################################### +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 20; +set global rpl_semi_sync_master_wait_for_slave_az_count=0; +INSERT INTO t1 VALUES(21); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 10 + 0] +include/assert.inc [rpl_semi_sync_master_no_tx should be 4 + 1] +################################################################### +# Test Case: az_count=0, slave_count has enough slaves +################################################################### +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 4; +INSERT INTO t1 VALUES(22); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 10 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 5 + 0] +######################################################################### +# Test Case: az_count=0, slave_count has more slaves +######################################################################### +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 2; +INSERT INTO t1 VALUES(23); +include/assert.inc [rpl_semi_sync_master_yes_tx should be 11 + 1] +include/assert.inc [rpl_semi_sync_master_no_tx should be 5 + 0] +SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 1; +SET GLOBAL rpl_semi_sync_master_wait_no_slave = 0; +[connection server_2] +include/uninstall_semisync_slave.inc +[connection server_3] +include/uninstall_semisync_slave.inc +[connection server_4] +include/uninstall_semisync_slave.inc +[connection server_5] +include/uninstall_semisync_slave.inc +[connection server_1] +include/uninstall_semisync_master.inc +[connection server_1] +DROP TABLE t1; +CALL mtr.add_suppression(".* Timeout waiting for reply of binlog .*"); +CALL mtr.add_suppression(".* Failed to allocate memory for ack_array .*"); +include/rpl_end.inc diff --git a/plugin/semisync/semisync_master.cc b/plugin/semisync/semisync_master.cc index 0ec9eb6..6d2a3b5 100644 --- a/plugin/semisync/semisync_master.cc +++ b/plugin/semisync/semisync_master.cc @@ -61,6 +61,7 @@ unsigned long long rpl_semi_sync_master_net_wait_time = 0; unsigned long long rpl_semi_sync_master_trx_wait_time = 0; bool rpl_semi_sync_master_wait_no_slave = true; unsigned int rpl_semi_sync_master_wait_for_slave_count = 1; +unsigned int rpl_semi_sync_master_wait_for_slave_available_zone_count = 0; static int getWaitTime(const struct timespec &start_ts); @@ -427,6 +428,8 @@ int ReplSemiSyncMaster::initObject() { */ if (setWaitSlaveCount(rpl_semi_sync_master_wait_for_slave_count)) return 1; + if (setWaitSlaveAZCount(rpl_semi_sync_master_wait_for_slave_available_zone_count)) return 1; + if (rpl_semi_sync_master_enabled) result = enableMaster(); else @@ -435,6 +438,16 @@ int ReplSemiSyncMaster::initObject() { return result; } +void ReplSemiSyncMaster::add_slave_az_id_to_map(int server_id, int available_zoon_id_slave) +{ + if (available_zoon_id_slave != static_cast(available_zoon_id)) { + lock(); + server_id_az_map[server_id] = available_zoon_id_slave; + unlock(); + } +} + + int ReplSemiSyncMaster::enableMaster() { int result = 0; @@ -491,6 +504,7 @@ int ReplSemiSyncMaster::disableMaster() { commit_file_name_inited_ = false; ack_container_.clear(); + az_ack_container_.clear(); set_master_enabled(false); LogErr(INFORMATION_LEVEL, ER_SEMISYNC_DISABLED_ON_MASTER); @@ -1130,6 +1144,7 @@ int ReplSemiSyncMaster::resetMaster() { lock(); ack_container_.clear(); + az_ack_container_.clear(); wait_file_name_inited_ = false; reply_file_name_inited_ = false; @@ -1169,6 +1184,28 @@ void ReplSemiSyncMaster::setExportStats() { unlock(); } +int ReplSemiSyncMaster::setWaitSlaveAZCount(unsigned int new_value) { + const AckInfo *ackinfo = NULL; + int result = 0; + + const char *kWho = "ReplSemiSyncMaster::updateWaitAZSlaves"; + function_enter(kWho); + + lock(); + if (new_value > (unsigned int)0) + result = az_ack_container_.resize(new_value, &ackinfo); + if (result == 0) { + rpl_semi_sync_master_wait_for_slave_available_zone_count = new_value; + if (ackinfo != NULL) + reportReplyBinlog(ackinfo->binlog_name, ackinfo->binlog_pos); + } + if (!new_value) + az_ack_container_.clear(); + + unlock(); + return function_exit(kWho, result); +} + int ReplSemiSyncMaster::setWaitSlaveCount(unsigned int new_value) { const AckInfo *ackinfo = NULL; int result = 0; diff --git a/plugin/semisync/semisync_master.h b/plugin/semisync/semisync_master.h index 95a01ab..0860a79 100644 --- a/plugin/semisync/semisync_master.h +++ b/plugin/semisync/semisync_master.h @@ -31,6 +31,7 @@ #include "my_io.h" #include "my_psi_config.h" #include "plugin/semisync/semisync.h" +#include extern PSI_memory_key key_ss_memory_TranxNodeAllocator_block; @@ -44,6 +45,8 @@ extern PSI_stage_info stage_waiting_for_semi_sync_slave; extern PSI_stage_info stage_reading_semi_sync_ack; extern unsigned int rpl_semi_sync_master_wait_for_slave_count; +extern unsigned int rpl_semi_sync_master_wait_for_slave_available_zone_count; +extern int get_slave_available_zoon_id(THD *thd); struct TranxNode { char log_name_[FN_REFLEN]; @@ -625,6 +628,7 @@ class ReplSemiSyncMaster : public ReplSemiSyncBase { bool state_ = false; /* whether semi-sync is switched */ AckContainer ack_container_; + AckContainer az_ack_container_; void lock(); void unlock(); @@ -642,6 +646,8 @@ class ReplSemiSyncMaster : public ReplSemiSyncBase { /* Switch semi-sync on when slaves catch up. */ int try_switch_on(const char *log_file_name, my_off_t log_file_pos); + std::map server_id_az_map; /*map*/ + public: ReplSemiSyncMaster(); ~ReplSemiSyncMaster(); @@ -650,6 +656,7 @@ class ReplSemiSyncMaster : public ReplSemiSyncBase { void setTraceLevel(unsigned long trace_level) { trace_level_ = trace_level; ack_container_.trace_level_ = trace_level; + az_ack_container_.trace_level_ = trace_level; if (active_tranxs_) active_tranxs_->trace_level_ = trace_level; } @@ -804,6 +811,17 @@ class ReplSemiSyncMaster : public ReplSemiSyncBase { int setWaitSlaveCount(unsigned int new_value); /* + 'SET rpl_semi_sync_master_wait_for_slave_available_zone_count' command is issued from user + and semi-sync need to rpl_semi_sync_master_wait_for_slave_available_zone_count and + notify az_ack_container_ to resize itself. + + @param[in] new_value The value users want to set to. + + @return It returns 0 if succeeds, otherwise 1 is returned. + */ + int setWaitSlaveAZCount(unsigned int new_value); + + /* Update ack_array after receiving an ack from a dump connection. If any binlog pos is already replied by rpl_semi_sync_master_wait_for_slave_count slaves, it will call reportReplyBinlog to increase received binlog @@ -821,13 +839,36 @@ class ReplSemiSyncMaster : public ReplSemiSyncBase { reportReplyBinlog(log_file_name, log_file_pos); else { const AckInfo *ackinfo = NULL; + const AckInfo *ackinfo_az = NULL; + if (rpl_semi_sync_master_wait_for_slave_available_zone_count && server_id_az_map.count(server_id)) { + int az_slave_id = server_id_az_map[server_id]; + ackinfo_az = az_ack_container_.insert(az_slave_id, log_file_name, log_file_pos); + } ackinfo = ack_container_.insert(server_id, log_file_name, log_file_pos); + /*choose the biggest ackinfo from ack_container_ and az_ack_container_*/ + if (ackinfo_az) { + if (!ackinfo) + ackinfo = ackinfo_az; + else { + if (ackinfo->less_than(ackinfo_az->binlog_name, ackinfo_az->binlog_pos)) + ackinfo = ackinfo_az; + } + } if (ackinfo != NULL) reportReplyBinlog(ackinfo->binlog_name, ackinfo->binlog_pos); } unlock(); } + + void add_slave_az_id_to_map(int server_id, int available_zoon_id_slave); + void remove_slave_az_id_to_map(int server_id) + { + lock(); + if (server_id_az_map.count(server_id)) + server_id_az_map.erase(server_id); + unlock(); + } }; /* System and status variables for the master component */ diff --git a/plugin/semisync/semisync_master_plugin.cc b/plugin/semisync/semisync_master_plugin.cc index 06f3668..d62564b 100644 --- a/plugin/semisync/semisync_master_plugin.cc +++ b/plugin/semisync/semisync_master_plugin.cc @@ -121,6 +121,9 @@ static int repl_semi_binlog_dump_start(Binlog_transmit_param *param, /* One more semi-sync slave */ repl_semisync->add_slave(); + uint32_t az_id_slave = get_slave_available_zoon_id(current_thd); + if (az_id_slave > 0) + repl_semisync->add_slave_az_id_to_map(param->server_id, az_id_slave); /* Tell server it will observe the transmission.*/ param->set_observe_flag(); @@ -149,6 +152,7 @@ static int repl_semi_binlog_dump_end(Binlog_transmit_param *param) { ack_receiver->remove_slave(current_thd); /* One less semi-sync slave */ repl_semisync->remove_slave(); + repl_semisync->remove_slave_az_id_to_map(param->server_id); THR_RPL_SEMI_SYNC_DUMP = false; } return 0; @@ -218,6 +222,10 @@ static void fix_rpl_semi_sync_master_wait_for_slave_count(MYSQL_THD thd, SYS_VAR *var, void *ptr, const void *val); +static void fix_rpl_semi_sync_master_wait_for_slave_az_count(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val); static MYSQL_SYSVAR_BOOL( enabled, rpl_semi_sync_master_enabled, PLUGIN_VAR_OPCMDARG, @@ -282,6 +290,18 @@ static MYSQL_SYSVAR_UINT( &fix_rpl_semi_sync_master_wait_for_slave_count, /* update */ 1, 1, 65535, 1); +static MYSQL_SYSVAR_UINT( + wait_for_slave_az_count, /* name */ + rpl_semi_sync_master_wait_for_slave_available_zone_count, /* var */ + PLUGIN_VAR_OPCMDARG, /* flags */ + "How many different available zoon slaves the events should be replicated" + " to. Semisynchronous replication master will wait until all events of the" + " transaction are replicated to at least" + " rpl_semi_sync_master_wait_for_slave_az_count slave avaliable zoons", + NULL, /* check() */ + &fix_rpl_semi_sync_master_wait_for_slave_az_count, /* update */ + 0, 0, 65535, 1); + static SYS_VAR *semi_sync_master_system_vars[] = { MYSQL_SYSVAR(enabled), MYSQL_SYSVAR(timeout), @@ -289,6 +309,7 @@ static SYS_VAR *semi_sync_master_system_vars[] = { MYSQL_SYSVAR(trace_level), MYSQL_SYSVAR(wait_point), MYSQL_SYSVAR(wait_for_slave_count), + MYSQL_SYSVAR(wait_for_slave_az_count), NULL, }; static void fix_rpl_semi_sync_master_timeout(MYSQL_THD, SYS_VAR *, void *ptr, @@ -332,6 +353,16 @@ static void fix_rpl_semi_sync_master_wait_for_slave_count(MYSQL_THD, SYS_VAR *, *static_cast(val)); } +static void fix_rpl_semi_sync_master_wait_for_slave_az_count(MYSQL_THD, SYS_VAR *, + void *, + const void *val) { + (void)repl_semisync->setWaitSlaveAZCount( + *static_cast(val)); +// rpl_semi_sync_master_wait_for_slave_available_zone_count +// = *static_cast(val); +} + + static void fix_rpl_semi_sync_master_wait_no_slave(MYSQL_THD, SYS_VAR *, void *ptr, const void *val) { if (rpl_semi_sync_master_wait_no_slave != *static_cast(val)) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c30315d..84ee5e3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1124,7 +1124,7 @@ ulong delay_key_write_options; uint protocol_version; uint lower_case_table_names; long tc_heuristic_recover; -ulong back_log, connect_timeout, server_id; +ulong back_log, connect_timeout, server_id, available_zoon_id; ulong table_cache_size; ulong table_cache_instances; ulong table_cache_size_per_instance; diff --git a/sql/mysqld.h b/sql/mysqld.h index 06961e2..d06d572 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -334,6 +334,7 @@ extern const char *binlog_error_action_list[]; extern ulong stored_program_cache_size; extern ulong back_log; extern "C" MYSQL_PLUGIN_IMPORT ulong server_id; +extern "C" MYSQL_PLUGIN_IMPORT ulong available_zoon_id; extern time_t server_start_time; extern char *opt_mysql_tmpdir; extern size_t mysql_unpacked_real_data_home_len; diff --git a/sql/rpl_master.cc b/sql/rpl_master.cc index a857c57..2d8cd96 100644 --- a/sql/rpl_master.cc +++ b/sql/rpl_master.cc @@ -1036,6 +1036,31 @@ String *get_slave_uuid(THD *thd, String *value) { } /** + An auxiliary function extracts slave available_zoon_id. + + @param[in] thd THD to access a user variable + @param[out] value String to return UUID value. + + @return if success value is returned else NULL is returned. +*/ +int get_slave_available_zoon_id(THD *thd) { + String value; + + mysql_mutex_lock(&thd->LOCK_thd_data); + const auto it = thd->user_vars.find("available_zoon_id"); + if (it != thd->user_vars.end() && it->second->length() > 0) { + value.copy(it->second->ptr(), it->second->length(), nullptr); + } + + mysql_mutex_unlock(&thd->LOCK_thd_data); + + if (value.is_empty()) + return 0; + + return atoi(value.ptr()); +} + +/** Callback function used by kill_zombie_dump_threads() function to to find zombie dump thread from the thd list. diff --git a/sql/rpl_master.h b/sql/rpl_master.h index 0fafba5..091ae96 100644 --- a/sql/rpl_master.h +++ b/sql/rpl_master.h @@ -55,6 +55,7 @@ int register_slave(THD *thd, uchar *packet, size_t packet_length); void unregister_slave(THD *thd, bool only_mine, bool need_lock_slave_list); bool show_slave_hosts(THD *thd); String *get_slave_uuid(THD *thd, String *value); +int get_slave_available_zoon_id(THD *thd); bool show_master_status(THD *thd); bool show_binlogs(THD *thd); void kill_zombie_dump_threads(THD *thd); diff --git a/sql/rpl_slave.cc b/sql/rpl_slave.cc index c4a620e..43fc38f 100644 --- a/sql/rpl_slave.cc +++ b/sql/rpl_slave.cc @@ -2355,6 +2355,11 @@ int io_thread_init_commands(MYSQL *mysql, Master_info *mi) { !check_io_slave_killed(mi->info_thd, mi, nullptr)) goto err; + sprintf(query, "SET @available_zoon_id= '%d'", static_cast(available_zoon_id)); + if (mysql_real_query(mysql, query, static_cast(strlen(query))) && + !check_io_slave_killed(mi->info_thd, mi, nullptr)) + goto err; + mysql_free_result(mysql_store_result(mysql)); return ret; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 29ad50e..d8036da 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -520,6 +520,7 @@ THD::THD(bool enable_plugins) where = THD::DEFAULT_WHERE; server_id = ::server_id; unmasked_server_id = server_id; + available_zoon_id = 1; set_command(COM_CONNECT); *scramble = '\0'; diff --git a/sql/sql_class.h b/sql/sql_class.h index d8275d6..650c240 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1295,6 +1295,7 @@ class THD : public MDL_context_owner, uint32 unmasked_server_id; uint32 server_id; + uint32 available_zoon_id; uint32 file_id; // for LOAD DATA INFILE /* remote (peer) port */ uint16 peer_port; @@ -1401,6 +1402,7 @@ class THD : public MDL_context_owner, const uchar *old_data, const uchar *new_data, const uchar *extra_row_info); void set_server_id(uint32 sid) { server_id = sid; } + void set_avaiable_zoon_id(uint32 aid) { available_zoon_id = aid; } /* Member functions to handle pending event for row-level logging. diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 0a8c8e6..13e6ec8 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3555,6 +3555,7 @@ static bool fix_server_id(sys_var *, THD *thd, enum_var_type) { thd->server_id = static_cast(server_id); return false; } + static Sys_var_ulong Sys_server_id( "server_id", "Uniquely identifies the server instance in the community of " @@ -3563,6 +3564,14 @@ static Sys_var_ulong Sys_server_id( VALID_RANGE(0, UINT_MAX32), DEFAULT(1), BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_server_id)); +static Sys_var_ulong Sys_available_zoon_id( + "available_zoon_id", + "Uniquely identifies the available zoon instance in the community of " + "replication partners", + GLOBAL_VAR(available_zoon_id), CMD_LINE(REQUIRED_ARG, OPT_SERVER_ID), + VALID_RANGE(0, UINT_MAX32), DEFAULT(1), BLOCK_SIZE(1), NO_MUTEX_GUARD, + NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(NULL)); + static Sys_var_charptr Sys_server_uuid( "server_uuid", "Uniquely identifies the server instance in the universe", READ_ONLY NON_PERSIST GLOBAL_VAR(server_uuid_ptr), NO_CMD_LINE,