Commit 83f8e172 authored by mats@romeo.(none)'s avatar mats@romeo.(none)

BUG#18581 (Creation of system tables recorded in binlog causing slave failure):

Not replicating the mysql database *at all* any more. All changes to
mysql tables are replicated by replicating the statements that do
the changes.
parent d728519d
...@@ -23,6 +23,8 @@ password<>_binary'' ...@@ -23,6 +23,8 @@ password<>_binary''
delete from mysql.user where user=_binary'rpl_do_grant'; delete from mysql.user where user=_binary'rpl_do_grant';
delete from mysql.db where user=_binary'rpl_do_grant'; delete from mysql.db where user=_binary'rpl_do_grant';
flush privileges; flush privileges;
delete from mysql.user where user=_binary'rpl_do_grant';
delete from mysql.db where user=_binary'rpl_do_grant';
flush privileges; flush privileges;
show grants for rpl_do_grant@localhost; show grants for rpl_do_grant@localhost;
ERROR 42000: There is no such grant defined for user 'rpl_do_grant' on host 'localhost' ERROR 42000: There is no such grant defined for user 'rpl_do_grant' on host 'localhost'
......
...@@ -39,11 +39,11 @@ connection master; ...@@ -39,11 +39,11 @@ connection master;
delete from mysql.user where user=_binary'rpl_do_grant'; delete from mysql.user where user=_binary'rpl_do_grant';
delete from mysql.db where user=_binary'rpl_do_grant'; delete from mysql.db where user=_binary'rpl_do_grant';
flush privileges; flush privileges;
save_master_pos; sync_slave_with_master;
connection slave; # The mysql database is not replicated, so we have to do the deletes
sync_with_master; # manually on the slave as well.
# no need to delete manually, as the DELETEs must have done some real job on delete from mysql.user where user=_binary'rpl_do_grant';
# master (updated binlog) delete from mysql.db where user=_binary'rpl_do_grant';
flush privileges; flush privileges;
# End of 4.1 tests # End of 4.1 tests
......
...@@ -3456,38 +3456,15 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) ...@@ -3456,38 +3456,15 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
declared static, but it works by putting it into an anonymous declared static, but it works by putting it into an anonymous
namespace. */ namespace. */
namespace { namespace {
struct st_table_data {
char const *db;
char const *name;
};
static int table_name_compare(void const *a, void const *b)
{
st_table_data const *x = (st_table_data const*) a;
st_table_data const *y = (st_table_data const*) b;
/* Doing lexical compare in order (db,name) */
int const res= strcmp(x->db, y->db);
return res != 0 ? res : strcmp(x->name, y->name);
}
bool check_table_binlog_row_based(THD *thd, TABLE *table) bool check_table_binlog_row_based(THD *thd, TABLE *table)
{ {
static st_table_data const ignore[] = {
{ "mysql", "event" },
{ "mysql", "general_log" },
{ "mysql", "slow_log" }
};
my_size_t const ignore_size = sizeof(ignore)/sizeof(*ignore);
st_table_data const item = { table->s->db.str, table->s->table_name.str };
if (table->s->cached_row_logging_check == -1) if (table->s->cached_row_logging_check == -1)
table->s->cached_row_logging_check= {
(table->s->tmp_table == NO_TMP_TABLE) && int const check(table->s->tmp_table == NO_TMP_TABLE &&
binlog_filter->db_ok(table->s->db.str) && binlog_filter->db_ok(table->s->db.str) &&
bsearch(&item, ignore, ignore_size, strcmp("mysql", table->s->db.str) != 0);
sizeof(st_table_data), table_name_compare) == NULL; table->s->cached_row_logging_check= check;
}
DBUG_ASSERT(table->s->cached_row_logging_check == 0 || DBUG_ASSERT(table->s->cached_row_logging_check == 0 ||
table->s->cached_row_logging_check == 1); table->s->cached_row_logging_check == 1);
......
...@@ -5694,7 +5694,6 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) ...@@ -5694,7 +5694,6 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global) for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
{ {
rli->m_table_map.set_table(ptr->table_id, ptr->table); rli->m_table_map.set_table(ptr->table_id, ptr->table);
rli->touching_table(ptr->db, ptr->table_name, ptr->table_id);
} }
#ifdef HAVE_QUERY_CACHE #ifdef HAVE_QUERY_CACHE
query_cache.invalidate_locked_for_write(rli->tables_to_lock); query_cache.invalidate_locked_for_write(rli->tables_to_lock);
......
...@@ -289,22 +289,6 @@ typedef struct st_relay_log_info ...@@ -289,22 +289,6 @@ typedef struct st_relay_log_info
void cached_charset_invalidate(); void cached_charset_invalidate();
bool cached_charset_compare(char *charset); bool cached_charset_compare(char *charset);
/*
To reload special tables when they are changes, we introduce a set
of functions that will mark whenever special functions need to be
called after modifying tables. Right now, the tables are either
ACL tables or grants tables.
*/
enum enum_reload_flag
{
RELOAD_NONE_F = 0UL,
RELOAD_GRANT_F = (1UL << 0),
RELOAD_ACCESS_F = (1UL << 1)
};
ulong m_reload_flags;
void touching_table(char const* db, char const* table, ulong table_id);
void transaction_end(THD*); void transaction_end(THD*);
void cleanup_context(THD *, bool); void cleanup_context(THD *, bool);
......
...@@ -2373,7 +2373,6 @@ st_relay_log_info::st_relay_log_info() ...@@ -2373,7 +2373,6 @@ st_relay_log_info::st_relay_log_info()
inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE), inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
until_log_pos(0), retried_trans(0), until_log_pos(0), retried_trans(0),
tables_to_lock(0), tables_to_lock_count(0), tables_to_lock(0), tables_to_lock_count(0),
m_reload_flags(RELOAD_NONE_F),
unsafe_to_stop_at(0) unsafe_to_stop_at(0)
{ {
DBUG_ENTER("st_relay_log_info::st_relay_log_info"); DBUG_ENTER("st_relay_log_info::st_relay_log_info");
...@@ -4989,87 +4988,12 @@ end: ...@@ -4989,87 +4988,12 @@ end:
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/*
Some system tables needed to be re-read by the MySQL server after it has
updated them; in statement-based replication, the GRANT and other commands
are sent verbatim to the slave which then reloads; in row-based replication,
changes to these tables are done through ordinary Rows binlog events, so
master must add some flag for the slave to know it has to reload the tables.
*/
struct st_reload_entry
{
char const *table;
st_relay_log_info::enum_reload_flag flag;
};
/*
Sorted array of table names, please keep it sorted since we are
using bsearch() on it below.
*/
static st_reload_entry s_mysql_tables[] =
{
{ "columns_priv", st_relay_log_info::RELOAD_GRANT_F },
{ "db", st_relay_log_info::RELOAD_ACCESS_F },
{ "host", st_relay_log_info::RELOAD_ACCESS_F },
{ "procs_priv", st_relay_log_info::RELOAD_GRANT_F },
{ "tables_priv", st_relay_log_info::RELOAD_GRANT_F },
{ "user", st_relay_log_info::RELOAD_ACCESS_F }
};
static const my_size_t s_mysql_tables_size =
sizeof(s_mysql_tables)/sizeof(*s_mysql_tables);
static int reload_entry_compare(const void *lhs, const void *rhs)
{
const char *lstr = static_cast<const char *>(lhs);
const char *rstr = static_cast<const st_reload_entry*>(rhs)->table;
DBUG_ENTER("reload_entry_compare");
DBUG_RETURN(strcmp(lstr, rstr));
}
void st_relay_log_info::touching_table(char const* db, char const* table,
ulong table_id)
{
DBUG_ENTER("st_relay_log_info::touching_table");
if (strcmp(db,"mysql") == 0)
{
#if defined(HAVE_BSEARCH) && defined(HAVE_SIZE_T)
void *const ptr= bsearch(table, s_mysql_tables,
s_mysql_tables_size,
sizeof(*s_mysql_tables), reload_entry_compare);
st_reload_entry const *const entry= static_cast<st_reload_entry*>(ptr);
#else
/*
Fall back to full scan, there are few rows anyway and updating the
"mysql" database is rare.
*/
st_reload_entry const *entry= s_mysql_tables;
for ( ; entry < s_mysql_tables + s_mysql_tables_size ; entry++)
if (reload_entry_compare(table, entry) == 0)
break;
#endif
if (entry)
m_reload_flags|= entry->flag;
}
DBUG_VOID_RETURN;
}
void st_relay_log_info::transaction_end(THD* thd) void st_relay_log_info::transaction_end(THD* thd)
{ {
DBUG_ENTER("st_relay_log_info::transaction_end"); DBUG_ENTER("st_relay_log_info::transaction_end");
/*
if (m_reload_flags != RELOAD_NONE_F) Nothing to do here. Maybe remove the function?
{ */
if (m_reload_flags & RELOAD_ACCESS_F)
acl_reload(thd);
if (m_reload_flags & RELOAD_GRANT_F)
grant_reload(thd);
m_reload_flags= RELOAD_NONE_F;
}
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -2778,6 +2778,12 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, ...@@ -2778,6 +2778,12 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype,
#endif /*HAVE_ROW_BASED_REPLICATION*/ #endif /*HAVE_ROW_BASED_REPLICATION*/
switch (qtype) { switch (qtype) {
case THD::ROW_QUERY_TYPE:
#ifdef HAVE_ROW_BASED_REPLICATION
if (current_stmt_binlog_row_based)
DBUG_RETURN(0);
#endif
/* Otherwise, we fall through */
case THD::MYSQL_QUERY_TYPE: case THD::MYSQL_QUERY_TYPE:
/* /*
Using this query type is a conveniece hack, since we have been Using this query type is a conveniece hack, since we have been
...@@ -2787,12 +2793,6 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, ...@@ -2787,12 +2793,6 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype,
Make sure to change in check_table_binlog_row_based() according Make sure to change in check_table_binlog_row_based() according
to how you treat this. to how you treat this.
*/ */
case THD::ROW_QUERY_TYPE:
#ifdef HAVE_ROW_BASED_REPLICATION
if (current_stmt_binlog_row_based)
DBUG_RETURN(0);
#endif
/* Otherwise, we fall through */
case THD::STMT_QUERY_TYPE: case THD::STMT_QUERY_TYPE:
/* /*
The MYSQL_LOG::write() function will set the STMT_END_F flag and The MYSQL_LOG::write() function will set the STMT_END_F flag and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment