summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <knielsen@knielsen-hq.org>2013-04-29 10:57:48 +0200
committerunknown <knielsen@knielsen-hq.org>2013-04-29 10:57:48 +0200
commit59830e1ab8d5e60442b5d15729c8ef06132fc827 (patch)
treed1c19e900025b234c90cb2a3d00e53e575b65e95
parentced65e21c60ca7342e8b11b888360b86bf83952d (diff)
downloadmariadb-git-59830e1ab8d5e60442b5d15729c8ef06132fc827.tar.gz
MDEV-4446: Incorrect handling of binlog checksum when searching for GTID start position in binlog
When the slave connects, the master skips binlog event groups until it reaches the position requested by the slave. To identify event groups, it needs to detect COMMIT events. But this detection did not correctly handle binlog checksums, so could incorrectly skip extra groups due to not detecting the end of an event group.
-rw-r--r--sql/log_event.cc26
-rw-r--r--sql/log_event.h3
-rw-r--r--sql/sql_repl.cc7
3 files changed, 32 insertions, 4 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc
index f0b4ca5f8fc..83789400924 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -4236,8 +4236,19 @@ Query_log_event::do_shall_skip(Relay_log_info *rli)
bool
Query_log_event::peek_is_commit_rollback(const char *event_start,
- size_t event_len)
+ size_t event_len, uint8 checksum_alg)
{
+ if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
+ {
+ if (event_len > BINLOG_CHECKSUM_LEN)
+ event_len-= BINLOG_CHECKSUM_LEN;
+ else
+ event_len= 0;
+ }
+ else
+ DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
+ checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
+
if (event_len < LOG_EVENT_HEADER_LEN + QUERY_HEADER_LEN || event_len < 9)
return false;
return !memcmp(event_start + (event_len-7), "\0COMMIT", 7) ||
@@ -6050,10 +6061,23 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
*/
bool
Gtid_log_event::peek(const char *event_start, size_t event_len,
+ uint8 checksum_alg,
uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
uchar *flags2)
{
const char *p;
+
+ if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
+ {
+ if (event_len > BINLOG_CHECKSUM_LEN)
+ event_len-= BINLOG_CHECKSUM_LEN;
+ else
+ event_len= 0;
+ }
+ else
+ DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
+ checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
+
if (event_len < LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN)
return true;
*server_id= uint4korr(event_start + SERVER_ID_OFFSET);
diff --git a/sql/log_event.h b/sql/log_event.h
index 1c2b2769915..5026b280b27 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1946,7 +1946,7 @@ public: /* !!! Public in this patch to allow old usage */
const char *query_arg,
uint32 q_len_arg);
static bool peek_is_commit_rollback(const char *event_start,
- size_t event_len);
+ size_t event_len, uint8 checksum_alg);
#endif /* HAVE_REPLICATION */
/*
If true, the event always be applied by slave SQL thread or be printed by
@@ -3084,6 +3084,7 @@ public:
static int make_compatible_event(String *packet, bool *need_dummy_event,
ulong ev_offset, uint8 checksum_alg);
static bool peek(const char *event_start, size_t event_len,
+ uint8 checksum_alg,
uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
uchar *flags2);
#endif
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 550b78832ae..f5f503b9fc8 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1160,7 +1160,8 @@ gtid_state_from_pos(const char *name, uint32 offset,
{
rpl_gtid gtid;
uchar flags2;
- if (Gtid_log_event::peek(packet.ptr(), packet.length(), &gtid.domain_id,
+ if (Gtid_log_event::peek(packet.ptr(), packet.length(),
+ current_checksum_alg, &gtid.domain_id,
&gtid.server_id, &gtid.seq_no, &flags2))
{
errormsg= "Corrupt gtid_log_event found while scanning binlog to find "
@@ -1253,6 +1254,7 @@ send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags,
if (ev_offset > len ||
Gtid_log_event::peek(packet->ptr()+ev_offset, len - ev_offset,
+ current_checksum_alg,
&domain_id, &server_id, &seq_no, &flags2))
return "Failed to read Gtid_log_event: corrupt binlog";
gtid= gtid_state->find(domain_id);
@@ -1287,7 +1289,8 @@ send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags,
if (event_type == XID_EVENT ||
(event_type == QUERY_EVENT &&
Query_log_event::peek_is_commit_rollback(packet->ptr() + ev_offset,
- len - ev_offset)))
+ len - ev_offset,
+ current_checksum_alg)))
*gtid_skip_group= GTID_SKIP_NOT;
return NULL;
case GTID_SKIP_NOT: