WL#5404: Propagation of Rows_query log event
Affects: Server-5.6
—
Status: Complete
RATIONALE ========= * Rows_query was introduced to record the original query for rows events in RBR, but the Rows query will be lost when replicating on slave or re-applying the statments dumped by mysqlbinlog. This worklog will fix that. Requirements ============ 1. The original SQL statement will be relayed by Rows_query log event in a replication chain if the '--binlog-rows-query-log-events' option is enabled. 2. The BINLOG '...' dumped by MYSQLBINLOG will be applied by MySQL server if the '--binlog-rows-query-log-events' option is enabled. 3. The Rows_query_log event will follow replication filtering rules as Rows_log event does. It will be relayed if slave filters out part Rows events or nothing from a rows statement. It will be filtered out if slave filters out all its Rows events. PROPOSED SOLUTIONS ================== There are basically two solutions to that: 1. Output original SQL statement using '#' comment, and also use a BINLOG statement to ship the Rows_query_log_event so that it can be applied by MySQL server as following: #100519 13:20:24 server id 1 end_log_pos 3913 Rows_query # original SQL statement BINLOG '...' The Slave SQL Thread will set the original SQL statement into current THD when executing the Rows_query log event and then binlog it with its rows event. So that it can be relayed in a replication chain. Pro: It is consistent with Table_map event and Rows_log event as they are using the BINLOG '...' for the purpose. 2. Use a variant of the special comments to construct Rows_query log event, that is, something like this: #100519 13:20:24 server id 1 end_log_pos 3913 Rows_query /*!original SQL statement */ The special comment would automatically be ignored by anything that is not MySQL (this is the reason for the /*!*/ comment as well). The Slave SQL Thread will set the special comment into current THD and parse it when executing the Rows_query log event. So that it can be relayed in a replication chain. Pro: The special comment will be applied and relayed by itself. Con: The special comment will not work fine if the original SQL statement include version comment. The MySQL will introduce more syntax for special comment. It's related to WL#4033 and BUG#50935. SUMMARY ======= * The solution one is taken, considering the pro and con of the two solutions.
RELAY AND APPLY INTERFACE ========================= Rows_query_log_event::print will print BINLOG'...' with base64 format, So that the Rows_query_log_event can be applied by MySQL server. It was implemented in WL#4033 as following: Rows_query_log_event::print: my_b_printf(&cache, "\tRows_query\n"); my_b_printf(&cache, "# %s\n", m_rows_query); //Print BINLOG'...' IO_CACHE *const body= &print_event_info->body_cache; print_base64(body, print_event_info, true); Rows_query_log_event::do_apply_event should set the original SQL statement into current THD. 1. The slave SQL thread will call the interface to set query into THD when executing the event, and then binlog the event with its rows event. So that it will be relayed. 2. The MySQL server will construct the Rows_query log event from BINLOG'...' statement and then call the interface to set query into THD and then binlog the event with its rows event when applying. The proposed method is the followings: 1. Set the 'm_rows_query' member of Rows_query_log_event into THD directly, and delay to delete the Rows_query log event until all its rows event are executed. Pro: The 'query' memory space is easily freed when deleting the event. Con: Have to delay to delete the Rows_query log event until all its rows event are executed. 2. Allocate space to save the query by thd->alloc and free it later Pro: The Rows_query log event will be deleted immediately after it is executed. Con: The allocated space is not easily freed. It will cause memory leak easily. According the pros and cons, we decide to take the first method.
1. Set the 'm_rows_query' member of Rows_query_log_event into THD directly as the event is constructed from its BINLOG'...' statement by MySQl server when applying, and the slave SQL thread will get it from relay log. int Rows_query_log_event::do_apply_event(Relay_log_info const *rli) { /* Set query for writing Rows_query log event into binlog later.*/ thd->set_query(m_rows_query, (uint32) strlen(m_rows_query)); } 2. For the THD still hold the original SQL statement when binlogging the Rows_query log event, delay to delete the Rows_query log event until all its rows event are executed when delaying and applying. /* Delete the Rows_query log event after its last rows event are applied */ if ((ev_type == WRITE_ROWS_EVENT || ev_type == DELETE_ROWS_EVENT || ev_type == UPDATE_ROWS_EVENT) && rli->rows_query_ev != NULL && ((Rows_log_event*) ev)->get_flags(Rows_log_event::STMT_END_F)) { delete rli->rows_query_ev; rli->rows_query_ev= NULL; } /* Record the Rows_query log event until all its rows event are applied */ if (ev_type == ROWS_QUERY_LOG_EVENT) rli->rows_query_ev= (Rows_query_log_event*) ev;
Copyright (c) 2000, 2024, Oracle Corporation and/or its affiliates. All rights reserved.