diff --git a/mysql-test/suite/rpl/r/rpl_gtid_ignored_domain_ids_validation.result b/mysql-test/suite/rpl/r/rpl_gtid_ignored_domain_ids_validation.result new file mode 100644 index 0000000000000..745a5cf573b8a --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_gtid_ignored_domain_ids_validation.result @@ -0,0 +1,103 @@ +include/rpl_init.inc [topology=1->2] +# +# Setup: Create tables in two GTID domains on master +# +connection server_1; +SET @@session.gtid_domain_id= 1; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +SET @@session.gtid_domain_id= 2; +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES (100); +connection server_2; +SELECT * FROM t1; +a +1 +SELECT * FROM t2; +a +100 +# +# Test 1: IGNORE_DOMAIN_IDS with purged binlogs should not cause error 1236 +# +connection server_2; +include/stop_slave.inc +connection server_1; +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (200); +INSERT INTO t2 VALUES (201); +FLUSH LOGS; +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (202); +FLUSH LOGS; +include/wait_for_purge.inc "master-bin.000003" +show binary logs; +Log_name File_size +master-bin.000003 # +connection server_2; +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(2), MASTER_USE_GTID=slave_pos; +include/start_slave.inc +connection server_1; +SET @@session.gtid_domain_id= 1; +INSERT INTO t1 VALUES (2); +connection server_2; +# Slave should have domain 1 data (the domain it cares about) +SELECT * FROM t1 ORDER BY a; +a +1 +2 +# +# Test 2: DO_DOMAIN_IDS with purged binlogs should not cause error 1236 +# +connection server_2; +include/stop_slave.inc +connection server_1; +connection server_2; +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(), DO_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +include/start_slave.inc +connection server_1; +SET @@session.gtid_domain_id= 1; +INSERT INTO t1 VALUES (3); +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (300); +connection server_2; +include/stop_slave.inc +connection server_1; +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (400); +INSERT INTO t2 VALUES (401); +FLUSH LOGS; +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (402); +FLUSH LOGS; +include/wait_for_purge.inc "master-bin.000005" +show binary logs; +Log_name File_size +master-bin.000005 # +connection server_2; +CHANGE MASTER TO DO_DOMAIN_IDS=(1), IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +include/start_slave.inc +connection server_1; +SET @@session.gtid_domain_id= 1; +INSERT INTO t1 VALUES (4); +connection server_2; +# Slave should have all domain 1 data +SELECT * FROM t1 ORDER BY a; +a +1 +2 +3 +4 +# +# Cleanup +# +connection server_2; +include/stop_slave.inc +connection server_1; +connection server_2; +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +include/start_slave.inc +connection server_1; +SET @@session.gtid_domain_id= 0; +DROP TABLE t1, t2; +connection server_2; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_ignored_domain_ids_validation.test b/mysql-test/suite/rpl/t/rpl_gtid_ignored_domain_ids_validation.test new file mode 100644 index 0000000000000..12fffa0a9c3ab --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_ignored_domain_ids_validation.test @@ -0,0 +1,185 @@ +--source include/have_innodb.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +# +# MDEV-28213: A slave's ignored domain ids should not be validated when +# connecting to a master. +# +# When a slave connects to a master using MASTER_USE_GTID=Slave_Pos and the +# master has purged old binlogs, the master validates the slave's GTID state +# against the oldest available binlog's Gtid_list event. If the master's +# Gtid_list contains domains that the slave is configured to ignore (via +# IGNORE_DOMAIN_IDS or DO_DOMAIN_IDS), those domains should NOT be validated. +# Previously this would cause error 1236. +# + +--echo # +--echo # Setup: Create tables in two GTID domains on master +--echo # + +--connection server_1 +SET @@session.gtid_domain_id= 1; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); + +SET @@session.gtid_domain_id= 2; +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES (100); + +# Sync slave with master for both domains +--save_master_pos + +--connection server_2 +--sync_with_master + +SELECT * FROM t1; +SELECT * FROM t2; + +--echo # +--echo # Test 1: IGNORE_DOMAIN_IDS with purged binlogs should not cause error 1236 +--echo # + +--connection server_2 +--source include/stop_slave.inc + +--connection server_1 +# While slave is stopped, only advance domain 2 (which will be ignored). +# Domain 1 stays at the same position so the slave can still connect for it. +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (200); +INSERT INTO t2 VALUES (201); + +# Flush logs to rotate the binlog file, then flush again so we have a newer +# file to purge up to. +FLUSH LOGS; +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (202); +FLUSH LOGS; + +# Now purge all binlogs except the latest. +# The oldest remaining binlog's Gtid_list will reference both domains. +# Domain 1 will still be at the position the slave knows (up to date). +# Domain 2 will have advanced past the slave's position (stale for slave). +--let $purge_binlogs_to= query_get_value(SHOW MASTER STATUS, File, 1) +--source include/wait_for_purge.inc +--source include/show_binary_logs.inc + +--connection server_2 +# Configure slave to ignore domain 2. The slave has no up-to-date position +# for domain 2 since it was stopped before the latest domain 2 transactions. +# Without the fix, connecting would fail with error 1236 because the master +# validates domain 2's position even though the slave doesn't care about it. +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(2), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +# Verify slave can connect and replicate domain 1 data +--connection server_1 +SET @@session.gtid_domain_id= 1; +INSERT INTO t1 VALUES (2); +--save_master_pos + +--connection server_2 +--sync_with_master + +--echo # Slave should have domain 1 data (the domain it cares about) +SELECT * FROM t1 ORDER BY a; + +--echo # +--echo # Test 2: DO_DOMAIN_IDS with purged binlogs should not cause error 1236 +--echo # + +--connection server_2 +--source include/stop_slave.inc + +# The slave ignored domain 2 during test 1, so its position for domain 2 +# is stale. We need to update it to match the master before we can start +# replication without the ignore filter. +--connection server_1 +--let $master_pos= `SELECT @@GLOBAL.gtid_binlog_pos` +--connection server_2 +--disable_query_log +--eval SET GLOBAL gtid_slave_pos='$master_pos' +--enable_query_log + +# Reset domain filtering and sync up +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(), DO_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +# Sync up everything +--connection server_1 +SET @@session.gtid_domain_id= 1; +INSERT INTO t1 VALUES (3); +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (300); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + +--connection server_1 +# While slave is stopped, only advance domain 2 (which will NOT be in DO list). +# Domain 1 stays current so the slave can connect for it. +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (400); +INSERT INTO t2 VALUES (401); + +# Create new binlog and purge old ones +FLUSH LOGS; +SET @@session.gtid_domain_id= 2; +INSERT INTO t2 VALUES (402); +FLUSH LOGS; + +# Purge all old binlogs +--let $purge_binlogs_to= query_get_value(SHOW MASTER STATUS, File, 1) +--source include/wait_for_purge.inc +--source include/show_binary_logs.inc + +--connection server_2 +# Configure slave with DO_DOMAIN_IDS=(1) -- only replicate domain 1. +# This means domain 2 should be ignored during validation. +# Without the fix, this would fail because the master's oldest binlog +# references domain 2 but slave may not have the latest position for it. +CHANGE MASTER TO DO_DOMAIN_IDS=(1), IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +--connection server_1 +SET @@session.gtid_domain_id= 1; +INSERT INTO t1 VALUES (4); +--save_master_pos + +--connection server_2 +--sync_with_master + +--echo # Slave should have all domain 1 data +SELECT * FROM t1 ORDER BY a; + +--echo # +--echo # Cleanup +--echo # + +--connection server_2 +--source include/stop_slave.inc + +# Update slave's GTID position to match master for all domains, +# since domain 2 was not replicated during test 2. +--connection server_1 +--let $master_pos= `SELECT @@GLOBAL.gtid_binlog_pos` +--connection server_2 +--disable_query_log +--eval SET GLOBAL gtid_slave_pos='$master_pos' +--enable_query_log + +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +--connection server_1 +SET @@session.gtid_domain_id= 0; +DROP TABLE t1, t2; +--save_master_pos + +--connection server_2 +--sync_with_master + +--source include/rpl_end.inc diff --git a/sql/slave.cc b/sql/slave.cc index de1476e592542..218f1beb1673f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2558,6 +2558,117 @@ when it try to get the value of TIME_ZONE global variable from master."; } } } + + /* + Send the slave's IGNORE_DOMAIN_IDS and DO_DOMAIN_IDS to the master, + so it can skip GTID state validation for domains the slave doesn't + care about. See MDEV-28213. + + This is done as user variables so that older masters that don't know + about these variables simply ignore them (backwards compatible). + */ + { + DYNAMIC_ARRAY *ignore_ids= + &mi->domain_id_filter.m_domain_ids[Domain_id_filter::IGNORE_DOMAIN_IDS]; + DYNAMIC_ARRAY *do_ids= + &mi->domain_id_filter.m_domain_ids[Domain_id_filter::DO_DOMAIN_IDS]; + + if (ignore_ids->elements > 0) + { + query_str.length(0); + if (query_str.append( + STRING_WITH_LEN("SET @slave_connect_state_domain_ids_ignore='"), + system_charset_info)) + { + err_code= ER_OUTOFMEMORY; + errmsg= "The slave I/O thread stops because a fatal out-of-memory " + "error is encountered when it tries to set " + "@slave_connect_state_domain_ids_ignore."; + sprintf(err_buff, "%s Error: Out of memory", errmsg); + goto err; + } + for (uint i= 0; i < ignore_ids->elements; i++) + { + ulong domain_id; + get_dynamic(ignore_ids, (void *) &domain_id, i); + if (i > 0) + query_str.append(','); + query_str.append_ulonglong(domain_id); + } + query_str.append(STRING_WITH_LEN("'"), system_charset_info); + + rc= mysql_real_query(mysql, query_str.ptr(), query_str.length()); + if (unlikely(rc)) + { + if (check_io_slave_killed(mi, NULL)) + goto slave_killed_err; + err_code= mysql_errno(mysql); + if (is_network_error(err_code)) + { + mi->report(ERROR_LEVEL, err_code, NULL, + "Setting @slave_connect_state_domain_ids_ignore " + "failed with error: %s", mysql_error(mysql)); + goto network_err; + } + else + { + errmsg= "The slave I/O thread stops because a fatal error is " + "encountered when it tries to set " + "@slave_connect_state_domain_ids_ignore."; + sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql)); + goto err; + } + } + } + + if (do_ids->elements > 0) + { + query_str.length(0); + if (query_str.append( + STRING_WITH_LEN("SET @slave_connect_state_domain_ids_do='"), + system_charset_info)) + { + err_code= ER_OUTOFMEMORY; + errmsg= "The slave I/O thread stops because a fatal out-of-memory " + "error is encountered when it tries to set " + "@slave_connect_state_domain_ids_do."; + sprintf(err_buff, "%s Error: Out of memory", errmsg); + goto err; + } + for (uint i= 0; i < do_ids->elements; i++) + { + ulong domain_id; + get_dynamic(do_ids, (void *) &domain_id, i); + if (i > 0) + query_str.append(','); + query_str.append_ulonglong(domain_id); + } + query_str.append(STRING_WITH_LEN("'"), system_charset_info); + + rc= mysql_real_query(mysql, query_str.ptr(), query_str.length()); + if (unlikely(rc)) + { + if (check_io_slave_killed(mi, NULL)) + goto slave_killed_err; + err_code= mysql_errno(mysql); + if (is_network_error(err_code)) + { + mi->report(ERROR_LEVEL, err_code, NULL, + "Setting @slave_connect_state_domain_ids_do " + "failed with error: %s", mysql_error(mysql)); + goto network_err; + } + else + { + errmsg= "The slave I/O thread stops because a fatal error is " + "encountered when it tries to set " + "@slave_connect_state_domain_ids_do."; + sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql)); + goto err; + } + } + } + } } else { diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index f1661fbad950d..ef9d8a5d97ba3 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -139,6 +139,17 @@ struct binlog_send_info { bool slave_gtid_ignore_duplicates; bool using_gtid_state; + /* + Domain IDs that the slave has configured to ignore (via + CHANGE MASTER ... IGNORE_DOMAIN_IDS or DO_DOMAIN_IDS). + These domains should be excluded from GTID state validation + when the slave connects, to avoid spurious errors when the master's + binlog contains domains the slave doesn't care about. + See MDEV-28213. + */ + DYNAMIC_ARRAY slave_ignore_domain_ids; + DYNAMIC_ARRAY slave_do_domain_ids; + int error; const char *errmsg; char error_text[MAX_SLAVE_ERRMSG]; @@ -185,6 +196,15 @@ struct binlog_send_info { error_text[0] = 0; bzero(&error_gtid, sizeof(error_gtid)); until_binlog_state.init(); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &slave_ignore_domain_ids, + sizeof(ulong), 4, 4, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &slave_do_domain_ids, + sizeof(ulong), 4, 4, MYF(0)); + } + ~binlog_send_info() + { + delete_dynamic(&slave_ignore_domain_ids); + delete_dynamic(&slave_do_domain_ids); } }; @@ -801,6 +821,153 @@ get_slave_until_gtid(THD *thd, String *out_str) } +/* + Get the value of the @slave_connect_state_domain_ids_ignore user variable + into the supplied String. + + The slave sends this variable to let the master know which GTID domain IDs + it is configured to ignore (via IGNORE_DOMAIN_IDS or implied by + DO_DOMAIN_IDS). See MDEV-28213. + + Returns false if error (ie. slave did not set the variable), + true if success. +*/ +static bool +get_slave_ignore_domain_ids(THD *thd, String *out_str) +{ + bool null_value; + + const LEX_CSTRING name= + { STRING_WITH_LEN("slave_connect_state_domain_ids_ignore") }; + user_var_entry *entry= + (user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name.str, + name.length); + return entry && entry->val_str(&null_value, out_str, 0) && !null_value; +} + + +/* + Get the value of the @slave_connect_state_domain_ids_do user variable + into the supplied String. + + The slave sends this to let the master know which GTID domain IDs + it is configured to replicate (via DO_DOMAIN_IDS). Any domain NOT in + this list should be skipped during validation. See MDEV-28213. + + Returns false if not set, true if success. +*/ +static bool +get_slave_do_domain_ids(THD *thd, String *out_str) +{ + bool null_value; + + const LEX_CSTRING name= + { STRING_WITH_LEN("slave_connect_state_domain_ids_do") }; + user_var_entry *entry= + (user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name.str, + name.length); + return entry && entry->val_str(&null_value, out_str, 0) && !null_value; +} + + +/* + Parse a comma-separated list of domain IDs from a string and load them + into a DYNAMIC_ARRAY. Used to parse the slave's ignored domain IDs + sent via @slave_connect_state_domain_ids_ignore. + + @retval 0 success + @retval 1 error +*/ +static int +load_ignore_domain_ids(const char *str, size_t len, DYNAMIC_ARRAY *ids) +{ + const char *p= str; + const char *end= str + len; + bool expect_number= true; + + /* Skip leading whitespace */ + while (p < end && *p == ' ') + p++; + if (p >= end) + return 0; /* Empty string is valid */ + + while (p < end) + { + char *endptr; + ulong domain_id; + + /* Skip whitespace */ + while (p < end && *p == ' ') + p++; + if (p >= end) + break; + + if (expect_number) + { + domain_id= strtoul(p, &endptr, 10); + if (endptr == p) + return 1; /* Parse error: expected a number */ + if (insert_dynamic(ids, (uchar *) &domain_id)) + return 1; /* Out of memory */ + p= endptr; + expect_number= false; + } + else + { + if (*p != ',') + return 1; /* Parse error: expected a comma */ + p++; + expect_number= true; + } + } + + /* Trailing comma is invalid */ + if (expect_number && ids->elements > 0) + return 1; + + return 0; +} + + +/* + Check whether the given domain_id should be skipped based on the slave's + configured DO_DOMAIN_IDS and IGNORE_DOMAIN_IDS lists (MDEV-28213). + + A domain is skipped if: + - It is explicitly in the IGNORE list, OR + - A DO list is configured (non-empty) and the domain is NOT in it. +*/ +static bool +is_domain_id_ignored(const DYNAMIC_ARRAY *ignore_ids, + const DYNAMIC_ARRAY *do_ids, ulong domain_id) +{ + /* If IGNORE_DOMAIN_IDS is set, check if this domain is in it */ + for (uint32 i= 0; i < ignore_ids->elements; i++) + { + ulong id; + get_dynamic((DYNAMIC_ARRAY*) ignore_ids, (void*) &id, i); + if (id == domain_id) + return true; + } + /* + If DO_DOMAIN_IDS is set (non-empty), only domains in the DO list + should be validated. Any domain NOT in the list should be skipped. + */ + if (do_ids->elements > 0) + { + for (uint32 i= 0; i < do_ids->elements; i++) + { + ulong id; + get_dynamic((DYNAMIC_ARRAY*) do_ids, (void*) &id, i); + if (id == domain_id) + return false; /* Domain is in DO list, don't ignore */ + } + return true; /* Domain is NOT in DO list, ignore it */ + } + return false; +} + + /* Function prepares and sends repliation heartbeat event. @@ -1000,9 +1167,16 @@ get_binlog_list(MEM_ROOT *memroot, bool reverse= true, Gtid_list_log_event where D is not present in the requested slave state at all. Since if D is not in requested slave state, it means that slave needs to start at the very first GTID in domain D. + + The ignore_ids parameter (MDEV-28213) allows domains that the slave has + configured to ignore to be skipped during this check. Without this, a slave + that ignores a domain would fail to connect if the master's oldest binlog + references that domain but the slave has no position for it. */ static bool -contains_all_slave_gtid(slave_connection_state *st, Gtid_list_log_event *glev) +contains_all_slave_gtid(slave_connection_state *st, Gtid_list_log_event *glev, + const DYNAMIC_ARRAY *ignore_ids, + const DYNAMIC_ARRAY *do_ids) { uint32 i; @@ -1012,6 +1186,12 @@ contains_all_slave_gtid(slave_connection_state *st, Gtid_list_log_event *glev) const rpl_gtid *gtid= st->find(gl_domain_id); if (!gtid) { + /* + If the slave is configured to ignore this domain, skip the check. + The slave doesn't need events from this domain at all (MDEV-28213). + */ + if (is_domain_id_ignored(ignore_ids, do_ids, gl_domain_id)) + continue; /* The slave needs to start from the very beginning of this domain, which is in an earlier binlog file. So we need to search back further. @@ -1021,6 +1201,12 @@ contains_all_slave_gtid(slave_connection_state *st, Gtid_list_log_event *glev) if (gtid->server_id == glev->list[i].server_id && gtid->seq_no <= glev->list[i].seq_no) { + /* + If the slave is configured to ignore this domain, skip the check + even if the slave's position is behind the master's (MDEV-28213). + */ + if (is_domain_id_ignored(ignore_ids, do_ids, gl_domain_id)) + continue; /* The slave needs to start after gtid, but it is contained in an earlier binlog file. So we need to search back further, unless it was the very @@ -1102,6 +1288,18 @@ check_slave_start_position(binlog_send_info *info, const char **errormsg, rpl_gtid master_gtid; rpl_gtid master_replication_gtid; rpl_gtid start_gtid; + + /* + If the slave has configured this domain to be ignored (MDEV-28213), + skip validation for it entirely. The slave doesn't care about this + domain's events so there's no point requiring the master to have + the right binlog position for it. + */ + if (is_domain_id_ignored(&info->slave_ignore_domain_ids, + &info->slave_do_domain_ids, + slave_gtid->domain_id)) + continue; + bool start_at_own_slave_pos= rpl_global_gtid_slave_state->domain_to_gtid(slave_gtid->domain_id, &master_replication_gtid) && @@ -1294,7 +1492,9 @@ check_slave_start_position(binlog_send_info *info, const char **errormsg, */ static const char * gtid_find_binlog_file(slave_connection_state *state, char *out_name, - slave_connection_state *until_gtid_state) + slave_connection_state *until_gtid_state, + const DYNAMIC_ARRAY *ignore_ids, + const DYNAMIC_ARRAY *do_ids) { MEM_ROOT memroot; binlog_file_entry *list; @@ -1345,7 +1545,7 @@ gtid_find_binlog_file(slave_connection_state *state, char *out_name, if (unlikely(errormsg)) goto end; - if (!glev || contains_all_slave_gtid(state, glev)) + if (!glev || contains_all_slave_gtid(state, glev, ignore_ids, do_ids)) { strmake(out_name, buf, FN_REFLEN); @@ -2110,6 +2310,12 @@ static int init_binlog_sender(binlog_send_info *info, String connect_gtid_state(str_buf, sizeof(str_buf), system_charset_info); char str_buf2[128]; String slave_until_gtid_str(str_buf2, sizeof(str_buf2), system_charset_info); + char str_buf3[128]; + String slave_ignore_domain_ids_str(str_buf3, sizeof(str_buf3), + system_charset_info); + char str_buf4[128]; + String slave_do_domain_ids_str(str_buf4, sizeof(str_buf4), + system_charset_info); connect_gtid_state.length(0); /** save start file/pos that was requested by slave */ @@ -2132,6 +2338,35 @@ static int init_binlog_sender(binlog_send_info *info, info->slave_gtid_ignore_duplicates= get_slave_gtid_ignore_duplicates(thd); if (get_slave_until_gtid(thd, &slave_until_gtid_str)) info->until_gtid_state= &info->until_gtid_state_obj; + /* + Read the slave's ignored domain IDs, if sent (MDEV-28213). + Older slaves won't send this, which is fine - the array will just + remain empty and all domains will be validated as before. + */ + if (get_slave_ignore_domain_ids(thd, &slave_ignore_domain_ids_str)) + { + if (load_ignore_domain_ids(slave_ignore_domain_ids_str.ptr(), + slave_ignore_domain_ids_str.length(), + &info->slave_ignore_domain_ids)) + { + info->errmsg= "Out of memory or malformed slave request when " + "obtaining ignored domain IDs"; + info->error= ER_UNKNOWN_ERROR; + return 1; + } + } + if (get_slave_do_domain_ids(thd, &slave_do_domain_ids_str)) + { + if (load_ignore_domain_ids(slave_do_domain_ids_str.ptr(), + slave_do_domain_ids_str.length(), + &info->slave_do_domain_ids)) + { + info->errmsg= "Out of memory or malformed slave request when " + "obtaining DO domain IDs"; + info->error= ER_UNKNOWN_ERROR; + return 1; + } + } } DBUG_EXECUTE_IF("binlog_force_reconnect_after_22_events", @@ -2195,7 +2430,9 @@ static int init_binlog_sender(binlog_send_info *info, } if ((info->errmsg= gtid_find_binlog_file(&info->gtid_state, search_file_name, - info->until_gtid_state))) + info->until_gtid_state, + &info->slave_ignore_domain_ids, + &info->slave_do_domain_ids))) { info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG; return 1;