mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-20574 Position of events reported by mysqlbinlog is wrong with encrypted binlogs, SHOW BINLOG EVENTS reports the correct one.
Analysis Mysqlbinlog output for encrypted binary log #Q> insert into tab1 values (3,'row 003') #190912 17:36:35 server id 10221 end_log_pos 980 CRC32 0x53bcb3d3 Table_map: `test`.`tab1` mapped to number 19 # at 940 #190912 17:36:35 server id 10221 end_log_pos 1026 CRC32 0xf2ae5136 Write_rows: table id 19 flags: STMT_END_F Here we can see Table_map_log_event ends at 980 but Next event starts at 940. And the reason for that is we do not send START_ENCRYPTION_EVENT to the slave Solution:- Send Start_encryption_log_event as Ignorable_log_event to slave(mysqlbinlog), So that mysqlbinlog can update its log_pos. Since Slave can request multiple FORMAT_DESCRIPTION_EVENT while master does not have so We only update slave master pos when master actually have the FORMAT_DESCRIPTION_EVENT. Similar logic should be applied for START_ENCRYPTION_EVENT. Also added the test case when new server reads the data from old server which does not send START_ENCRYPTION_EVENT to slave. Master Slave Upgrade Scenario. When Slave is updated first, Slave will have extra logic of handling START_ENCRYPTION_EVENT But master willnot be sending START_ENCRYPTION_EVENT. So there will be no issue. When Master is updated first, It will send START_ENCRYPTION_EVENT to slave , But slave will ignore this event in queue_event.
This commit is contained in:
@ -399,16 +399,27 @@ static int send_file(THD *thd)
|
||||
|
||||
/**
|
||||
Internal to mysql_binlog_send() routine that recalculates checksum for
|
||||
a FD event (asserted) that needs additional arranment prior sending to slave.
|
||||
1. FD event (asserted) that needs additional arranment prior sending to slave.
|
||||
2. Start_encryption_log_event whose Ignored flag is set
|
||||
TODO DBUG_ASSERT can be removed if this function is used for more general cases
|
||||
*/
|
||||
inline void fix_checksum(String *packet, ulong ev_offset)
|
||||
|
||||
inline void fix_checksum(enum_binlog_checksum_alg checksum_alg, String *packet,
|
||||
ulong ev_offset)
|
||||
{
|
||||
if (checksum_alg == BINLOG_CHECKSUM_ALG_OFF ||
|
||||
checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF)
|
||||
return;
|
||||
/* recalculate the crc for this event */
|
||||
uint data_len = uint4korr(packet->ptr() + ev_offset + EVENT_LEN_OFFSET);
|
||||
ha_checksum crc;
|
||||
DBUG_ASSERT(data_len ==
|
||||
DBUG_ASSERT((data_len ==
|
||||
LOG_EVENT_MINIMAL_HEADER_LEN + FORMAT_DESCRIPTION_HEADER_LEN +
|
||||
BINLOG_CHECKSUM_ALG_DESC_LEN + BINLOG_CHECKSUM_LEN);
|
||||
BINLOG_CHECKSUM_ALG_DESC_LEN + BINLOG_CHECKSUM_LEN) ||
|
||||
(data_len ==
|
||||
LOG_EVENT_MINIMAL_HEADER_LEN + BINLOG_CRYPTO_SCHEME_LENGTH +
|
||||
BINLOG_KEY_VERSION_LENGTH + BINLOG_NONCE_LENGTH +
|
||||
BINLOG_CHECKSUM_LEN));
|
||||
crc= my_checksum(0, (uchar *)packet->ptr() + ev_offset, data_len -
|
||||
BINLOG_CHECKSUM_LEN);
|
||||
int4store(packet->ptr() + ev_offset + data_len - BINLOG_CHECKSUM_LEN, crc);
|
||||
@ -2135,6 +2146,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
|
||||
THD *thd= info->thd;
|
||||
String *packet= info->packet;
|
||||
Log_event_type event_type;
|
||||
bool initial_log_pos= info->clear_initial_log_pos;
|
||||
DBUG_ENTER("send_format_descriptor_event");
|
||||
|
||||
/**
|
||||
@ -2233,7 +2245,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
|
||||
|
||||
(*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F;
|
||||
|
||||
if (info->clear_initial_log_pos)
|
||||
if (initial_log_pos)
|
||||
{
|
||||
info->clear_initial_log_pos= false;
|
||||
/*
|
||||
@ -2251,9 +2263,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
|
||||
ST_CREATED_OFFSET+ev_offset, (ulong) 0);
|
||||
|
||||
/* fix the checksum due to latest changes in header */
|
||||
if (info->current_checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
|
||||
info->current_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
|
||||
fix_checksum(packet, ev_offset);
|
||||
fix_checksum(info->current_checksum_alg, packet, ev_offset);
|
||||
}
|
||||
else if (info->using_gtid_state)
|
||||
{
|
||||
@ -2274,9 +2284,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
|
||||
{
|
||||
int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+
|
||||
ST_CREATED_OFFSET+ev_offset, (ulong) 0);
|
||||
if (info->current_checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
|
||||
info->current_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
|
||||
fix_checksum(packet, ev_offset);
|
||||
fix_checksum(info->current_checksum_alg, packet, ev_offset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2289,12 +2297,16 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
|
||||
}
|
||||
|
||||
/*
|
||||
Read the following Start_encryption_log_event but don't send it to slave.
|
||||
Slave doesn't need to know whether master's binlog is encrypted,
|
||||
and if it'll want to encrypt its logs, it should generate its own
|
||||
random nonce, not use the one from the master.
|
||||
Read the following Start_encryption_log_event and send it to slave as
|
||||
Ignorable_log_event. Although Slave doesn't need to know whether master's
|
||||
binlog is encrypted but it needs to update slave log pos (for mysqlbinlog).
|
||||
|
||||
If slave want to encrypt its logs, it should generate its own
|
||||
random nonce, it should not use the one from the master.
|
||||
*/
|
||||
packet->length(0);
|
||||
/* reset transmit packet for the event read from binary log file */
|
||||
if (reset_transmit_packet(info, info->flags, &ev_offset, &info->errmsg))
|
||||
DBUG_RETURN(1);
|
||||
info->last_pos= linfo->pos;
|
||||
error= Log_event::read_log_event(log, packet, info->fdev,
|
||||
opt_master_verify_checksum
|
||||
@ -2308,12 +2320,13 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
event_type= (Log_event_type)((uchar)(*packet)[LOG_EVENT_OFFSET]);
|
||||
event_type= (Log_event_type)((uchar)(*packet)[LOG_EVENT_OFFSET + ev_offset]);
|
||||
if (event_type == START_ENCRYPTION_EVENT)
|
||||
{
|
||||
Start_encryption_log_event *sele= (Start_encryption_log_event *)
|
||||
Log_event::read_log_event(packet->ptr(), packet->length(), &info->errmsg,
|
||||
info->fdev, BINLOG_CHECKSUM_ALG_OFF);
|
||||
Log_event::read_log_event(packet->ptr() + ev_offset, packet->length()
|
||||
- ev_offset, &info->errmsg, info->fdev,
|
||||
BINLOG_CHECKSUM_ALG_OFF);
|
||||
if (!sele)
|
||||
{
|
||||
info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG;
|
||||
@ -2327,6 +2340,18 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
|
||||
delete sele;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
/* Make it Ignorable_log_event and send it */
|
||||
(*packet)[FLAGS_OFFSET+ev_offset] |= LOG_EVENT_IGNORABLE_F;
|
||||
if (initial_log_pos)
|
||||
int4store((char*) packet->ptr()+LOG_POS_OFFSET+ev_offset, (ulong) 0);
|
||||
/* fix the checksum due to latest changes in header */
|
||||
fix_checksum(info->current_checksum_alg, packet, ev_offset);
|
||||
if (my_net_write(info->net, (uchar*) packet->ptr(), packet->length()))
|
||||
{
|
||||
info->errmsg= "Failed on my_net_write()";
|
||||
info->error= ER_UNKNOWN_ERROR;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
delete sele;
|
||||
}
|
||||
else if (start_pos == BIN_LOG_HEADER_SIZE)
|
||||
|
Reference in New Issue
Block a user