diff options
author | Brandon Nesterenko <brandon.nesterenko@mariadb.com> | 2021-09-14 12:58:04 -0600 |
---|---|---|
committer | Brandon Nesterenko <brandon.nesterenko@mariadb.com> | 2021-11-10 15:27:25 -0700 |
commit | c9896eb15bfc11414577128d0463ef2fefb66407 (patch) | |
tree | 71751d54a10c7cf78b5896fcda3a93258bdd2faa | |
parent | 303ed1a153630138ebefe3079f509aeb3bcac264 (diff) | |
download | mariadb-git-c9896eb15bfc11414577128d0463ef2fefb66407.tar.gz |
MDEV-4989: Support for GTID in mysqlbinlog
Intermediary commit addressing the following:
1) Repeat --start-position or --stop-position specified
on the command line will override previous
specifications
2) Added gtid strict mode for omitting out-of-order
warnings after processing events and erroring if a
stop position is greater than a start position
3) Updated ID delegation gtid event filter to use MariaDB
HASH type instead of manual hash implementation.
4) Updated mariadb-binlog event processing to activate or
deactivate an event only when a Gtid_log_event is
encountered, rather than keeping track of each event
in the group.
-rw-r--r-- | client/mysqlbinlog.cc | 128 | ||||
-rw-r--r-- | man/mysqlbinlog.1 | 17 | ||||
-rw-r--r-- | mysql-test/suite/binlog/include/mysqlbinlog_gtid_strict_mode.inc | 199 | ||||
-rw-r--r-- | mysql-test/suite/binlog/include/mysqlbinlog_gtid_window_test_cases.inc | 40 | ||||
-rw-r--r-- | mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_strict_mode.result | 293 | ||||
-rw-r--r-- | mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result | 126 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_strict_mode.test | 60 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window-master.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window.test | 158 | ||||
-rw-r--r-- | sql/log_event.h | 2 | ||||
-rw-r--r-- | sql/log_event_client.cc | 26 | ||||
-rw-r--r-- | sql/rpl_gtid.cc | 603 | ||||
-rw-r--r-- | sql/rpl_gtid.h | 218 | ||||
-rw-r--r-- | sql/sql_repl.cc | 3 |
14 files changed, 1249 insertions, 625 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 46de0b9e1eb..d4e10a7141a 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -150,10 +150,8 @@ static ulonglong start_position= BIN_LOG_HEADER_SIZE, #define start_position_mot ((my_off_t)start_position) #define stop_position_mot ((my_off_t)stop_position) +static Gtid_stream_auditor *gtid_stream_auditor= NULL; static Domain_gtid_event_filter *domain_gtid_filter= NULL; -static rpl_gtid *start_gtids, *stop_gtids; -static uint32 n_start_gtid_ranges= 0; -static uint32 n_stop_gtid_ranges= 0; static char *start_datetime_str, *stop_datetime_str; static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX; @@ -1034,9 +1032,11 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, if (ev_type == GTID_LIST_EVENT && is_gtid_filtering_enabled()) { Gtid_list_log_event *glev= (Gtid_list_log_event *)ev; - for (uint i= 0; i < n_start_gtid_ranges; i++) + size_t n_start_gtid_ranges= domain_gtid_filter->get_num_start_gtids(); + rpl_gtid *start_gtids= domain_gtid_filter->get_start_gtids(); + for (size_t i= 0; i < n_start_gtid_ranges; i++) { - for (uint k= 0; k < glev->count; k++) + for (size_t k= 0; k < glev->count; k++) { if (start_gtids[i].domain_id == glev->list[k].domain_id) { @@ -1045,20 +1045,18 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, "past binlog files; some of event groups of the domain %u " "may be missed from the expected output; the domain's gtid " "state of the current binlog file is %u-%u-%llu", - start_gtids[i].domain_id, - start_gtids[i].server_id, - start_gtids[i].seq_no, + PARAM_GTID(start_gtids[i]), glev->list[k].domain_id, - glev->list[k].domain_id, - glev->list[k].server_id, - glev->list[k].seq_no); + PARAM_GTID(glev->list[k])); break; } } } - for (uint i= 0; i < n_stop_gtid_ranges; i++) + size_t n_stop_gtid_ranges= domain_gtid_filter->get_num_stop_gtids(); + rpl_gtid *stop_gtids= domain_gtid_filter->get_stop_gtids(); + for (size_t i= 0; i < n_stop_gtid_ranges; i++) { - for (uint k= 0; k < glev->count; k++) + for (size_t k= 0; k < glev->count; k++) { if (stop_gtids[i].domain_id == glev->list[k].domain_id) { @@ -1067,33 +1065,44 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, "past binlog files so no output may be provided for " "the domain %u; the domain's gtid " "state of the current binlog file is %u-%u-%llu", - stop_gtids[i].domain_id, - stop_gtids[i].server_id, - stop_gtids[i].seq_no, - glev->list[k].domain_id, + PARAM_GTID(stop_gtids[i]), glev->list[k].domain_id, - glev->list[k].server_id, - glev->list[k].seq_no); + PARAM_GTID(glev->list[k])); break; } } } + my_free(start_gtids); + my_free(stop_gtids); } + /* If the binlog output should be filtered using GTIDs, test the new event group to see if its events should be written or ignored. */ - if (ev_type == GTID_EVENT && domain_gtid_filter) + if (ev_type == GTID_EVENT && (domain_gtid_filter || gtid_stream_auditor)) { Gtid_log_event *gle= (Gtid_log_event*) ev; rpl_gtid gtid; - gtid.domain_id= gle->domain_id; - gtid.server_id= gle->server_id; - gtid.seq_no= gle->seq_no; - if (!domain_gtid_filter->exclude(>id)) - ev->activate_current_event_group(); - ev->last_gtid_standalone= - (gle->flags2 & Gtid_log_event::FL_STANDALONE) ? true : false; + set_rpl_gtid(>id, gle->domain_id, gle->server_id, gle->seq_no); + + if (domain_gtid_filter) + { + if (domain_gtid_filter->has_finished()) + { + retval= OK_STOP; + goto end; + } + + if (!domain_gtid_filter->exclude(>id)) + ev->activate_current_event_group(); + else + ev->deactivate_current_event_group(); + } + + /* Out of order check */ + if (gtid_stream_auditor && ev->is_event_group_active()) + gtid_stream_auditor->record(>id); } /* @@ -1531,14 +1540,6 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, } } - /* - If all filters have finished, e.g. all --stop-position GTIDs have been hit, - and the last event group has finished printing, then we are finished - */ - if (domain_gtid_filter && domain_gtid_filter->has_finished() && - !Log_event::is_event_group_active()) - retval= OK_STOP; - goto end; err: @@ -1923,11 +1924,10 @@ static void cleanup() my_free(stop_datetime_str); my_free(start_pos_str); my_free(stop_pos_str); - my_free(start_gtids); - my_free(stop_gtids); free_root(&glob_root, MYF(0)); delete domain_gtid_filter; + delete gtid_stream_auditor; delete binlog_filter; delete glob_description_event; @@ -2180,8 +2180,13 @@ get_one_option(const struct my_option *opt, const char *argument, const char *fi break; case OPT_STOP_POSITION: { - stop_gtids= gtid_parse_string_to_list(stop_pos_str, strlen(stop_pos_str), - &n_stop_gtid_ranges); + /* Stop position was already specified, so reset it and use the new list */ + if (domain_gtid_filter && domain_gtid_filter->get_num_stop_gtids() > 0) + domain_gtid_filter->clear_stop_gtids(); + + uint32 n_stop_gtid_ranges= 0; + rpl_gtid *stop_gtids= gtid_parse_string_to_list( + stop_pos_str, strlen(stop_pos_str), &n_stop_gtid_ranges); if (stop_gtids == NULL) { int err= 0; @@ -2211,8 +2216,12 @@ get_one_option(const struct my_option *opt, const char *argument, const char *fi { rpl_gtid *stop_gtid= &stop_gtids[gtid_idx]; if (domain_gtid_filter->add_stop_gtid(stop_gtid)) + { + my_free(stop_gtids); return 1; + } } + my_free(stop_gtids); } else { @@ -2222,7 +2231,12 @@ get_one_option(const struct my_option *opt, const char *argument, const char *fi } case 'j': { - start_gtids= gtid_parse_string_to_list( + /* Start position was already specified, so reset it and use the new list */ + if (domain_gtid_filter && domain_gtid_filter->get_num_start_gtids() > 0) + domain_gtid_filter->clear_start_gtids(); + + uint32 n_start_gtid_ranges= 0; + rpl_gtid *start_gtids= gtid_parse_string_to_list( start_pos_str, strlen(start_pos_str), &n_start_gtid_ranges); if (start_gtids == NULL) @@ -2254,8 +2268,12 @@ get_one_option(const struct my_option *opt, const char *argument, const char *fi { rpl_gtid *start_gtid= &start_gtids[gtid_idx]; if (domain_gtid_filter->add_start_gtid(start_gtid)) + { + my_free(start_gtids); return 1; + } } + my_free(start_gtids); } else { @@ -2297,9 +2315,22 @@ static int parse_args(int *argc, char*** argv) } if (domain_gtid_filter) - { Log_event::enable_event_group_filtering(); + + if (opt_gtid_strict_mode) + { + if (domain_gtid_filter && domain_gtid_filter->validate_window_filters()) + { + /* + In strict mode, if any --start/stop-position GTID ranges are invalid, + quit in error. Note that any specific error messages will have + already been written. + */ + die(); + } + gtid_stream_auditor= new Gtid_stream_auditor(); } + return 0; } @@ -2481,7 +2512,7 @@ static Exit_status check_master_version() goto err; } - if (n_start_gtid_ranges > 0) + if (domain_gtid_filter && domain_gtid_filter->get_num_start_gtids() > 0) { char str_buf[256]; String query_str(str_buf, sizeof(str_buf), system_charset_info); @@ -2489,7 +2520,10 @@ static Exit_status check_master_version() query_str.append(STRING_WITH_LEN("SET @slave_connect_state='"), system_charset_info); - for (uint32 gtid_idx = 0; gtid_idx < n_start_gtid_ranges; gtid_idx++) + size_t n_start_gtids= domain_gtid_filter->get_num_start_gtids(); + rpl_gtid *start_gtids= domain_gtid_filter->get_start_gtids(); + + for (size_t gtid_idx = 0; gtid_idx < n_start_gtids; gtid_idx++) { char buf[256]; rpl_gtid *start_gtid= &start_gtids[gtid_idx]; @@ -2498,9 +2532,10 @@ static Exit_status check_master_version() start_gtid->domain_id, start_gtid->server_id, start_gtid->seq_no); query_str.append(buf, strlen(buf)); - if (gtid_idx < n_start_gtid_ranges - 1) + if (gtid_idx < n_start_gtids - 1) query_str.append(','); } + my_free(start_gtids); query_str.append(STRING_WITH_LEN("'"), system_charset_info); if (unlikely(mysql_real_query(mysql, query_str.ptr(), query_str.length()))) @@ -3443,13 +3478,12 @@ int main(int argc, char** argv) } } - if (domain_gtid_filter) - domain_gtid_filter->write_warnings(stderr); - if (tmpdir.list) free_tmpdir(&tmpdir); if (result_file && result_file != stdout) my_fclose(result_file, MYF(0)); + if (opt_gtid_strict_mode && gtid_stream_auditor) + gtid_stream_auditor->report(stderr); cleanup(); /* We cannot free DBUG, it is used in global destructors after exit(). */ my_end(my_end_arg | MY_DONT_FREE_DBUG); diff --git a/man/mysqlbinlog.1 b/man/mysqlbinlog.1 index 86b7b33a333..17c81809ce2 100644 --- a/man/mysqlbinlog.1 +++ b/man/mysqlbinlog.1 @@ -1013,6 +1013,23 @@ This option is useful for point\-in\-time recovery\&. .sp -1 .IP \(bu 2.3 .\} +.\" mysqlbinlog: gtid-strict-mode +.\" gtid-strict-mode option: mysqlbinlog +\fB\-\-gtid\-strict\-mode +.sp +Process binlog according to gtid-strict-mode specification\&. The start, stop +positions are verified to satisfy start < stop comparison condition\&. Sequence +numbers of any gtid domain must comprise monotically growing sequence\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} .\" mysqlbinlog: stop-datetime option .\" stop-datetime option: mysqlbinlog \fB\-\-stop\-datetime=\fR\fB\fIdatetime\fR\fR diff --git a/mysql-test/suite/binlog/include/mysqlbinlog_gtid_strict_mode.inc b/mysql-test/suite/binlog/include/mysqlbinlog_gtid_strict_mode.inc new file mode 100644 index 00000000000..292a1d260c4 --- /dev/null +++ b/mysql-test/suite/binlog/include/mysqlbinlog_gtid_strict_mode.inc @@ -0,0 +1,199 @@ +# +# This file runs test cases for using --gtid-strict-mode with mariadb-binlog to +# ensure warnings are properly displayed +# +# param $is_strict_mode boolean (0 for false, 1 for true) to enable or +# disable strict mode for GTID processing +# + +--let MYSQLD_DATADIR=`select @@datadir` +--let OUT_FILE=$MYSQLTEST_VARDIR/tmp/binlog.out + +if ($is_strict_mode == 0) +{ + --let BINLOG_STRICT_MODE_PARAM=--skip-gtid-strict-mode +} +if ($is_strict_mode == 1) +{ + --let BINLOG_STRICT_MODE_PARAM=--gtid-strict-mode +} + +--let $log_error_ = $MYSQLTEST_VARDIR/tmp/out.err +--let SEARCH_FILE=$log_error_ + +--echo # +--echo # Test Case 1: +--echo # No skipped sequence numbers results in no warnings +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +INSERT INTO t1 values (3); +FLUSH LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> log_error_ > OUT_FILE +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> $log_error_ > $OUT_FILE +--let SEARCH_PATTERN=WARNING +--source include/search_pattern_in_file.inc +--remove_file $log_error_ +DROP TABLE t1; +RESET MASTER; + +--echo # +--echo # Test Case 2: +--echo # A skipped sequence number results in a warning +RESET MASTER; +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 5; +INSERT INTO t1 values (3); +FLUSH LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> log_error_ > OUT_FILE +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> $log_error_ > $OUT_FILE +--let SEARCH_PATTERN=WARNING +--source include/search_pattern_in_file.inc +--remove_file $log_error_ +DROP TABLE t1; +RESET MASTER; + +--echo # +--echo # Test Case 3: +--echo # A backwards sequence number results in a warning +CREATE TABLE t1 (a int); +RESET MASTER; +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +SET @@session.gtid_seq_no= 2; +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 1; +INSERT INTO t1 values (1); +FLUSH LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> log_error_ > OUT_FILE +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> $log_error_ > $OUT_FILE +--let SEARCH_PATTERN=WARNING +--source include/search_pattern_in_file.inc +--remove_file $log_error_ +DROP TABLE t1; +RESET MASTER; + +--echo # +--echo # Test Case 4: +--echo # Skipping a GTID and later receiving it results in two warnings +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +SET @@session.gtid_seq_no= 3; +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 2; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (4); +INSERT INTO t1 values (5); +FLUSH LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> log_error_ > OUT_FILE +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> $log_error_ > $OUT_FILE +--let SEARCH_PATTERN=WARNING +--source include/search_pattern_in_file.inc +--remove_file $log_error_ +DROP TABLE t1; +RESET MASTER; + +--echo # +--echo # Test Case 5: +--echo # Warnings from different domains are all displayed +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +SET @@session.gtid_seq_no= 3; +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 2; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (4); +SET @@session.gtid_domain_id= 1; +SET @@session.server_id= 2; +CREATE TABLE t2 (a int); +SET @@session.gtid_seq_no= 3; +INSERT INTO t2 values (2); +SET @@session.gtid_seq_no= 2; +INSERT INTO t2 values (3); +SET @@session.gtid_seq_no= 4; +INSERT INTO t2 values (4); +FLUSH LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> log_error_ > OUT_FILE +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 $BINLOG_STRICT_MODE_PARAM 2> $log_error_ > $OUT_FILE +--let SEARCH_PATTERN=WARNING +--source include/search_pattern_in_file.inc +--remove_file $log_error_ +DROP TABLE t1; +DROP TABLE t2; +RESET MASTER; + +--echo # +--echo # Test Case 6: +--echo # A gap outside of a --start/--stop position window is ignored +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 5; +INSERT INTO t1 values (4); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 6; +INSERT INTO t1 values (5); +FLUSH LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-3 $BINLOG_STRICT_MODE_PARAM > log_error_ > OUT_FILE +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-3 $BINLOG_STRICT_MODE_PARAM 2> $log_error_ > $OUT_FILE +--let SEARCH_PATTERN=WARNING +--source include/search_pattern_in_file.inc +--remove_file $log_error_ +DROP TABLE t1; +RESET MASTER; + +--echo # +--echo # Test Case 7: +--echo # A gap inside of a --start/--stop position window is displayed +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 5; +INSERT INTO t1 values (4); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 6; +INSERT INTO t1 values (5); +FLUSH LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-6 $BINLOG_STRICT_MODE_PARAM > log_error_ > OUT_FILE +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-6 $BINLOG_STRICT_MODE_PARAM 2> $log_error_ > $OUT_FILE +--let SEARCH_PATTERN=WARNING +--source include/search_pattern_in_file.inc +--remove_file $log_error_ +DROP TABLE t1; +RESET MASTER; + +--echo # +--echo # Test Case 8: +--echo # Error if --stop-position is not strictly greater than +--echo # --start-position +FLUSH LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2 --stop-position=0-1-1 $BINLOG_STRICT_MODE_PARAM > OUT_FILE +--error $is_strict_mode +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2 --stop-position=0-1-1 $BINLOG_STRICT_MODE_PARAM > $OUT_FILE + +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 --stop-position=0-1-1 $BINLOG_STRICT_MODE_PARAM > OUT_FILE +--error $is_strict_mode +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 --stop-position=0-1-1 $BINLOG_STRICT_MODE_PARAM > $OUT_FILE + +--echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2,1-2-1 --stop-position=0-1-1,1-2-2 $BINLOG_STRICT_MODE_PARAM > OUT_FILE +--error $is_strict_mode +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2,1-2-1 --stop-position=0-1-1,1-2-2 $BINLOG_STRICT_MODE_PARAM > $OUT_FILE +RESET MASTER; + +--remove_file $OUT_FILE diff --git a/mysql-test/suite/binlog/include/mysqlbinlog_gtid_window_test_cases.inc b/mysql-test/suite/binlog/include/mysqlbinlog_gtid_window_test_cases.inc index 0b2e3180a62..3fce31920cc 100644 --- a/mysql-test/suite/binlog/include/mysqlbinlog_gtid_window_test_cases.inc +++ b/mysql-test/suite/binlog/include/mysqlbinlog_gtid_window_test_cases.inc @@ -7,7 +7,6 @@ # --let MYSQLD_DATADIR=`select @@datadir` ---let OUT_FILE=$MYSQLTEST_VARDIR/tmp/binlog.out --let BINLOG_FILE=master-bin.000001 --let data_inconsistent_err= "table data is inconsistent after replaying binlog using GTID start/stop positions"; @@ -215,11 +214,11 @@ DROP TABLE t2; --echo # Seq_no=0 in --stop-position excludes all events for a domain --echo # MYSQL_BINLOG BINLOG_FILE_PARAM --stop-position=0-1-0,1-2-0 | MYSQL --exec $MYSQL_BINLOG $BINLOG_FILE_PARAM --stop-position=0-1-0,1-2-0 | $MYSQL -if (0 < `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't1'`) +if (`SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't1'`) { die "t1 should not exist as binlog replay should exclude domain 0 from results"; } -if (0 < `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2'`) +if (`SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2'`) { die "t2 should not exist as binlog replay should exclude domain 1 from results"; } @@ -234,7 +233,7 @@ if ($test2_t1_good_checksum != `CHECKSUM TABLE t1`) { die $data_inconsistent_err; } -if (0 < `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2'`) +if (`SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2'`) { die "t2 should not exist as binlog replay should exclude domain 1 from results"; } @@ -276,7 +275,7 @@ if ($test2_t1_good_checksum != `CHECKSUM TABLE t1`) { die $data_inconsistent_err; } -if (0 < `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2'`) +if (`SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2'`) { die "t2 should not exist as binlog replay should exclude domain 1 from results"; } @@ -284,4 +283,33 @@ if (0 < `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'te --let SEARCH_FILE=$log_error_ --let SEARCH_PATTERN=WARNING --source include/search_pattern_in_file.inc -DROP TABLE t1;
\ No newline at end of file +DROP TABLE t1; + +--echo # Test Case 14: +--echo # Start position is specified twice on the command line +CREATE TABLE t1 (a int); +--echo # MYSQL_BINLOG BINLOG_FILE_PARAM --start-position=0-1-0 --start-position=0-1-1 --stop-position=0-1-2 | MYSQL +--exec $MYSQL_BINLOG $BINLOG_FILE_PARAM --start-position=0-1-0 --start-position=0-1-1 --stop-position=0-1-2 | $MYSQL +if ($test2_t1_good_checksum != `CHECKSUM TABLE t1`) +{ + die $data_inconsistent_err; +} +if (`SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2'`) +{ + die "t2 should not exist as binlog replay should exclude domain 1 from results"; +} +DROP TABLE t1; + +--echo # Test Case 15: +--echo # Stop position is specified twice on the command line +--echo # MYSQL_BINLOG BINLOG_FILE_PARAM --start-position=0-1-0 --stop-position=0-1-1 --stop-position=0-1-2 | MYSQL +--exec $MYSQL_BINLOG $BINLOG_FILE_PARAM --start-position=0-1-0 --stop-position=0-1-1 --stop-position=0-1-2 | $MYSQL +if ($test2_t1_good_checksum != `CHECKSUM TABLE t1`) +{ + die $data_inconsistent_err; +} +if (`SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2'`) +{ + die "t2 should not exist as binlog replay should exclude domain 1 from results"; +} +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_strict_mode.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_strict_mode.result new file mode 100644 index 00000000000..549edd41ca7 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_strict_mode.result @@ -0,0 +1,293 @@ +############################### +# Test Setup +############################### +RESET MASTER; +#################################################### +# Test Case Group 1 +# Run test cases with strict-gtid-mode +#################################################### +# +# Test Case 1: +# No skipped sequence numbers results in no warnings +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +INSERT INTO t1 values (3); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --gtid-strict-mode 2> log_error_ > OUT_FILE +NOT FOUND /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 2: +# A skipped sequence number results in a warning +RESET MASTER; +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 5; +INSERT INTO t1 values (3); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --gtid-strict-mode 2> log_error_ > OUT_FILE +FOUND 1 /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 3: +# A backwards sequence number results in a warning +CREATE TABLE t1 (a int); +RESET MASTER; +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +SET @@session.gtid_seq_no= 2; +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 1; +INSERT INTO t1 values (1); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --gtid-strict-mode 2> log_error_ > OUT_FILE +FOUND 1 /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 4: +# Skipping a GTID and later receiving it results in two warnings +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +SET @@session.gtid_seq_no= 3; +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 2; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (4); +INSERT INTO t1 values (5); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --gtid-strict-mode 2> log_error_ > OUT_FILE +FOUND 2 /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 5: +# Warnings from different domains are all displayed +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +SET @@session.gtid_seq_no= 3; +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 2; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (4); +SET @@session.gtid_domain_id= 1; +SET @@session.server_id= 2; +CREATE TABLE t2 (a int); +SET @@session.gtid_seq_no= 3; +INSERT INTO t2 values (2); +SET @@session.gtid_seq_no= 2; +INSERT INTO t2 values (3); +SET @@session.gtid_seq_no= 4; +INSERT INTO t2 values (4); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --gtid-strict-mode 2> log_error_ > OUT_FILE +FOUND 4 /WARNING/ in out.err +DROP TABLE t1; +DROP TABLE t2; +RESET MASTER; +# +# Test Case 6: +# A gap outside of a --start/--stop position window is ignored +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 5; +INSERT INTO t1 values (4); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 6; +INSERT INTO t1 values (5); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-3 --gtid-strict-mode > log_error_ > OUT_FILE +NOT FOUND /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 7: +# A gap inside of a --start/--stop position window is displayed +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 5; +INSERT INTO t1 values (4); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 6; +INSERT INTO t1 values (5); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-6 --gtid-strict-mode > log_error_ > OUT_FILE +FOUND 2 /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 8: +# Error if --stop-position is not strictly greater than +# --start-position +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2 --stop-position=0-1-1 --gtid-strict-mode > OUT_FILE +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 --stop-position=0-1-1 --gtid-strict-mode > OUT_FILE +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2,1-2-1 --stop-position=0-1-1,1-2-2 --gtid-strict-mode > OUT_FILE +RESET MASTER; +#################################################### +# Test Case Group 2 +# Run test cases with --skip-strict-gtid-mode +#################################################### +# +# Test Case 1: +# No skipped sequence numbers results in no warnings +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +INSERT INTO t1 values (3); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --skip-gtid-strict-mode 2> log_error_ > OUT_FILE +NOT FOUND /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 2: +# A skipped sequence number results in a warning +RESET MASTER; +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 5; +INSERT INTO t1 values (3); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --skip-gtid-strict-mode 2> log_error_ > OUT_FILE +NOT FOUND /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 3: +# A backwards sequence number results in a warning +CREATE TABLE t1 (a int); +RESET MASTER; +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +SET @@session.gtid_seq_no= 2; +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 1; +INSERT INTO t1 values (1); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --skip-gtid-strict-mode 2> log_error_ > OUT_FILE +NOT FOUND /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 4: +# Skipping a GTID and later receiving it results in two warnings +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +SET @@session.gtid_seq_no= 3; +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 2; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (4); +INSERT INTO t1 values (5); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --skip-gtid-strict-mode 2> log_error_ > OUT_FILE +NOT FOUND /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 5: +# Warnings from different domains are all displayed +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +SET @@session.gtid_seq_no= 3; +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 2; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (4); +SET @@session.gtid_domain_id= 1; +SET @@session.server_id= 2; +CREATE TABLE t2 (a int); +SET @@session.gtid_seq_no= 3; +INSERT INTO t2 values (2); +SET @@session.gtid_seq_no= 2; +INSERT INTO t2 values (3); +SET @@session.gtid_seq_no= 4; +INSERT INTO t2 values (4); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --skip-gtid-strict-mode 2> log_error_ > OUT_FILE +NOT FOUND /WARNING/ in out.err +DROP TABLE t1; +DROP TABLE t2; +RESET MASTER; +# +# Test Case 6: +# A gap outside of a --start/--stop position window is ignored +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 5; +INSERT INTO t1 values (4); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 6; +INSERT INTO t1 values (5); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-3 --skip-gtid-strict-mode > log_error_ > OUT_FILE +NOT FOUND /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 7: +# A gap inside of a --start/--stop position window is displayed +SET @@session.gtid_domain_id= 0; +SET @@session.server_id= 1; +CREATE TABLE t1 (a int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +SET @@session.gtid_seq_no= 5; +INSERT INTO t1 values (4); +SET @@session.gtid_seq_no= 4; +INSERT INTO t1 values (3); +SET @@session.gtid_seq_no= 6; +INSERT INTO t1 values (5); +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-6 --skip-gtid-strict-mode > log_error_ > OUT_FILE +NOT FOUND /WARNING/ in out.err +DROP TABLE t1; +RESET MASTER; +# +# Test Case 8: +# Error if --stop-position is not strictly greater than +# --start-position +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2 --stop-position=0-1-1 --skip-gtid-strict-mode > OUT_FILE +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 --stop-position=0-1-1 --skip-gtid-strict-mode > OUT_FILE +# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2,1-2-1 --stop-position=0-1-1,1-2-2 --skip-gtid-strict-mode > OUT_FILE +RESET MASTER; +############################## +# Cleanup +############################## +SET @@global.gtid_domain_id= 0; +SET @@global.server_id= 1; diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result index b1bf1e2a8b1..1e47da8c1cd 100644 --- a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result @@ -1,12 +1,6 @@ ############################### # Test Setup ############################### -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 'test.t1' -DROP TABLE IF EXISTS t2; -Warnings: -Note 1051 Unknown table 'test.t2' RESET MASTER; ###################################### # Test Group 1 @@ -120,6 +114,15 @@ CREATE TABLE t1 (a int); # MYSQL_BINLOG BINLOG_FILE_PARAM --start-position=0-1-1 --stop-position=0-1-2 | MYSQL NOT FOUND /WARNING/ in mysqld.1.err DROP TABLE t1; +# Test Case 14: +# Start position is specified twice on the command line +CREATE TABLE t1 (a int); +# MYSQL_BINLOG BINLOG_FILE_PARAM --start-position=0-1-0 --start-position=0-1-1 --stop-position=0-1-2 | MYSQL +DROP TABLE t1; +# Test Case 15: +# Stop position is specified twice on the command line +# MYSQL_BINLOG BINLOG_FILE_PARAM --start-position=0-1-0 --stop-position=0-1-1 --stop-position=0-1-2 | MYSQL +DROP TABLE t1; ###################################### # Test Group 2 # Run test cases on remote host @@ -232,6 +235,15 @@ CREATE TABLE t1 (a int); # MYSQL_BINLOG BINLOG_FILE_PARAM --start-position=0-1-1 --stop-position=0-1-2 | MYSQL NOT FOUND /WARNING/ in mysqld.1.err DROP TABLE t1; +# Test Case 14: +# Start position is specified twice on the command line +CREATE TABLE t1 (a int); +# MYSQL_BINLOG BINLOG_FILE_PARAM --start-position=0-1-0 --start-position=0-1-1 --stop-position=0-1-2 | MYSQL +DROP TABLE t1; +# Test Case 15: +# Stop position is specified twice on the command line +# MYSQL_BINLOG BINLOG_FILE_PARAM --start-position=0-1-0 --stop-position=0-1-1 --stop-position=0-1-2 | MYSQL +DROP TABLE t1; ############################## # Error Cases ############################## @@ -247,108 +259,6 @@ DROP TABLE t1; # Error Case 2: # User provides GTID ranges with repeated domain ids # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1,0-1-8 --stop-position=0-1-4,0-1-12 -# -# Error Case 3: -# --stop-position is not strictly greater than --start-position -# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2 --stop-position=0-1-1 -# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 --stop-position=0-1-1 -# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2,1-2-1 --stop-position=0-1-1,1-2-2 -############################## -# Warning Cases -############################## -# -# Warning Case 1: -# A gap in sequence number at end of window results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -INSERT INTO t1 values (2); -SET @@session.gtid_seq_no= 5; -INSERT INTO t1 values (3); -FLUSH LOGS; -# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-4 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog -FOUND 1 /WARNING/ in out.err -DROP TABLE t1; -# -# Warning Case 2: -# A gap in sequence number at beginning of window results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -SET @@session.gtid_seq_no= 3; -INSERT INTO t1 values (1); -FLUSH LOGS; -# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 > /home/brandon/workspace/server/build/mysql-test/var/tmp/out.err > MYSQLTEST_VARDIR/tmp/out.binlog -FOUND 1 /WARNING/ in out.err -DROP TABLE t1; -# -# Warning Case 3: -# A gap in sequence number within a window results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -SET @@session.gtid_seq_no= 4; -INSERT INTO t1 values (2); -FLUSH LOGS; -# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-4 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog -FOUND 1 /WARNING/ in out.err -DROP TABLE t1; -# -# Warning Case 4: -# When invoked with just --start-position, a gap in sequence number -# after the provided GTID results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -SET @@session.gtid_seq_no= 4; -INSERT INTO t1 values (2); -FLUSH LOGS; -# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog -FOUND 1 /WARNING/ in out.err -DROP TABLE t1; -# -# Warning Case 5: -# When invoked with just --stop-position, a gap in sequence number -# before the provided GTID results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -SET @@session.gtid_seq_no= 4; -INSERT INTO t1 values (2); -FLUSH LOGS; -# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --stop-position=0-1-4 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog -FOUND 1 /WARNING/ in out.err -DROP TABLE t1; -# -# Warning Case 6: -# One domain has a sequence number gap but another does not results in -# a warning -RESET MASTER; -SET @@session.gtid_domain_id= 1; -SET @@session.server_id= 2; -CREATE TABLE t2 (a int); -INSERT INTO t2 values (1); -INSERT INTO t2 values (2); -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -SET @@session.gtid_seq_no= 4; -INSERT INTO t1 values (2); -FLUSH LOGS; -# MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0,1-2-0 --stop-position=0-1-4,1-2-3 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog -FOUND 1 /WARNING/ in out.err -DROP TABLE t1; -DROP TABLE t2; ############################## # Cleanup ############################## diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_strict_mode.test b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_strict_mode.test new file mode 100644 index 00000000000..262143012e6 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_strict_mode.test @@ -0,0 +1,60 @@ +# +# Purpose: +# +# This test ensures that the mariadb-binlog CLI tool properly displays warnings +# when using --gtid-strict-mode +# +# +# Methodology: +# +# We simulate gaps by manually changing gtid_seq_no to differ from its expected +# linear sequence. Specifically, we test the following cases: +# Test Case 1) No skipped sequence numbers results in no warnings +# Test Case 2) A skipped sequence number results in a warning +# Test Case 3) A backwards sequence number results in a warning +# Test Case 4) Skipping a GTID and later receiving it results in two warnings +# Test Case 5) Warnings from different domains are all displayed +# Test Case 6) A gap outside of a --start/--stop position window is ignored +# Test Case 7) A gap inside of a --start/--stop position window is displayed +# Test Case 8: Error if --stop-position is not strictly greater than +# --start-position +# +# Note that test cases are tested with both --strict-gtid-mode and +# --skip-gtid-strict-mode to ensure out of order warnings are hidden when not in +# strict mode. +# +# References: +# MDEV-4989: Support for GTID in mysqlbinlog +# + +--source include/have_log_bin.inc + +--echo ############################### +--echo # Test Setup +--echo ############################### + +## Save old state +# +let orig_gtid_domain_id = `select @@session.gtid_domain_id`; +let orig_server_id = `select @@session.server_id`; +RESET MASTER; + +--echo #################################################### +--echo # Test Case Group 1 +--echo # Run test cases with strict-gtid-mode +--echo #################################################### +--let is_strict_mode= 1 +--source include/mysqlbinlog_gtid_strict_mode.inc + +--echo #################################################### +--echo # Test Case Group 2 +--echo # Run test cases with --skip-strict-gtid-mode +--echo #################################################### +--let is_strict_mode= 0 +--source include/mysqlbinlog_gtid_strict_mode.inc + +--echo ############################## +--echo # Cleanup +--echo ############################## +--eval SET @@global.gtid_domain_id= $orig_gtid_domain_id +--eval SET @@global.server_id= $orig_server_id diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window-master.opt b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window-master.opt deleted file mode 100644 index d17999c07c1..00000000000 --- a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window-master.opt +++ /dev/null @@ -1 +0,0 @@ ---timezone=GMT-8
\ No newline at end of file diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window.test b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window.test index dedcfbf14aa..3c8f2bb9f98 100644 --- a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window.test +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window.test @@ -34,29 +34,22 @@ # the --stop-position values are hit # Test Case 12) Scalar and GTID values can be used together for stop or start # position +# Test Case 13) Start position is delayed within the binlog +# Test Case 14) Start position is specified twice on the command line +# Test Case 15) Stop position is specified twice on the command line # # To validate for data consistency, each test case compares a checksum of # correct data against a variant created after replaying the binlog using # --(start|stop)-position. If the checksums are identical, the test passes. # If the checksums differ, data has been changed and the test fails. # -# Additionally, this test validates the following error and warning scenarios: +# Additionally, this test validates the following error scenarios: # Error Case 1) User provides invalid positions # Error Case 2) User provides GTID ranges with repeated domain ids -# Error Case 3) --stop-position is not strictly greater than --start-position -# -# Warning Case 1) A gap in sequence number at the beginning of a window results -# in a warning -# Warning Case 2) A gap in sequence number at the end of a window results in -# a warning -# Warning Case 3) A gap in sequence number within a window results in a warning -# Warning Case 4) When invoked with just --start-position, a gap in sequence -# number after the provided GTID results in a warning -# Warning Case 5) When invoked with just --stop-position, a gap in sequence -# number before the provided GTID results in a warning -# Warning Case 6) One domain has a sequence number gap but another does not -# results in a warning # +# Note that warning cases are tested with both --strict-gtid-mode and +# --skip-gtid-strict-mode to ensure out of order warnings are hidden when not in +# strict mode. # # References: # MDEV-4989: Support for GTID in mysqlbinlog @@ -72,9 +65,6 @@ # let orig_gtid_domain_id = `select @@session.gtid_domain_id`; let orig_server_id = `select @@session.server_id`; - -DROP TABLE IF EXISTS t1; -DROP TABLE IF EXISTS t2; RESET MASTER; @@ -85,7 +75,6 @@ RESET MASTER; --let is_remote= 0 --source include/mysqlbinlog_gtid_window_test_cases.inc - --echo ###################################### --echo # Test Group 2 --echo # Run test cases on remote host @@ -93,7 +82,6 @@ RESET MASTER; --let is_remote= 1 --source include/mysqlbinlog_gtid_window_test_cases.inc - --echo ############################## --echo # Error Cases --echo ############################## @@ -129,141 +117,9 @@ RESET MASTER; --error 1 --exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1,0-1-8 --stop-position=0-1-4,0-1-12 ---echo # ---echo # Error Case 3: ---echo # --stop-position is not strictly greater than --start-position ---echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2 --stop-position=0-1-1 ---error 1 ---exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2 --stop-position=0-1-1 ---echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 --stop-position=0-1-1 ---error 1 ---exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 --stop-position=0-1-1 ---echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2,1-2-1 --stop-position=0-1-1,1-2-2 ---error 1 ---exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-2,1-2-1 --stop-position=0-1-1,1-2-2 - - ---echo ############################## ---echo # Warning Cases ---echo ############################## ---let $log_error_ = $MYSQLTEST_VARDIR/tmp/out.err ---let SEARCH_FILE=$log_error_ - ---echo # ---echo # Warning Case 1: ---echo # A gap in sequence number at end of window results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -INSERT INTO t1 values (2); -SET @@session.gtid_seq_no= 5; -INSERT INTO t1 values (3); -FLUSH LOGS; ---echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-4 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog ---exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-4 2> $log_error_ > $MYSQLTEST_VARDIR/tmp/out.binlog ---let SEARCH_PATTERN=WARNING ---source include/search_pattern_in_file.inc -DROP TABLE t1; - ---echo # ---echo # Warning Case 2: ---echo # A gap in sequence number at beginning of window results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -SET @@session.gtid_seq_no= 3; -INSERT INTO t1 values (1); -FLUSH LOGS; ---echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 > $log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog ---exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-1 2> $log_error_ > $MYSQLTEST_VARDIR/tmp/out.binlog ---let SEARCH_PATTERN=WARNING ---source include/search_pattern_in_file.inc -DROP TABLE t1; - ---echo # ---echo # Warning Case 3: ---echo # A gap in sequence number within a window results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -SET @@session.gtid_seq_no= 4; -INSERT INTO t1 values (2); -FLUSH LOGS; ---echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-4 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog ---exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 --stop-position=0-1-4 2> $log_error_ > $MYSQLTEST_VARDIR/tmp/out.binlog ---let SEARCH_PATTERN=WARNING ---source include/search_pattern_in_file.inc -DROP TABLE t1; - ---echo # ---echo # Warning Case 4: ---echo # When invoked with just --start-position, a gap in sequence number ---echo # after the provided GTID results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -SET @@session.gtid_seq_no= 4; -INSERT INTO t1 values (2); -FLUSH LOGS; ---echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog ---exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0 2> $log_error_ > $MYSQLTEST_VARDIR/tmp/out.binlog ---let SEARCH_PATTERN=WARNING ---source include/search_pattern_in_file.inc -DROP TABLE t1; - ---echo # ---echo # Warning Case 5: ---echo # When invoked with just --stop-position, a gap in sequence number ---echo # before the provided GTID results in a warning -RESET MASTER; -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -SET @@session.gtid_seq_no= 4; -INSERT INTO t1 values (2); -FLUSH LOGS; ---echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --stop-position=0-1-4 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog ---exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --stop-position=0-1-4 2> $log_error_ > $MYSQLTEST_VARDIR/tmp/out.binlog ---let SEARCH_PATTERN=WARNING ---source include/search_pattern_in_file.inc -DROP TABLE t1; - ---echo # ---echo # Warning Case 6: ---echo # One domain has a sequence number gap but another does not results in ---echo # a warning -RESET MASTER; -SET @@session.gtid_domain_id= 1; -SET @@session.server_id= 2; -CREATE TABLE t2 (a int); -INSERT INTO t2 values (1); -INSERT INTO t2 values (2); -SET @@session.gtid_domain_id= 0; -SET @@session.server_id= 1; -CREATE TABLE t1 (a int); -INSERT INTO t1 values (1); -SET @@session.gtid_seq_no= 4; -INSERT INTO t1 values (2); -FLUSH LOGS; ---echo # MYSQL_BINLOG MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0,1-2-0 --stop-position=0-1-4,1-2-3 2> log_error_ > MYSQLTEST_VARDIR/tmp/out.binlog ---exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 --start-position=0-1-0,1-2-0 --stop-position=0-1-4,1-2-3 2> $log_error_ > $MYSQLTEST_VARDIR/tmp/out.binlog ---let SEARCH_PATTERN=WARNING ---source include/search_pattern_in_file.inc -DROP TABLE t1; -DROP TABLE t2; - --echo ############################## --echo # Cleanup --echo ############################## --eval SET @@global.gtid_domain_id= $orig_gtid_domain_id --eval SET @@global.server_id= $orig_server_id - diff --git a/sql/log_event.h b/sql/log_event.h index abd9ddc89e7..520209d8fde 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1311,8 +1311,6 @@ public: */ static my_bool m_is_event_group_filtering_enabled; - static my_bool last_gtid_standalone; // gtid type of last seen gtid - /* Notify that all events part of the current group should be printed */ diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc index ba51631c447..1917a90a1e2 100644 --- a/sql/log_event_client.cc +++ b/sql/log_event_client.cc @@ -326,7 +326,6 @@ static inline bool is_enum_or_set_type(uint type) { my_bool Log_event::m_is_event_group_active= FALSE; my_bool Log_event::m_is_event_group_filtering_enabled= FALSE; -my_bool Log_event::last_gtid_standalone= FALSE; /* Log_event::print_header() @@ -2013,15 +2012,6 @@ bool Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) { Write_on_release_cache cache(&print_event_info->head_cache, file, 0, this); -#ifndef MYSQL_SERVER - /* - This marks the end of an event group. All events prior to this have been - printed, need to reset the tracking for future event groups - */ - if (is_commit() || is_rollback() || last_gtid_standalone) - deactivate_current_event_group(); -#endif - /** reduce the size of io cache so that the write function is called for every call to my_b_write(). @@ -2396,14 +2386,6 @@ bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) Write_on_release_cache cache(&print_event_info->head_cache, file, Write_on_release_cache::FLUSH_F, this); -#ifndef MYSQL_SERVER - /* - This marks the end of an event group. All events prior to this have been - printed, need to reset the tracking for future event groups - */ - deactivate_current_event_group(); -#endif - if (!print_event_info->short_form) { char buf[64]; @@ -3941,14 +3923,6 @@ bool XA_prepare_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) Write_on_release_cache::FLUSH_F, this); m_xid.serialize(); -#ifndef MYSQL_SERVER - /* - All events prior to this have been printed, need to reset the tracking for - future event groups - */ - deactivate_current_event_group(); -#endif - if (!print_event_info->short_form) { print_header(&cache, print_event_info, FALSE); diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index 56e6cacbc2a..a7f8298506f 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -25,7 +25,6 @@ #include "sql_base.h" #include "sql_parse.h" #include "key.h" -#include "rpl_gtid.h" #include "rpl_rli.h" #include "slave.h" #include "log_event.h" @@ -1276,7 +1275,15 @@ rpl_slave_state::domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid) #endif -/* +void set_rpl_gtid(rpl_gtid *out, uint32 domain_id_arg, + uint32 server_id_arg, uint64 seq_no_arg) +{ + out->domain_id= domain_id_arg; + out->server_id= server_id_arg; + out->seq_no= seq_no_arg; +} + + /* Parse a GTID at the start of a string, and update the pointer to point at the first character after the parsed GTID. @@ -1305,9 +1312,7 @@ gtid_parser_helper(const char **ptr, const char *end, rpl_gtid *out_gtid) if (err != 0) return 1; - out_gtid->domain_id= (uint32) v1; - out_gtid->server_id= (uint32) v2; - out_gtid->seq_no= v3; + set_rpl_gtid(out_gtid, (uint32) v1, (uint32) v2, v3); *ptr= q; return 0; } @@ -3016,80 +3021,180 @@ gtid_waiting::remove_from_wait_queue(gtid_waiting::hash_element *he, #endif -Window_gtid_event_filter::Window_gtid_event_filter() : - m_has_start(FALSE), - m_has_stop(FALSE), - m_is_active(FALSE), - m_has_passed(FALSE), - m_warning_flags(0) - { - // m_start and m_stop do not need initial values if unused - } +void free_domain_lookup_element(void *p) +{ + struct Gtid_stream_auditor::out_of_order_elem *ooo_elem= + (struct Gtid_stream_auditor::out_of_order_elem *) p; + delete_dynamic(&ooo_elem->gtids_last); + delete_dynamic(&ooo_elem->gtids_real); + my_free(ooo_elem); +} -int Window_gtid_event_filter::set_start_gtid(rpl_gtid *start) +Gtid_stream_auditor::Gtid_stream_auditor() { - int err= 0; - if (m_has_start) + my_hash_init(PSI_INSTRUMENT_ME, &m_last_gtid_by_domain_hash, &my_charset_bin, 32, + offsetof(rpl_gtid, domain_id), sizeof(rpl_gtid::domain_id), + NULL, my_free, HASH_UNIQUE); + my_hash_init(PSI_INSTRUMENT_ME, &m_out_of_order_domain_lookup, &my_charset_bin, 32, + offsetof(struct out_of_order_elem, domain_id), sizeof(uint32), + NULL, free_domain_lookup_element, HASH_UNIQUE); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &m_out_of_order_domains, + sizeof(rpl_gtid::domain_id), 8, 8, MYF(0)); +} + +Gtid_stream_auditor::~Gtid_stream_auditor() +{ + my_hash_free(&m_last_gtid_by_domain_hash); + my_hash_free(&m_out_of_order_domain_lookup); + delete_dynamic(&m_out_of_order_domains); +} + +void Gtid_stream_auditor::record(rpl_gtid *gtid) +{ + rpl_gtid *last_gtid= (rpl_gtid *) my_hash_search( + &m_last_gtid_by_domain_hash, (const uchar *) &(gtid->domain_id), 0); + + if (!last_gtid) { - err= 1; - goto err; + /* + We haven't seen any GTIDs in this domian yet. Perform initial set up for + this domain so we can monitor following GTIDs here. + */ + rpl_gtid *new_gtid= (rpl_gtid *) my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(rpl_gtid), MYF(MY_WME)); + if (!new_gtid) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return; + } + set_rpl_gtid(new_gtid, PARAM_GTID((*gtid))); + if (my_hash_insert(&m_last_gtid_by_domain_hash, (const uchar *) new_gtid)) + { + my_free(new_gtid); + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return; + } + return; } - if (m_has_stop) + /* Out of order check */ + if (gtid->seq_no != (last_gtid->seq_no+1)) { - DBUG_ASSERT(m_stop.domain_id == start->domain_id); - if (start->seq_no >= m_stop.seq_no) + struct out_of_order_elem *ooo_elem= + (struct out_of_order_elem *) my_hash_search( + &m_out_of_order_domain_lookup, (const uchar *) &(gtid->domain_id), + 0); + + if (!ooo_elem) { - sql_print_error("stop position %d-%d-%llu is not strictly greater than " - "its counterpart start position %d-%d-%llu", - m_stop.domain_id, m_stop.server_id, m_stop.seq_no, - start->domain_id, start->server_id, start->seq_no); - err= 1; - goto err; + /* + First out of order sequence number on this domain, put it in the lookup + hash and initialize a new list to hold its specific out-of-order + sequence numbers + */ + + ooo_elem= (struct out_of_order_elem *) my_malloc( + PSI_NOT_INSTRUMENTED, sizeof(struct out_of_order_elem), MYF(MY_WME)); + if (!ooo_elem) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return; + } + ooo_elem->domain_id= gtid->domain_id; + my_init_dynamic_array(PSI_INSTRUMENT_ME, &ooo_elem->gtids_real, + sizeof(rpl_gtid), 8, 8, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &ooo_elem->gtids_last, + sizeof(rpl_gtid), 8, 8, MYF(0)); + + if(my_hash_insert(&m_out_of_order_domain_lookup, + (uchar*) ooo_elem)) + { + my_free(ooo_elem); + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return; + } + insert_dynamic(&m_out_of_order_domains, + (const void *) &last_gtid->domain_id); } - } - // Copy values - m_has_start= TRUE; - m_start.domain_id= start->domain_id; - m_start.server_id= start->server_id; - m_start.seq_no= start->seq_no; + insert_dynamic(&ooo_elem->gtids_real, (const void *) gtid); + insert_dynamic(&ooo_elem->gtids_last, (const void *) last_gtid); + } -err: - return err; + if (gtid->seq_no > last_gtid->seq_no) + set_rpl_gtid(last_gtid, PARAM_GTID((*gtid))); } -int Window_gtid_event_filter::set_stop_gtid(rpl_gtid *stop) +void Gtid_stream_auditor::report(FILE *out) { - int err= 0; - if (m_has_stop) - { - err= 1; - goto err; - } + size_t i, j; - if (m_has_start) + for(i = 0; i < m_out_of_order_domains.elements; i++) { - DBUG_ASSERT(m_start.domain_id == stop->domain_id); - if (m_start.seq_no >= stop->seq_no) + uint32 *domain_id_ptr= + (uint32 *) dynamic_array_ptr(&m_out_of_order_domains, i); + DBUG_ASSERT(domain_id_ptr); + struct out_of_order_elem *ooo_elem= + (struct out_of_order_elem *) my_hash_search( + &m_out_of_order_domain_lookup, (const uchar *) domain_id_ptr, 0); + + if (ooo_elem) { - sql_print_error("stop position %d-%d-%llu is not strictly greater than " - "its counterpart start position %d-%d-%llu", - stop->domain_id, stop->server_id, stop->seq_no, - m_start.domain_id, m_start.server_id, m_start.seq_no); - err= 1; - goto err; + for(j = 0; j < ooo_elem->gtids_last.elements; j++) + { + rpl_gtid *real_gtid= + (rpl_gtid *) dynamic_array_ptr(&(ooo_elem->gtids_real), j); + rpl_gtid *last_gtid= + (rpl_gtid *) dynamic_array_ptr(&(ooo_elem->gtids_last), j); + DBUG_ASSERT(real_gtid && last_gtid); + fprintf( + out, + "WARNING: Out of order GTID while in strict mode. Got %u-%u-%llu " + "after %u-%u-%llu\n", + PARAM_GTID((*real_gtid)), PARAM_GTID((*last_gtid))); + } } } +} + +Window_gtid_event_filter::Window_gtid_event_filter() + : m_has_start(FALSE), m_has_stop(FALSE), m_is_active(FALSE), + m_has_passed(FALSE) +{ + // m_start and m_stop do not need initial values if unused +} + +int Window_gtid_event_filter::set_start_gtid(rpl_gtid *start) +{ + if (m_has_start) + return 1; + + m_has_start= TRUE; + set_rpl_gtid(&m_start, PARAM_GTID((*start))); + return 0; +} + +int Window_gtid_event_filter::set_stop_gtid(rpl_gtid *stop) +{ + if (m_has_stop) + return 1; - // Copy values m_has_stop= TRUE; - m_stop.domain_id= stop->domain_id; - m_stop.server_id= stop->server_id; - m_stop.seq_no= stop->seq_no; + set_rpl_gtid(&m_stop, PARAM_GTID((*stop))); + return 0; +} -err: - return err; +my_bool Window_gtid_event_filter::is_range_invalid() +{ + if (m_has_start && m_has_stop && m_start.seq_no >= m_stop.seq_no) + { + sql_print_error( + "Queried GTID range is invalid in strict mode. Stop position " + "%u-%u-%llu is not strictly greater than start %u-%u-%llu.", + PARAM_GTID(m_stop), PARAM_GTID(m_start)); + return TRUE; + } + return FALSE; } static inline my_bool is_gtid_at_or_after(rpl_gtid *boundary, @@ -3106,16 +3211,6 @@ static inline my_bool is_gtid_at_or_before(rpl_gtid *boundary, test_gtid->seq_no <= boundary->seq_no; } -void Window_gtid_event_filter::verify_gtid_is_expected(rpl_gtid *gtid) -{ - if (gtid->seq_no != last_gtid_seen.seq_no + 1) - { - m_warning_flags |= WARN_GTID_SEQUENCE_NUMBER_OUT_OF_ORDER; - } - - last_gtid_seen.seq_no++; -} - my_bool Window_gtid_event_filter::exclude(rpl_gtid *gtid) { /* Assume result should be excluded to start */ @@ -3140,22 +3235,15 @@ my_bool Window_gtid_event_filter::exclude(rpl_gtid *gtid) */ m_is_active= TRUE; should_exclude= FALSE; - last_gtid_seen= *gtid; } - else if (is_gtid_at_or_after(&m_start, gtid) && + else if ((m_has_start && is_gtid_at_or_after(&m_start, gtid)) && (!m_has_stop || is_gtid_at_or_before(&m_stop, gtid))) { m_is_active= TRUE; - /* - Once the window has started, we expect GTIDs to be sequential from here on out - */ - last_gtid_seen= *gtid; - DBUG_PRINT("gtid-event-filter", - ("Window: Begin (%d-%d-%llu, %d-%d-%llu]", m_start.domain_id, - m_start.server_id, m_start.seq_no, m_stop.domain_id, - m_stop.server_id, m_stop.seq_no)); + ("Window: Begin (%d-%d-%llu, %d-%d-%llu]", + PARAM_GTID(m_start), PARAM_GTID(m_stop))); /* As the start of the range is exclusive, if this gtid is the start of @@ -3165,6 +3253,14 @@ my_bool Window_gtid_event_filter::exclude(rpl_gtid *gtid) should_exclude= TRUE; else should_exclude= FALSE; + + if (m_has_stop && gtid->seq_no == m_stop.seq_no) + { + m_has_passed= TRUE; + DBUG_PRINT("gtid-event-filter", + ("Window: End (%d-%d-%llu, %d-%d-%llu]", + PARAM_GTID(m_start), PARAM_GTID(m_stop))); + } } } /* if (!m_is_active && !m_has_passed) */ else if (m_is_active && !m_has_passed) @@ -3174,15 +3270,13 @@ my_bool Window_gtid_event_filter::exclude(rpl_gtid *gtid) in the results. Additionally check if we are at the end of the window. If no end of the window is provided, go indefinitely */ - verify_gtid_is_expected(gtid); should_exclude= FALSE; if (m_has_stop && is_gtid_at_or_after(&m_stop, gtid)) { DBUG_PRINT("gtid-event-filter", - ("Window: End (%d-%d-%llu, %d-%d-%llu]", m_start.domain_id, - m_start.server_id, m_start.seq_no, m_stop.domain_id, - m_stop.server_id, m_stop.seq_no)); + ("Window: End (%d-%d-%llu, %d-%d-%llu]", + PARAM_GTID(m_start), PARAM_GTID(m_stop))); m_is_active= FALSE; m_has_passed= TRUE; @@ -3202,71 +3296,36 @@ my_bool Window_gtid_event_filter::exclude(rpl_gtid *gtid) my_bool Window_gtid_event_filter::has_finished() { - if (!m_has_stop) - return FALSE; - - return last_gtid_seen.seq_no == m_stop.seq_no; + return m_has_stop ? m_has_passed : FALSE; } -void Window_gtid_event_filter::write_warnings(FILE *out) +void free_gtid_filter_element(void *p) { - if (m_warning_flags & WARN_GTID_SEQUENCE_NUMBER_OUT_OF_ORDER) - { - fprintf(out, "WARNING: " - "Found out of order GTID sequence number during event processing\n"); - } + gtid_filter_element *gfe = (gtid_filter_element *) p; + if (gfe->filter) + delete gfe->filter; + my_free(gfe); } Id_delegating_gtid_event_filter::Id_delegating_gtid_event_filter() : m_num_explicit_filters(0), m_num_completed_filters(0) { - uint32 i; - - m_filter_id_mask= 0xf; - - m_filters_by_id= (gtid_filter_element **) my_malloc( - PSI_NOT_INSTRUMENTED, - (m_filter_id_mask + 1) * sizeof(gtid_filter_element *), - MYF(MY_WME) - ); - - if (m_filters_by_id == NULL) - my_error(ER_OUT_OF_RESOURCES, MYF(0)); - - for (i = 0; i <= m_filter_id_mask; i++) - { - m_filters_by_id[i]= NULL; - } + my_hash_init(PSI_INSTRUMENT_ME, &m_filters_by_id_hash, &my_charset_bin, 32, + offsetof(gtid_filter_element, identifier), + sizeof(gtid_filter_identifier), NULL, free_gtid_filter_element, + HASH_UNIQUE); m_default_filter= new Accept_all_gtid_filter(); } -/* - Deconstructor deletes: - 1) All Identifiable_gtid_event_filters added - 2) All gtid_filter_element allocations -*/ Id_delegating_gtid_event_filter::~Id_delegating_gtid_event_filter() { - uint32 i; - for (i = 0; i <= m_filter_id_mask; i++) - { - gtid_filter_element *filter_element= m_filters_by_id[i], - *filter_element_to_del= NULL; - while(filter_element) - { - filter_element_to_del= filter_element; - filter_element= filter_element->next; - delete filter_element_to_del->filter; - my_free(filter_element_to_del); - } - } - my_free(m_filters_by_id); - + my_hash_free(&m_filters_by_id_hash); delete m_default_filter; } -void Id_delegating_gtid_event_filter::set_default_filter(Gtid_event_filter *filter) +void Id_delegating_gtid_event_filter::set_default_filter( + Gtid_event_filter *filter) { if (m_default_filter) delete m_default_filter; @@ -3275,103 +3334,61 @@ void Id_delegating_gtid_event_filter::set_default_filter(Gtid_event_filter *filt } gtid_filter_element * -Id_delegating_gtid_event_filter::try_find_filter_element_for_id( - gtid_filter_identifier filter_id) -{ - // Add this into the domain id list - uint32 map_idx= filter_id & m_filter_id_mask; - gtid_filter_element *filter_idx= m_filters_by_id[map_idx]; - - /* Find list index to add this filter */ - while (filter_idx) - { - if (filter_idx->filter->get_filter_identifier() == filter_id) - break; - filter_idx= filter_idx->next; - } - - return filter_idx; -} - -gtid_filter_element * Id_delegating_gtid_event_filter::find_or_create_filter_element_for_id( gtid_filter_identifier filter_id) { - // Add this into the domain id list - uint32 map_idx= filter_id & m_filter_id_mask; - gtid_filter_element *filter_idx= m_filters_by_id[map_idx], - *prev_idx= NULL; + gtid_filter_element *fe= (gtid_filter_element *) my_hash_search( + &m_filters_by_id_hash, (const uchar *) &filter_id, 0); - /* Find list index to add this filter */ - while (filter_idx) + if (!fe) { - prev_idx= filter_idx; - if (filter_idx->filter->get_filter_identifier() == filter_id) - { - break; - } - prev_idx= filter_idx; - filter_idx= filter_idx->next; - } - - if (filter_idx == NULL) - { - // No other domain ids have filters that index here, create this one - filter_idx= (gtid_filter_element *) my_malloc( + gtid_filter_element *new_fe= (gtid_filter_element *) my_malloc( PSI_NOT_INSTRUMENTED, sizeof(gtid_filter_element), MYF(MY_WME)); - filter_idx->filter= NULL; - filter_idx->next= NULL; - - if (prev_idx == NULL) + new_fe->filter= NULL; + new_fe->next= NULL; + new_fe->identifier= filter_id; + if (my_hash_insert(&m_filters_by_id_hash, (uchar*) new_fe)) { - // This is the first filter in the bucket - m_filters_by_id[map_idx]= filter_idx; - } - else - { - // End of list, append filter list to tail - prev_idx->next= filter_idx; + my_free(new_fe); + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return NULL; } + fe= new_fe; } - return filter_idx; + return fe; } my_bool Id_delegating_gtid_event_filter::has_finished() { + /* + If all user-defined filters have deactivated, we are effectively + deactivated + */ return m_num_completed_filters == m_num_explicit_filters; } -void Id_delegating_gtid_event_filter::write_warnings(FILE *out) -{ - uint32 i; - for (i = 0; i <= m_filter_id_mask; i++) - { - gtid_filter_element *filter_element= m_filters_by_id[i]; - while(filter_element && filter_element->filter) - { - filter_element->filter->write_warnings(out); - filter_element= filter_element->next; - } - } -} - my_bool Id_delegating_gtid_event_filter::exclude(rpl_gtid *gtid) { gtid_filter_identifier filter_id= get_id_from_gtid(gtid); - gtid_filter_element *filter_element= try_find_filter_element_for_id(filter_id); + gtid_filter_element *filter_element= (gtid_filter_element *) my_hash_search( + &m_filters_by_id_hash, (const uchar *) &filter_id, 0); Gtid_event_filter *filter= (filter_element ? filter_element->filter : m_default_filter); - my_bool ret= filter->exclude(gtid); + my_bool ret= TRUE; - /* - If this is an explicitly defined filter, e.g. Window-based filter, check - if it has completed, and update the counter accordingly if so. - */ - if (filter_element && filter->has_finished()) + if(!filter_element || !filter->has_finished()) { - m_num_completed_filters++; + ret= filter->exclude(gtid); + + /* + If this is an explicitly defined filter, e.g. Window-based filter, check + if it has completed, and update the counter accordingly if so. + */ + if (filter_element && filter->has_finished()) + m_num_completed_filters++; } + return ret; } @@ -3385,23 +3402,22 @@ Domain_gtid_event_filter::find_or_create_window_filter_for_id( if (filter_element->filter == NULL) { - // New filter + /* New filter */ wgef= new Window_gtid_event_filter(); - filter_element->filter= new Identifiable_gtid_event_filter(domain_id, wgef); + filter_element->filter= wgef; m_num_explicit_filters++; } else if (filter_element->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE) { - // We have an existing window filter here - wgef= (Window_gtid_event_filter *) - filter_element->filter->get_identified_filter(); + /* We have an existing window filter here */ + wgef= (Window_gtid_event_filter *) filter_element->filter; } else { - /* - We have an existing filter but it is not of window type so propogate NULL - filter - */ + /* + We have an existing filter but it is not of window type so propogate NULL + filter + */ sql_print_error("cannot subset domain id %d by position, another rule " "exists on that domain", domain_id); @@ -3410,6 +3426,33 @@ Domain_gtid_event_filter::find_or_create_window_filter_for_id( return wgef; } +static my_bool check_filter_entry_validity(void *entry, void *are_filters_invalid_arg) +{ + gtid_filter_element *fe= (gtid_filter_element*) entry; + + if (fe) + { + Gtid_event_filter *gef= fe->filter; + if (gef->get_filter_type() == Gtid_event_filter::WINDOW_GTID_FILTER_TYPE) + { + Window_gtid_event_filter *wgef= (Window_gtid_event_filter *) gef; + if (wgef->is_range_invalid()) + { + *((int *) are_filters_invalid_arg)= 1; + return TRUE; + } + } + } + return FALSE; +} + +int Domain_gtid_event_filter::validate_window_filters() +{ + int are_filters_invalid= 0; + my_hash_iterate(&m_filters_by_id_hash, check_filter_entry_validity, &are_filters_invalid); + return are_filters_invalid; +} + int Domain_gtid_event_filter::add_start_gtid(rpl_gtid *gtid) { int err= 0; @@ -3417,9 +3460,15 @@ int Domain_gtid_event_filter::add_start_gtid(rpl_gtid *gtid) find_or_create_window_filter_for_id(gtid->domain_id); if (filter_to_update == NULL) + { err= 1; - else - err= filter_to_update->set_start_gtid(gtid); + } + else if (!(err= filter_to_update->set_start_gtid(gtid))) + { + gtid_filter_element *fe= (gtid_filter_element *) my_hash_search( + &m_filters_by_id_hash, (const uchar *) &(gtid->domain_id), 0); + insert_dynamic(&m_start_filters, (const void *) &fe); + } return err; } @@ -3431,9 +3480,131 @@ int Domain_gtid_event_filter::add_stop_gtid(rpl_gtid *gtid) find_or_create_window_filter_for_id(gtid->domain_id); if (filter_to_update == NULL) + { err= 1; - else - err= filter_to_update->set_stop_gtid(gtid); + } + else if (!(err= filter_to_update->set_stop_gtid(gtid))) + { + gtid_filter_element *fe= (gtid_filter_element *) my_hash_search( + &m_filters_by_id_hash, (const uchar *) &(gtid->domain_id), 0); + insert_dynamic(&m_stop_filters, (const void *) &fe); + } return err; -}
\ No newline at end of file +} + +rpl_gtid *Domain_gtid_event_filter::get_start_gtids() +{ + rpl_gtid *gtid_list; + uint32 i; + size_t n_start_gtids= get_num_start_gtids(); + + gtid_list= (rpl_gtid *) my_malloc( + PSI_INSTRUMENT_ME, n_start_gtids * sizeof(rpl_gtid), MYF(MY_WME)); + + for (i = 0; i < n_start_gtids; i++) + { + gtid_filter_element *fe= + *(gtid_filter_element **) dynamic_array_ptr(&m_start_filters, i); + DBUG_ASSERT(fe->filter && + fe->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE); + Window_gtid_event_filter *wgef= + (Window_gtid_event_filter *) fe->filter; + + rpl_gtid win_start_gtid= wgef->get_start_gtid(); + set_rpl_gtid(>id_list[i], PARAM_GTID(win_start_gtid)); + } + + return gtid_list; +} + +rpl_gtid *Domain_gtid_event_filter::get_stop_gtids() +{ + rpl_gtid *gtid_list; + uint32 i; + size_t n_stop_gtids= get_num_stop_gtids(); + + gtid_list= (rpl_gtid *) my_malloc( + PSI_INSTRUMENT_ME, n_stop_gtids * sizeof(rpl_gtid), MYF(MY_WME)); + + for (i = 0; i < n_stop_gtids; i++) + { + gtid_filter_element *fe= + *(gtid_filter_element **) dynamic_array_ptr(&m_stop_filters, i); + DBUG_ASSERT(fe->filter && + fe->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE); + Window_gtid_event_filter *wgef= + (Window_gtid_event_filter *) fe->filter; + + rpl_gtid win_stop_gtid= wgef->get_stop_gtid(); + set_rpl_gtid(>id_list[i], PARAM_GTID(win_stop_gtid)); + } + + return gtid_list; +} + +void Domain_gtid_event_filter::clear_start_gtids() +{ + uint32 i; + for (i = 0; i < get_num_start_gtids(); i++) + { + gtid_filter_element *fe= + *(gtid_filter_element **) dynamic_array_ptr(&m_start_filters, i); + DBUG_ASSERT(fe->filter && + fe->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE); + Window_gtid_event_filter *wgef= + (Window_gtid_event_filter *) fe->filter; + + if (wgef->has_stop()) + { + /* + Don't delete the whole filter if it already has a stop position attached + */ + wgef->clear_start_pos(); + } + else + { + /* + This domain only has a stop, so delete the whole filter + */ + my_hash_delete(&m_filters_by_id_hash, (uchar *) fe); + m_num_explicit_filters--; + } + } + + reset_dynamic(&m_start_filters); +} + +void Domain_gtid_event_filter::clear_stop_gtids() +{ + uint32 i; + + for (i = 0; i < get_num_stop_gtids(); i++) + { + gtid_filter_element *fe= + *(gtid_filter_element **) dynamic_array_ptr(&m_stop_filters, i); + DBUG_ASSERT(fe->filter && + fe->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE); + Window_gtid_event_filter *wgef= + (Window_gtid_event_filter *) fe->filter; + + if (wgef->has_start()) + { + /* + Don't delete the whole filter if it already has a start position + attached + */ + wgef->clear_stop_pos(); + } + else + { + /* + This domain only has a start, so delete the whole filter + */ + my_hash_delete(&m_filters_by_id_hash, (uchar *) fe); + m_num_explicit_filters--; + } + } + + reset_dynamic(&m_stop_filters); +} diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h index 3e39e5f7823..927937d5162 100644 --- a/sql/rpl_gtid.h +++ b/sql/rpl_gtid.h @@ -28,6 +28,7 @@ extern const LEX_CSTRING rpl_gtid_slave_state_table_name; class String; #define GTID_MAX_STR_LENGTH (10+1+10+1+20) +#define PARAM_GTID(G) G.domain_id, G.server_id, G.seq_no struct rpl_gtid { @@ -382,6 +383,67 @@ extern rpl_gtid *gtid_parse_string_to_list(const char *p, size_t len, uint32 *out_len); extern rpl_gtid *gtid_unpack_string_to_list(const char *p, size_t len, uint32 *out_len); +extern void set_rpl_gtid(rpl_gtid *out, uint32 domain_id, uint32 server_id, + uint64 seq_no); + + + +/* + Class which audits a stream of GTIDs (from arbitrary domains) to see if the + sequence numbers are out of order in any domains. This class silently + collects problem GTIDs and writes them as warnings in `report()`. +*/ +class Gtid_stream_auditor +{ +public: + + struct out_of_order_elem + { + uint32 domain_id; + + /* + List of the problematic GTIDs received which were out of order + */ + DYNAMIC_ARRAY gtids_real; + + /* + For each problematic GTID in gtids_real, this list contains the last + GTID of the domain at the time of receiving the out of order GTID. + */ + DYNAMIC_ARRAY gtids_last; + }; + + Gtid_stream_auditor(); + ~Gtid_stream_auditor(); + + /* + Take note of a new GTID being processed + */ + void record(rpl_gtid *gtid); + + /* + Writes warnings found (if any) during GTID processing + */ + void report(FILE *out); + +private: + + /* + Holds the largest GTID received, and is indexed by domain_id + */ + HASH m_last_gtid_by_domain_hash; + + /* + Holds all out-of-order GTIDs for each domain id. Elements are of type + `struct out_of_order_elem` and indexed by domian_id. + */ + HASH m_out_of_order_domain_lookup; + + /* + A set (unique) of all domain_ids which contain out of order GTIDs. + */ + DYNAMIC_ARRAY m_out_of_order_domains; +}; /* Interface to support different methods of filtering log events by GTID @@ -422,12 +484,6 @@ public: Returns TRUE when completed, and FALSE when the filter has not finished. */ virtual my_bool has_finished() = 0; - - /* - If any non-fatal issues occurred during filtering, to not pollute the - output with warnings, we wait until after processing to write them. - */ - virtual void write_warnings(FILE *out) = 0; }; /* @@ -445,40 +501,6 @@ public: my_bool exclude(rpl_gtid *gtid) { return FALSE; } uint32 get_filter_type() { return ACCEPT_ALL_GTID_FILTER_TYPE; } my_bool has_finished() { return FALSE; } - void write_warnings(FILE *out) {} -}; - -/* - A sub-class of Gtid_event_filter which allows for quick identification - of potentially applicable filters for arbitrary GTIDs. -*/ -typedef uint32 gtid_filter_identifier; -class Identifiable_gtid_event_filter : public Gtid_event_filter -{ - -public: - Identifiable_gtid_event_filter(gtid_filter_identifier filter_id, - Gtid_event_filter *filter) - : m_filter_id(filter_id), m_filter(filter){}; - - ~Identifiable_gtid_event_filter() { - delete m_filter; - }; - - Gtid_event_filter *get_identified_filter() { return m_filter; } - gtid_filter_identifier get_filter_identifier() { return m_filter_id; } - - /* - Inherited functionality uses composition to call the pass-through filter - */ - my_bool exclude(rpl_gtid *gtid) { return m_filter->exclude(gtid); } - uint32 get_filter_type() { return m_filter->get_filter_type(); } - my_bool has_finished() { return m_filter->has_finished(); } - void write_warnings(FILE *out) { return m_filter->write_warnings(out); } - -protected: - gtid_filter_identifier m_filter_id; - Gtid_event_filter *m_filter; }; /* @@ -505,7 +527,6 @@ public: my_bool exclude(rpl_gtid*); my_bool has_finished(); - void write_warnings(FILE *out); /* Set the GTID that begins this window (exclusive) @@ -523,6 +544,34 @@ public: uint32 get_filter_type() { return WINDOW_GTID_FILTER_TYPE; } + /* + Validates the underlying range is correct, and writes an error if not, i.e. + m_start >= m_stop. + + Returns FALSE on ok, TRUE if range is invalid + */ + my_bool is_range_invalid(); + + /* + Getter/setter methods + */ + my_bool has_start() { return m_has_start; } + my_bool has_stop() { return m_has_stop; } + rpl_gtid get_start_gtid() { return m_start; } + rpl_gtid get_stop_gtid() { return m_stop; } + + void clear_start_pos() + { + m_has_start= FALSE; + set_rpl_gtid(&m_start, 0, 0, 0); + } + + void clear_stop_pos() + { + m_has_stop= FALSE; + set_rpl_gtid(&m_stop, 0, 0, 0); + } + protected: /* @@ -570,15 +619,6 @@ private: /* m_stop : marks the GTID that ends the range (inclusive). */ rpl_gtid m_stop; - - /* last_gtid_seen: saves the last */ - rpl_gtid last_gtid_seen; - - /* - warning_flags: holds flags for any non-fatal issues encountered during - filtering - */ - uint32 m_warning_flags; }; /* @@ -586,9 +626,11 @@ private: if two filters have identifiers that lead to the same hash, they will be put into a linked list. */ +typedef uint32 gtid_filter_identifier; typedef struct _gtid_filter_element { - Identifiable_gtid_event_filter *filter; + Gtid_event_filter *filter; + gtid_filter_identifier identifier; /* Used for HASH lookup */ struct _gtid_filter_element *next; } gtid_filter_element; @@ -610,31 +652,20 @@ public: my_bool exclude(rpl_gtid *gtid); my_bool has_finished(); - void write_warnings(FILE *out); void set_default_filter(Gtid_event_filter *default_filter); uint32 get_filter_type() { return DELEGATING_GTID_FILTER_TYPE; } virtual gtid_filter_identifier get_id_from_gtid(rpl_gtid *) = 0; - protected: uint32 m_num_explicit_filters; uint32 m_num_completed_filters; - uint32 m_filter_id_mask; Gtid_event_filter *m_default_filter; - /* - To reduce time to find a gtid window, they are indexed by domain_id. More - specifically, domain_ids are arranged into m_filter_id_mask+1 buckets, and - each bucket is a linked list of gtid_filter_elements that share the same - index. The index itself is found by a bitwise and, i.e. - some_rpl_gtid.domain_id & m_filter_id_mask - */ - gtid_filter_element **m_filters_by_id; + HASH m_filters_by_id_hash; - gtid_filter_element *try_find_filter_element_for_id(gtid_filter_identifier); gtid_filter_element *find_or_create_filter_element_for_id(gtid_filter_identifier); }; @@ -643,14 +674,32 @@ protected: domain id of a GTID. Additional helper functions include: - add_start_gtid(GTID) : adds a start GTID position to this filter, to be - identified by its domain id - add_stop_gtid(GTID) : adds a stop GTID position to this filter, to be - identified by its domain id + add_start_gtid(GTID) : adds a start GTID position to this filter, to be + identified by its domain id + add_stop_gtid(GTID) : adds a stop GTID position to this filter, to be + identified by its domain id + clear_start_gtids() : removes existing GTID start positions + clear_stop_gtids() : removes existing GTID stop positions + get_start_gtids() : gets all added GTID start positions + get_stop_gtids() : gets all added GTID stop positions + get_num_start_gtids() : gets the count of added GTID start positions + get_num_stop_gtids() : gets the count of added GTID stop positions */ class Domain_gtid_event_filter : public Id_delegating_gtid_event_filter { public: + Domain_gtid_event_filter() + { + my_init_dynamic_array(PSI_INSTRUMENT_ME, &m_start_filters, + sizeof(gtid_filter_element), 8, 8, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &m_stop_filters, + sizeof(gtid_filter_element), 8, 8, MYF(0)); + } + ~Domain_gtid_event_filter() + { + delete_dynamic(&m_start_filters); + delete_dynamic(&m_stop_filters); + } /* Returns the domain id of from the input GTID @@ -661,6 +710,14 @@ public: } /* + Validates that window filters with both a start and stop GTID satisfy + stop_gtid > start_gtid + + Returns 0 on ok, non-zero if any windows are invalid. + */ + int validate_window_filters(); + + /* Helper function to start a GTID window filter at the given GTID Returns 0 on ok, non-zero on error @@ -674,7 +731,34 @@ public: */ int add_stop_gtid(rpl_gtid *gtid); + /* + If start or stop position is respecified, we remove all existing values + and start over with the new specification. + */ + void clear_start_gtids(); + void clear_stop_gtids(); + + /* + Return list of all GTIDs used as start position. + + Note that this list is allocated and it is up to the user to free it + */ + rpl_gtid *get_start_gtids(); + + /* + Return list of all GTIDs used as stop position. + + Note that this list is allocated and it is up to the user to free it + */ + rpl_gtid *get_stop_gtids(); + + size_t get_num_start_gtids() { return m_start_filters.elements; } + size_t get_num_stop_gtids() { return m_stop_filters.elements; } + private: + DYNAMIC_ARRAY m_start_filters; + DYNAMIC_ARRAY m_stop_filters; + Window_gtid_event_filter *find_or_create_window_filter_for_id(gtid_filter_identifier); }; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index d884dad876c..90fdce1b56f 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2839,7 +2839,8 @@ static int send_one_binlog_file(binlog_send_info *info, return 1; } -void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags) +void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, + ushort flags) { LOG_INFO linfo; |