Skip to content

Commit a69a6dd

Browse files
committed
MDEV-4487 Allow replication from MySQL 5.6+ when GTID is enabled on the master
MDEV-8685 MariaDB fails to decode Anonymous_GTID entries MDEV-5705 Replication testing: 5.6->10.0 - Ignoring GTID events from MySQL 5.6+ (Allows replication from MySQL 5.6+ with GTID enabled) - Added ignorable events from MySQL 5.6 - mysqlbinlog now writes information about GTID and ignorable events. - Added more information in error message when replication stops because of wrong information in binary log. - Fixed wrong test when write_on_release() should flush cache.
1 parent 7c1e2fe commit a69a6dd

File tree

3 files changed

+194
-11
lines changed

3 files changed

+194
-11
lines changed

sql/log_event.cc

Lines changed: 116 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ class Write_on_release_cache
305305
~Write_on_release_cache()
306306
{
307307
copy_event_cache_to_file_and_reinit(m_cache, m_file);
308-
if (m_flags | FLUSH_F)
308+
if (m_flags & FLUSH_F)
309309
fflush(m_file);
310310
}
311311

@@ -813,6 +813,15 @@ const char* Log_event::get_type_str(Log_event_type type)
813813
case BINLOG_CHECKPOINT_EVENT: return "Binlog_checkpoint";
814814
case GTID_EVENT: return "Gtid";
815815
case GTID_LIST_EVENT: return "Gtid_list";
816+
817+
/* The following is only for mysqlbinlog */
818+
case IGNORABLE_LOG_EVENT: return "Ignorable log event";
819+
case ROWS_QUERY_LOG_EVENT: return "MySQL Rows_query";
820+
case GTID_LOG_EVENT: return "MySQL Gtid";
821+
case ANONYMOUS_GTID_LOG_EVENT: return "MySQL Anonymous_Gtid";
822+
case PREVIOUS_GTIDS_LOG_EVENT: return "MySQL Previous_gtids";
823+
case HEARTBEAT_LOG_EVENT: return "Heartbeat";
824+
816825
default: return "Unknown"; /* impossible */
817826
}
818827
}
@@ -1416,6 +1425,8 @@ Log_event* Log_event::read_log_event(IO_CACHE* file,
14161425
DBUG_ENTER("Log_event::read_log_event");
14171426
DBUG_ASSERT(description_event != 0);
14181427
char head[LOG_EVENT_MINIMAL_HEADER_LEN];
1428+
my_off_t position= my_b_tell(file);
1429+
14191430
/*
14201431
First we only want to read at most LOG_EVENT_MINIMAL_HEADER_LEN, just to
14211432
check the event for sanity and to know its length; no need to really parse
@@ -1427,7 +1438,7 @@ Log_event* Log_event::read_log_event(IO_CACHE* file,
14271438
LOG_EVENT_MINIMAL_HEADER_LEN);
14281439

14291440
LOCK_MUTEX;
1430-
DBUG_PRINT("info", ("my_b_tell: %lu", (ulong) my_b_tell(file)));
1441+
DBUG_PRINT("info", ("my_b_tell: %llu", (ulonglong) position));
14311442
if (my_b_read(file, (uchar *) head, header_size))
14321443
{
14331444
DBUG_PRINT("info", ("Log_event::read_log_event(IO_CACHE*,Format_desc*) \
@@ -1484,8 +1495,9 @@ failed my_b_read"));
14841495
{
14851496
DBUG_ASSERT(error != 0);
14861497
sql_print_error("Error in Log_event::read_log_event(): "
1487-
"'%s', data_len: %lu, event_type: %d",
1488-
error,data_len,(uchar)(head[EVENT_TYPE_OFFSET]));
1498+
"'%s' at offset: %llu data_len: %lu event_type: %d",
1499+
error, position, data_len,
1500+
(uchar)(head[EVENT_TYPE_OFFSET]));
14891501
my_free(buf);
14901502
/*
14911503
The SQL slave thread will check if file->error<0 to know
@@ -1518,10 +1530,12 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
15181530
DBUG_PRINT("info", ("binlog_version: %d", description_event->binlog_version));
15191531
DBUG_DUMP("data", (unsigned char*) buf, event_len);
15201532

1521-
/* Check the integrity */
1533+
/*
1534+
Check the integrity; This is needed because handle_slave_io() doesn't
1535+
check if packet is of proper length.
1536+
*/
15221537
if (event_len < EVENT_LEN_OFFSET ||
1523-
(uchar)buf[EVENT_TYPE_OFFSET] >= ENUM_END_EVENT ||
1524-
(uint) event_len != uint4korr(buf+EVENT_LEN_OFFSET))
1538+
event_len != uint4korr(buf+EVENT_LEN_OFFSET))
15251539
{
15261540
*error="Sanity check failed"; // Needed to free buffer
15271541
DBUG_RETURN(NULL); // general sanity check - will fail on a partial read
@@ -1703,6 +1717,15 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
17031717
case DELETE_ROWS_EVENT:
17041718
ev = new Delete_rows_log_event(buf, event_len, description_event);
17051719
break;
1720+
1721+
/* MySQL GTID events are ignored */
1722+
case GTID_LOG_EVENT:
1723+
case ANONYMOUS_GTID_LOG_EVENT:
1724+
case PREVIOUS_GTIDS_LOG_EVENT:
1725+
ev= new Ignorable_log_event(buf, description_event,
1726+
get_type_str((Log_event_type) event_type));
1727+
break;
1728+
17061729
case TABLE_MAP_EVENT:
17071730
ev = new Table_map_log_event(buf, event_len, description_event);
17081731
break;
@@ -1720,10 +1743,22 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
17201743
ev = new Annotate_rows_log_event(buf, event_len, description_event);
17211744
break;
17221745
default:
1723-
DBUG_PRINT("error",("Unknown event code: %d",
1724-
(int) buf[EVENT_TYPE_OFFSET]));
1725-
ev= NULL;
1726-
break;
1746+
/*
1747+
Create an object of Ignorable_log_event for unrecognized sub-class.
1748+
So that SLAVE SQL THREAD will only update the position and continue.
1749+
*/
1750+
if (uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F)
1751+
{
1752+
ev= new Ignorable_log_event(buf, description_event,
1753+
get_type_str((Log_event_type) event_type));
1754+
}
1755+
else
1756+
{
1757+
DBUG_PRINT("error",("Unknown event code: %d",
1758+
(int) buf[EVENT_TYPE_OFFSET]));
1759+
ev= NULL;
1760+
break;
1761+
}
17271762
}
17281763
}
17291764

@@ -4891,6 +4926,9 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
48914926
post_header_len[HEARTBEAT_LOG_EVENT-1]= 0;
48924927
post_header_len[IGNORABLE_LOG_EVENT-1]= 0;
48934928
post_header_len[ROWS_QUERY_LOG_EVENT-1]= 0;
4929+
post_header_len[GTID_LOG_EVENT-1]= 0;
4930+
post_header_len[ANONYMOUS_GTID_LOG_EVENT-1]= 0;
4931+
post_header_len[PREVIOUS_GTIDS_LOG_EVENT-1]= 0;
48944932
post_header_len[WRITE_ROWS_EVENT-1]= ROWS_HEADER_LEN_V2;
48954933
post_header_len[UPDATE_ROWS_EVENT-1]= ROWS_HEADER_LEN_V2;
48964934
post_header_len[DELETE_ROWS_EVENT-1]= ROWS_HEADER_LEN_V2;
@@ -12639,6 +12677,52 @@ Incident_log_event::write_data_body(IO_CACHE *file)
1263912677
}
1264012678

1264112679

12680+
Ignorable_log_event::Ignorable_log_event(const char *buf,
12681+
const Format_description_log_event
12682+
*descr_event,
12683+
const char *event_name)
12684+
:Log_event(buf, descr_event), number((int) (uchar) buf[EVENT_TYPE_OFFSET]),
12685+
description(event_name)
12686+
{
12687+
DBUG_ENTER("Ignorable_log_event::Ignorable_log_event");
12688+
DBUG_VOID_RETURN;
12689+
}
12690+
12691+
Ignorable_log_event::~Ignorable_log_event()
12692+
{
12693+
}
12694+
12695+
#ifndef MYSQL_CLIENT
12696+
/* Pack info for its unrecognized ignorable event */
12697+
void Ignorable_log_event::pack_info(THD *thd, Protocol *protocol)
12698+
{
12699+
char buf[256];
12700+
size_t bytes;
12701+
bytes= my_snprintf(buf, sizeof(buf), "# Ignorable event type %d (%s)",
12702+
number, description);
12703+
protocol->store(buf, bytes, &my_charset_bin);
12704+
}
12705+
#endif
12706+
12707+
#ifdef MYSQL_CLIENT
12708+
/* Print for its unrecognized ignorable event */
12709+
void
12710+
Ignorable_log_event::print(FILE *file,
12711+
PRINT_EVENT_INFO *print_event_info)
12712+
{
12713+
if (print_event_info->short_form)
12714+
return;
12715+
12716+
print_header(&print_event_info->head_cache, print_event_info, FALSE);
12717+
my_b_printf(&print_event_info->head_cache, "\tIgnorable\n");
12718+
my_b_printf(&print_event_info->head_cache,
12719+
"# Ignorable event type %d (%s)\n", number, description);
12720+
copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
12721+
file);
12722+
}
12723+
#endif
12724+
12725+
1264212726
#ifdef MYSQL_CLIENT
1264312727
/**
1264412728
The default values for these variables should be values that are
@@ -12720,4 +12804,25 @@ bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
1272012804
return TRUE;
1272112805
#endif
1272212806
}
12807+
12808+
/**
12809+
Check if we should write event to the relay log
12810+
12811+
This is used to skip events that is only supported by MySQL
12812+
12813+
Return:
12814+
0 ok
12815+
1 Don't write event
12816+
*/
12817+
12818+
bool event_that_should_be_ignored(const char *buf)
12819+
{
12820+
uint event_type= (uchar)buf[EVENT_TYPE_OFFSET];
12821+
if (event_type == GTID_LOG_EVENT ||
12822+
event_type == ANONYMOUS_GTID_LOG_EVENT ||
12823+
event_type == PREVIOUS_GTIDS_LOG_EVENT ||
12824+
(uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
12825+
return 1;
12826+
return 0;
12827+
}
1272312828
#endif

sql/log_event.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ struct sql_ex_info
260260
#define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN)
261261
#define INCIDENT_HEADER_LEN 2
262262
#define HEARTBEAT_HEADER_LEN 0
263+
#define IGNORABLE_HEADER_LEN 0
263264
#define ROWS_HEADER_LEN_V2 10
264265
#define ANNOTATE_ROWS_HEADER_LEN 0
265266
#define BINLOG_CHECKPOINT_HEADER_LEN 4
@@ -519,6 +520,17 @@ struct sql_ex_info
519520
*/
520521
#define LOG_EVENT_RELAY_LOG_F 0x40
521522

523+
/**
524+
@def LOG_EVENT_IGNORABLE_F
525+
526+
For an event, 'e', carrying a type code, that a slave,
527+
's', does not recognize, 's' will check 'e' for
528+
LOG_EVENT_IGNORABLE_F, and if the flag is set, then 'e'
529+
is ignored. Otherwise, 's' acknowledges that it has
530+
found an unknown event in the relay log.
531+
*/
532+
#define LOG_EVENT_IGNORABLE_F 0x80
533+
522534
/**
523535
@def LOG_EVENT_SKIP_REPLICATION_F
524536
@@ -697,6 +709,11 @@ enum Log_event_type
697709
UPDATE_ROWS_EVENT = 31,
698710
DELETE_ROWS_EVENT = 32,
699711

712+
/* MySQL 5.6 GTID events, ignored by MariaDB */
713+
GTID_LOG_EVENT= 33,
714+
ANONYMOUS_GTID_LOG_EVENT= 34,
715+
PREVIOUS_GTIDS_LOG_EVENT= 35,
716+
700717
/*
701718
Add new events here - right above this comment!
702719
Existing events (except ENUM_END_EVENT) should never change their numbers
@@ -4740,6 +4757,60 @@ class Incident_log_event : public Log_event {
47404757
LEX_STRING m_message;
47414758
};
47424759

4760+
/**
4761+
@class Ignorable_log_event
4762+
4763+
Base class for ignorable log events. Events deriving from
4764+
this class can be safely ignored by slaves that cannot
4765+
recognize them. Newer slaves, will be able to read and
4766+
handle them. This has been designed to be an open-ended
4767+
architecture, so adding new derived events shall not harm
4768+
the old slaves that support ignorable log event mechanism
4769+
(they will just ignore unrecognized ignorable events).
4770+
4771+
@note The only thing that makes an event ignorable is that it has
4772+
the LOG_EVENT_IGNORABLE_F flag set. It is not strictly necessary
4773+
that ignorable event types derive from Ignorable_log_event; they may
4774+
just as well derive from Log_event and pass LOG_EVENT_IGNORABLE_F as
4775+
argument to the Log_event constructor.
4776+
**/
4777+
4778+
class Ignorable_log_event : public Log_event {
4779+
public:
4780+
int number;
4781+
const char *description;
4782+
4783+
#ifndef MYSQL_CLIENT
4784+
Ignorable_log_event(THD *thd_arg)
4785+
:Log_event(thd_arg, LOG_EVENT_IGNORABLE_F, FALSE),
4786+
number(0), description("internal")
4787+
{
4788+
DBUG_ENTER("Ignorable_log_event::Ignorable_log_event");
4789+
DBUG_VOID_RETURN;
4790+
}
4791+
#endif
4792+
4793+
Ignorable_log_event(const char *buf,
4794+
const Format_description_log_event *descr_event,
4795+
const char *event_name);
4796+
virtual ~Ignorable_log_event();
4797+
4798+
#ifndef MYSQL_CLIENT
4799+
void pack_info(THD *, Protocol*);
4800+
#endif
4801+
4802+
#ifdef MYSQL_CLIENT
4803+
virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
4804+
#endif
4805+
4806+
virtual Log_event_type get_type_code() { return IGNORABLE_LOG_EVENT; }
4807+
4808+
virtual bool is_valid() const { return 1; }
4809+
4810+
virtual int get_data_size() { return IGNORABLE_HEADER_LEN; }
4811+
};
4812+
4813+
47434814
static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache,
47444815
FILE *file)
47454816
{
@@ -4797,6 +4868,7 @@ bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
47974868
ulonglong *relay_log_pos);
47984869

47994870
bool event_checksum_test(uchar *buf, ulong event_len, uint8 alg);
4871+
bool event_that_should_be_ignored(const char *buf);
48004872
uint8 get_checksum_alg(const char* buf, ulong len);
48014873
extern TYPELIB binlog_checksum_typelib;
48024874

sql/slave.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5615,6 +5615,11 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
56155615
error_msg.append(llbuf, strlen(llbuf));
56165616
goto err;
56175617
}
5618+
5619+
/*
5620+
Heartbeat events doesn't count in the binlog size, so we don't have to
5621+
increment mi->master_log_pos
5622+
*/
56185623
goto skip_relay_logging;
56195624
}
56205625
break;
@@ -5844,6 +5849,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
58445849
else
58455850
if ((s_id == global_system_variables.server_id &&
58465851
!mi->rli.replicate_same_server_id) ||
5852+
event_that_should_be_ignored(buf) ||
58475853
/*
58485854
the following conjunction deals with IGNORE_SERVER_IDS, if set
58495855
If the master is on the ignore list, execution of

0 commit comments

Comments
 (0)