summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <knielsen@knielsen-hq.org>2013-05-22 17:36:48 +0200
committerunknown <knielsen@knielsen-hq.org>2013-05-22 17:36:48 +0200
commit1cd6eb5f942ca3e94e86a48512d992fbb3aeecd9 (patch)
treea23bba541fbfbc0fc92f9666d29340320b9be428 /sql
parentd795bc9ff8d4a4e17f249a0eb9ac01f25d53a259 (diff)
downloadmariadb-git-1cd6eb5f942ca3e94e86a48512d992fbb3aeecd9.tar.gz
MDEV-26: Global transaction ID.
Change of user interface to be more logical and more in line with expectations to work similar to old-style replication. User can now explicitly choose in CHANGE MASTER whether binlog position is taken into account (master_gtid_pos=current_pos) or not (master_gtid_pos= slave_pos) when slave connects to master. @@gtid_pos is replaced by three separate variables @@gtid_slave_pos (can be set by user, replicated GTIDs only), @@gtid_binlog_pos (read only), and @@gtid_current_pos (a combination of the two, most recent GTID within each domain). mysql.rpl_slave_state is renamed to mysql.gtid_slave_pos to match. This fixes MDEV-4474.
Diffstat (limited to 'sql')
-rw-r--r--sql/lex.h2
-rw-r--r--sql/log.cc14
-rw-r--r--sql/log.h1
-rw-r--r--sql/log_event.cc4
-rw-r--r--sql/rpl_gtid.cc38
-rw-r--r--sql/rpl_gtid.h6
-rw-r--r--sql/rpl_mi.cc15
-rw-r--r--sql/rpl_mi.h10
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--sql/slave.cc25
-rw-r--r--sql/sql_lex.h9
-rw-r--r--sql/sql_repl.cc72
-rw-r--r--sql/sql_repl.h2
-rw-r--r--sql/sql_yacc.yy31
-rw-r--r--sql/sys_vars.cc80
-rw-r--r--sql/sys_vars.h108
16 files changed, 344 insertions, 77 deletions
diff --git a/sql/lex.h b/sql/lex.h
index 756e7e80f7e..e269c3e4040 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -152,6 +152,7 @@ static SYMBOL symbols[] = {
{ "CROSS", SYM(CROSS)},
{ "CUBE", SYM(CUBE_SYM)},
{ "CURRENT_DATE", SYM(CURDATE)},
+ { "CURRENT_POS", SYM(CURRENT_POS_SYM)},
{ "CURRENT_TIME", SYM(CURTIME)},
{ "CURRENT_TIMESTAMP", SYM(NOW_SYM)},
{ "CURRENT_USER", SYM(CURRENT_USER)},
@@ -517,6 +518,7 @@ static SYMBOL symbols[] = {
{ "SIMPLE", SYM(SIMPLE_SYM)},
{ "SLAVE", SYM(SLAVE)},
{ "SLAVES", SYM(SLAVES)},
+ { "SLAVE_POS", SYM(SLAVE_POS_SYM)},
{ "SLOW", SYM(SLOW)},
{ "SNAPSHOT", SYM(SNAPSHOT_SYM)},
{ "SMALLINT", SYM(SMALLINT)},
diff --git a/sql/log.cc b/sql/log.cc
index 3266934beda..238452070ff 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -5521,6 +5521,18 @@ MYSQL_BIN_LOG::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size)
bool
+MYSQL_BIN_LOG::append_state_pos(String *str)
+{
+ bool err;
+
+ mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
+ err= rpl_global_gtid_binlog_state.append_pos(str);
+ mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
+ return err;
+}
+
+
+bool
MYSQL_BIN_LOG::find_in_binlog_state(uint32 domain_id, uint32 server_id,
rpl_gtid *out_gtid)
{
@@ -8508,7 +8520,7 @@ binlog_background_thread(void *arg __attribute__((unused)))
thd->store_globals();
/*
- Load the slave replication GTID state from the mysql.rpl_slave_state
+ Load the slave replication GTID state from the mysql.gtid_slave_pos
table.
This is mostly so that we can start our seq_no counter from the highest
diff --git a/sql/log.h b/sql/log.h
index bd20c8aee09..f41b48eba7c 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -779,6 +779,7 @@ public:
int read_state_from_file();
int write_state_to_file();
int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size);
+ bool append_state_pos(String *str);
bool find_in_binlog_state(uint32 domain_id, uint32 server_id,
rpl_gtid *out_gtid);
bool lookup_domain_in_binlog_state(uint32 domain_id, rpl_gtid *out_gtid);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 9fbcbb68145..f896d3521de 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -4004,7 +4004,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
const_cast<Relay_log_info*>(rli)->gtid_sub_id= 0;
gtid= rli->current_gtid;
- if (rpl_global_gtid_slave_state.record_gtid(thd, &gtid, sub_id, true))
+ if (rpl_global_gtid_slave_state.record_gtid(thd, &gtid, sub_id, true, false))
{
rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE,
"Error during COMMIT: failed to update GTID state in "
@@ -6895,7 +6895,7 @@ int Xid_log_event::do_apply_event(Relay_log_info const *rli)
const_cast<Relay_log_info*>(rli)->gtid_sub_id= 0;
gtid= rli->current_gtid;
- err= rpl_global_gtid_slave_state.record_gtid(thd, &gtid, sub_id, true);
+ err= rpl_global_gtid_slave_state.record_gtid(thd, &gtid, sub_id, true, false);
if (err)
{
rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE,
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index a4bdeb9932b..01502c5b0f1 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -29,7 +29,7 @@
const LEX_STRING rpl_gtid_slave_state_table_name=
- { C_STRING_WITH_LEN("rpl_slave_state") };
+ { C_STRING_WITH_LEN("gtid_slave_pos") };
void
@@ -73,7 +73,7 @@ rpl_slave_state::record_and_update_gtid(THD *thd, Relay_log_info *rli)
if ((sub_id= rli->gtid_sub_id))
{
rli->gtid_sub_id= 0;
- if (record_gtid(thd, &rli->current_gtid, sub_id, false))
+ if (record_gtid(thd, &rli->current_gtid, sub_id, false, false))
return 1;
update_state_hash(sub_id, &rli->current_gtid);
}
@@ -186,8 +186,6 @@ rpl_slave_state::truncate_state_table(THD *thd)
int err= 0;
TABLE *table;
- mysql_reset_thd_for_next_command(thd, 0);
-
tlist.init_one_table(STRING_WITH_LEN("mysql"),
rpl_gtid_slave_state_table_name.str,
rpl_gtid_slave_state_table_name.length,
@@ -234,7 +232,7 @@ static const TABLE_FIELD_TYPE mysql_rpl_slave_state_coltypes[4]= {
static const uint mysql_rpl_slave_state_pk_parts[]= {0, 1};
-static const TABLE_FIELD_DEF mysql_rpl_slave_state_tabledef= {
+static const TABLE_FIELD_DEF mysql_gtid_slave_pos_tabledef= {
array_elements(mysql_rpl_slave_state_coltypes),
mysql_rpl_slave_state_coltypes,
array_elements(mysql_rpl_slave_state_pk_parts),
@@ -256,14 +254,14 @@ protected:
static Gtid_db_intact gtid_table_intact;
/*
- Check that the mysql.rpl_slave_state table has the correct definition.
+ Check that the mysql.gtid_slave_pos table has the correct definition.
*/
int
gtid_check_rpl_slave_state_table(TABLE *table)
{
int err;
- if ((err= gtid_table_intact.check(table, &mysql_rpl_slave_state_tabledef)))
+ if ((err= gtid_table_intact.check(table, &mysql_gtid_slave_pos_tabledef)))
my_error(ER_GTID_OPEN_TABLE_FAILED, MYF(0), "mysql",
rpl_gtid_slave_state_table_name.str);
return err;
@@ -286,7 +284,7 @@ gtid_check_rpl_slave_state_table(TABLE *table)
*/
int
rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
- bool in_transaction)
+ bool in_transaction, bool in_statement)
{
TABLE_LIST tlist;
int err= 0;
@@ -297,7 +295,8 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
ulonglong thd_saved_option= thd->variables.option_bits;
Query_tables_list lex_backup;
- mysql_reset_thd_for_next_command(thd, 0);
+ if (!in_statement)
+ mysql_reset_thd_for_next_command(thd, 0);
DBUG_EXECUTE_IF("gtid_inject_record_gtid",
{
@@ -626,7 +625,7 @@ gtid_parser_helper(char **ptr, char *end, rpl_gtid *out_gtid)
*/
int
rpl_slave_state::load(THD *thd, char *state_from_master, size_t len,
- bool reset)
+ bool reset, bool in_statement)
{
char *end= state_from_master + len;
@@ -645,7 +644,7 @@ rpl_slave_state::load(THD *thd, char *state_from_master, size_t len,
if (gtid_parser_helper(&state_from_master, end, &gtid) ||
!(sub_id= next_subid(gtid.domain_id)) ||
- record_gtid(thd, &gtid, sub_id, false) ||
+ record_gtid(thd, &gtid, sub_id, false, in_statement) ||
update(gtid.domain_id, gtid.server_id, sub_id, gtid.seq_no))
return 1;
if (state_from_master == end)
@@ -980,6 +979,23 @@ rpl_binlog_state::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size)
}
+bool
+rpl_binlog_state::append_pos(String *str)
+{
+ uint32 i;
+ bool first= true;
+
+ for (i= 0; i < hash.records; ++i)
+ {
+ element *e= (element *)my_hash_element(&hash, i);
+ if (rpl_slave_state_tostring_helper(str, e->last_gtid, &first))
+ return true;
+ }
+
+ return false;
+}
+
+
slave_connection_state::slave_connection_state()
{
my_hash_init(&hash, &my_charset_bin, 32,
diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h
index bd6663c0659..cc3c99f40b7 100644
--- a/sql/rpl_gtid.h
+++ b/sql/rpl_gtid.h
@@ -91,11 +91,12 @@ struct rpl_slave_state
int update(uint32 domain_id, uint32 server_id, uint64 sub_id, uint64 seq_no);
int truncate_state_table(THD *thd);
int record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
- bool in_transaction);
+ bool in_transaction, bool in_statement);
uint64 next_subid(uint32 domain_id);
int tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra);
bool domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid);
- int load(THD *thd, char *state_from_master, size_t len, bool reset);
+ int load(THD *thd, char *state_from_master, size_t len, bool reset,
+ bool in_statement);
bool is_empty();
void lock() { DBUG_ASSERT(inited); mysql_mutex_lock(&LOCK_slave_state); }
@@ -150,6 +151,7 @@ struct rpl_binlog_state
uint32 count();
int get_gtid_list(rpl_gtid *gtid_list, uint32 list_size);
int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size);
+ bool append_pos(String *str);
rpl_gtid *find(uint32 domain_id, uint32 server_id);
};
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index 92dbf68d7a2..4ffe4f37cac 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -37,7 +37,8 @@ Master_info::Master_info(LEX_STRING *connection_name_arg,
checksum_alg_before_fd(BINLOG_CHECKSUM_ALG_UNDEF),
connect_retry(DEFAULT_CONNECT_RETRY), inited(0), abort_slave(0),
slave_running(0), slave_run_id(0), sync_counter(0),
- heartbeat_period(0), received_heartbeats(0), master_id(0), using_gtid(0)
+ heartbeat_period(0), received_heartbeats(0), master_id(0),
+ using_gtid(USE_GTID_NO)
{
host[0] = 0; user[0] = 0; password[0] = 0;
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
@@ -152,7 +153,7 @@ void init_master_log_pos(Master_info* mi)
mi->master_log_name[0] = 0;
mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number
- mi->using_gtid= false;
+ mi->using_gtid= Master_info::USE_GTID_NO;
/* Intentionally init ssl_verify_server_cert to 0, no option available */
mi->ssl_verify_server_cert= 0;
@@ -447,7 +448,15 @@ file '%s')", fname);
while (!init_strvar_from_file(buf, sizeof(buf), &mi->file, 0))
{
if (0 == strncmp(buf, STRING_WITH_LEN("using_gtid=")))
- mi->using_gtid= (0 != atoi(buf + sizeof("using_gtid")));
+ {
+ int val= atoi(buf + sizeof("using_gtid"));
+ if (val == Master_info::USE_GTID_CURRENT_POS)
+ mi->using_gtid= Master_info::USE_GTID_CURRENT_POS;
+ else if (val == Master_info::USE_GTID_SLAVE_POS)
+ mi->using_gtid= Master_info::USE_GTID_SLAVE_POS;
+ else
+ mi->using_gtid= Master_info::USE_GTID_NO;
+ }
}
}
}
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index 64501e96f00..916bd0dae02 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -130,10 +130,14 @@ class Master_info : public Slave_reporting_capability
DYNAMIC_ARRAY ignore_server_ids;
ulong master_id;
/*
- True if slave position is set using GTID state rather than old-style
- file/offset binlog position.
+ Which kind of GTID position (if any) is used when connecting to master.
+
+ Note that you can not change the numeric values of these, they are used
+ in master.info.
*/
- bool using_gtid;
+ enum {
+ USE_GTID_NO= 0, USE_GTID_CURRENT_POS= 1, USE_GTID_SLAVE_POS= 2
+ } using_gtid;
};
int init_master_info(Master_info* mi, const char* master_info_fname,
const char* slave_info_fname,
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index d7d5710b048..539e90d7cb5 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6540,8 +6540,8 @@ ER_GTID_POSITION_NOT_FOUND_IN_BINLOG
ER_CANNOT_LOAD_SLAVE_GTID_STATE
eng "Failed to load replication slave GTID state from table %s.%s"
ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG
- eng "Requested GTID_POS %u-%u-%llu conflicts with the binary log which contains a more recent GTID %u-%u-%llu. To use the requested GTID_POS, the old binlog must be removed with RESET MASTER to avoid out-of-order binlog"
+ eng "Specified GTID %u-%u-%llu conflicts with the binary log which contains a more recent GTID %u-%u-%llu. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos."
ER_MASTER_GTID_POS_MISSING_DOMAIN
- eng "Requested GTID_POS contains no value for replication domain %u. This conflicts with the binary log which contains GTID %u-%u-%llu. To use the requested GTID_POS, the old binlog must be removed with RESET MASTER to avoid out-of-order binlog"
+ eng "Specified value for @@gtid_slave_pos contains no value for replication domain %u. This conflicts with the binary log which contains GTID %u-%u-%llu. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos."
ER_UNTIL_REQUIRES_USING_GTID
eng "START SLAVE UNTIL master_gtid_pos requires that slave is using GTID"
diff --git a/sql/slave.cc b/sql/slave.cc
index 1b3154e20ab..bf7e81edf71 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -810,7 +810,8 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
while one of the threads is running, they are in use and cannot be
removed.
*/
- if (mi->using_gtid && !mi->slave_running && !mi->rli.slave_running)
+ if (mi->using_gtid != Master_info::USE_GTID_NO &&
+ !mi->slave_running && !mi->rli.slave_running)
{
purge_relay_logs(&mi->rli, NULL, 0, &errmsg);
mi->master_log_name[0]= 0;
@@ -1819,7 +1820,7 @@ after_set_capability:
restart or reconnect, we might end up re-fetching and hence re-applying
the same event(s) again.
*/
- if (mi->using_gtid && !mi->master_log_name[0])
+ if (mi->using_gtid != Master_info::USE_GTID_NO && !mi->master_log_name[0])
{
int rc;
char str_buf[256];
@@ -1849,7 +1850,9 @@ after_set_capability:
connect_state.append(STRING_WITH_LEN("SET @slave_connect_state='"),
system_charset_info);
- if (rpl_append_gtid_state(&connect_state, true))
+ if (rpl_append_gtid_state(&connect_state,
+ mi->using_gtid ==
+ Master_info::USE_GTID_CURRENT_POS))
{
err_code= ER_OUTOFMEMORY;
errmsg= "The slave I/O thread stops because a fatal out-of-memory "
@@ -1917,7 +1920,7 @@ after_set_capability:
}
}
}
- if (!mi->using_gtid)
+ if (mi->using_gtid == Master_info::USE_GTID_NO)
{
/*
If we are not using GTID to connect this time, then instead request
@@ -1943,7 +1946,7 @@ after_set_capability:
(master_row[0] != NULL))
{
rpl_global_gtid_slave_state.load(mi->io_thd, master_row[0],
- strlen(master_row[0]), false);
+ strlen(master_row[0]), false, false);
}
else if (check_io_slave_killed(mi->io_thd, mi, NULL))
goto slave_killed_err;
@@ -2307,8 +2310,8 @@ static bool send_show_master_info_header(THD *thd, bool full,
FN_REFLEN));
field_list.push_back(new Item_return_int("Master_Server_Id", sizeof(ulong),
MYSQL_TYPE_LONG));
- field_list.push_back(new Item_return_int("Using_Gtid", sizeof(ulong),
- MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_empty_string("Using_Gtid",
+ sizeof("Current_Pos")-1));
if (full)
{
field_list.push_back(new Item_return_int("Retried_transactions",
@@ -2321,7 +2324,8 @@ static bool send_show_master_info_header(THD *thd, bool full,
10, MYSQL_TYPE_LONG));
field_list.push_back(new Item_float("Slave_heartbeat_period",
0.0, 3, 10));
- field_list.push_back(new Item_empty_string("Gtid_Pos", gtid_pos_length));
+ field_list.push_back(new Item_empty_string("Gtid_Slave_Pos",
+ gtid_pos_length));
}
if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
@@ -2488,7 +2492,10 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
}
// Master_Server_id
protocol->store((uint32) mi->master_id);
- protocol->store((uint32) (mi->using_gtid != 0));
+ protocol->store((mi->using_gtid==Master_info::USE_GTID_NO ? "No" :
+ (mi->using_gtid==Master_info::USE_GTID_SLAVE_POS ?
+ "Slave_Pos" : "Current_Pos")),
+ &my_charset_bin);
if (full)
{
protocol->store((uint32) mi->rli.retried_trans);
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 4c1d917aeae..f654c00810e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -301,8 +301,10 @@ struct LEX_MASTER_INFO
changed variable or if it should be left at old value
*/
enum {LEX_MI_UNCHANGED, LEX_MI_DISABLE, LEX_MI_ENABLE}
- ssl, ssl_verify_server_cert, heartbeat_opt, repl_ignore_server_ids_opt,
- use_gtid_opt;
+ ssl, ssl_verify_server_cert, heartbeat_opt, repl_ignore_server_ids_opt;
+ enum {
+ LEX_GTID_UNCHANGED, LEX_GTID_NO, LEX_GTID_CURRENT_POS, LEX_GTID_SLAVE_POS
+ } use_gtid_opt;
void init()
{
@@ -318,9 +320,10 @@ struct LEX_MASTER_INFO
pos= relay_log_pos= server_id= port= connect_retry= 0;
heartbeat_period= 0;
ssl= ssl_verify_server_cert= heartbeat_opt=
- repl_ignore_server_ids_opt= use_gtid_opt= LEX_MI_UNCHANGED;
+ repl_ignore_server_ids_opt= LEX_MI_UNCHANGED;
gtid_pos_str.length= 0;
gtid_pos_str.str= NULL;
+ use_gtid_opt= LEX_GTID_UNCHANGED;
}
};
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 2e10af0aa8c..82f471d5ddf 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -2511,7 +2511,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
slave_errno= ER_BAD_SLAVE_UNTIL_COND;
goto err;
}
- if (!mi->using_gtid)
+ if (mi->using_gtid == Master_info::USE_GTID_NO)
{
slave_errno= ER_UNTIL_REQUIRES_USING_GTID;
goto err;
@@ -3112,12 +3112,14 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
mi->rli.group_relay_log_pos= mi->rli.event_relay_log_pos= lex_mi->relay_log_pos;
}
- if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_MI_ENABLE)
- mi->using_gtid= true;
- else if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_MI_DISABLE ||
+ if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_GTID_SLAVE_POS)
+ mi->using_gtid= Master_info::USE_GTID_SLAVE_POS;
+ else if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_GTID_CURRENT_POS)
+ mi->using_gtid= Master_info::USE_GTID_CURRENT_POS;
+ else if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_GTID_NO ||
lex_mi->log_file_name || lex_mi->pos ||
lex_mi->relay_log_name || lex_mi->relay_log_pos)
- mi->using_gtid= false;
+ mi->using_gtid= Master_info::USE_GTID_NO;
/*
If user did specify neither host nor port nor any log name nor any log
@@ -3173,7 +3175,7 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
goto err;
}
- if (mi->using_gtid)
+ if (mi->using_gtid != Master_info::USE_GTID_NO)
{
/*
Clear the position in the master binlogs, so that we request the
@@ -3657,7 +3659,7 @@ int log_loaded_block(IO_CACHE* file)
/**
- Initialise the slave replication state from the mysql.rpl_slave_state table.
+ Initialise the slave replication state from the mysql.gtid_slave_pos table.
This is called each time an SQL thread starts, but the data is only actually
loaded on the first call.
@@ -3669,7 +3671,7 @@ int log_loaded_block(IO_CACHE* file)
The one containing the current slave state is the one with the maximal
sub_id value, within each domain_id.
- CREATE TABLE mysql.rpl_slave_state (
+ CREATE TABLE mysql.gtid_slave_pos (
domain_id INT UNSIGNED NOT NULL,
sub_id BIGINT UNSIGNED NOT NULL,
server_id INT UNSIGNED NOT NULL,
@@ -3705,7 +3707,7 @@ rpl_append_gtid_state(String *dest, bool use_binlog)
rpl_gtid *gtid_list= NULL;
uint32 num_gtids= 0;
- if (opt_bin_log &&
+ if (use_binlog && opt_bin_log &&
(err= mysql_bin_log.get_most_recent_gtid_list(&gtid_list, &num_gtids)))
return err;
@@ -3717,9 +3719,12 @@ rpl_append_gtid_state(String *dest, bool use_binlog)
bool
-rpl_gtid_pos_check(char *str, size_t len)
+rpl_gtid_pos_check(THD *thd, char *str, size_t len)
{
+ /* ToDo: Use gtid_strict_mode sysvar, when implemented. */
+ static const bool gtid_strict_mode= false;
slave_connection_state tmp_slave_state;
+ bool gave_conflict_warning= false, gave_missing_warning= false;
/* Check that we can parse the supplied string. */
if (tmp_slave_state.load(str, len))
@@ -3754,18 +3759,43 @@ rpl_gtid_pos_check(char *str, size_t len)
continue;
if (!(slave_gtid= tmp_slave_state.find(binlog_gtid->domain_id)))
{
- my_error(ER_MASTER_GTID_POS_MISSING_DOMAIN, MYF(0),
- binlog_gtid->domain_id, binlog_gtid->domain_id,
- binlog_gtid->server_id, binlog_gtid->seq_no);
- break;
+ if (gtid_strict_mode)
+ {
+ my_error(ER_MASTER_GTID_POS_MISSING_DOMAIN, MYF(0),
+ binlog_gtid->domain_id, binlog_gtid->domain_id,
+ binlog_gtid->server_id, binlog_gtid->seq_no);
+ break;
+ }
+ else if (!gave_missing_warning)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_MASTER_GTID_POS_MISSING_DOMAIN,
+ ER(ER_MASTER_GTID_POS_MISSING_DOMAIN),
+ binlog_gtid->domain_id, binlog_gtid->domain_id,
+ binlog_gtid->server_id, binlog_gtid->seq_no);
+ gave_missing_warning= true;
+ }
}
- if (slave_gtid->seq_no < binlog_gtid->seq_no)
+ else if (slave_gtid->seq_no < binlog_gtid->seq_no)
{
- my_error(ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG, MYF(0),
- slave_gtid->domain_id, slave_gtid->server_id,
- slave_gtid->seq_no, binlog_gtid->domain_id,
- binlog_gtid->server_id, binlog_gtid->seq_no);
- break;
+ if (gtid_strict_mode)
+ {
+ my_error(ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG, MYF(0),
+ slave_gtid->domain_id, slave_gtid->server_id,
+ slave_gtid->seq_no, binlog_gtid->domain_id,
+ binlog_gtid->server_id, binlog_gtid->seq_no);
+ break;
+ }
+ else if (!gave_conflict_warning)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG,
+ ER(ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG),
+ slave_gtid->domain_id, slave_gtid->server_id,
+ slave_gtid->seq_no, binlog_gtid->domain_id,
+ binlog_gtid->server_id, binlog_gtid->seq_no);
+ gave_conflict_warning= true;
+ }
}
}
my_free(binlog_gtid_list);
@@ -3780,7 +3810,7 @@ rpl_gtid_pos_check(char *str, size_t len)
bool
rpl_gtid_pos_update(THD *thd, char *str, size_t len)
{
- if (rpl_global_gtid_slave_state.load(thd, str, len, true))
+ if (rpl_global_gtid_slave_state.load(thd, str, len, true, true))
{
my_error(ER_FAILED_GTID_STATE_INIT, MYF(0));
return true;
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 3af8f721bd7..820ffed0928 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -70,7 +70,7 @@ void rpl_init_gtid_slave_state();
void rpl_deinit_gtid_slave_state();
int gtid_state_from_binlog_pos(const char *name, uint32 pos, String *out_str);
int rpl_append_gtid_state(String *dest, bool use_binlog);
-bool rpl_gtid_pos_check(char *str, size_t len);
+bool rpl_gtid_pos_check(THD *thd, char *str, size_t len);
bool rpl_gtid_pos_update(THD *thd, char *str, size_t len);
#endif /* HAVE_REPLICATION */
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e995b410a85..d02f87c6bab 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -916,6 +916,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CUBE_SYM /* SQL-2003-R */
%token CURDATE /* MYSQL-FUNC */
%token CURRENT_USER /* SQL-2003-R */
+%token CURRENT_POS_SYM
%token CURSOR_SYM /* SQL-2003-R */
%token CURSOR_NAME_SYM /* SQL-2003-N */
%token CURTIME /* MYSQL-FUNC */
@@ -1295,6 +1296,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SIMPLE_SYM /* SQL-2003-N */
%token SLAVE
%token SLAVES
+%token SLAVE_POS_SYM
%token SLOW
%token SMALLINT /* SQL-2003-R */
%token SNAPSHOT_SYM
@@ -2065,15 +2067,34 @@ master_file_def:
/* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */
Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos);
}
- | MASTER_USE_GTID_SYM EQ ulong_num
+ | MASTER_USE_GTID_SYM EQ CURRENT_POS_SYM
{
- if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
+ if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED)
{
my_error(ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid");
MYSQL_YYABORT;
}
- Lex->mi.use_gtid_opt= $3 ?
- LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE;
+ Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_CURRENT_POS;
+ }
+ ;
+ | MASTER_USE_GTID_SYM EQ SLAVE_POS_SYM
+ {
+ if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED)
+ {
+ my_error(ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid");
+ MYSQL_YYABORT;
+ }
+ Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_SLAVE_POS;
+ }
+ ;
+ | MASTER_USE_GTID_SYM EQ NO_SYM
+ {
+ if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED)
+ {
+ my_error(ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid");
+ MYSQL_YYABORT;
+ }
+ Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_NO;
}
;
@@ -13254,6 +13275,7 @@ keyword_sp:
| CONSTRAINT_NAME_SYM {}
| CONTEXT_SYM {}
| CONTRIBUTORS_SYM {}
+ | CURRENT_POS_SYM {}
| CPU_SYM {}
| CUBE_SYM {}
| CURSOR_NAME_SYM {}
@@ -13440,6 +13462,7 @@ keyword_sp:
| SIMPLE_SYM {}
| SHARE_SYM {}
| SHUTDOWN {}
+ | SLAVE_POS_SYM {}
| SLOW {}
| SNAPSHOT_SYM {}
| SOFT_SYM {}
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index e51fd1cc11c..9edbe789196 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1228,8 +1228,61 @@ static Sys_var_ulonglong Sys_gtid_seq_no(
#ifdef HAVE_REPLICATION
+static unsigned char opt_gtid_binlog_pos_dummy;
+static Sys_var_gtid_binlog_pos Sys_gtid_binlog_pos(
+ "gtid_binlog_pos", "Last GTID logged to the binary log, per replication"
+ "domain",
+ READ_ONLY GLOBAL_VAR(opt_gtid_binlog_pos_dummy), NO_CMD_LINE);
+
+
+uchar *
+Sys_var_gtid_binlog_pos::global_value_ptr(THD *thd, LEX_STRING *base)
+{
+ char buf[128];
+ String str(buf, sizeof(buf), system_charset_info);
+ char *p;
+
+ str.length(0);
+ if ((opt_bin_log && mysql_bin_log.append_state_pos(&str)) ||
+ !(p= thd->strmake(str.ptr(), str.length())))
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return NULL;
+ }
+
+ return (uchar *)p;
+}
+
+
+static unsigned char opt_gtid_current_pos_dummy;
+static Sys_var_gtid_current_pos Sys_gtid_current_pos(
+ "gtid_current_pos", "Current GTID position of the server. Per "
+ "replication domain, this is either the last GTID replicated by a "
+ "slave thread, or the GTID logged to the binary log, whichever is "
+ "most recent.",
+ READ_ONLY GLOBAL_VAR(opt_gtid_current_pos_dummy), NO_CMD_LINE);
+
+
+uchar *
+Sys_var_gtid_current_pos::global_value_ptr(THD *thd, LEX_STRING *base)
+{
+ String str;
+ char *p;
+
+ str.length(0);
+ if (rpl_append_gtid_state(&str, true) ||
+ !(p= thd->strmake(str.ptr(), str.length())))
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return NULL;
+ }
+
+ return (uchar *)p;
+}
+
+
bool
-Sys_var_gtid_pos::do_check(THD *thd, set_var *var)
+Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var)
{
String str, *res;
bool running;
@@ -1242,7 +1295,12 @@ Sys_var_gtid_pos::do_check(THD *thd, set_var *var)
return true;
if (!(res= var->value->val_str(&str)))
return true;
- if (rpl_gtid_pos_check(&((*res)[0]), res->length()))
+ if (thd->in_active_multi_stmt_transaction())
+ {
+ my_error(ER_CANT_DO_THIS_DURING_AN_TRANSACTION, MYF(0));
+ return true;
+ }
+ if (rpl_gtid_pos_check(thd, &((*res)[0]), res->length()))
return true;
if (!(var->save_result.string_value.str=
@@ -1257,7 +1315,7 @@ Sys_var_gtid_pos::do_check(THD *thd, set_var *var)
bool
-Sys_var_gtid_pos::global_update(THD *thd, set_var *var)
+Sys_var_gtid_slave_pos::global_update(THD *thd, set_var *var)
{
bool err;
@@ -1283,13 +1341,13 @@ Sys_var_gtid_pos::global_update(THD *thd, set_var *var)
uchar *
-Sys_var_gtid_pos::global_value_ptr(THD *thd, LEX_STRING *base)
+Sys_var_gtid_slave_pos::global_value_ptr(THD *thd, LEX_STRING *base)
{
String str;
char *p;
str.length(0);
- if (rpl_append_gtid_state(&str, true) ||
+ if (rpl_append_gtid_state(&str, false) ||
!(p= thd->strmake(str.ptr(), str.length())))
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -1300,14 +1358,12 @@ Sys_var_gtid_pos::global_value_ptr(THD *thd, LEX_STRING *base)
}
-static unsigned char opt_gtid_pos_dummy;
-static Sys_var_gtid_pos Sys_gtid_pos(
- "gtid_pos",
+static unsigned char opt_gtid_slave_pos_dummy;
+static Sys_var_gtid_slave_pos Sys_gtid_slave_pos(
+ "gtid_slave_pos",
"The list of global transaction IDs that were last replicated on the "
- "server, one for each replication domain. This defines where a slave "
- "starts replicating from on a master when connecting with global "
- "transaction ID.",
- GLOBAL_VAR(opt_gtid_pos_dummy), NO_CMD_LINE);
+ "server, one for each replication domain.",
+ GLOBAL_VAR(opt_gtid_slave_pos_dummy), NO_CMD_LINE);
#endif
diff --git a/sql/sys_vars.h b/sql/sys_vars.h
index 8a92f22f3c2..d68761d91ca 100644
--- a/sql/sys_vars.h
+++ b/sql/sys_vars.h
@@ -2024,12 +2024,114 @@ public:
/**
- Class for @@global.gtid_pos.
+ Class for @@global.gtid_current_pos.
*/
-class Sys_var_gtid_pos: public sys_var
+class Sys_var_gtid_current_pos: public sys_var
{
public:
- Sys_var_gtid_pos(const char *name_arg,
+ Sys_var_gtid_current_pos(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, NULL)
+ {
+ option.var_type= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool check_update_type(Item_result type) {
+ DBUG_ASSERT(false);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ DBUG_ASSERT(false);
+ return NULL;
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base);
+};
+
+
+/**
+ Class for @@global.gtid_binlog_pos.
+*/
+class Sys_var_gtid_binlog_pos: public sys_var
+{
+public:
+ Sys_var_gtid_binlog_pos(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, NULL)
+ {
+ option.var_type= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool check_update_type(Item_result type) {
+ DBUG_ASSERT(false);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ DBUG_ASSERT(false);
+ return NULL;
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base);
+};
+
+
+/**
+ Class for @@global.gtid_slave_pos.
+*/
+class Sys_var_gtid_slave_pos: public sys_var
+{
+public:
+ Sys_var_gtid_slave_pos(const char *name_arg,
const char *comment, int flag_args, ptrdiff_t off, size_t size,
CMD_LINE getopt)
: sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,