Commit c132bce1 authored by Brandon Nesterenko's avatar Brandon Nesterenko

MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and...

MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog

New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.

Example usage:
  mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
  master-bin.000001

Functional Notes:
 1. --do-domain-ids cannot be combined with --ignore-domain-ids
 2. --do-server-ids cannot be combined with --ignore-server-ids
 3. A domain id filter can be combined with a server id filter
 4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
 5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.

Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
parent f326b43c
......@@ -106,6 +106,10 @@ enum options_client
OPT_COPY_S3_TABLES,
OPT_PRINT_TABLE_METADATA,
OPT_ASOF_TIMESTAMP,
OPT_IGNORE_DOMAIN_IDS,
OPT_DO_DOMAIN_IDS,
OPT_IGNORE_SERVER_IDS,
OPT_DO_SERVER_IDS,
OPT_MAX_CLIENT_OPTION /* should be always the last */
};
......
This diff is collapsed.
......@@ -882,11 +882,78 @@ quote the value (e.g. \fB--rewrite-db="oldname->newname"\fR\&.
.sp -1
.IP \(bu 2.3
.\}
.\" mysqlbinlog: ignore-domain-ids option
.\" ignore-domain-ids option: mysqlbinlog
\fB\-\-ignore\-domain\-ids=\fR\fB\fIIDs\fR\fR
.sp
Hide events which are a part of any stream identified by the domain ID
list \fIIDs\fR\&. Cannot be used with \-\-do\-domain\-ids\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
.\" mysqlbinlog: do-domain-ids option
.\" do-domain-ids option: mysqlbinlog
\fB\-\-do\-domain\-ids=\fR\fB\fIIDs\fR\fR
.sp
Display only the events which exist in a stream identified by \fIIDs\fR\&.
Cannot be used with \-\-ignore\-domain\-ids\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
.\" mysqlbinlog: ignore-server-ids option
.\" ignore-server-ids option: mysqlbinlog
\fB\-\-ignore\-server\-ids=\fR\fB\fIIDs\fR\fR
.sp
Hide events which originated from any server whose ID is specified in
\fIIDs\fR\&. Cannot be used with \-\-do\-server\-ids\ or \-\-server\-id\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
.\" mysqlbinlog: do-server-ids option
.\" do-server-ids option: mysqlbinlog
\fB\-\-do\-server\-ids=\fR\fB\fIIDs\fR\fR
.sp
Display only the events that originated from a server identified in
\fIIDs\fR\&. Cannot be used with \-\-ignore\-server\-ids, and
is an alias for \-\-server\-id\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
.\" mysqlbinlog: server-id option
.\" server-id option: mysqlbinlog
\fB\-\-server\-id=\fR\fB\fIid\fR\fR
.sp
Display only those events created by the server having the given server ID\&.
Cannot be used with \-\-ignore\-server\-ids, and is an alias for
\-\-do\-server\-ids\&.
.RE
.sp
.RS 4
......
###############################
# Test Setup
###############################
set @a=UNIX_TIMESTAMP("1970-01-21 15:32:22");
SET timestamp=@a;
RESET MASTER;
SET @@session.gtid_domain_id= 0;
SET @@session.server_id= 1;
CREATE TABLE t1 (a int);
SET @@session.server_id= 2;
CREATE TABLE t2 (a int);
INSERT INTO t2 values (3);
SET @@session.gtid_domain_id= 1;
SET @@session.server_id= 1;
CREATE TABLE t3 (a int);
INSERT INTO t3 values (4);
SET @@session.server_id= 3;
SET timestamp=@a+1;
CREATE TABLE t4 (a int);
SET timestamp=@a+2;
INSERT INTO t4 values (5);
SET @@session.gtid_domain_id= 0;
SET @@session.server_id= 1;
INSERT INTO t1 values (1);
SET @@session.gtid_domain_id= 2;
SET @@session.server_id= 1;
CREATE TABLE t5 (a int);
INSERT INTO t5 values (6);
SET @@session.gtid_domain_id= 0;
SET @@session.server_id= 1;
INSERT INTO t1 values (2);
FLUSH LOGS;
SET @@session.gtid_domain_id= 0;
SET @@session.server_id= 2;
CREATE TABLE t6 (a int);
INSERT INTO t6 values (1);
FLUSH LOGS;
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
DROP TABLE t4;
DROP TABLE t5;
DROP TABLE t6;
RESET MASTER;
###############################
# Test Cases
###############################
#
# Test Case 1) --do-server-ids with a single server id limits output
# to that single server
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=2 | MYSQL
DROP TABLE t2;
#
# Test Case 2) --do-server-ids with multiple server ids limits output
# to the provided servers
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=2,3 | MYSQL
DROP TABLE t2;
DROP TABLE t4;
#
# Test Case 3) --do-server-ids when combined with --do-domain-ids should
# intersect the results
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=1 --do-domain-ids=0 | MYSQL
DROP TABLE t1;
#
# Test Case 4) --do-server-ids when combined with --ignore-domain-ids should
# intersect the results
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=1 --ignore-domain-ids=0 | MYSQL
DROP TABLE t3;
DROP TABLE t5;
#
# Test Case 5) --do-server-ids when combined with a GTID range should
# intersect the results
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=1 --stop-position=0-1-4 | MYSQL
DROP TABLE t1;
#
# Test Case 6) --do-server-ids when combined with both --ignore-domain-ids
# and a GTID range should intersect all results
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=1 --ignore-domain-ids=0 --start-position=1-1-0 | MYSQL
DROP TABLE t3;
DROP TABLE t5;
#
# Test Case 7) --do-server-ids when combined with both --do-domain-ids and
# a GTID range should intersect all results
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=2 --do-domain-ids=0 --start-position=0-1-0 | MYSQL
DROP TABLE t2;
#
# Test Case 8) --do-server-ids and --offset=<n> skips n events after the
# first GTID is found
CREATE TABLE t4 (a int);
# MYSQL_BINLOG BINLOG_FILE_PARAM --offset=5 --do-server-ids=3 --do-domain-ids=1 | MYSQL
DROP TABLE t4;
#
# Test Case 9) --do-server-ids with --start-datetime=<T> where T occurs
# after the first GTID is found results in no events before T
CREATE TABLE t4 (a int);
# MYSQL_BINLOG BINLOG_FILE_PARAM --start-datetime="1970-01-21 15:32:24" --do-server-ids=3 --do-domain-ids=1 | MYSQL
DROP TABLE t4;
#
# Test Case 10) --do-server-ids works with --read-from-remote-server
# Setup test specific data
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.server_id= 2;
CREATE TABLE t2 (a int);
INSERT INTO t2 VALUES (1);
SET @@session.server_id= 1;
DROP TABLE t1;
DROP TABLE t2;
# MYSQL_BINLOG BINLOG_FILENAME --read-from-remote-server --do-server-ids=2 | MYSQL
DROP TABLE t2;
#
# Test Case 11) --do-server-ids works over multiple binary log input
# files
# MYSQL_BINLOG BINLOG_FILE_PARAM BINLOG_FILE_PARAM2 --do-server-ids=2 | MYSQL
DROP TABLE t2;
DROP TABLE t6;
#
# Test Case 12) --do-server-ids re-specifications should override
# previous ones
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=1 --do-server-ids=2 | MYSQL
DROP TABLE t2;
#
# Test Case 13) --do-server-ids and --server-id should be aliases and
# a re-specification of one should override the former
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=1 --server-id=2 | MYSQL
DROP TABLE t2;
#
# Test Case 14) --ignore-server-ids re-specifications should override
# previous ones
# MYSQL_BINLOG BINLOG_FILE_PARAM --ignore-server-ids=2 --ignore-server-ids=1,3 | MYSQL
DROP TABLE t2;
#
# Test Case 15) --do-domain-ids re-specifications should override
# previous ones
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-domain-ids=1 --do-domain-ids=0 | MYSQL
DROP TABLE t1,t2;
#
# Test Case 16) --ignore-domain-ids re-specifications should override
# previous ones
# MYSQL_BINLOG BINLOG_FILE_PARAM --ignore-domain-ids=0 --ignore-domain-ids=1,2 | MYSQL
DROP TABLE t1,t2;
##############################
# Error Cases
##############################
#
# Error Case 1:
# --ignore-server-ids and --do-server-ids both specified
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=1 --ignore-server-ids=2
#
# Error Case 2:
# Invalid server ID number provided
# MYSQL_BINLOG BINLOG_FILE_PARAM --do-server-ids=-1
##############################
# Cleanup
##############################
SET @@global.gtid_domain_id= 0;
SET @@global.server_id= 1;
# End of tests
# This file provides the structure to run a single test that ensures the
# mariadb-binlog command line tool is consistent with replicas for event
# filtering. The test is configured using the following input parameters, where
# each is nullable (i.e. it will not be used to configure mariadb-binlog or
# the replica).
#
# param $do_domain_ids : A list of domain ids to include in replication
# param $ignore_domain_ids : A list of domain ids to exclude from replication
# param $ignore_server_ids : A list of server ids to exclude from replication
# param $start_position : The GTID positions to begin replication from in
# the specified domains
# param $stop_position : The GTID positions that mark the end of an event
# stream in a particular domain
#
# param $con1 : The connection name of the primary server
# param $con2 : The connection name of the replica server
# param $strict_mode : Uses input and checks for out of order GTIDs
# param $strict_mode_err : A boolean that provides expectations for strict
# mode to error
# param $slave_sql_errno : Expected error number of the slave SQL thread
--let $include_filename= mysqlbinlog_slave_consistency.inc
--source include/begin_include_file.inc
--enable_query_log
if (!$con1)
{
--let $con1=master
}
if (!$con2)
{
--let $con2=slave
}
if (!$strict_mode)
{
--connection $con2
set @@global.gtid_strict_mode=0;
--let $sql_input_file=include/sql_multisource.inc
}
if ($strict_mode)
{
--connection $con2
set @@global.gtid_strict_mode=1;
--let $sql_input_file=include/sql_out_of_order_gtid.inc
}
--connection $con2
--source include/stop_slave.inc
--connection $con1
--echo # Populating $con1 data
--source $sql_input_file
--let $MYSQLD_DATADIR=`select @@datadir`
--let $MYSQLBINLOG_STDERR=$MYSQLD_DATADIR/mysqlbinlog_stderr.out
--let BINLOG_FILENAME= query_get_value(SHOW BINARY LOGS, Log_name, 1)
--let BINLOG_FILE_PARAM= $MYSQLD_DATADIR/$BINLOG_FILENAME.orig
--copy_file $MYSQLD_DATADIR/$BINLOG_FILENAME $BINLOG_FILE_PARAM
--connection $con2
--let $msbl_args=
if (`SELECT strcmp("$start_position","") != 0`)
{
eval set global gtid_slave_pos="$start_position";
--let $msbl_args= $msbl_args --start-position=$start_position
}
--let $cm_args= MASTER_USE_GTID=slave_pos
if (`SELECT strcmp("$do_domain_ids","") != 0`)
{
--let $cm_args= $cm_args, DO_DOMAIN_IDS=($do_domain_ids)
--let $msbl_args= $msbl_args --do-domain-ids=$do_domain_ids
}
if (`SELECT strcmp("$ignore_domain_ids","") != 0`)
{
--let $cm_args= $cm_args, IGNORE_DOMAIN_IDS=($ignore_domain_ids)
--let $msbl_args= $msbl_args --ignore-domain-ids=$ignore_domain_ids
}
if (`SELECT strcmp("$ignore_server_ids","") != 0`)
{
--let $cm_args= $cm_args, IGNORE_SERVER_IDS=($ignore_server_ids)
--let $msbl_args= $msbl_args --ignore-server-ids=$ignore_server_ids
}
if ($strict_mode)
{
--let $msbl_args= $msbl_args --gtid-strict-mode
}
eval CHANGE MASTER TO $cm_args;
--let $start_slave_args=
if (`SELECT strcmp("$stop_position","") != 0`)
{
--let $start_slave_args= UNTIL master_gtid_pos="$stop_position"
--let $msbl_args= $msbl_args --stop-position=$stop_position
}
eval START SLAVE $start_slave_args;
if ($slave_sql_errno)
{
--echo # $con2 SQL Thread error expected - waiting for errno $slave_sql_errno
--source include/wait_for_slave_sql_error.inc
}
# If we are not expecting an error, wait for con2 to catch up
if (!$slave_sql_errno)
{
--echo # No $con2 error expecting - waiting for $con2 to catch up to $con1
# Stop position was not specified
if (`SELECT strcmp("$stop_position","") = 0`)
{
--source include/wait_for_slave_to_start.inc
--echo # Wait for $con2 IO thread to catch up
--let $wait_condition= SELECT STATE="Waiting for master to send event" from information_schema.PROCESSLIST where COMMAND="Slave_IO"
--source include/wait_condition.inc
--echo # Wait for $con2 SQL thread to catch up
--let $wait_condition= SELECT STATE="Slave has read all relay log; waiting for more updates" from information_schema.PROCESSLIST where COMMAND="Slave_SQL"
--source include/wait_condition.inc
}
# Stop position was specified
if (`SELECT strcmp("$stop_position","") != 0`)
{
--echo # Because there is a stop position we wait for all events to process
--echo # and $con2 to automatically stop
--source include/wait_for_slave_to_stop.inc
}
}
--echo # Stop $con2 so it stops receiving $con1 events.
--source include/stop_slave.inc
--connection $con1
DROP TABLE IF EXISTS t1, t2, t3, t4, t5;
RESET MASTER;
--echo # MYSQL_BINLOG BINLOG_FILE_PARAM $msbl_args 2> MYSQLBINLOG_STDERR | MYSQL
--exec $MYSQL_BINLOG $BINLOG_FILE_PARAM $msbl_args 2> $MYSQLBINLOG_STDERR | $MYSQL
--source include/rpl_check_table_consistency.inc
if ($strict_mode)
{
--echo # Strict mode enabled - checking mysqlbinlog error output for out
--echo # of order GTIDs
--let SEARCH_FILE=$MYSQLBINLOG_STDERR
--let SEARCH_PATTERN=Found out of order GTID
if ($strict_mode_err)
{
--echo # Expecting to find out of order GTID error..
}
if (!$strict_mode_err)
{
--echo # Not expecting to find out of order GTID error..
}
--source include/search_pattern_in_file.inc
}
--echo # Test finished - resetting $con1 and $con2..
--connection $con2
RESET SLAVE;
RESET MASTER;
set global gtid_slave_pos="";
CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(), IGNORE_SERVER_IDS=();
--connection $con1
RESET MASTER;
DROP TABLE IF EXISTS t1, t2, t3, t4, t5;
--source include/save_master_gtid.inc
--connection $con2
--source include/start_slave.inc
--source include/wait_for_slave_to_start.inc
--source include/sync_with_master_gtid.inc
--source include/stop_slave.inc
RESET SLAVE;
set global gtid_slave_pos="";
RESET MASTER;
--connection $con1
RESET MASTER;
--connection $con2
if ($strict_mode)
{
set @@global.gtid_strict_mode=0;
}
--source include/start_slave.inc
--connection $con1
--remove_file $BINLOG_FILE_PARAM
--remove_file $MYSQLBINLOG_STDERR
--let $include_filename= mysqlbinlog_slave_consistency.inc
--source include/end_include_file.inc
# This file provides logic to ensure that all tables in a database are the
# same between two connections.
#
# param $check_db : The name of the database to validate all tables are the
# same within (test by default)
# param $con1 : The connection name of the primary server, defaults to
# master
# param $con2 : The connection name of the replica server, defaults to
# slave
--let $include_filename= rpl_check_table_consistency.inc
--source include/begin_include_file.inc
if (!$con1)
{
--let $con1= master
}
if (!$con2)
{
--let $con2= slave
}
if (!$check_db)
{
--let $check_db= test
}
--connection $con2
--let $n_tables= `select count(*) from information_schema.tables WHERE table_schema = '$check_db'`
--echo # Checking consistency of '$check_db' database tables between $con1 and $con2
--connection $con1
--let $c1_n_tables= `select count(*) from information_schema.tables WHERE table_schema = '$check_db'`
if (`SELECT $c1_n_tables != $n_tables`)
{
die "$con1 had $c1_n_tables tables but $con2 had $n_tables after binlog replay";
}
--echo # Both servers have $n_tables tables
--let $ctr= 1
--echo # Verifying integrity of tables..
while($ctr <= $n_tables)
{
--let $cksum_tbl= query_get_value(SELECT table_name FROM information_schema.tables WHERE table_schema = 'test' ORDER BY table_name ASC, table_name, $ctr)
--connection $con1
--let $c1_cksum= `CHECKSUM TABLE $cksum_tbl`
--connection $con2
--let $c2_cksum= `CHECKSUM TABLE $cksum_tbl`
if ($c1_cksum != $c2_cksum)
{
die "Table $cksum_tbl differs between connections $con1 and $con2";
}
if ($c1_cksum == $c2_cksum)
{
--echo # $cksum_tbl is equivalent on $con1 and $con2
}
--let $ctr= `SELECT $ctr+1`
}
--echo # All tables are consistent
--let $include_filename= rpl_check_table_consistency.inc
--source include/end_include_file.inc
# Populate the active connection server with events that come from varying
# domain and server ids
--disable_query_log
# Save old state
let $ORIG_GTID_DOMAIN_ID = `select @@session.gtid_domain_id`;
let $ORIG_SERVER_ID = `select @@session.server_id`;
SET @@session.gtid_domain_id= 0;
SET @@session.server_id= 1;
CREATE TABLE t1 (a int);
SET @@session.server_id= 3;
CREATE TABLE t2 (a int);
INSERT INTO t2 values (3);
SET @@session.gtid_domain_id= 1;
SET @@session.server_id= 1;
CREATE TABLE t3 (a int);
INSERT INTO t3 values (4);
SET @@session.server_id= 4;
CREATE TABLE t4 (a int);
INSERT INTO t4 values (5);
SET @@session.gtid_domain_id= 0;
SET @@session.server_id= 1;
INSERT INTO t1 values (1);
SET @@session.gtid_domain_id= 2;
SET @@session.server_id= 1;
CREATE TABLE t5 (a int);
INSERT INTO t5 values (6);
SET @@session.gtid_domain_id= 0;
SET @@session.server_id= 1;
INSERT INTO t1 values (2);
FLUSH LOGS;
--eval SET @@session.gtid_domain_id= $ORIG_GTID_DOMAIN_ID
--eval SET @@session.server_id= $ORIG_SERVER_ID
--enable_query_log
# SQL file with out of order GTIDs coming from various domains and servers
--disable_query_log
# Save old state
let $ORIG_GTID_DOMAIN_ID = `select @@session.gtid_domain_id`;
let $ORIG_SERVER_ID = `select @@session.server_id`;
SET @@session.gtid_domain_id= 0;
SET @@session.server_id= 1;
CREATE TABLE t1 (a int);
INSERT INTO t1 values (1);
SET @@session.server_id= 3;
CREATE TABLE t2 (a int);
SET @@session.gtid_seq_no= 6;
INSERT INTO t2 values (2);
SET @@session.gtid_seq_no= 5;
INSERT INTO t2 values (1);
SET @@session.gtid_seq_no= 7;
INSERT INTO t2 values (3);
SET @@session.gtid_domain_id= 1;
SET @@session.server_id= 1;
CREATE TABLE t3 (a int);
INSERT INTO t3 values (1);
SET @@session.gtid_seq_no= 4;
INSERT INTO t3 values (3);
SET @@session.gtid_seq_no= 3;
INSERT INTO t3 values (2);
SET @@session.gtid_seq_no= 5;
INSERT INTO t3 values (4);
SET @@session.gtid_domain_id= 0;
SET @@session.server_id= 1;
INSERT INTO t1 values (2);
FLUSH LOGS;
--eval SET @@session.gtid_domain_id= $ORIG_GTID_DOMAIN_ID
--eval SET @@session.server_id= $ORIG_SERVER_ID
--enable_query_log
This diff is collapsed.
This diff is collapsed.
......@@ -37,9 +37,6 @@ struct rpl_gtid
uint64 seq_no;
};
/* Data structure to help with quick lookup for filters. */
typedef decltype(rpl_gtid::domain_id) gtid_filter_identifier;
inline bool operator==(const rpl_gtid& lhs, const rpl_gtid& rhs)
{
return
......@@ -464,7 +461,8 @@ class Binlog_gtid_state_validator
Ensures that the expected stop GTID positions exist within the specified
binary logs.
*/
my_bool verify_stop_state(FILE *out, rpl_gtid *stop_gtids, size_t n_stop_gtids);
my_bool verify_stop_state(FILE *out, rpl_gtid *stop_gtids,
size_t n_stop_gtids);
/*
Ensure a GTID state (e.g., from a Gtid_list_log_event) is consistent with
......@@ -513,8 +511,8 @@ class Binlog_gtid_state_validator
private:
/*
Holds the records for each domain id we are monitoring. Elements are of type
`struct audit_elem` and indexed by domian_id.
Holds the records for each domain id we are monitoring. Elements are of
type `struct audit_elem` and indexed by domian_id.
*/
HASH m_audit_elem_domain_lookup;
};
......@@ -533,7 +531,15 @@ class Gtid_event_filter
DELEGATING_GTID_FILTER_TYPE = 1,
WINDOW_GTID_FILTER_TYPE = 2,
ACCEPT_ALL_GTID_FILTER_TYPE = 3,
REJECT_ALL_GTID_FILTER_TYPE = 4
REJECT_ALL_GTID_FILTER_TYPE = 4,
INTERSECTING_GTID_FILTER_TYPE = 5
};
enum class id_restriction_mode
{
MODE_NOT_SET,
WHITELIST_MODE,
BLACKLIST_MODE,
};
/*
......@@ -596,8 +602,9 @@ class Reject_all_gtid_filter : public Gtid_event_filter
positions, m_start (exclusive) and m_stop (inclusive), within a domain.
This filter is stateful, such that it expects GTIDs to be an increasing
stream, and internally, the window will activate and deactivate when the start
and stop positions of the event stream have passed through, respectively.
stream, and internally, the window will activate and deactivate when the
start and stop positions of the event stream have passed through,
respectively.
*/
class Window_gtid_event_filter : public Gtid_event_filter
{
......@@ -701,11 +708,11 @@ class Window_gtid_event_filter : public Gtid_event_filter
rpl_gtid m_stop;
};
typedef struct _gtid_filter_element
template <typename T> struct gtid_filter_element
{
Gtid_event_filter *filter;
gtid_filter_identifier identifier; /* Used for HASH lookup */
} gtid_filter_element;
T identifier; /* Used for HASH lookup */
};
/*
Gtid_event_filter subclass which has no specific implementation, but rather
......@@ -715,8 +722,10 @@ typedef struct _gtid_filter_element
filter can be identified.
This class should be subclassed, where the get_id_from_gtid function
specifies how to extract the filter identifier from a GTID.
specifies how to extract the filter identifier from a GTID. The type of the
filter identifier is a template for the class.
*/
template <typename T>
class Id_delegating_gtid_event_filter : public Gtid_event_filter
{
public:
......@@ -729,7 +738,21 @@ class Id_delegating_gtid_event_filter : public Gtid_event_filter
uint32 get_filter_type() { return DELEGATING_GTID_FILTER_TYPE; }
virtual gtid_filter_identifier get_id_from_gtid(rpl_gtid *) = 0;
virtual T get_id_from_gtid(rpl_gtid *) = 0;
virtual const char* get_id_type_name() = 0;
/*
Sets restrictions on entire ids using the corresponding mode (i.e. either
whitelist or blacklist, refer to Gtid_event_filter::id_restriction_mode)
A blacklist will allow all ids except for the ones provided in the input
list.
A whitelist will only allow ids provided in the input list.
Returns 0 on ok, non-zero on error.
*/
int set_id_restrictions(T *id_list, size_t n_ids,
Gtid_event_filter::id_restriction_mode mode);
protected:
......@@ -739,12 +762,14 @@ class Id_delegating_gtid_event_filter : public Gtid_event_filter
HASH m_filters_by_id_hash;
gtid_filter_element *find_or_create_filter_element_for_id(gtid_filter_identifier);
Gtid_event_filter::id_restriction_mode m_id_restriction_mode;
gtid_filter_element<T> *find_or_create_filter_element_for_id(T);
};
/*
A subclass of Id_delegating_gtid_event_filter which identifies filters using the
domain id of a GTID.
A subclass of Id_delegating_gtid_event_filter which identifies filters using
the domain id of a GTID.
Additional helper functions include:
add_start_gtid(GTID) : adds a start GTID position to this filter, to be
......@@ -758,15 +783,18 @@ class Id_delegating_gtid_event_filter : public Gtid_event_filter
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
class Domain_gtid_event_filter
: public Id_delegating_gtid_event_filter<decltype(rpl_gtid::domain_id)>
{
public:
Domain_gtid_event_filter()
{
my_init_dynamic_array(PSI_INSTRUMENT_ME, &m_start_filters,
sizeof(gtid_filter_element*), 8, 8, MYF(0));
sizeof(decltype(rpl_gtid::domain_id) *), 8, 8,
MYF(0));
my_init_dynamic_array(PSI_INSTRUMENT_ME, &m_stop_filters,
sizeof(gtid_filter_element*), 8, 8, MYF(0));
sizeof(decltype(rpl_gtid::domain_id) *), 8, 8,
MYF(0));
}
~Domain_gtid_event_filter()
{
......@@ -777,11 +805,13 @@ class Domain_gtid_event_filter : public Id_delegating_gtid_event_filter
/*
Returns the domain id of from the input GTID
*/
gtid_filter_identifier get_id_from_gtid(rpl_gtid *gtid)
decltype(rpl_gtid::domain_id) get_id_from_gtid(rpl_gtid *gtid)
{
return gtid->domain_id;
}
const char* get_id_type_name() { return "domain"; }
/*
Override Id_delegating_gtid_event_filter to extend with domain specific
filtering logic
......@@ -838,7 +868,65 @@ class Domain_gtid_event_filter : public Id_delegating_gtid_event_filter
DYNAMIC_ARRAY m_start_filters;
DYNAMIC_ARRAY m_stop_filters;
Window_gtid_event_filter *find_or_create_window_filter_for_id(gtid_filter_identifier);
Window_gtid_event_filter *
find_or_create_window_filter_for_id(decltype(rpl_gtid::domain_id));
};
/*
A subclass of Id_delegating_gtid_event_filter which identifies filters using
the server id of a GTID.
*/
class Server_gtid_event_filter
: public Id_delegating_gtid_event_filter<decltype(rpl_gtid::server_id)>
{
public:
/*
Returns the server id of from the input GTID
*/
decltype(rpl_gtid::server_id) get_id_from_gtid(rpl_gtid *gtid)
{
return gtid->server_id;
}
const char* get_id_type_name() { return "server"; }
};
/*
A Gtid_event_filter implementation that delegates the filtering to other
filters, where the result is the intersection between them all.
*/
class Intersecting_gtid_event_filter : public Gtid_event_filter
{
public:
Intersecting_gtid_event_filter(Gtid_event_filter *filter1,
Gtid_event_filter *filter2);
~Intersecting_gtid_event_filter();
/*
Returns TRUE if any filers exclude the gtid, returns FALSE otherwise, i.e.
all filters must allow the GTID.
*/
my_bool exclude(rpl_gtid *gtid);
/*
Returns true if any filters have finished. To elaborate, as this filter
performs an intersection, if any filter has finished, the result would
be excluded regardless.
*/
my_bool has_finished();
uint32 get_filter_type() { return INTERSECTING_GTID_FILTER_TYPE; }
/*
Adds a new filter to the intersection
*/
my_bool add_filter(Gtid_event_filter *filter)
{
return insert_dynamic(&m_filters, (void *) &filter);
}
protected:
DYNAMIC_ARRAY m_filters;
};
#endif /* RPL_GTID_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment