diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 77f74e0d42c..b06b8fb74e5 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -160,7 +160,13 @@ static Server_gtid_event_filter *server_id_gtid_filter= NULL; static char *start_datetime_str, *stop_datetime_str; static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX; -static my_time_t last_processed_datetime= MY_TIME_T_MAX; + +typedef struct _last_processed_ev_t +{ + ulonglong position; + my_time_t datetime; +} last_processed_ev_t; +static last_processed_ev_t last_processed_ev= {0, MY_TIME_T_MAX}; static ulonglong rec_count= 0; static MYSQL* mysql = NULL; @@ -1611,7 +1617,19 @@ err: end: rec_count++; end_skip_count: - last_processed_datetime= ev_when; + /* + Update the last_processed_ev, unless the event is a fake event (i.e. format + description (ev pointer is reset to 0) or rotate event (ev->when is 0)), or + the event is encrypted (i.e. type is Unknown). + */ + if (ev && + !(ev_type == UNKNOWN_EVENT && + ((Unknown_log_event *) ev)->what == Unknown_log_event::ENCRYPTED) && + !(ev_type == ROTATE_EVENT && !ev->when)) + { + last_processed_ev.position= pos + ev->data_written; + last_processed_ev.datetime= ev_when; + } DBUG_PRINT("info", ("end event processing")); /* @@ -2925,6 +2943,9 @@ static Exit_status handle_event_text_mode(PRINT_EVENT_INFO *print_event_info, if (old_off != BIN_LOG_HEADER_SIZE) *len= 1; // fake event, don't increment old_off } + DBUG_ASSERT(old_off + ev->data_written == old_off + (*len - 1) || + (*len == 1 && + (type == ROTATE_EVENT || type == FORMAT_DESCRIPTION_EVENT))); Exit_status retval= process_event(print_event_info, ev, old_off, logname); if (retval != OK_CONTINUE) DBUG_RETURN(retval); @@ -2943,6 +2964,9 @@ static Exit_status handle_event_text_mode(PRINT_EVENT_INFO *print_event_info, DBUG_RETURN(ERROR_STOP); } + DBUG_ASSERT(old_off + ev->data_written == old_off + (*len - 1) || + (*len == 1 && + (type == ROTATE_EVENT || type == FORMAT_DESCRIPTION_EVENT))); retval= process_event(print_event_info, ev, old_off, logname); if (retval != OK_CONTINUE) { @@ -3342,6 +3366,8 @@ static Exit_status check_header(IO_CACHE* file, the new one, so we should not do it ourselves in this case. */ + DBUG_ASSERT(tmp_pos + new_description_event->data_written == + my_b_tell(file)); Exit_status retval= process_event(print_event_info, new_description_event, tmp_pos, logname); @@ -3495,20 +3521,17 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, } // else read_error == 0 means EOF, that's OK, we break in this case - /* - Emit a warning in the event that we finished processing input - before reaching the boundary indicated by --stop-position. - */ - if (((longlong)stop_position != stop_position_default) && - stop_position > my_b_tell(file)) - { - retval = OK_STOP; - warning("Did not reach stop position %llu before " - "end of input", stop_position); - } - goto end; } + + /* + The real location that we have read up to in the file should align with + the size of the event, unless the event is encrypted. + */ + DBUG_ASSERT( + ((ev->get_type_code() == UNKNOWN_EVENT && + ((Unknown_log_event *) ev)->what == Unknown_log_event::ENCRYPTED)) || + old_off + ev->data_written == my_b_tell(file)); if ((retval= process_event(print_event_info, ev, old_off, logname)) != OK_CONTINUE) goto end; @@ -3687,10 +3710,18 @@ int main(int argc, char** argv) start_position= BIN_LOG_HEADER_SIZE; } + /* + Emit a warning if we finished processing input before reaching the stop + boundaries indicated by --stop-datetime or --stop-position. + */ if (stop_datetime != MY_TIME_T_MAX && - stop_datetime > last_processed_datetime) + stop_datetime > last_processed_ev.datetime) warning("Did not reach stop datetime '%s' before end of input", stop_datetime_str); + if ((static_cast(stop_position) != stop_position_default) && + stop_position > last_processed_ev.position) + warning("Did not reach stop position %llu before end of input", + stop_position); /* If enable flashback, need to print the events from the end to the diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_position.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_position.result index 1517fd765ac..40fb791cf02 100644 --- a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_position.result +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_position.result @@ -18,6 +18,51 @@ drop table t1; # Ensuring file offset of binlog_f2_mid < binlog_f1_end # # +# Test using --read-from-remote-server +# +connection default; +# +# --stop-position tests +# +# Case 1.a) With one binlog file, a --stop-position before the end of +# the file should not result in a warning +# MYSQL_BINLOG --read-from-remote-server --stop-position=binlog_f1_pre_rotate binlog_f1_full --result-file=tmp/warn_position_test_file.out 2>&1 +# +# Case 1.b) With one binlog file, a --stop-position at the exact end of +# the file should not result in a warning +# MYSQL_BINLOG --read-from-remote-server --stop-position=binlog_f1_end binlog_f1_full --result-file=tmp/warn_position_test_file.out 2>&1 +# +# Case 1.c) With one binlog file, a --stop-position past the end of the +# file should(!) result in a warning +# MYSQL_BINLOG --read-from-remote-server --short-form --stop-position=binlog_f1_over_eof binlog_f1_full --result-file=tmp/warn_position_test_file.out 2>&1 +WARNING: Did not reach stop position before end of input +# +# Case 2.a) With two binlog files, a --stop-position targeting b2 which +# exists in the size of b1 should: +# 1) not provide any warnings +# 2) not prevent b2 from outputting its desired events before the +# stop position +# MYSQL_BINLOG --read-from-remote-server --stop-position=binlog_f2_mid binlog_f1_full binlog_f2_full --result-file=tmp/warn_position_test_file.out 2>&1 +include/assert_grep.inc [Ensure all intended GTIDs are present] +include/assert_grep.inc [Ensure the next GTID binlogged is _not_ present] +# +# Case 2.b) With two binlog files, a --stop-position targeting the end +# of binlog 2 should: +# 1) not provide any warnings +# 2) not prevent b2 from outputting its entire binary log +# MYSQL_BINLOG --read-from-remote-server --stop-position=binlog_f2_end binlog_f1_full binlog_f2_full --result-file=tmp/warn_position_test_file.out 2>&1 +include/assert_grep.inc [Ensure a GTID exists for each transaction] +include/assert_grep.inc [Ensure the last GTID binlogged is present] +# +# Case 2.c) With two binlog files, a --stop-position targeting beyond +# the eof of binlog 2 should: +# 1) provide a warning that the stop position was not reached +# 2) not prevent b2 from outputting its entire binary log +# MYSQL_BINLOG --read-from-remote-server --stop-position=binlog_f2_over_eof binlog_f1_full binlog_f2_full --result-file=tmp/warn_position_test_file.out 2>&1 +WARNING: Did not reach stop position before end of input +include/assert_grep.inc [Ensure a GTID exists for each transaction] +# +# # Test using local binlog files # connection default; diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.test b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.test index a9179297220..472e208229c 100644 --- a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.test +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.test @@ -64,13 +64,12 @@ if ($binlog_f2_mid > $binlog_f1_end) --die Mid point chosen to end in binlog 2 does not exist in earlier binlog } -#--echo # -#--echo # -#--echo # Test using --read-from-remote-server -#--echo # -#--let $read_from_remote_server= 1 -#--emit warning is not supported by --read-from-remote-server now -#--source binlog_mysqlbinlog_warn_stop_position.inc +--echo # +--echo # +--echo # Test using --read-from-remote-server +--echo # +--let $read_from_remote_server= 1 +--source binlog_mysqlbinlog_warn_stop_position.inc --echo # --echo #