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.
This commit is contained in:
parent
ced65e21c6
commit
59830e1ab8
@ -4236,8 +4236,19 @@ Query_log_event::do_shall_skip(Relay_log_info *rli)
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
Query_log_event::peek_is_commit_rollback(const char *event_start,
|
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)
|
if (event_len < LOG_EVENT_HEADER_LEN + QUERY_HEADER_LEN || event_len < 9)
|
||||||
return false;
|
return false;
|
||||||
return !memcmp(event_start + (event_len-7), "\0COMMIT", 7) ||
|
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
|
bool
|
||||||
Gtid_log_event::peek(const char *event_start, size_t event_len,
|
Gtid_log_event::peek(const char *event_start, size_t event_len,
|
||||||
|
uint8 checksum_alg,
|
||||||
uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
|
uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
|
||||||
uchar *flags2)
|
uchar *flags2)
|
||||||
{
|
{
|
||||||
const char *p;
|
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)
|
if (event_len < LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN)
|
||||||
return true;
|
return true;
|
||||||
*server_id= uint4korr(event_start + SERVER_ID_OFFSET);
|
*server_id= uint4korr(event_start + SERVER_ID_OFFSET);
|
||||||
|
@ -1946,7 +1946,7 @@ public: /* !!! Public in this patch to allow old usage */
|
|||||||
const char *query_arg,
|
const char *query_arg,
|
||||||
uint32 q_len_arg);
|
uint32 q_len_arg);
|
||||||
static bool peek_is_commit_rollback(const char *event_start,
|
static bool peek_is_commit_rollback(const char *event_start,
|
||||||
size_t event_len);
|
size_t event_len, uint8 checksum_alg);
|
||||||
#endif /* HAVE_REPLICATION */
|
#endif /* HAVE_REPLICATION */
|
||||||
/*
|
/*
|
||||||
If true, the event always be applied by slave SQL thread or be printed by
|
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,
|
static int make_compatible_event(String *packet, bool *need_dummy_event,
|
||||||
ulong ev_offset, uint8 checksum_alg);
|
ulong ev_offset, uint8 checksum_alg);
|
||||||
static bool peek(const char *event_start, size_t event_len,
|
static bool peek(const char *event_start, size_t event_len,
|
||||||
|
uint8 checksum_alg,
|
||||||
uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
|
uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
|
||||||
uchar *flags2);
|
uchar *flags2);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1160,7 +1160,8 @@ gtid_state_from_pos(const char *name, uint32 offset,
|
|||||||
{
|
{
|
||||||
rpl_gtid gtid;
|
rpl_gtid gtid;
|
||||||
uchar flags2;
|
uchar flags2;
|
||||||
if (Gtid_log_event::peek(packet.ptr(), packet.length(), >id.domain_id,
|
if (Gtid_log_event::peek(packet.ptr(), packet.length(),
|
||||||
|
current_checksum_alg, >id.domain_id,
|
||||||
>id.server_id, >id.seq_no, &flags2))
|
>id.server_id, >id.seq_no, &flags2))
|
||||||
{
|
{
|
||||||
errormsg= "Corrupt gtid_log_event found while scanning binlog to find "
|
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 ||
|
if (ev_offset > len ||
|
||||||
Gtid_log_event::peek(packet->ptr()+ev_offset, len - ev_offset,
|
Gtid_log_event::peek(packet->ptr()+ev_offset, len - ev_offset,
|
||||||
|
current_checksum_alg,
|
||||||
&domain_id, &server_id, &seq_no, &flags2))
|
&domain_id, &server_id, &seq_no, &flags2))
|
||||||
return "Failed to read Gtid_log_event: corrupt binlog";
|
return "Failed to read Gtid_log_event: corrupt binlog";
|
||||||
gtid= gtid_state->find(domain_id);
|
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 ||
|
if (event_type == XID_EVENT ||
|
||||||
(event_type == QUERY_EVENT &&
|
(event_type == QUERY_EVENT &&
|
||||||
Query_log_event::peek_is_commit_rollback(packet->ptr() + ev_offset,
|
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;
|
*gtid_skip_group= GTID_SKIP_NOT;
|
||||||
return NULL;
|
return NULL;
|
||||||
case GTID_SKIP_NOT:
|
case GTID_SKIP_NOT:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user