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