Commit 1d357776 authored by unknown's avatar unknown

MDEV-26: Global transaction ID.

When starting slave, check binlog state in addition to mysql.rpl_slave.state.

This allows to switch a previous master to be a slave directly
with MASTER_GTID_POS=AUTO.
parent 0b36233a
...@@ -120,7 +120,7 @@ static MYSQL_BIN_LOG::xid_count_per_binlog * ...@@ -120,7 +120,7 @@ static MYSQL_BIN_LOG::xid_count_per_binlog *
static bool start_binlog_background_thread(); static bool start_binlog_background_thread();
rpl_binlog_state rpl_global_gtid_binlog_state; static rpl_binlog_state rpl_global_gtid_binlog_state;
/** /**
purge logs, master and slave sides both, related error code purge logs, master and slave sides both, related error code
...@@ -5488,6 +5488,13 @@ end: ...@@ -5488,6 +5488,13 @@ end:
} }
int
MYSQL_BIN_LOG::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size)
{
return rpl_global_gtid_binlog_state.get_most_recent_gtid_list(list, size);
}
/** /**
Write an event to the binary log. If with_annotate != NULL and Write an event to the binary log. If with_annotate != NULL and
*with_annotate = TRUE write also Annotate_rows before the event *with_annotate = TRUE write also Annotate_rows before the event
...@@ -8176,8 +8183,7 @@ int TC_LOG_BINLOG::open(const char *opt_name) ...@@ -8176,8 +8183,7 @@ int TC_LOG_BINLOG::open(const char *opt_name)
else else
error= read_state_from_file(); error= read_state_from_file();
/* Pick the next unused seq_no from the loaded/recovered binlog state. */ /* Pick the next unused seq_no from the loaded/recovered binlog state. */
global_gtid_counter= rpl_global_gtid_binlog_state.seq_no_for_server_id global_gtid_counter= rpl_global_gtid_binlog_state.seq_no_from_state();
(global_system_variables.server_id);
delete ev; delete ev;
end_io_cache(&log); end_io_cache(&log);
......
...@@ -396,6 +396,7 @@ private: ...@@ -396,6 +396,7 @@ private:
( ((ulong)(c)>>1) == BINLOG_COOKIE_DUMMY_ID ) ( ((ulong)(c)>>1) == BINLOG_COOKIE_DUMMY_ID )
class binlog_cache_mngr; class binlog_cache_mngr;
class rpl_gtid;
class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
{ {
private: private:
...@@ -773,6 +774,7 @@ public: ...@@ -773,6 +774,7 @@ public:
bool write_gtid_event(THD *thd, bool standalone, bool is_transactional); bool write_gtid_event(THD *thd, bool standalone, bool is_transactional);
int read_state_from_file(); int read_state_from_file();
int write_state_to_file(); int write_state_to_file();
int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size);
}; };
class Log_event_handler class Log_event_handler
......
This diff is collapsed.
...@@ -2981,7 +2981,7 @@ struct rpl_slave_state ...@@ -2981,7 +2981,7 @@ struct rpl_slave_state
uint32 domain_id; uint32 domain_id;
list_element *grab_list() { list_element *l= list; list= NULL; return l; } list_element *grab_list() { list_element *l= list; list= NULL; return l; }
void add (list_element *l) void add(list_element *l)
{ {
l->next= list; l->next= list;
list= l; list= l;
...@@ -3008,7 +3008,7 @@ struct rpl_slave_state ...@@ -3008,7 +3008,7 @@ struct rpl_slave_state
int record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, int record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
bool in_transaction); bool in_transaction);
uint64 next_subid(uint32 domain_id); uint64 next_subid(uint32 domain_id);
int tostring(String *dest); int tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra);
bool is_empty(); bool is_empty();
void lock() { DBUG_ASSERT(inited); mysql_mutex_lock(&LOCK_slave_state); } void lock() { DBUG_ASSERT(inited); mysql_mutex_lock(&LOCK_slave_state); }
...@@ -3027,10 +3027,21 @@ struct rpl_slave_state ...@@ -3027,10 +3027,21 @@ struct rpl_slave_state
containing a gigen GTID, by simply scanning backwards from the newest containing a gigen GTID, by simply scanning backwards from the newest
one until a lower seq_no is found in the Gtid_list_log_event at the one until a lower seq_no is found in the Gtid_list_log_event at the
start of a binlog for the given domain_id and server_id. start of a binlog for the given domain_id and server_id.
We also remember the last logged GTID for every domain_id. This is used
to know where to start when a master is changed to a slave. As a side
effect, it also allows to skip a hash lookup in the very common case of
logging a new GTID with same server id as last GTID.
*/ */
struct rpl_binlog_state struct rpl_binlog_state
{ {
/* Mapping from (domain_id,server_id) to its GTID. */ struct element {
uint32 domain_id;
HASH hash; /* Containing all server_id for one domain_id */
/* The most recent entry in the hash. */
rpl_gtid *last_gtid;
};
/* Mapping from domain_id to collection of elements. */
HASH hash; HASH hash;
/* Mutex protecting access to the state. */ /* Mutex protecting access to the state. */
mysql_mutex_t LOCK_binlog_state; mysql_mutex_t LOCK_binlog_state;
...@@ -3038,12 +3049,14 @@ struct rpl_binlog_state ...@@ -3038,12 +3049,14 @@ struct rpl_binlog_state
rpl_binlog_state(); rpl_binlog_state();
~rpl_binlog_state(); ~rpl_binlog_state();
ulong count() const { return hash.records; }
int update(const struct rpl_gtid *gtid);
void reset(); void reset();
uint32 seq_no_for_server_id(uint32 server_id); int update(const struct rpl_gtid *gtid);
uint32 seq_no_from_state();
int write_to_iocache(IO_CACHE *dest); int write_to_iocache(IO_CACHE *dest);
int read_from_iocache(IO_CACHE *src); int read_from_iocache(IO_CACHE *src);
uint32 count();
int get_gtid_list(rpl_gtid *gtid_list, uint32 list_size);
int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size);
}; };
......
...@@ -1792,10 +1792,29 @@ after_set_capability: ...@@ -1792,10 +1792,29 @@ after_set_capability:
char str_buf[256]; char str_buf[256];
String connect_state(str_buf, sizeof(str_buf), system_charset_info); String connect_state(str_buf, sizeof(str_buf), system_charset_info);
connect_state.length(0); connect_state.length(0);
rpl_gtid *binlog_gtid_list= NULL;
uint32 num_binlog_gtids= 0;
if (opt_bin_log)
{
int err= mysql_bin_log.get_most_recent_gtid_list(&binlog_gtid_list,
&num_binlog_gtids);
if (err)
{
err_code= ER_OUTOFMEMORY;
errmsg= "The slave I/O thread stops because a fatal out-of-memory "
"error is encountered when it tries to compute @slave_connect_state.";
sprintf(err_buff, "%s Error: Out of memory", errmsg);
goto err;
}
}
connect_state.append(STRING_WITH_LEN("SET @slave_connect_state='"), connect_state.append(STRING_WITH_LEN("SET @slave_connect_state='"),
system_charset_info); system_charset_info);
rpl_global_gtid_slave_state.tostring(&connect_state); rpl_global_gtid_slave_state.tostring(&connect_state, binlog_gtid_list,
num_binlog_gtids);
if (binlog_gtid_list)
my_free(binlog_gtid_list);
connect_state.append(STRING_WITH_LEN("'"), system_charset_info); connect_state.append(STRING_WITH_LEN("'"), system_charset_info);
rc= mysql_real_query(mysql, connect_state.ptr(), connect_state.length()); rc= mysql_real_query(mysql, connect_state.ptr(), connect_state.length());
if (rc) if (rc)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment