diff options
author | unknown <lars@mysql.com> | 2005-03-21 23:05:55 +0100 |
---|---|---|
committer | unknown <lars@mysql.com> | 2005-03-21 23:05:55 +0100 |
commit | 69ca9a9416df9084c2a75aeb62a6979cecf4e5c6 (patch) | |
tree | 8b6efeea8d68c7888aaf78f4150376d941b923e5 | |
parent | 796b352862a5c94ea2de1c5910ab45d2ca5eb8ae (diff) | |
parent | 03c42246a5a50ce62b49e8fce4b263b0468d5f46 (diff) | |
download | mariadb-git-69ca9a9416df9084c2a75aeb62a6979cecf4e5c6.tar.gz |
Merge
sql/log_event.cc:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/mysqld.cc:
Auto merged
sql/slave.cc:
Auto merged
sql/slave.h:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_acl.h:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_repl.cc:
Auto merged
sql/sql_repl.h:
Auto merged
sql/Makefile.am:
Manual merge
sql/log.cc:
Manual merge
-rw-r--r-- | sql/Makefile.am | 5 | ||||
-rw-r--r-- | sql/log.cc | 6 | ||||
-rw-r--r-- | sql/log_event.cc | 11 | ||||
-rw-r--r-- | sql/mysql_priv.h | 1 | ||||
-rw-r--r-- | sql/mysqld.cc | 68 | ||||
-rw-r--r-- | sql/repl_failsafe.cc | 9 | ||||
-rw-r--r-- | sql/rpl_filter.cc | 539 | ||||
-rw-r--r-- | sql/rpl_filter.h | 110 | ||||
-rw-r--r-- | sql/slave.cc | 390 | ||||
-rw-r--r-- | sql/slave.h | 39 | ||||
-rw-r--r-- | sql/sql_acl.cc | 23 | ||||
-rw-r--r-- | sql/sql_acl.h | 3 | ||||
-rw-r--r-- | sql/sql_class.h | 11 | ||||
-rw-r--r-- | sql/sql_parse.cc | 23 | ||||
-rw-r--r-- | sql/sql_repl.cc | 5 | ||||
-rw-r--r-- | sql/sql_repl.h | 4 |
16 files changed, 743 insertions, 504 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am index bd371cd77bf..1f766564f56 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -55,7 +55,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ ha_ndbcluster.h opt_range.h protocol.h \ sql_select.h structs.h table.h sql_udf.h hash_filo.h\ lex.h lex_symbol.h sql_acl.h sql_crypt.h \ - log_event.h sql_repl.h slave.h \ + log_event.h sql_repl.h slave.h rpl_filter.h \ stacktrace.h sql_sort.h sql_cache.h set_var.h \ spatial.h gstream.h client_settings.h tzfile.h \ tztime.h my_decimal.h\ @@ -90,7 +90,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \ sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ - slave.cc sql_repl.cc sql_union.cc sql_derived.cc \ + slave.cc sql_repl.cc rpl_filter.cc \ + sql_union.cc sql_derived.cc \ client.c sql_client.cc mini_client_errors.c pack.c\ stacktrace.c repl_failsafe.h repl_failsafe.cc \ sql_olap.cc sql_view.cc \ diff --git a/sql/log.cc b/sql/log.cc index 43786990797..f477faa4912 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -24,6 +24,7 @@ #include "mysql_priv.h" #include "sql_repl.h" +#include "rpl_filter.h" #include <my_dir.h> #include <stdarg.h> @@ -1571,10 +1572,11 @@ bool MYSQL_LOG::write(Log_event *event_info) binlog_[wild_]{do|ignore}_table?" (WL#1049)" */ if ((thd && !(thd->options & OPTION_BIN_LOG)) || - (!db_ok(local_db, binlog_do_db, binlog_ignore_db))) + (!binlog_filter->db_ok(local_db))) { VOID(pthread_mutex_unlock(&LOCK_log)); - DBUG_PRINT("error",("!db_ok('%s')", local_db)); + DBUG_PRINT("info",("db_ok('%s')==%d", local_db, + binlog_filter->db_ok(local_db))); DBUG_RETURN(0); } #endif /* HAVE_REPLICATION */ diff --git a/sql/log_event.cc b/sql/log_event.cc index ba018e859c1..7c05392a873 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -21,6 +21,7 @@ #endif #include "mysql_priv.h" #include "slave.h" +#include "rpl_filter.h" #include <my_dir.h> #endif /* MYSQL_CLIENT */ @@ -1445,7 +1446,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query */ thd->catalog= (char*) catalog; thd->db_length= db_len; - thd->db= (char*) rewrite_db(db, &thd->db_length); + thd->db= (char *) rpl_filter->get_rewrite_db(db, &thd->db_length); thd->variables.auto_increment_increment= auto_increment_increment; thd->variables.auto_increment_offset= auto_increment_offset; @@ -1464,7 +1465,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query clear_all_errors(thd, rli); - if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) + if (rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); thd->query_length= q_len_arg; @@ -2569,7 +2570,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, bool use_rli_only_for_errors) { thd->db_length= db_len; - thd->db= (char*) rewrite_db(db, &thd->db_length); + thd->db= (char *) rpl_filter->get_rewrite_db(db, &thd->db_length); DBUG_ASSERT(thd->query == 0); thd->query_length= 0; // Should not be needed thd->query_error= 0; @@ -2598,7 +2599,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, al. Another way is do the filtering in the I/O thread (more efficient: no disk writes at all). */ - if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) + if (rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); VOID(pthread_mutex_lock(&LOCK_thread_count)); @@ -2620,7 +2621,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, tables.updating= 1; // the table will be opened in mysql_load - if (table_rules_on && !tables_ok(thd, &tables)) + if (rpl_filter->is_on() && !rpl_filter->tables_ok(thd->db, &tables)) { // TODO: this is a bug - this needs to be moved to the I/O thread if (net) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ba9f382fc33..07bc235e2eb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1128,7 +1128,6 @@ extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[]; extern String null_string; extern HASH open_cache; extern TABLE *unused_tables; -extern I_List<i_string> binlog_do_db, binlog_ignore_db; extern const char* any_db; extern struct my_option my_long_options[]; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6747b79703b..682fe8b9cac 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -19,6 +19,7 @@ #include <my_dir.h> #include "slave.h" #include "sql_repl.h" +#include "rpl_filter.h" #include "repl_failsafe.h" #include "stacktrace.h" #include "mysqld_suffix.h" @@ -397,12 +398,10 @@ Le_creator le_creator; FILE *bootstrap_file; int bootstrap_error; -I_List<i_string_pair> replicate_rewrite_db; -I_List<i_string> replicate_do_db, replicate_ignore_db; -// allow the user to tell us which db to replicate and which to ignore -I_List<i_string> binlog_do_db, binlog_ignore_db; I_List<THD> threads,thread_cache; I_List<NAMED_LIST> key_caches; +Rpl_filter* rpl_filter; +Rpl_filter* binlog_filter; struct system_variables global_system_variables; struct system_variables max_system_variables; @@ -1013,12 +1012,9 @@ void clean_up(bool print_message) free_max_user_conn(); #ifdef HAVE_REPLICATION end_slave_list(); - free_list(&replicate_do_db); - free_list(&replicate_ignore_db); - free_list(&binlog_do_db); - free_list(&binlog_ignore_db); - free_list(&replicate_rewrite_db); #endif + delete binlog_filter; + delete rpl_filter; #ifdef HAVE_OPENSSL if (ssl_acceptor_fd) my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR)); @@ -2970,9 +2966,16 @@ int win_main(int argc, char **argv) int main(int argc, char **argv) #endif { - DEBUGGER_OFF; + rpl_filter= new Rpl_filter; + binlog_filter= new Rpl_filter; + if (!rpl_filter || !binlog_filter) + { + sql_perror("Could not allocate replication and binlog filters"); + exit(1); + } + MY_INIT(argv[0]); // init my_sys library & pthreads #ifdef _CUSTOMSTARTUPCONFIG_ @@ -3309,7 +3312,6 @@ default_service_handling(char **argv, int main(int argc, char **argv) { - /* When several instances are running on the same machine, we need to have an unique named hEventShudown through the application PID e.g.: MySQLShutdown1890; MySQLShutdown2342 @@ -5882,13 +5884,6 @@ static void mysql_init_variables(void) exit(1); multi_keycache_init(); /* set key_cache_hash.default_value = dflt_key_cache */ - /* Initialize structures that is used when processing options */ - replicate_rewrite_db.empty(); - replicate_do_db.empty(); - replicate_ignore_db.empty(); - binlog_do_db.empty(); - binlog_ignore_db.empty(); - /* Set directory paths */ strmake(language, LANGUAGE, sizeof(language)-1); strmake(mysql_real_data_home, get_relative_path(DATADIR), @@ -6143,14 +6138,12 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } case (int)OPT_REPLICATE_IGNORE_DB: { - i_string *db = new i_string(argument); - replicate_ignore_db.push_back(db); + rpl_filter->add_ignore_db(argument); break; } case (int)OPT_REPLICATE_DO_DB: { - i_string *db = new i_string(argument); - replicate_do_db.push_back(db); + rpl_filter->add_do_db(argument); break; } case (int)OPT_REPLICATE_REWRITE_DB: @@ -6183,71 +6176,54 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), exit(1); } - i_string_pair *db_pair = new i_string_pair(key, val); - replicate_rewrite_db.push_back(db_pair); + rpl_filter->add_db_rewrite(key, val); break; } case (int)OPT_BINLOG_IGNORE_DB: { - i_string *db = new i_string(argument); - binlog_ignore_db.push_back(db); + binlog_filter->add_ignore_db(argument); break; } case (int)OPT_BINLOG_DO_DB: { - i_string *db = new i_string(argument); - binlog_do_db.push_back(db); + binlog_filter->add_do_db(argument); break; } case (int)OPT_REPLICATE_DO_TABLE: { - if (!do_table_inited) - init_table_rule_hash(&replicate_do_table, &do_table_inited); - if (add_table_rule(&replicate_do_table, argument)) + if (rpl_filter->add_do_table(argument)) { fprintf(stderr, "Could not add do table rule '%s'!\n", argument); exit(1); } - table_rules_on = 1; break; } case (int)OPT_REPLICATE_WILD_DO_TABLE: { - if (!wild_do_table_inited) - init_table_rule_array(&replicate_wild_do_table, - &wild_do_table_inited); - if (add_wild_table_rule(&replicate_wild_do_table, argument)) + if (rpl_filter->add_wild_do_table(argument)) { fprintf(stderr, "Could not add do table rule '%s'!\n", argument); exit(1); } - table_rules_on = 1; break; } case (int)OPT_REPLICATE_WILD_IGNORE_TABLE: { - if (!wild_ignore_table_inited) - init_table_rule_array(&replicate_wild_ignore_table, - &wild_ignore_table_inited); - if (add_wild_table_rule(&replicate_wild_ignore_table, argument)) + if (rpl_filter->add_wild_ignore_table(argument)) { fprintf(stderr, "Could not add ignore table rule '%s'!\n", argument); exit(1); } - table_rules_on = 1; break; } case (int)OPT_REPLICATE_IGNORE_TABLE: { - if (!ignore_table_inited) - init_table_rule_hash(&replicate_ignore_table, &ignore_table_inited); - if (add_table_rule(&replicate_ignore_table, argument)) + if (rpl_filter->add_ignore_table(argument)) { fprintf(stderr, "Could not add ignore table rule '%s'!\n", argument); exit(1); } - table_rules_on = 1; break; } #endif /* HAVE_REPLICATION */ diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index de4ad83fdbb..ec4682e37b5 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -20,6 +20,7 @@ #include "repl_failsafe.h" #include "sql_repl.h" #include "slave.h" +#include "rpl_filter.h" #include "log_event.h" #include <mysql.h> @@ -735,14 +736,14 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db, TABLE_LIST table; const char* table_name= row[0]; int error; - if (table_rules_on) + if (rpl_filter->is_on()) { bzero((char*) &table, sizeof(table)); //just for safe table.db= (char*) db; table.table_name= (char*) table_name; table.updating= 1; - if (!tables_ok(thd, &table)) + if (!rpl_filter->tables_ok(thd->db, &table)) continue; } /* download master's table and overwrite slave's table */ @@ -860,8 +861,8 @@ bool load_master_data(THD* thd) data from master */ - if (!db_ok(db, replicate_do_db, replicate_ignore_db) || - !db_ok_with_wild_table(db) || + if (!rpl_filter->db_ok(db) || + !rpl_filter->db_ok_with_wild_table(db) || !strcmp(db,"mysql")) { *cur_table_res = 0; diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc new file mode 100644 index 00000000000..f9f8a3e98a7 --- /dev/null +++ b/sql/rpl_filter.cc @@ -0,0 +1,539 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysql_priv.h" +#include "rpl_filter.h" + +#define TABLE_RULE_HASH_SIZE 16 +#define TABLE_RULE_ARR_SIZE 16 + +Rpl_filter::Rpl_filter() : + table_rules_on(0), do_table_inited(0), ignore_table_inited(0), + wild_do_table_inited(0), wild_ignore_table_inited(0) +{ + do_db.empty(); + ignore_db.empty(); + rewrite_db.empty(); +} + + +Rpl_filter::~Rpl_filter() +{ + if (do_table_inited) + hash_free(&do_table); + if (ignore_table_inited) + hash_free(&ignore_table); + if (wild_do_table_inited) + free_string_array(&wild_do_table); + if (wild_ignore_table_inited) + free_string_array(&wild_ignore_table); + free_list(&do_db); + free_list(&ignore_db); + free_list(&rewrite_db); +} + + +/* + Returns true if table should be logged/replicated + + SYNOPSIS + tables_ok() + db db to use if db in TABLE_LIST is undefined for a table + tables list of tables to check + + NOTES + Changing table order in the list can lead to different results. + + Note also order of precedence of do/ignore rules (see code). For + that reason, users should not set conflicting rules because they + may get unpredicted results (precedence order is explained in the + manual). + + If no table in the list is marked "updating", then we always + return 0, because there is no reason to execute this statement on + slave if it updates nothing. (Currently, this can only happen if + statement is a multi-delete (SQLCOM_DELETE_MULTI) and "tables" are + the tables in the FROM): + + In the case of SQLCOM_DELETE_MULTI, there will be a second call to + tables_ok(), with tables having "updating==TRUE" (those after the + DELETE), so this second call will make the decision (because + all_tables_not_ok() = !tables_ok(1st_list) && + !tables_ok(2nd_list)). + + TODO + "Include all tables like "abc.%" except "%.EFG"". (Can't be done now.) + If we supported Perl regexps, we could do it with pattern: /^abc\.(?!EFG)/ + (I could not find an equivalent in the regex library MySQL uses). + + RETURN VALUES + 0 should not be logged/replicated + 1 should be logged/replicated +*/ + +bool +Rpl_filter::tables_ok(const char* db, TABLE_LIST* tables) +{ + bool some_tables_updating= 0; + DBUG_ENTER("Rpl_filter::tables_ok"); + + for (; tables; tables= tables->next_global) + { + char hash_key[2*NAME_LEN+2]; + char *end; + uint len; + + if (!tables->updating) + continue; + some_tables_updating= 1; + end= strmov(hash_key, tables->db ? tables->db : db); + *end++= '.'; + len= (uint) (strmov(end, tables->table_name) - hash_key); + if (do_table_inited) // if there are any do's + { + if (hash_search(&do_table, (byte*) hash_key, len)) + DBUG_RETURN(1); + } + if (ignore_table_inited) // if there are any ignores + { + if (hash_search(&ignore_table, (byte*) hash_key, len)) + DBUG_RETURN(0); + } + if (wild_do_table_inited && + find_wild(&wild_do_table, hash_key, len)) + DBUG_RETURN(1); + if (wild_ignore_table_inited && + find_wild(&wild_ignore_table, hash_key, len)) + DBUG_RETURN(0); + } + + /* + If no table was to be updated, ignore statement (no reason we play it on + slave, slave is supposed to replicate _changes_ only). + If no explicit rule found and there was a do list, do not replicate. + If there was no do list, go ahead + */ + DBUG_RETURN(some_tables_updating && + !do_table_inited && !wild_do_table_inited); +} + + +/* + Checks whether a db matches some do_db and ignore_db rules + + SYNOPSIS + db_ok() + db name of the db to check + + RETURN VALUES + 0 should not be logged/replicated + 1 should be logged/replicated +*/ + +bool +Rpl_filter::db_ok(const char* db) +{ + DBUG_ENTER("Rpl_filter::db_ok"); + + if (do_db.is_empty() && ignore_db.is_empty()) + DBUG_RETURN(1); // Ok to replicate if the user puts no constraints + + /* + If the user has specified restrictions on which databases to replicate + and db was not selected, do not replicate. + */ + if (!db) + DBUG_RETURN(0); + + if (!do_db.is_empty()) // if the do's are not empty + { + I_List_iterator<i_string> it(do_db); + i_string* tmp; + + while ((tmp=it++)) + { + if (!strcmp(tmp->ptr, db)) + DBUG_RETURN(1); // match + } + DBUG_RETURN(0); + } + else // there are some elements in the don't, otherwise we cannot get here + { + I_List_iterator<i_string> it(ignore_db); + i_string* tmp; + + while ((tmp=it++)) + { + if (!strcmp(tmp->ptr, db)) + DBUG_RETURN(0); // match + } + DBUG_RETURN(1); + } +} + + +/* + Checks whether a db matches wild_do_table and wild_ignore_table + rules (for replication) + + SYNOPSIS + db_ok_with_wild_table() + db name of the db to check. + Is tested with check_db_name() before calling this function. + + NOTES + Here is the reason for this function. + We advise users who want to exclude a database 'db1' safely to do it + with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or + replicate_ignore_db because the two lasts only check for the selected db, + which won't work in that case: + USE db2; + UPDATE db1.t SET ... #this will be replicated and should not + whereas replicate_wild_ignore_table will work in all cases. + With replicate_wild_ignore_table, we only check tables. When + one does 'DROP DATABASE db1', tables are not involved and the + statement will be replicated, while users could expect it would not (as it + rougly means 'DROP db1.first_table, DROP db1.second_table...'). + In other words, we want to interpret 'db1.%' as "everything touching db1". + That is why we want to match 'db1' against 'db1.%' wild table rules. + + RETURN VALUES + 0 should not be logged/replicated + 1 should be logged/replicated +*/ + +bool +Rpl_filter::db_ok_with_wild_table(const char *db) +{ + DBUG_ENTER("Rpl_filter::db_ok_with_wild_table"); + + char hash_key[NAME_LEN+2]; + char *end; + int len; + end= strmov(hash_key, db); + *end++= '.'; + len= end - hash_key ; + if (wild_do_table_inited && find_wild(&wild_do_table, hash_key, len)) + { + DBUG_PRINT("return",("1")); + DBUG_RETURN(1); + } + if (wild_ignore_table_inited && find_wild(&wild_ignore_table, hash_key, len)) + { + DBUG_PRINT("return",("0")); + DBUG_RETURN(0); + } + + /* + If no explicit rule found and there was a do list, do not replicate. + If there was no do list, go ahead + */ + DBUG_PRINT("return",("db=%s,retval=%d", db, !wild_do_table_inited)); + DBUG_RETURN(!wild_do_table_inited); +} + + +bool +Rpl_filter::is_on() +{ + return table_rules_on; +} + + +int +Rpl_filter::add_do_table(const char* table_spec) +{ + DBUG_ENTER("Rpl_filter::add_do_table"); + if (!do_table_inited) + init_table_rule_hash(&do_table, &do_table_inited); + table_rules_on= 1; + DBUG_RETURN(add_table_rule(&do_table, table_spec)); +} + + +int +Rpl_filter::add_ignore_table(const char* table_spec) +{ + DBUG_ENTER("Rpl_filter::add_ignore_table"); + if (!ignore_table_inited) + init_table_rule_hash(&ignore_table, &ignore_table_inited); + table_rules_on= 1; + DBUG_RETURN(add_table_rule(&ignore_table, table_spec)); +} + + +int +Rpl_filter::add_wild_do_table(const char* table_spec) +{ + DBUG_ENTER("Rpl_filter::add_wild_do_table"); + if (!wild_do_table_inited) + init_table_rule_array(&wild_do_table, &wild_do_table_inited); + table_rules_on= 1; + DBUG_RETURN(add_wild_table_rule(&wild_do_table, table_spec)); +} + + +int +Rpl_filter::add_wild_ignore_table(const char* table_spec) +{ + DBUG_ENTER("Rpl_filter::add_wild_ignore_table"); + if (!wild_ignore_table_inited) + init_table_rule_array(&wild_ignore_table, &wild_ignore_table_inited); + table_rules_on= 1; + DBUG_RETURN(add_wild_table_rule(&wild_ignore_table, table_spec)); +} + + +void +Rpl_filter::add_db_rewrite(const char* from_db, const char* to_db) +{ + i_string_pair *db_pair = new i_string_pair(from_db, to_db); + rewrite_db.push_back(db_pair); +} + + +int +Rpl_filter::add_table_rule(HASH* h, const char* table_spec) +{ + const char* dot = strchr(table_spec, '.'); + if (!dot) return 1; + // len is always > 0 because we know the there exists a '.' + uint len = (uint)strlen(table_spec); + TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + + len, MYF(MY_WME)); + if (!e) return 1; + e->db= (char*)e + sizeof(TABLE_RULE_ENT); + e->tbl_name= e->db + (dot - table_spec) + 1; + e->key_len= len; + memcpy(e->db, table_spec, len); + + return my_hash_insert(h, (byte*)e); +} + + +/* + Add table expression with wildcards to dynamic array +*/ + +int +Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec) +{ + const char* dot = strchr(table_spec, '.'); + if (!dot) return 1; + uint len = (uint)strlen(table_spec); + TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + + len, MYF(MY_WME)); + if (!e) return 1; + e->db= (char*)e + sizeof(TABLE_RULE_ENT); + e->tbl_name= e->db + (dot - table_spec) + 1; + e->key_len= len; + memcpy(e->db, table_spec, len); + insert_dynamic(a, (gptr)&e); + return 0; +} + + +void +Rpl_filter::add_do_db(const char* table_spec) +{ + DBUG_ENTER("Rpl_filter::add_do_db"); + i_string *db = new i_string(table_spec); + do_db.push_back(db); +} + + +void +Rpl_filter::add_ignore_db(const char* table_spec) +{ + DBUG_ENTER("Rpl_filter::add_ignore_db"); + i_string *db = new i_string(table_spec); + ignore_db.push_back(db); +} + + +static byte* get_table_key(const byte* a, uint* len, + my_bool __attribute__((unused))) +{ + TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a; + + *len= e->key_len; + return (byte*)e->db; +} + + +static void free_table_ent(void* a) +{ + TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a; + + my_free((gptr) e, MYF(0)); +} + + +void +Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited) +{ + hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0, + get_table_key, free_table_ent, 0); + *h_inited = 1; +} + + +void +Rpl_filter::init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited) +{ + my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE, + TABLE_RULE_ARR_SIZE); + *a_inited = 1; +} + + +TABLE_RULE_ENT* +Rpl_filter::find_wild(DYNAMIC_ARRAY *a, const char* key, int len) +{ + uint i; + const char* key_end= key + len; + + for (i= 0; i < a->elements; i++) + { + TABLE_RULE_ENT* e ; + get_dynamic(a, (gptr)&e, i); + if (!my_wildcmp(system_charset_info, key, key_end, + (const char*)e->db, + (const char*)(e->db + e->key_len), + '\\',wild_one,wild_many)) + return e; + } + + return 0; +} + + +void +Rpl_filter::free_string_array(DYNAMIC_ARRAY *a) +{ + uint i; + for (i= 0; i < a->elements; i++) + { + char* p; + get_dynamic(a, (gptr) &p, i); + my_free(p, MYF(MY_WME)); + } + delete_dynamic(a); +} + + +/* + Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other + hash, as it assumes that the hash entries are TABLE_RULE_ENT. + + SYNOPSIS + table_rule_ent_hash_to_str() + s pointer to the String to fill + h pointer to the HASH to read + + RETURN VALUES + none +*/ + +void +Rpl_filter::table_rule_ent_hash_to_str(String* s, HASH* h) +{ + s->length(0); + for (uint i= 0; i < h->records; i++) + { + TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i); + if (s->length()) + s->append(','); + s->append(e->db,e->key_len); + } +} + + +void +Rpl_filter::table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a) +{ + s->length(0); + for (uint i= 0; i < a->elements; i++) + { + TABLE_RULE_ENT* e; + get_dynamic(a, (gptr)&e, i); + if (s->length()) + s->append(','); + s->append(e->db,e->key_len); + } +} + + +void +Rpl_filter::get_do_table(String* str) +{ + table_rule_ent_hash_to_str(str, &do_table); +} + + +void +Rpl_filter::get_ignore_table(String* str) +{ + table_rule_ent_hash_to_str(str, &ignore_table); +} + + +void +Rpl_filter::get_wild_do_table(String* str) +{ + table_rule_ent_dynamic_array_to_str(str, &wild_do_table); +} + + +void +Rpl_filter::get_wild_ignore_table(String* str) +{ + table_rule_ent_dynamic_array_to_str(str, &wild_ignore_table); +} + + +const char* +Rpl_filter::get_rewrite_db(const char* db, uint32 *new_len) +{ + if (rewrite_db.is_empty() || !db) + return db; + I_List_iterator<i_string_pair> it(rewrite_db); + i_string_pair* tmp; + + while ((tmp=it++)) + { + if (!strcmp(tmp->key, db)) + { + *new_len= strlen(tmp->val); + return tmp->val; + } + } + return db; +} + + +I_List<i_string>* +Rpl_filter::get_do_db() +{ + return &do_db; +} + + +I_List<i_string>* +Rpl_filter::get_ignore_db() +{ + return &ignore_db; +} diff --git a/sql/rpl_filter.h b/sql/rpl_filter.h new file mode 100644 index 00000000000..70bb137790e --- /dev/null +++ b/sql/rpl_filter.h @@ -0,0 +1,110 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef __RPL_FILTER_H__ +#define __RPL_FILTER_H__ + +#include "mysql.h" +#include "my_list.h" + +typedef struct st_table_rule_ent +{ + char* db; + char* tbl_name; + uint key_len; +} TABLE_RULE_ENT; + +/* + Rpl_filter + + Inclusion and exclusion rules of tables and databases. + Also handles rewrites of db. + Used for replication and binlogging. + */ +class Rpl_filter +{ +public: + Rpl_filter(); + ~Rpl_filter(); + Rpl_filter(Rpl_filter const&); + Rpl_filter& operator=(Rpl_filter const&); + + /* Checks - returns true if ok to replicate/log */ + + bool tables_ok(const char* db, TABLE_LIST* tables); + bool db_ok(const char* db); + bool db_ok_with_wild_table(const char *db); + + bool is_on(); + + /* Setters - add filtering rules */ + + int add_do_table(const char* table_spec); + int add_ignore_table(const char* table_spec); + + int add_wild_do_table(const char* table_spec); + int add_wild_ignore_table(const char* table_spec); + + void add_do_db(const char* db_spec); + void add_ignore_db(const char* db_spec); + + void add_db_rewrite(const char* from_db, const char* to_db); + + /* Getters - to get information about current rules */ + + void get_do_table(String* str); + void get_ignore_table(String* str); + + void get_wild_do_table(String* str); + void get_wild_ignore_table(String* str); + + const char* get_rewrite_db(const char* db, uint32 *new_len); + + I_List<i_string>* get_do_db(); + I_List<i_string>* get_ignore_db(); + +private: + bool table_rules_on; + + void init_table_rule_hash(HASH* h, bool* h_inited); + void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited); + + int add_table_rule(HASH* h, const char* table_spec); + int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec); + + void free_string_array(DYNAMIC_ARRAY *a); + + void table_rule_ent_hash_to_str(String* s, HASH* h); + void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a); + TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len); + + HASH do_table; + HASH ignore_table; + DYNAMIC_ARRAY wild_do_table; + DYNAMIC_ARRAY wild_ignore_table; + + bool do_table_inited; + bool ignore_table_inited; + bool wild_do_table_inited; + bool wild_ignore_table_inited; + + I_List<i_string> do_db; + I_List<i_string> ignore_db; + + I_List<i_string_pair> rewrite_db; +}; + +#endif // __TABLE_FILTER_H__ diff --git a/sql/slave.cc b/sql/slave.cc index 73dd0fd13c3..838efae6d11 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -22,6 +22,7 @@ #include <myisam.h> #include "slave.h" #include "sql_repl.h" +#include "rpl_filter.h" #include "repl_failsafe.h" #include <thr_alarm.h> #include <my_dir.h> @@ -35,11 +36,7 @@ typedef bool (*CHECK_KILLED_FUNC)(THD*,void*); volatile bool slave_sql_running = 0, slave_io_running = 0; char* slave_load_tmpdir = 0; MASTER_INFO *active_mi; -HASH replicate_do_table, replicate_ignore_table; -DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table; -bool do_table_inited = 0, ignore_table_inited = 0; -bool wild_do_table_inited = 0, wild_ignore_table_inited = 0; -bool table_rules_on= 0, replicate_same_server_id; +bool replicate_same_server_id; ulonglong relay_log_space_limit = 0; /* @@ -193,20 +190,6 @@ err: } -static void free_table_ent(TABLE_RULE_ENT* e) -{ - my_free((gptr) e, MYF(0)); -} - - -static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, - my_bool not_used __attribute__((unused))) -{ - *len = e->key_len; - return (byte*)e->db; -} - - /* Open the given relay log @@ -808,228 +791,6 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start, } -void init_table_rule_hash(HASH* h, bool* h_inited) -{ - hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0, - (hash_get_key) get_table_key, - (hash_free_key) free_table_ent, 0); - *h_inited = 1; -} - - -void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited) -{ - my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE, - TABLE_RULE_ARR_SIZE); - *a_inited = 1; -} - - -static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len) -{ - uint i; - const char* key_end = key + len; - - for (i = 0; i < a->elements; i++) - { - TABLE_RULE_ENT* e ; - get_dynamic(a, (gptr)&e, i); - if (!my_wildcmp(system_charset_info, key, key_end, - (const char*)e->db, - (const char*)(e->db + e->key_len), - '\\',wild_one,wild_many)) - return e; - } - - return 0; -} - - -/* - Checks whether tables match some (wild_)do_table and (wild_)ignore_table - rules (for replication) - - SYNOPSIS - tables_ok() - thd thread (SQL slave thread normally) - tables list of tables to check - - NOTES - Note that changing the order of the tables in the list can lead to - different results. Note also the order of precedence of the do/ignore - rules (see code below). For that reason, users should not set conflicting - rules because they may get unpredicted results (precedence order is - explained in the manual). - If no table of the list is marked "updating" (so far this can only happen - if the statement is a multi-delete (SQLCOM_DELETE_MULTI) and the "tables" - is the tables in the FROM): then we always return 0, because there is no - reason we play this statement on this slave if it updates nothing. In the - case of SQLCOM_DELETE_MULTI, there will be a second call to tables_ok(), - with tables having "updating==TRUE" (those after the DELETE), so this - second call will make the decision (because - all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)). - - Thought which arose from a question of a big customer "I want to include - all tables like "abc.%" except the "%.EFG"". This can't be done now. If we - supported Perl regexps we could do it with this pattern: /^abc\.(?!EFG)/ - (I could not find an equivalent in the regex library MySQL uses). - - RETURN VALUES - 0 should not be logged/replicated - 1 should be logged/replicated -*/ - -bool tables_ok(THD* thd, TABLE_LIST* tables) -{ - bool some_tables_updating= 0; - DBUG_ENTER("tables_ok"); - - for (; tables; tables= tables->next_global) - { - char hash_key[2*NAME_LEN+2]; - char *end; - uint len; - - if (!tables->updating) - continue; - some_tables_updating= 1; - end= strmov(hash_key, tables->db ? tables->db : thd->db); - *end++= '.'; - len= (uint) (strmov(end, tables->table_name) - hash_key); - if (do_table_inited) // if there are any do's - { - if (hash_search(&replicate_do_table, (byte*) hash_key, len)) - DBUG_RETURN(1); - } - if (ignore_table_inited) // if there are any ignores - { - if (hash_search(&replicate_ignore_table, (byte*) hash_key, len)) - DBUG_RETURN(0); - } - if (wild_do_table_inited && find_wild(&replicate_wild_do_table, - hash_key, len)) - DBUG_RETURN(1); - if (wild_ignore_table_inited && find_wild(&replicate_wild_ignore_table, - hash_key, len)) - DBUG_RETURN(0); - } - - /* - If no table was to be updated, ignore statement (no reason we play it on - slave, slave is supposed to replicate _changes_ only). - If no explicit rule found and there was a do list, do not replicate. - If there was no do list, go ahead - */ - DBUG_RETURN(some_tables_updating && - !do_table_inited && !wild_do_table_inited); -} - - -/* - Checks whether a db matches wild_do_table and wild_ignore_table - rules (for replication) - - SYNOPSIS - db_ok_with_wild_table() - db name of the db to check. - Is tested with check_db_name() before calling this function. - - NOTES - Here is the reason for this function. - We advise users who want to exclude a database 'db1' safely to do it - with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or - replicate_ignore_db because the two lasts only check for the selected db, - which won't work in that case: - USE db2; - UPDATE db1.t SET ... #this will be replicated and should not - whereas replicate_wild_ignore_table will work in all cases. - With replicate_wild_ignore_table, we only check tables. When - one does 'DROP DATABASE db1', tables are not involved and the - statement will be replicated, while users could expect it would not (as it - rougly means 'DROP db1.first_table, DROP db1.second_table...'). - In other words, we want to interpret 'db1.%' as "everything touching db1". - That is why we want to match 'db1' against 'db1.%' wild table rules. - - RETURN VALUES - 0 should not be logged/replicated - 1 should be logged/replicated - */ - -int db_ok_with_wild_table(const char *db) -{ - char hash_key[NAME_LEN+2]; - char *end; - int len; - end= strmov(hash_key, db); - *end++= '.'; - len= end - hash_key ; - if (wild_do_table_inited && find_wild(&replicate_wild_do_table, - hash_key, len)) - return 1; - if (wild_ignore_table_inited && find_wild(&replicate_wild_ignore_table, - hash_key, len)) - return 0; - - /* - If no explicit rule found and there was a do list, do not replicate. - If there was no do list, go ahead - */ - return !wild_do_table_inited; -} - - -int add_table_rule(HASH* h, const char* table_spec) -{ - const char* dot = strchr(table_spec, '.'); - if (!dot) return 1; - // len is always > 0 because we know the there exists a '.' - uint len = (uint)strlen(table_spec); - TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) - + len, MYF(MY_WME)); - if (!e) return 1; - e->db = (char*)e + sizeof(TABLE_RULE_ENT); - e->tbl_name = e->db + (dot - table_spec) + 1; - e->key_len = len; - memcpy(e->db, table_spec, len); - (void)my_hash_insert(h, (byte*)e); - return 0; -} - - -/* - Add table expression with wildcards to dynamic array -*/ - -int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec) -{ - const char* dot = strchr(table_spec, '.'); - if (!dot) return 1; - uint len = (uint)strlen(table_spec); - TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) - + len, MYF(MY_WME)); - if (!e) return 1; - e->db = (char*)e + sizeof(TABLE_RULE_ENT); - e->tbl_name = e->db + (dot - table_spec) + 1; - e->key_len = len; - memcpy(e->db, table_spec, len); - insert_dynamic(a, (gptr)&e); - return 0; -} - - -static void free_string_array(DYNAMIC_ARRAY *a) -{ - uint i; - for (i = 0; i < a->elements; i++) - { - char* p; - get_dynamic(a, (gptr) &p, i); - my_free(p, MYF(MY_WME)); - } - delete_dynamic(a); -} - - #ifdef NOT_USED_YET static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/) { @@ -1065,14 +826,6 @@ void end_slave() */ terminate_slave_threads(active_mi,SLAVE_FORCE_ALL); end_master_info(active_mi); - if (do_table_inited) - hash_free(&replicate_do_table); - if (ignore_table_inited) - hash_free(&replicate_ignore_table); - if (wild_do_table_inited) - free_string_array(&replicate_wild_do_table); - if (wild_ignore_table_inited) - free_string_array(&replicate_wild_ignore_table); delete active_mi; active_mi= 0; } @@ -1152,24 +905,6 @@ bool net_request_file(NET* net, const char* fname) } -const char *rewrite_db(const char* db, uint32 *new_len) -{ - if (replicate_rewrite_db.is_empty() || !db) - return db; - I_List_iterator<i_string_pair> it(replicate_rewrite_db); - i_string_pair* tmp; - - while ((tmp=it++)) - { - if (!strcmp(tmp->key, db)) - { - *new_len= (uint32)strlen(tmp->val); - return tmp->val; - } - } - return db; -} - /* From other comments and tests in code, it looks like sometimes Query_log_event and Load_log_event can have db == 0 @@ -1182,60 +917,6 @@ const char *print_slave_db_safe(const char* db) return (db ? db : ""); } -/* - Checks whether a db matches some do_db and ignore_db rules - (for logging or replication) - - SYNOPSIS - db_ok() - db name of the db to check - do_list either binlog_do_db or replicate_do_db - ignore_list either binlog_ignore_db or replicate_ignore_db - - RETURN VALUES - 0 should not be logged/replicated - 1 should be logged/replicated -*/ - -int db_ok(const char* db, I_List<i_string> &do_list, - I_List<i_string> &ignore_list ) -{ - if (do_list.is_empty() && ignore_list.is_empty()) - return 1; // ok to replicate if the user puts no constraints - - /* - If the user has specified restrictions on which databases to replicate - and db was not selected, do not replicate. - */ - if (!db) - return 0; - - if (!do_list.is_empty()) // if the do's are not empty - { - I_List_iterator<i_string> it(do_list); - i_string* tmp; - - while ((tmp=it++)) - { - if (!strcmp(tmp->ptr, db)) - return 1; // match - } - return 0; - } - else // there are some elements in the don't, otherwise we cannot get here - { - I_List_iterator<i_string> it(ignore_list); - i_string* tmp; - - while ((tmp=it++)) - { - if (!strcmp(tmp->ptr, db)) - return 0; // match - } - return 1; - } -} - static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val) @@ -2245,48 +1926,6 @@ int register_slave_on_master(MYSQL* mysql) } -/* - Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other - hash, as it assumes that the hash entries are TABLE_RULE_ENT. - - SYNOPSIS - table_rule_ent_hash_to_str() - s pointer to the String to fill - h pointer to the HASH to read - - RETURN VALUES - none -*/ - -void table_rule_ent_hash_to_str(String* s, HASH* h) -{ - s->length(0); - for (uint i=0 ; i < h->records ; i++) - { - TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i); - if (s->length()) - s->append(','); - s->append(e->db,e->key_len); - } -} - -/* - Mostly the same thing as above -*/ - -void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a) -{ - s->length(0); - for (uint i=0 ; i < a->elements ; i++) - { - TABLE_RULE_ENT* e; - get_dynamic(a, (gptr)&e, i); - if (s->length()) - s->append(','); - s->append(e->db,e->key_len); - } -} - bool show_master_info(THD* thd, MASTER_INFO* mi) { // TODO: fix this for multi-master @@ -2381,23 +2020,18 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) protocol->store(mi->rli.group_master_log_name, &my_charset_bin); protocol->store(mi->slave_running ? "Yes":"No", &my_charset_bin); protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin); - protocol->store(&replicate_do_db); - protocol->store(&replicate_ignore_db); - /* - We can't directly use some protocol->store for - replicate_*_table, - as Protocol doesn't know the TABLE_RULE_ENT struct. - We first build Strings and then pass them to protocol->store. - */ + protocol->store(rpl_filter->get_do_db()); + protocol->store(rpl_filter->get_ignore_db()); + char buf[256]; String tmp(buf, sizeof(buf), &my_charset_bin); - table_rule_ent_hash_to_str(&tmp, &replicate_do_table); + rpl_filter->get_do_table(&tmp); protocol->store(&tmp); - table_rule_ent_hash_to_str(&tmp, &replicate_ignore_table); + rpl_filter->get_ignore_table(&tmp); protocol->store(&tmp); - table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_do_table); + rpl_filter->get_wild_do_table(&tmp); protocol->store(&tmp); - table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_ignore_table); + rpl_filter->get_wild_ignore_table(&tmp); protocol->store(&tmp); protocol->store((uint32) mi->rli.last_slave_errno); @@ -3845,10 +3479,8 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) if (unlikely(!cev->is_valid())) DBUG_RETURN(1); - /* - TODO: fix to honor table rules, not only db rules - */ - if (!db_ok(cev->db, replicate_do_db, replicate_ignore_db)) + + if (!rpl_filter->db_ok(cev->db)) { skip_load_data_infile(net); DBUG_RETURN(0); diff --git a/sql/slave.h b/sql/slave.h index ee5541ffe08..a29315f7ae4 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -21,10 +21,14 @@ #include "mysql.h" #include "my_list.h" +#include "rpl_filter.h" + #define SLAVE_NET_TIMEOUT 3600 #define MAX_SLAVE_ERRMSG 1024 #define MAX_SLAVE_ERROR 2000 +extern Rpl_filter *rpl_filter; + /***************************************************************************** MySQL Replication @@ -454,15 +458,6 @@ typedef struct st_master_info int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len); -typedef struct st_table_rule_ent -{ - char* db; - char* tbl_name; - uint key_len; -} TABLE_RULE_ENT; - -#define TABLE_RULE_HASH_SIZE 16 -#define TABLE_RULE_ARR_SIZE 16 #define MAX_SLAVE_ERRMSG 1024 #define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\ @@ -516,27 +511,9 @@ int mysql_table_dump(THD* thd, const char* db, int fetch_master_table(THD* thd, const char* db_name, const char* table_name, MASTER_INFO* mi, MYSQL* mysql, bool overwrite); -void table_rule_ent_hash_to_str(String* s, HASH* h); -void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a); bool show_master_info(THD* thd, MASTER_INFO* mi); bool show_binlog_info(THD* thd); -/* See if the query uses any tables that should not be replicated */ -bool tables_ok(THD* thd, TABLE_LIST* tables); - -/* - Check to see if the database is ok to operate on with respect to the - do and ignore lists - used in replication -*/ -int db_ok(const char* db, I_List<i_string> &do_list, - I_List<i_string> &ignore_list ); -int db_ok_with_wild_table(const char *db); - -int add_table_rule(HASH* h, const char* table_spec); -int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec); -void init_table_rule_hash(HASH* h, bool* h_inited); -void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited); -const char *rewrite_db(const char* db, uint32 *new_db_len); const char *print_slave_db_safe(const char *db); int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code); void skip_load_data_infile(NET* net); @@ -569,11 +546,7 @@ extern "C" pthread_handler_decl(handle_slave_sql,arg); extern bool volatile abort_loop; extern MASTER_INFO main_mi, *active_mi; /* active_mi for multi-master */ extern LIST master_list; -extern HASH replicate_do_table, replicate_ignore_table; -extern DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table; -extern bool do_table_inited, ignore_table_inited, - wild_do_table_inited, wild_ignore_table_inited; -extern bool table_rules_on, replicate_same_server_id; +extern bool replicate_same_server_id; extern int disconnect_slave_event_count, abort_slave_event_count ; @@ -587,8 +560,6 @@ extern my_bool master_ssl; extern my_string master_ssl_ca, master_ssl_capath, master_ssl_cert, master_ssl_cipher, master_ssl_key; -extern I_List<i_string> replicate_do_db, replicate_ignore_db; -extern I_List<i_string_pair> replicate_rewrite_db; extern I_List<THD> threads; #endif diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b71b79cb1c6..3e6aba32feb 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -27,9 +27,6 @@ #include "mysql_priv.h" #include "hash_filo.h" -#ifdef HAVE_REPLICATION -#include "sql_repl.h" //for tables_ok() -#endif #include <m_ctype.h> #include <stdarg.h> #include "sp_head.h" @@ -1499,7 +1496,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && table_rules_on) + if (thd->slave_thread && rpl_filter->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into @@ -1507,7 +1504,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user, */ tables.updating= 1; /* Thanks to bzero, tables.next==0 */ - if (!tables_ok(0, &tables)) + if (!rpl_filter->tables_ok(0, &tables)) DBUG_RETURN(0); } #endif @@ -2670,14 +2667,14 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && table_rules_on) + if (thd->slave_thread && rpl_filter->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into account in tests. */ tables[0].updating= tables[1].updating= tables[2].updating= 1; - if (!tables_ok(0, tables)) + if (!rpl_filter->tables_ok(0, tables)) DBUG_RETURN(FALSE); } #endif @@ -2873,14 +2870,14 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && table_rules_on) + if (thd->slave_thread && rpl_filter->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into account in tests. */ tables[0].updating= tables[1].updating= 1; - if (!tables_ok(0, tables)) + if (!rpl_filter->tables_ok(0, tables)) DBUG_RETURN(FALSE); } #endif @@ -3002,14 +2999,14 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && table_rules_on) + if (thd->slave_thread && rpl_filter->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into account in tests. */ tables[0].updating= tables[1].updating= 1; - if (!tables_ok(0, tables)) + if (!rpl_filter->tables_ok(0, tables)) DBUG_RETURN(FALSE); } #endif @@ -4210,7 +4207,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && table_rules_on) + if (thd->slave_thread && rpl_filter->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into @@ -4218,7 +4215,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) */ tables[0].updating=tables[1].updating=tables[2].updating= tables[3].updating=tables[4].updating=1; - if (!tables_ok(0, tables)) + if (!rpl_filter->tables_ok(0, tables)) DBUG_RETURN(1); tables[0].updating=tables[1].updating=tables[2].updating= tables[3].updating=tables[4].updating=0;; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index fd22da2a9fc..21f14fc3045 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -14,6 +14,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "slave.h" // for tables_ok(), rpl_filter +extern Rpl_filter *rpl_filter; + #define SELECT_ACL (1L << 0) #define INSERT_ACL (1L << 1) #define UPDATE_ACL (1L << 2) diff --git a/sql/sql_class.h b/sql/sql_class.h index ffb7a9ab12d..469eb86803a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -466,19 +466,20 @@ public: class i_string: public ilink { public: - char* ptr; + const char* ptr; i_string():ptr(0) { } - i_string(char* s) : ptr(s) {} + i_string(const char* s) : ptr(s) {} }; /* needed for linked list of two strings for replicate-rewrite-db */ class i_string_pair: public ilink { public: - char* key; - char* val; + const char* key; + const char* val; i_string_pair():key(0),val(0) { } - i_string_pair(char* key_arg, char* val_arg) : key(key_arg),val(val_arg) {} + i_string_pair(const char* key_arg, const char* val_arg) : + key(key_arg),val(val_arg) {} }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e8cc445e123..981013479df 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -16,6 +16,7 @@ #include "mysql_priv.h" #include "sql_repl.h" +#include "rpl_filter.h" #include "repl_failsafe.h" #include <m_ctype.h> #include <myisam.h> @@ -167,10 +168,12 @@ static bool begin_trans(THD *thd) #ifdef HAVE_REPLICATION inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) { - return (table_rules_on && tables && !tables_ok(thd,tables) && + return (rpl_filter->is_on() && tables && + !rpl_filter->tables_ok(thd->db, tables) && ((thd->lex->sql_command != SQLCOM_DELETE_MULTI) || - !tables_ok(thd, - (TABLE_LIST *)thd->lex->auxilliary_table_list.first))); + !rpl_filter->tables_ok(thd->db, + (TABLE_LIST *) + thd->lex->auxilliary_table_list.first))); } #endif @@ -3441,9 +3444,9 @@ unsent_create_error: above was not called. So we have to check rules again here. */ #ifdef HAVE_REPLICATION - if (thd->slave_thread && - (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) || - !db_ok_with_wild_table(lex->name))) + if (thd->slave_thread && + (!rpl_filter->db_ok(lex->name) || + !rpl_filter->db_ok_with_wild_table(lex->name))) { my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); break; @@ -3471,8 +3474,8 @@ unsent_create_error: */ #ifdef HAVE_REPLICATION if (thd->slave_thread && - (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) || - !db_ok_with_wild_table(lex->name))) + (!rpl_filter->db_ok(lex->name) || + !rpl_filter->db_ok_with_wild_table(lex->name))) { my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); break; @@ -3511,8 +3514,8 @@ unsent_create_error: */ #ifdef HAVE_REPLICATION if (thd->slave_thread && - (!db_ok(db, replicate_do_db, replicate_ignore_db) || - !db_ok_with_wild_table(db))) + (!rpl_filter->db_ok(lex->name) || + !rpl_filter->db_ok_with_wild_table(lex->name))) { my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); break; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 634b6ab0995..b1e169b9427 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -19,6 +19,7 @@ #include "sql_repl.h" #include "log_event.h" +#include "rpl_filter.h" #include <my_dir.h> int max_binlog_dump_events = 0; // unlimited @@ -1429,8 +1430,8 @@ bool show_binlog_info(THD* thd) int dir_len = dirname_length(li.log_file_name); protocol->store(li.log_file_name + dir_len, &my_charset_bin); protocol->store((ulonglong) li.pos); - protocol->store(&binlog_do_db); - protocol->store(&binlog_ignore_db); + protocol->store(binlog_filter->get_do_db()); + protocol->store(binlog_filter->get_ignore_db()); if (protocol->write()) DBUG_RETURN(TRUE); } diff --git a/sql/sql_repl.h b/sql/sql_repl.h index 9eb6456ee20..eec85826da4 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -17,6 +17,9 @@ #ifdef HAVE_REPLICATION #include "slave.h" +extern Rpl_filter *binlog_filter; +extern Rpl_filter *rpl_filter; + typedef struct st_slave_info { uint32 server_id; @@ -31,7 +34,6 @@ typedef struct st_slave_info extern my_bool opt_show_slave_auth_info; extern char *master_host, *master_info_file; extern bool server_id_supplied; -extern I_List<i_string> binlog_do_db, binlog_ignore_db; extern int max_binlog_dump_events; extern my_bool opt_sporadic_binlog_dump_fail; |