diff options
author | unknown <petr/cps@mysql.com/owlet.> | 2006-08-03 21:28:15 +0400 |
---|---|---|
committer | unknown <petr/cps@mysql.com/owlet.> | 2006-08-03 21:28:15 +0400 |
commit | 157c42de9713618c23116079f634fa8b54fd403e (patch) | |
tree | cb952c4fb976588566dd3442e145ab59847f7c7c /sql | |
parent | d090462abc2925a22a4d2dee4c87d679a9ad32f1 (diff) | |
download | mariadb-git-157c42de9713618c23116079f634fa8b54fd403e.tar.gz |
Fix Bug #18559 "log tables cannot change engine, and
gets deadlocked when dropping w/ log on"
Log tables rely on concurrent insert machinery to add data.
This means that log tables are always opened and locked by
special (artificial) logger threads. Because of this, the thread
which tries to drop a log table starts to wait for the table
to be unlocked. Which will happen only if the log table is disabled.
Alike situation happens if one tries to alter a log table.
However in addition to the problem above, alter table calls
check_if_locking_is_allowed() routine for the engine. The
routine does not allow alter for the log tables. So, alter
doesn't start waiting forever for logs to be disabled, but
returns with an error.
Another problem is that not all engines could be used for
the log tables. That's because they need concurrent insert.
In this patch we:
(1) Explicitly disallow to drop/alter a log table if it
is currently used by the logger.
(2) Update MyISAM to support log tables
(3) Allow to drop log tables/alter log tables if log is
disabled
At the same time we (4) Disallow to alter log tables to
unsupported engine (after this patch CSV and MyISAM are
alowed)
Recommit with review fixes.
mysql-test/r/log_tables.result:
Update result file.
Note: there are warnings in result file. This is because of CSV
bug (Bug #21328). They should go away after it is fixed.
mysql-test/t/log_tables.test:
Add a test for the bug
sql/ha_myisam.cc:
Add log table handling to myisam: as log tables
use concurrent insert, they are typically
locked with TL_CONCURRERENT_INSERT lock. So,
disallow other threads to attempt locking of
the log tables in incompatible modes. Because
otherwise the threads will wait for the tables
to be unlocked forever.
sql/handler.cc:
Add a function to check if a table we're going to lock
is a log table and if the lock mode we want allowed
sql/handler.h:
Add a new function to check compatibility of the locking
sql/log.cc:
we shouldn't close the log table if and only
if this particular table is already closed
sql/log.h:
add new functions to check if a log is enabled
sql/share/errmsg.txt:
add new error messages
sql/sql_table.cc:
DROP and ALTER TABLE should not work on log
tables if the log tables are enabled
storage/csv/ha_tina.cc:
move function to check if the locking for the log
tables allowed to handler class, so that we can
reuse it in other engines.
storage/myisam/mi_extra.c:
add new ::extra() flag processing to myisam
storage/myisam/mi_open.c:
init log table flag
storage/myisam/mi_write.c:
update status after each write if it's a log table
storage/myisam/myisamdef.h:
Add new log table flag to myisam share.
We need it to distinguish between usual
and log tables, as for the log tables we
should provide concurrent insert in a
different way than for usual tables: we
want new rows to be immediately visible
to other threads.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_myisam.cc | 9 | ||||
-rw-r--r-- | sql/handler.cc | 28 | ||||
-rw-r--r-- | sql/handler.h | 2 | ||||
-rw-r--r-- | sql/log.cc | 7 | ||||
-rw-r--r-- | sql/log.h | 8 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 6 | ||||
-rw-r--r-- | sql/sql_table.cc | 48 |
7 files changed, 105 insertions, 3 deletions
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 2d097c34f97..8aa17bdbaa6 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -274,6 +274,15 @@ bool ha_myisam::check_if_locking_is_allowed(uint sql_command, table->s->table_name.str); return FALSE; } + + /* + Deny locking of the log tables, which is incompatible with + concurrent insert. Unless called from a logger THD: + general_log_thd or slow_log_thd. + */ + if (!called_by_logger_thread) + return check_if_log_table_locking_is_allowed(sql_command, type, table); + return TRUE; } diff --git a/sql/handler.cc b/sql/handler.cc index b356102a61a..754b0996d77 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1422,6 +1422,34 @@ void handler::ha_statistic_increment(ulong SSV::*offset) const statistic_increment(table->in_use->status_var.*offset, &LOCK_status); } + +bool handler::check_if_log_table_locking_is_allowed(uint sql_command, + ulong type, TABLE *table) +{ + /* + Deny locking of the log tables, which is incompatible with + concurrent insert. Unless called from a logger THD: + general_log_thd or slow_log_thd. + */ + if (table->s->log_table && + sql_command != SQLCOM_TRUNCATE && + sql_command != SQLCOM_ALTER_TABLE && + !(sql_command == SQLCOM_FLUSH && + type & REFRESH_LOG) && + (table->reginfo.lock_type >= TL_READ_NO_INSERT)) + { + /* + The check >= TL_READ_NO_INSERT denies all write locks + plus the only read lock (TL_READ_NO_INSERT itself) + */ + table->reginfo.lock_type == TL_READ_NO_INSERT ? + my_error(ER_CANT_READ_LOCK_LOG_TABLE, MYF(0)) : + my_error(ER_CANT_WRITE_LOCK_LOG_TABLE, MYF(0)); + return FALSE; + } + return TRUE; +} + /* Open database-handler. diff --git a/sql/handler.h b/sql/handler.h index 3c090b887a3..d4a62fb1e82 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -974,6 +974,8 @@ public: { return TRUE; } + bool check_if_log_table_locking_is_allowed(uint sql_command, + ulong type, TABLE *table); int ha_open(TABLE *table, const char *name, int mode, int test_if_locked); void adjust_next_insert_id_after_explicit_value(ulonglong nr); bool update_auto_increment(); diff --git a/sql/log.cc b/sql/log.cc index dba4b65efd9..b93d36cf630 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1106,15 +1106,16 @@ void Log_to_csv_event_handler:: THD *log_thd, *curr= current_thd; TABLE_LIST *table; - if (!logger.is_log_tables_initialized) - return; /* do nothing */ - switch (log_table_type) { case QUERY_LOG_GENERAL: + if (!logger.is_general_log_table_enabled()) + return; /* do nothing */ log_thd= general_log_thd; table= &general_log; break; case QUERY_LOG_SLOW: + if (!logger.is_slow_log_table_enabled()) + return; /* do nothing */ log_thd= slow_log_thd; table= &slow_log; break; diff --git a/sql/log.h b/sql/log.h index b4818a370d7..d598952a853 100644 --- a/sql/log.h +++ b/sql/log.h @@ -497,6 +497,14 @@ public: {} void lock() { (void) pthread_mutex_lock(&LOCK_logger); } void unlock() { (void) pthread_mutex_unlock(&LOCK_logger); } + bool is_general_log_table_enabled() + { + return table_log_handler && table_log_handler->general_log.table != 0; + } + bool is_slow_log_table_enabled() + { + return table_log_handler && table_log_handler->slow_log.table != 0; + } /* We want to initialize all log mutexes as soon as possible, but we cannot do it in constructor, as safe_mutex relies on diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 75aba522543..e0f6a463ad8 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5841,3 +5841,9 @@ ER_RBR_NOT_AVAILABLE eng "The server was not built with row-based replication" ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA eng "Triggers can not be created on system tables" +ER_CANT_ALTER_LOG_TABLE + eng "You can't alter a log table if logging is enabled" +ER_BAD_LOG_ENGINE + eng "One can use only CSV and MyISAM engines for the log tables" +ER_CANT_DROP_LOG_TABLE + eng "Cannot drop log table if log is enabled" diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ccddefab421..c0c88039051 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1537,6 +1537,18 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, table->db_type= NULL; if ((share= get_cached_table_share(table->db, table->table_name))) table->db_type= share->db_type; + + /* Disable drop of enabled log tables */ + if (share && share->log_table && + ((!my_strcasecmp(system_charset_info, table->table_name, + "general_log") && opt_log && + logger.is_general_log_table_enabled()) || + (!my_strcasecmp(system_charset_info, table->table_name, "slow_log") + && opt_slow_log && logger.is_slow_log_table_enabled()))) + { + my_error(ER_CANT_DROP_LOG_TABLE, MYF(0)); + DBUG_RETURN(1); + } } if (lock_table_names(thd, tables)) @@ -4991,6 +5003,42 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, LINT_INIT(index_add_buffer); LINT_INIT(index_drop_buffer); + if (table_list && table_list->db && + !my_strcasecmp(system_charset_info, table_list->db, "mysql") && + table_list->table_name) + { + enum enum_table_kind { NOT_LOG_TABLE= 1, GENERAL_LOG, SLOW_LOG } + table_kind= NOT_LOG_TABLE; + + if (!my_strcasecmp(system_charset_info, table_list->table_name, + "general_log")) + table_kind= GENERAL_LOG; + else + if (!my_strcasecmp(system_charset_info, table_list->table_name, + "slow_log")) + table_kind= SLOW_LOG; + + /* Disable alter of enabled log tables */ + if ((table_kind == GENERAL_LOG && opt_log && + logger.is_general_log_table_enabled()) || + (table_kind == SLOW_LOG && opt_slow_log && + logger.is_slow_log_table_enabled())) + { + my_error(ER_CANT_ALTER_LOG_TABLE, MYF(0)); + DBUG_RETURN(TRUE); + } + + /* Disable alter of log tables to unsupported engine */ + if ((table_kind == GENERAL_LOG || table_kind == SLOW_LOG) && + (lex_create_info->used_fields & HA_CREATE_USED_ENGINE) && + !(lex_create_info->db_type->db_type == DB_TYPE_MYISAM || + lex_create_info->db_type->db_type == DB_TYPE_CSV_DB)) + { + my_error(ER_BAD_LOG_ENGINE, MYF(0)); + DBUG_RETURN(TRUE); + } + } + thd->proc_info="init"; if (!(create_info= copy_create_info(lex_create_info))) { |