1 /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef RPL_FILTER_H
24 #define RPL_FILTER_H
25 
26 #include "my_config.h"
27 
28 #include <stddef.h>
29 #include <sys/types.h>
30 #include <atomic>
31 #include <memory>
32 #include <string>
33 #include <vector>
34 
35 #include "map_helpers.h"
36 #include "my_inttypes.h"
37 #include "my_sqlcommand.h"
38 #include "prealloced_array.h"    // Prealloced_arrray
39 #include "sql/options_mysqld.h"  // options_mysqld
40 #include "sql/rpl_gtid.h"
41 #include "sql/sql_cmd.h"   // Sql_cmd
42 #include "sql/sql_list.h"  // I_List
43 #include "sql_string.h"
44 
45 class Item;
46 class THD;
47 struct TABLE_LIST;
48 
49 /*
50 There are five classes related to replication filters:
51 - Rpl_filter contains all the seven filters do-db, ignore-db, do-table,
52   ignore-table, wild-do-table, wild-ignore-table, rewrite-db. We
53   instantiate one Rpl_filter for each replication channel and one for
54   the binlog. This contains member functions to apply the filters.
55 - Rpl_pfs_filter has one instance for each row in
56   P_S.replication_applier_filters and one instance for each row of
57   P_S.replication_applier_global_filters.
58 - Rpl_filter_statistics contains the data other than the key for each
59   P_S row. Each Rpl_filter object owns seven instances of this class
60   (one for each filter type) and each Rpl_pfs_filter points to one of
61   those instances.
62 - Rpl_channel_filters contains a map that maps channel names to
63   Rpl_filter objects, as well as a vector that references all
64   the Rpl_pfs_filter objects used to represent
65   P_S.replication_applier_filters.
66 - Rpl_global_filter is a Rpl_filter representing global replication
67   filters, with a vector that references all Rpl_pfs_filter objects
68   used to represent P_S.replication_applier_global_filters table.
69 
70 The vectors of Rpl_pfs_filters objects are rebuilt whenever filters
71 are modified (i.e., channels created/dropped or filters changed).
72 */
73 
74 struct TABLE_RULE_ENT {
75   char *db;
76   char *tbl_name;
77   uint key_len;
78 };
79 
80 /** Enum values for CONFIGURED_BY column. */
81 enum enum_configured_by {
82   CONFIGURED_BY_STARTUP_OPTIONS = 1,
83   CONFIGURED_BY_CHANGE_REPLICATION_FILTER,
84   CONFIGURED_BY_STARTUP_OPTIONS_FOR_CHANNEL,
85   CONFIGURED_BY_CHANGE_REPLICATION_FILTER_FOR_CHANNEL
86 };
87 
88 /**
89   The class Rpl_filter_statistics encapsulates the following three
90   statistics of replication filter:
91   The configured_by indicates that how the rpl filter is configured.
92   The active_since indicates when the configuration took place.
93   The counter indicates the hit amount of the filter since last
94   configuration.
95   Instances of this class are created in Rpl_filter for each filter
96   type for each channel and the global filter, and have the same
97   life cycle as the instance of Rpl_filter.
98   The reference of this class is used in Rpl_pfs_filter for
99   displaying the three statistics of replication filter in
100   performance_schema.replication_applier_filters table and
101   performance_schema.replication_applier_global_filters table.
102 */
103 class Rpl_filter_statistics {
104  public:
105   Rpl_filter_statistics();
106   ~Rpl_filter_statistics();
107   void reset();
108   /*
109     Set all member variables. The caller just needs to pass argument
110     for configured_by, since counter and active_since are set in the
111     funtion. We do that, since counter must be set to 0 and
112     active_since must be set to current time for any case.
113   */
114   void set_all(enum_configured_by configured_by);
115 
get_configured_by()116   enum_configured_by get_configured_by() { return m_configured_by; }
get_active_since()117   ulonglong get_active_since() { return m_active_since; }
get_counter()118   ulonglong get_counter() { return m_atomic_counter; }
increase_counter()119   void increase_counter() { m_atomic_counter++; }
120 
121  private:
122   /*
123     The replication filters can be configured with the following four states:
124     STARTUP_OPTIONS, //STARTUP_OPTIONS: --REPLICATE-*
125     CHANGE_REPLICATION_FILTER, //CHANGE REPLICATION FILTER filter [, filter...]
126     STARTUP_OPTIONS_FOR_CHANNEL, //STARTUP_OPTIONS: --REPLICATE-* (FOR_CHANNEL)
127     CHANGE_REPLICATION_FILTER_FOR_CHANNEL //CHANGE REPLICATION FILTER filter [,
128                                           filter...] FOR CHANNEL <channel_name>
129   */
130   enum_configured_by m_configured_by;
131 
132   /* Timestamp of when the configuration took place */
133   ulonglong m_active_since;
134 
135   /*
136     The hit amount of the filter since last configuration.
137     The m_atomic_counter may be increased by concurrent slave
138     workers, so we use the atomic<uint64>.
139   */
140   std::atomic<uint64> m_atomic_counter{0};
141 
142   /* Prevent user from invoking default constructor function. */
143   Rpl_filter_statistics(Rpl_filter_statistics const &);
144 
145   /* Prevent user from invoking default assignment function. */
146   Rpl_filter_statistics &operator=(Rpl_filter_statistics const &);
147 };
148 
149 /**
150   The class Rpl_pfs_filter is introduced to serve the
151   performance_schema.replication_applier_filters table
152   and performance_schema.replication_applier_global_filters
153   table to collect data for a row. The class Rpl_filter
154   does not use it directly, since it contains channel_name,
155   which does not belong to Rpl_filter. To decouple code,
156   it depends on Rpl_filter_statistics, does not inherit
157   Rpl_filter_statistics.
158   Instances of this class are created in Rpl_filter for
159   each filter type for each channel and the global filter.
160   Each instance is created when creating, changing or
161   deleting the filter, destroyed when creating, changing
162   or deleting the filter next time.
163 */
164 class Rpl_pfs_filter {
165  public:
166   Rpl_pfs_filter();
167   Rpl_pfs_filter(const char *channel_name, const char *filter_name,
168                  const String &filter_rule,
169                  Rpl_filter_statistics *rpl_filter_statistics);
170   Rpl_pfs_filter(const Rpl_pfs_filter &other);
171   ~Rpl_pfs_filter();
172 
get_channel_name()173   const char *get_channel_name() { return m_channel_name; }
get_filter_name()174   const char *get_filter_name() { return m_filter_name; }
get_filter_rule()175   const String &get_filter_rule() { return m_filter_rule; }
get_rpl_filter_statistics()176   Rpl_filter_statistics *get_rpl_filter_statistics() {
177     return m_rpl_filter_statistics;
178   }
179 
180  private:
181   /* A pointer to the channel name. */
182   const char *m_channel_name;
183 
184   /* A pointer to the filer name. */
185   const char *m_filter_name;
186 
187   /* A pointer to replication filter statistics. */
188   Rpl_filter_statistics *m_rpl_filter_statistics;
189 
190   /* A filter rule. */
191   String m_filter_rule;
192 
193   /* Prevent user from invoking default assignment function. */
194   Rpl_pfs_filter &operator=(Rpl_pfs_filter const &);
195 };
196 
197 /**
198   Rpl_filter
199 
200   Inclusion and exclusion rules of tables and databases.
201   Also handles rewrites of db.
202   Used for replication and binlogging.
203   - Instances of this class are created in Rpl_channel_filters
204     for replication filter for each channel. Each instance is
205     created when the channel is configured, destroyed when the
206     channel is removed.
207   - There is one instance, binlog_filter, created for binlog filter.
208     The instance is created when the server is started, destroyed
209     when the server is stopped.
210  */
211 class Rpl_filter {
212  public:
213   Rpl_filter();
214   virtual ~Rpl_filter();
215   Rpl_filter(Rpl_filter const &);
216   Rpl_filter &operator=(Rpl_filter const &);
217 
218   /* Checks - returns true if ok to replicate/log */
219 
220   bool tables_ok(const char *db, TABLE_LIST *tables);
221   bool db_ok(const char *db, bool need_increase_counter = true);
222   bool db_ok_with_wild_table(const char *db);
223 
224   bool is_on();
225   /**
226     Check if the replication filter is empty or not.
227 
228     @retval true if the replication filter is empty.
229     @retval false if the replication filter is not empty.
230   */
231   bool is_empty();
232   /**
233     Copy global replication filters to its per-channel replication filters
234     if there are no per-channel replication filters and there are global
235     filters on the filter type on channel creation.
236 
237     @retval 0 OK
238     @retval 1 Error
239   */
240   int copy_global_replication_filters();
241 
242   bool is_rewrite_empty();
243 
244   /* Setters - add filtering rules */
245   int build_do_table_hash();
246   int build_ignore_table_hash();
247 
248   int add_string_list(I_List<i_string> *list, const char *spec);
249   int add_string_pair_list(I_List<i_string_pair> *list, const char *key,
250                            const char *val);
251   int add_do_table_array(const char *table_spec);
252   int add_ignore_table_array(const char *table_spec);
253 
254   int add_wild_do_table(const char *table_spec);
255   int add_wild_ignore_table(const char *table_spec);
256 
257   int set_do_db(List<Item> *list, enum_configured_by configured_by);
258   int set_ignore_db(List<Item> *list, enum_configured_by configured_by);
259   int set_do_table(List<Item> *list, enum_configured_by configured_by);
260   int set_ignore_table(List<Item> *list, enum_configured_by configured_by);
261   int set_wild_do_table(List<Item> *list, enum_configured_by configured_by);
262   int set_wild_ignore_table(List<Item> *list, enum_configured_by configured_by);
263   int set_db_rewrite(List<Item> *list, enum_configured_by configured_by);
264   typedef int (Rpl_filter::*Add_filter)(char const *);
265   int parse_filter_list(List<Item> *item_list, Add_filter func);
266   /**
267     Execute the specified func with elements of the list as input.
268 
269     @param list A list with I_List\<i_string\> type
270     @param add A function with Add_filter type
271 
272     @retval 0 OK
273     @retval 1 Error
274   */
275   int parse_filter_list(I_List<i_string> *list, Add_filter add);
276   int add_do_db(const char *db_spec);
277   int add_ignore_db(const char *db_spec);
278 
279   int add_db_rewrite(const char *from_db, const char *to_db);
280 
281   /* Getters - to get information about current rules */
282 
283   void get_do_table(String *str);
284   void get_ignore_table(String *str);
285 
286   void get_wild_do_table(String *str);
287   void get_wild_ignore_table(String *str);
288 
289   const char *get_rewrite_db(const char *db, size_t *new_len);
290   void get_rewrite_db(String *str);
291 
292   I_List<i_string> *get_do_db();
293   /*
294     Get do_db rule.
295 
296     @param[out] str the db_db rule.
297   */
298   void get_do_db(String *str);
299 
300   I_List<i_string> *get_ignore_db();
301   /*
302     Get ignore_db rule.
303 
304     @param[out] str the ignore_db rule.
305   */
306   void get_ignore_db(String *str);
307   /*
308     Get rewrite_db_statistics.
309 
310     @retval A pointer to a rewrite_db_statistics object.
311   */
get_rewrite_db_statistics()312   Rpl_filter_statistics *get_rewrite_db_statistics() {
313     return &rewrite_db_statistics;
314   }
315 
316   void free_string_list(I_List<i_string> *l);
317   void free_string_pair_list(I_List<i_string_pair> *l);
318 
319 #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
320   /**
321     Put replication filters with attached channel name into a vector.
322 
323     @param rpl_pfs_filter_vec the vector.
324     @param channel_name the name of the channel attached or NULL if
325                         there is no channel attached.
326   */
327   void put_filters_into_vector(std::vector<Rpl_pfs_filter> &rpl_pfs_filter_vec,
328                                const char *channel_name);
329 #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
330 
331   /**
332     Acquire the write lock.
333   */
wrlock()334   void wrlock() { m_rpl_filter_lock->wrlock(); }
335 
336   /**
337     Acquire the read lock.
338   */
rdlock()339   void rdlock() { m_rpl_filter_lock->rdlock(); }
340 
341   /**
342     Release the lock (whether it is a write or read lock).
343   */
unlock()344   void unlock() { m_rpl_filter_lock->unlock(); }
345 
346   /**
347     Assert that some thread holds the write lock.
348   */
assert_some_wrlock()349   void assert_some_wrlock() { m_rpl_filter_lock->assert_some_wrlock(); }
350 
351   /**
352     Assert that some thread holds the read lock.
353   */
assert_some_rdlock()354   void assert_some_rdlock() { m_rpl_filter_lock->assert_some_rdlock(); }
355 
356   /**
357     Check if the relation between the per-channel filter and
358     the channel's Relay_log_info is established.
359 
360     @retval true if the relation is established
361     @retval false if the relation is not established
362   */
is_attached()363   bool is_attached() { return attached; }
364 
365   /**
366     Set attached to true when the relation between the per-channel filter
367     and the channel's Relay_log_info is established.
368   */
set_attached()369   void set_attached() { attached = true; }
370 
371   void reset();
372 
373   Rpl_filter_statistics do_table_statistics;
374   Rpl_filter_statistics ignore_table_statistics;
375   Rpl_filter_statistics wild_do_table_statistics;
376   Rpl_filter_statistics wild_ignore_table_statistics;
377   Rpl_filter_statistics do_db_statistics;
378   Rpl_filter_statistics ignore_db_statistics;
379   Rpl_filter_statistics rewrite_db_statistics;
380 
381  private:
382   bool table_rules_on;
383   /*
384     State if the relation between the per-channel filter
385     and the channel's Relay_log_info is established.
386   */
387   bool attached;
388 
389   /*
390     While slave is not running after server startup, the replication filter
391     can be modified by CHANGE REPLICATION FILTER filter [, filter...]
392     [FOR CHANNEL <channel_name>] and CHANGE MASTER TO ... FOR CHANNEL,
393     and read by querying P_S.replication_applier_global_filters,
394     querying P_S.replication_applier_filters, and SHOW SLAVE STATUS
395     [FOR CHANNEL <channel_name>]. So the lock is introduced to protect
396     some member functions called by above commands. See below.
397 
398     The read lock should be held when calling the following member functions:
399       get_do_table(String* str);  // SHOW SLAVE STATUS
400       get_ignore_table(String* str); // SHOW SLAVE STATUS
401       get_wild_do_table(String* str); // SHOW SLAVE STATUS
402       get_wild_ignore_table(String* str); // SHOW SLAVE STATUS
403       get_rewrite_db(const char* db, size_t *new_len); // SHOW SLAVE STATUS
404       get_rewrite_db(String *str); // SHOW SLAVE STATUS
405       get_do_db(); // SHOW SLAVE STATUS
406       get_do_db(String *str);  // SHOW SLAVE STATUS
407       get_ignore_db();  // SHOW SLAVE STATUS
408       get_ignore_db(String *str);  // SHOW SLAVE STATUS
409       put_filters_into_vector(...);  // query P_S tables
410       get_filter_count();  // query P_S tables
411 
412     The write lock should be held when calling the following member functions:
413       set_do_db(List<Item> *list); // CHANGE REPLICATION FILTER
414       set_ignore_db(List<Item> *list);  // CHANGE REPLICATION FILTER
415       set_do_table(List<Item> *list);  // CHANGE REPLICATION FILTER
416       set_ignore_table(List<Item> *list); // CHANGE REPLICATION FILTER
417       set_wild_do_table(List<Item> *list); // CHANGE REPLICATION FILTER
418       set_wild_ignore_table(List<Item> *list); // CHANGE REPLICATION FILTER
419       set_db_rewrite(List<Item> *list); // CHANGE REPLICATION FILTER
420       copy_global_replication_filters(); // CHANGE MASTER TO ... FOR CHANNEL
421 
422     Please acquire a wrlock when modifying the replication filter (CHANGE
423     REPLICATION FILTER filter [, filter...] [FOR CHANNEL <channel_name>]
424     and CHANGE MASTER TO ... FOR CHANNEL).
425     Please acqurie a rdlock when reading the replication filter (
426     SELECT * FROM performance_schema.replication_applier_global_filters,
427     SELECT * FROM performance_schema.replication_applier_filters and
428     SHOW SLAVE STATUS [FOR CHANNEL <channel_name>]).
429 
430     Other member functions do not need the protection of the lock and we can
431     access thd->rli_slave->rpl_filter to filter log event without the
432     protection of the lock while slave is running, since the replication
433     filter is read/modified by a single thread during server startup and
434     there is no command can change it while slave is running.
435   */
436   Checkable_rwlock *m_rpl_filter_lock;
437 
438   typedef Prealloced_array<TABLE_RULE_ENT *, 16> Table_rule_array;
439   typedef collation_unordered_map<std::string,
440                                   unique_ptr_my_free<TABLE_RULE_ENT>>
441       Table_rule_hash;
442 
443   void init_table_rule_hash(Table_rule_hash **h, bool *h_inited);
444   void init_table_rule_array(Table_rule_array *, bool *a_inited);
445 
446   int add_table_rule_to_array(Table_rule_array *a, const char *table_spec);
447   int add_table_rule_to_hash(Table_rule_hash *h, const char *table_spec,
448                              uint len);
449 
450   void free_string_array(Table_rule_array *a);
451 
452   void table_rule_ent_hash_to_str(String *s, Table_rule_hash *h, bool inited);
453   /**
454     Builds a Table_rule_array from a hash of TABLE_RULE_ENT. Cannot be used for
455     any other hash, as it assumes that the hash entries are TABLE_RULE_ENT.
456 
457     @param table_array Pointer to the Table_rule_array to fill
458     @param h Pointer to the hash to read
459     @param inited True if the hash is initialized
460 
461     @retval 0 OK
462     @retval 1 Error
463   */
464   int table_rule_ent_hash_to_array(Table_rule_array *table_array,
465                                    Table_rule_hash *h, bool inited);
466   /**
467     Builds a destination Table_rule_array from a source Table_rule_array
468     of TABLE_RULE_ENT.
469 
470     @param dest_array Pointer to the destination Table_rule_array to fill
471     @param source_array Pointer to the source Table_rule_array to read
472     @param inited True if the source Table_rule_array is initialized
473 
474     @retval 0 OK
475     @retval 1 Error
476   */
477   int table_rule_ent_array_to_array(Table_rule_array *dest_array,
478                                     Table_rule_array *source_array,
479                                     bool inited);
480   void table_rule_ent_dynamic_array_to_str(String *s, Table_rule_array *a,
481                                            bool inited);
482   TABLE_RULE_ENT *find_wild(Table_rule_array *a, const char *key, size_t len);
483 
484   int build_table_hash_from_array(Table_rule_array *table_array,
485                                   Table_rule_hash **table_hash,
486                                   bool array_inited, bool *hash_inited);
487 
488   /*
489     Those 6 structures below are uninitialized memory unless the
490     corresponding *_inited variables are "true".
491   */
492   /* For quick search */
493   Table_rule_hash *do_table_hash{nullptr};
494   Table_rule_hash *ignore_table_hash{nullptr};
495 
496   Table_rule_array do_table_array;
497   Table_rule_array ignore_table_array;
498 
499   Table_rule_array wild_do_table;
500   Table_rule_array wild_ignore_table;
501 
502   bool do_table_hash_inited;
503   bool ignore_table_hash_inited;
504   bool do_table_array_inited;
505   bool ignore_table_array_inited;
506   bool wild_do_table_inited;
507   bool wild_ignore_table_inited;
508 
509   I_List<i_string> do_db;
510   I_List<i_string> ignore_db;
511 
512   I_List<i_string_pair> rewrite_db;
513 };
514 
515 /**
516   The class is a Rpl_filter representing global replication filters,
517   with a vector that references all Rpl_pfs_filter objects used to
518   represent P_S.replication_applier_global_filters table.
519   There is one instance, rpl_global_filter, created globally for
520   replication global filter. The rpl_global_filter is created when
521   the server is started, destroyed when the server is stopped.
522 */
523 class Rpl_global_filter : public Rpl_filter {
524  public:
Rpl_global_filter()525   Rpl_global_filter() {}
~Rpl_global_filter()526   ~Rpl_global_filter() {}
527 
528 #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
529   /**
530     Used only by replication performance schema indices to get the count
531     of global replication filters.
532 
533     @retval the count of global replication filters.
534   */
535   uint get_filter_count();
536   /**
537     Used only by replication performance schema indices to get the global
538     replication filter at the position 'pos' from the
539     rpl_pfs_filter_vec vector.
540 
541     @param pos the index in the rpl_pfs_filter_vec vector.
542 
543     @retval Rpl_pfs_filter A pointer to a Rpl_pfs_filter, or NULL if it
544                            arrived the end of the rpl_pfs_filter_vec.
545   */
546   Rpl_pfs_filter *get_filter_at_pos(uint pos);
547   /**
548     This member function is called everytime the rules of the global
549     repliation filter are changed. Once that happens the PFS view of
550     global repliation filter is recreated.
551   */
552   void reset_pfs_view();
553 #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
554 
555  private:
556   /*
557     Store pointers of all Rpl_pfs_filter objects in
558     replication filter.
559   */
560   std::vector<Rpl_pfs_filter> rpl_pfs_filter_vec;
561   /* Prevent user from invoking default assignment function. */
562   Rpl_global_filter &operator=(const Rpl_global_filter &info);
563   /* Prevent user from invoking default copy constructor function. */
564   Rpl_global_filter(const Rpl_global_filter &info);
565 };
566 
567 /** Sql_cmd_change_repl_filter represents the command CHANGE REPLICATION
568  * FILTER.
569  */
570 class Sql_cmd_change_repl_filter : public Sql_cmd {
571  public:
572   /** Constructor.  */
Sql_cmd_change_repl_filter()573   Sql_cmd_change_repl_filter()
574       : do_db_list(nullptr),
575         ignore_db_list(nullptr),
576         do_table_list(nullptr),
577         ignore_table_list(nullptr),
578         wild_do_table_list(nullptr),
579         wild_ignore_table_list(nullptr),
580         rewrite_db_pair_list(nullptr) {}
581 
~Sql_cmd_change_repl_filter()582   ~Sql_cmd_change_repl_filter() {}
583 
sql_command_code()584   virtual enum_sql_command sql_command_code() const {
585     return SQLCOM_CHANGE_REPLICATION_FILTER;
586   }
587   bool execute(THD *thd);
588 
589   void set_filter_value(List<Item> *item_list, options_mysqld filter_type);
590   bool change_rpl_filter(THD *thd);
591 
592  private:
593   List<Item> *do_db_list;
594   List<Item> *ignore_db_list;
595   List<Item> *do_table_list;
596   List<Item> *ignore_table_list;
597   List<Item> *wild_do_table_list;
598   List<Item> *wild_ignore_table_list;
599   List<Item> *rewrite_db_pair_list;
600 };
601 
602 extern Rpl_filter *rpl_filter;
603 extern Rpl_filter *binlog_filter;
604 
605 #endif  // RPL_FILTER_H
606