summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Nesterenko <brandon.nesterenko@mariadb.com>2021-09-14 12:58:04 -0600
committerBrandon Nesterenko <brandon.nesterenko@mariadb.com>2021-11-10 15:27:25 -0700
commitc9896eb15bfc11414577128d0463ef2fefb66407 (patch)
tree71751d54a10c7cf78b5896fcda3a93258bdd2faa
parent303ed1a153630138ebefe3079f509aeb3bcac264 (diff)
downloadmariadb-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.cc128
-rw-r--r--man/mysqlbinlog.117
-rw-r--r--mysql-test/suite/binlog/include/mysqlbinlog_gtid_strict_mode.inc199
-rw-r--r--mysql-test/suite/binlog/include/mysqlbinlog_gtid_window_test_cases.inc40
-rw-r--r--mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_strict_mode.result293
-rw-r--r--mysql-test/suite/binlog/r/binlog_mysqlbinlog_gtid_window.result126
-rw-r--r--mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_strict_mode.test60
-rw-r--r--mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window-master.opt1
-rw-r--r--mysql-test/suite/binlog/t/binlog_mysqlbinlog_gtid_window.test158
-rw-r--r--sql/log_event.h2
-rw-r--r--sql/log_event_client.cc26
-rw-r--r--sql/rpl_gtid.cc603
-rw-r--r--sql/rpl_gtid.h218
-rw-r--r--sql/sql_repl.cc3
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(&gtid))
- ev->activate_current_event_group();
- ev->last_gtid_standalone=
- (gle->flags2 & Gtid_log_event::FL_STANDALONE) ? true : false;
+ set_rpl_gtid(&gtid, 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(&gtid))
+ 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(&gtid);
}
/*
@@ -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(&gtid_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(&gtid_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;