summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/rpl_gtid.cc143
-rw-r--r--sql/rpl_gtid.h101
2 files changed, 241 insertions, 3 deletions
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index a7f8298506f..367c8b7a8c5 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -3308,7 +3308,8 @@ void free_gtid_filter_element(void *p)
}
Id_delegating_gtid_event_filter::Id_delegating_gtid_event_filter()
- : m_num_explicit_filters(0), m_num_completed_filters(0)
+ : m_num_explicit_filters(0), m_num_completed_filters(0),
+ m_whitelist_set(FALSE), m_blacklist_set(FALSE)
{
my_hash_init(PSI_INSTRUMENT_ME, &m_filters_by_id_hash, &my_charset_bin, 32,
offsetof(gtid_filter_element, identifier),
@@ -3392,6 +3393,140 @@ my_bool Id_delegating_gtid_event_filter::exclude(rpl_gtid *gtid)
return ret;
}
+int Id_delegating_gtid_event_filter::set_blacklist(
+ gtid_filter_identifier *id_list, size_t n_ids)
+{
+ size_t id_ctr;
+ int err;
+
+ if (m_whitelist_set)
+ {
+ /*
+ Whitelist is already set, we can't do a blacklist and whitelist together
+ */
+ err= 1;
+ sql_print_error("Cannot create exclusion rule for %s ids because an "
+ "inclusion rule already exists (possibly from specifying "
+ "both --do-%s-ids and --ignore-%s-ids)",
+ get_id_type_name(), get_id_type_name(),
+ get_id_type_name());
+ goto err;
+ }
+
+ /* If a blacklist is specified more than once, only use the latest values */
+ if (m_blacklist_set)
+ my_hash_reset(&m_filters_by_id_hash);
+
+ for (id_ctr= 0; id_ctr < n_ids; id_ctr++)
+ {
+ gtid_filter_identifier filter_id= id_list[id_ctr];
+ gtid_filter_element *map_element=
+ find_or_create_filter_element_for_id(filter_id);
+
+ if(map_element == NULL)
+ {
+ err= 1;
+ goto err;
+ }
+ else if (map_element->filter == NULL)
+ {
+ map_element->filter= new Reject_all_gtid_filter();
+ m_num_explicit_filters++;
+ }
+ else if (map_element->filter->get_filter_type() !=
+ REJECT_ALL_GTID_FILTER_TYPE)
+ {
+ /*
+ There is a different filter placed on an id that should be blacklisted.
+ Error.
+ */
+ err= 1;
+ sql_print_error("Cannot set filter blacklist on %s id %lu because it "
+ "already has a filtering rule",
+ get_id_type_name(), filter_id);
+ goto err;
+ }
+ }
+
+ /*
+ With a blacklist, we by default want to accept everything that is not
+ specified in the list
+ */
+ set_default_filter(new Accept_all_gtid_filter());
+ m_blacklist_set= TRUE;
+ err= 0;
+
+err:
+ return err;
+}
+
+int Id_delegating_gtid_event_filter::set_whitelist(
+ gtid_filter_identifier *id_list, size_t n_ids)
+{
+ size_t id_ctr;
+ int err;
+
+ if (m_blacklist_set)
+ {
+ /*
+ Blacklist is already set, we can't do a blacklist and whitelist together
+ */
+ err= 1;
+ sql_print_error("Cannot create inclusion rule for %s ids because an "
+ "exclusion rule already exists (possibly from specifying "
+ "both --ignore-%s-ids and --do-%s-ids)",
+ get_id_type_name(), get_id_type_name(),
+ get_id_type_name());
+ goto err;
+ }
+
+ /* If a whitelist is specified more than once, only use the latest values */
+ if (m_whitelist_set)
+ my_hash_reset(&m_filters_by_id_hash);
+
+ for (id_ctr= 0; id_ctr < n_ids; id_ctr++)
+ {
+ gtid_filter_identifier filter_id= id_list[id_ctr];
+ gtid_filter_element *map_element=
+ find_or_create_filter_element_for_id(filter_id);
+
+ if(map_element == NULL)
+ {
+ err= 1;
+ goto err;
+ }
+ else if (map_element->filter == NULL)
+ {
+ map_element->filter= new Accept_all_gtid_filter();
+ m_num_explicit_filters++;
+ }
+ else if (map_element->filter->get_filter_type() !=
+ ACCEPT_ALL_GTID_FILTER_TYPE)
+ {
+ /*
+ There is a different filter placed on an id that should be whitelisted.
+ Error.
+ */
+ err= 1;
+ sql_print_error("Cannot set filter whitelist on %s id %lu because it "
+ "already has a filtering rule",
+ get_id_type_name(), filter_id);
+ goto err;
+ }
+ }
+
+ /*
+ With a whitelist, we by only want to accept the ids which are specified.
+ Everything else should be denied.
+ */
+ set_default_filter(new Reject_all_gtid_filter());
+ m_whitelist_set= TRUE;
+ err= 0;
+
+err:
+ return err;
+}
+
Window_gtid_event_filter *
Domain_gtid_event_filter::find_or_create_window_filter_for_id(
uint32 domain_id)
@@ -3608,3 +3743,9 @@ void Domain_gtid_event_filter::clear_stop_gtids()
reset_dynamic(&m_stop_filters);
}
+
+my_bool Intersecting_gtid_event_filter::exclude(rpl_gtid *gtid)
+{
+ DBUG_ASSERT(m_filter1 && m_filter2);
+ return m_filter1->exclude(gtid) || m_filter2->exclude(gtid);
+}
diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h
index 927937d5162..fe5286943d9 100644
--- a/sql/rpl_gtid.h
+++ b/sql/rpl_gtid.h
@@ -458,7 +458,9 @@ public:
{
DELEGATING_GTID_FILTER_TYPE = 1,
WINDOW_GTID_FILTER_TYPE = 2,
- ACCEPT_ALL_GTID_FILTER_TYPE = 3
+ ACCEPT_ALL_GTID_FILTER_TYPE = 3,
+ REJECT_ALL_GTID_FILTER_TYPE = 4,
+ INTERSECTING_GTID_FILTER_TYPE = 5
};
/*
@@ -504,6 +506,20 @@ public:
};
/*
+ Filter implementation to exclude all tested GTIDs.
+*/
+class Reject_all_gtid_filter : public Gtid_event_filter
+{
+public:
+ Reject_all_gtid_filter() {}
+ ~Reject_all_gtid_filter() {}
+ my_bool exclude(rpl_gtid *gtid) { return TRUE; }
+ uint32 get_filter_type() { return REJECT_ALL_GTID_FILTER_TYPE; }
+ my_bool has_finished() { return FALSE; }
+ void write_warnings(FILE *out) {}
+};
+
+/*
A filter implementation that passes through events between two GTIDs, m_start
(exclusive) and m_stop (inclusive).
@@ -657,6 +673,21 @@ public:
uint32 get_filter_type() { return DELEGATING_GTID_FILTER_TYPE; }
virtual gtid_filter_identifier get_id_from_gtid(rpl_gtid *) = 0;
+ virtual const char* get_id_type_name() = 0;
+
+ /*
+ Set the default behavior to include all ids except for the ones that are
+ provided in the input list or overridden with another filter.
+ Returns 0 on ok, non-zero on error
+ */
+ int set_blacklist(gtid_filter_identifier *id_list, size_t n_ids);
+
+ /*
+ Set the default behavior to exclude all ids except for the ones that are
+ provided in the input list or overridden with another filter.
+ Returns 0 on ok, non-zero on error
+ */
+ int set_whitelist(gtid_filter_identifier *id_list, size_t n_ids);
protected:
@@ -666,6 +697,8 @@ protected:
HASH m_filters_by_id_hash;
+ my_bool m_whitelist_set, m_blacklist_set;
+
gtid_filter_element *find_or_create_filter_element_for_id(gtid_filter_identifier);
};
@@ -709,6 +742,8 @@ public:
return gtid->domain_id;
}
+ const char* get_id_type_name() { return "domain"; }
+
/*
Validates that window filters with both a start and stop GTID satisfy
stop_gtid > start_gtid
@@ -759,7 +794,69 @@ 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);
+ Window_gtid_event_filter *
+ find_or_create_window_filter_for_id(gtid_filter_identifier);
+};
+
+/*
+ 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
+{
+
+public:
+ /*
+ Returns the server id of from the input GTID
+ */
+ gtid_filter_identifier 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 two
+ other filters, where the result is the intersection between the two.
+*/
+class Intersecting_gtid_event_filter : public Gtid_event_filter
+{
+public:
+ Intersecting_gtid_event_filter(Gtid_event_filter *filter1,
+ Gtid_event_filter *filter2)
+ : m_filter1(filter1), m_filter2(filter2) {}
+ ~Intersecting_gtid_event_filter()
+ {
+ delete m_filter1;
+ delete m_filter2;
+ }
+
+ /*
+ Returns TRUE if either m_filter1 or m_filter1 exclude the gtid, returns
+ FALSE otherwise, i.e. both m_filter1 and m_filter2 allow the gtid
+ */
+ my_bool exclude(rpl_gtid *gtid);
+ uint32 get_filter_type() { return INTERSECTING_GTID_FILTER_TYPE; }
+
+ Gtid_event_filter *get_filter_1() { return m_filter1; }
+ Gtid_event_filter *get_filter_2() { return m_filter2; }
+
+ /*
+ Returns true if either filter has finished. To elaborate, as this filter
+ performs an intersection, if either filter has finished, the result would
+ be excluded regardless.
+ */
+ my_bool has_finished()
+ {
+ DBUG_ASSERT(m_filter1 && m_filter2);
+ return m_filter1->has_finished() || m_filter2->has_finished();
+ }
+
+ protected:
+ Gtid_event_filter *m_filter1;
+ Gtid_event_filter *m_filter2;
};
#endif /* RPL_GTID_H */