diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/rpl_gtid.cc | 143 | ||||
-rw-r--r-- | sql/rpl_gtid.h | 101 |
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 */ |