mirror of
https://github.com/MariaDB/server.git
synced 2025-07-18 23:03:28 +03:00
There are two problems. First, replication fails when XA transactions are used where the slave has replicate_do_db set and the client has touched a different database when running DML such as inserts. This is because XA commands are not treated as keywords, and are thereby not exempt from the replication filter. The effect of this is that during an XA transaction, if its logged “use db” from the master is filtered out by the replication filter, then XA END will be ignored, yet its corresponding XA PREPARE will be executed in an invalid state, thereby breaking replication. Second, if the slave replicates an XA transaction which results in an empty transaction, the XA START through XA PREPARE first phase of the transaction won’t be binlogged, yet the XA COMMIT will be binlogged. This will break replication in chain configurations. The first problem is fixed by treating XA commands in Query_log_event as keywords, thus allowing them to bypass the replication filter. Note that Query_log_event::is_trans_keyword() is changed to accept a new parameter to define its mode, to either check for XA commands or regular transaction commands, but not both. In addition, mysqlbinlog is adapted to use this mode so its --database filter does not remove XA commands from its output. The second problem fixed by overwriting the XA state in the XID cache to be XA_ROLLBACK_ONLY, so at commit time, the server knows to rollback the transaction and skip its binlogging. If the xid cache is cleared before an XA transaction receives its completion command (e.g. on server shutdown), then before reporting ER_XAER_NOTA when the completion command is executed, the filter is first checked if the database is ignored, and if so, the error is ignored. Reviewed By: ============ Kristian Nielsen <knielsen@knielsen-hq.org> Andrei Elkin <andrei.elkin@mariadb.com>
160 lines
4.4 KiB
C++
160 lines
4.4 KiB
C++
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
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; version 2 of the License.
|
|
|
|
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
#ifndef RPL_FILTER_H
|
|
#define RPL_FILTER_H
|
|
|
|
#include "mysql.h"
|
|
#include "mysqld.h"
|
|
#include "sql_list.h" /* I_List */
|
|
#include "hash.h" /* HASH */
|
|
|
|
class String;
|
|
struct TABLE_LIST;
|
|
typedef struct st_dynamic_array DYNAMIC_ARRAY;
|
|
|
|
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 */
|
|
|
|
#ifndef MYSQL_CLIENT
|
|
bool tables_ok(const char* db, TABLE_LIST *tables);
|
|
#endif
|
|
bool db_ok(const char* db);
|
|
bool db_ok_with_wild_table(const char *db);
|
|
|
|
bool is_on();
|
|
bool is_db_empty();
|
|
|
|
/* Setters - add filtering rules */
|
|
|
|
int add_do_table(const char* table_spec);
|
|
int add_ignore_table(const char* table_spec);
|
|
|
|
int set_do_table(const char* table_spec);
|
|
int set_ignore_table(const char* table_spec);
|
|
|
|
int add_wild_do_table(const char* table_spec);
|
|
int add_wild_ignore_table(const char* table_spec);
|
|
|
|
int set_wild_do_table(const char* table_spec);
|
|
int set_wild_ignore_table(const char* table_spec);
|
|
|
|
int add_do_db(const char* db_spec);
|
|
int add_ignore_db(const char* db_spec);
|
|
|
|
int set_do_db(const char* db_spec);
|
|
int set_ignore_db(const char* db_spec);
|
|
|
|
void set_parallel_mode(enum_slave_parallel_mode mode)
|
|
{
|
|
parallel_mode= mode;
|
|
}
|
|
/* Return given parallel mode or if one is not given, the default mode */
|
|
enum_slave_parallel_mode get_parallel_mode()
|
|
{
|
|
return parallel_mode;
|
|
}
|
|
|
|
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);
|
|
|
|
bool rewrite_db_is_empty();
|
|
const char* get_rewrite_db(const char* db, size_t *new_len);
|
|
void copy_rewrite_db(Rpl_filter *from);
|
|
|
|
I_List<i_string>* get_do_db();
|
|
I_List<i_string>* get_ignore_db();
|
|
|
|
void get_do_db(String* str);
|
|
void get_ignore_db(String* str);
|
|
|
|
private:
|
|
|
|
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);
|
|
|
|
typedef int (Rpl_filter::*Add_filter)(char const*);
|
|
|
|
int parse_filter_rule(const char* spec, Add_filter func);
|
|
|
|
void free_string_array(DYNAMIC_ARRAY *a);
|
|
void free_string_list(I_List<i_string> *l);
|
|
|
|
void table_rule_ent_hash_to_str(String* s, HASH* h, bool inited);
|
|
void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
|
|
bool inited);
|
|
void db_rule_ent_list_to_str(String* s, I_List<i_string>* l);
|
|
TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len);
|
|
|
|
int add_string_list(I_List<i_string> *list, const char* spec);
|
|
|
|
/*
|
|
Those 4 structures below are uninitialized memory unless the
|
|
corresponding *_inited variables are "true".
|
|
*/
|
|
HASH do_table;
|
|
HASH ignore_table;
|
|
DYNAMIC_ARRAY wild_do_table;
|
|
DYNAMIC_ARRAY wild_ignore_table;
|
|
enum_slave_parallel_mode parallel_mode;
|
|
|
|
bool table_rules_on;
|
|
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;
|
|
};
|
|
|
|
extern Rpl_filter *global_rpl_filter;
|
|
extern Rpl_filter *binlog_filter;
|
|
|
|
#endif // RPL_FILTER_H
|