From 809aacbbb367abc6ef4a2b401a87c862506682ae Mon Sep 17 00:00:00 2001 From: "petr/cps@mysql.com/owlet." <> Date: Thu, 20 Jul 2006 17:18:13 +0400 Subject: [PATCH 1/4] Bug#17599 The server doesn't give a warning when --log is specified but log table is used (recommit after docs reviewed the text of warnings) --- sql/mysqld.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 93ed663ae06..01778126c2a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2770,6 +2770,19 @@ static int init_common_variables(const char *conf_file_name, int argc, else sys_init_slave.value=my_strdup("",MYF(0)); + /* check log options and issue warnings if needed */ + if (opt_log && opt_logname && !(log_output_options & LOG_FILE) && + !(log_output_options & LOG_NONE)) + sql_print_warning("Although a path was specified for the " + "--log option, log tables are used. " + "To enable logging to file use the --log-output option."); + + if (opt_slow_log && opt_slow_logname && !(log_output_options & LOG_FILE) + && !(log_output_options & LOG_NONE)) + sql_print_warning("Although a path was specified for the " + "--log-slow-queries option, log tables are used. " + "To enable logging to file use the --log-output option."); + if (!opt_logname) opt_logname= make_default_log_name(buff, ".log"); sys_var_general_log_path.value= my_strdup(opt_logname, MYF(0)); From 7aec1205493b9093d4b49bd68aa3a9e40728d44a Mon Sep 17 00:00:00 2001 From: "petr/cps@mysql.com/owlet." <> Date: Thu, 3 Aug 2006 17:23:37 +0400 Subject: [PATCH 2/4] Fix Bug #20139 Infinite loop after "FLUSH" and "LOCK tabX, general_log" Due to incorrect handling of FLUSH TABLES, log tables were marked for flush, but not reopened. Later we started to wait for the log table to be closed (disabled) after the flush. And as nobody disabled logs in concurrent treads, the command lasted forever. After internal consultations it was decided to skip logs during FLUSH TABLES. The reasoning is that logging is done in the "log device", whatever it is which is always active and controlled by FLUSH LOGS. So, to flush logs one should use FLUSH LOGS, and not FLUSH TABLES. --- mysql-test/r/log_tables.result | 5 +++++ mysql-test/t/log_tables.test | 10 ++++++++++ sql/sql_base.cc | 18 +++++++++++------- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index c61dd2247ee..c817c2752a0 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -72,3 +72,8 @@ sleep(2) select * from mysql.slow_log; start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text TIMESTAMP USER_HOST QUERY_TIME 00:00:00 1 0 test 0 0 1 select sleep(2) +flush tables with read lock; +unlock tables; +use mysql; +lock tables general_log read local, help_category read local; +unlock tables; diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test index 5b79e5e4625..236ef87e948 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -171,6 +171,16 @@ select sleep(2); --replace_column 1 TIMESTAMP 2 USER_HOST 3 QUERY_TIME select * from mysql.slow_log; +# +# Bug #20139 Infinite loop after "FLUSH" and "LOCK tabX, general_log" +# + +flush tables with read lock; +unlock tables; +use mysql; +lock tables general_log read local, help_category read local; +unlock tables; + # kill all connections disconnect con1; disconnect con2; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index db11a3442c2..53ece79562a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1997,17 +1997,17 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length, &state)) { - if (table->s->version != refresh_version) + /* + Here we flush tables marked for flush. However we never flush log + tables here. They are flushed only on FLUSH LOGS. + */ + if (table->s->version != refresh_version && !table->s->log_table) { DBUG_PRINT("note", ("Found table '%s.%s' with different refresh version", table_list->db, table_list->table_name)); - /* - Don't close tables if we are working with a log table or were - asked not to close the table explicitly - */ - if (flags & MYSQL_LOCK_IGNORE_FLUSH || table->s->log_table) + if (flags & MYSQL_LOCK_IGNORE_FLUSH) { /* Force close at once after usage */ thd->version= table->s->version; @@ -2346,7 +2346,11 @@ void close_old_data_files(THD *thd, TABLE *table, bool abort_locks, for (; table ; table=table->next) { - if (table->s->version != refresh_version) + /* + Reopen marked for flush. But close log tables. They are flushed only + explicitly on FLUSH LOGS + */ + if (table->s->version != refresh_version && !table->s->log_table) { found=1; if (table->db_stat) From be2ce2614ba6a6840c4d57dae5e75bc1826424d1 Mon Sep 17 00:00:00 2001 From: "petr/cps@mysql.com/owlet." <> Date: Thu, 3 Aug 2006 21:28:15 +0400 Subject: [PATCH 3/4] 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 | 141 +++++++++++++++++++++++++++++++++ mysql-test/t/log_tables.test | 133 +++++++++++++++++++++++++++++++ sql/ha_myisam.cc | 9 +++ sql/handler.cc | 28 +++++++ sql/handler.h | 2 + sql/log.cc | 7 +- sql/log.h | 8 ++ sql/share/errmsg.txt | 6 ++ sql/sql_table.cc | 48 +++++++++++ storage/csv/ha_tina.cc | 24 +----- storage/myisam/mi_extra.c | 5 ++ storage/myisam/mi_open.c | 1 + storage/myisam/mi_write.c | 12 +++ storage/myisam/myisamdef.h | 3 + 14 files changed, 403 insertions(+), 24 deletions(-) diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index c61dd2247ee..f27e4cfc44f 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -72,3 +72,144 @@ sleep(2) select * from mysql.slow_log; start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text TIMESTAMP USER_HOST QUERY_TIME 00:00:00 1 0 test 0 0 1 select sleep(2) +alter table mysql.general_log engine=myisam; +ERROR HY000: You can't alter a log table if logging is enabled +alter table mysql.slow_log engine=myisam; +ERROR HY000: You can't alter a log table if logging is enabled +drop table mysql.general_log; +ERROR HY000: Cannot drop log table if log is enabled +drop table mysql.slow_log; +ERROR HY000: Cannot drop log table if log is enabled +set global general_log='OFF'; +alter table mysql.slow_log engine=myisam; +ERROR HY000: You can't alter a log table if logging is enabled +set global slow_query_log='OFF'; +show create table mysql.general_log; +Table Create Table +general_log CREATE TABLE `general_log` ( + `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext, + `thread_id` int(11) DEFAULT NULL, + `server_id` int(11) DEFAULT NULL, + `command_type` varchar(64) DEFAULT NULL, + `argument` mediumtext +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log' +show create table mysql.slow_log; +Table Create Table +slow_log CREATE TABLE `slow_log` ( + `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext NOT NULL, + `query_time` time NOT NULL, + `lock_time` time NOT NULL, + `rows_sent` int(11) NOT NULL, + `rows_examined` int(11) NOT NULL, + `db` varchar(512) DEFAULT NULL, + `last_insert_id` int(11) DEFAULT NULL, + `insert_id` int(11) DEFAULT NULL, + `server_id` int(11) DEFAULT NULL, + `sql_text` mediumtext NOT NULL +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log' +alter table mysql.general_log engine=myisam; +alter table mysql.slow_log engine=myisam; +Warnings: +Warning 1264 Out of range value for column 'last_insert_id' at row 0 +Warning 1264 Out of range value for column 'insert_id' at row 0 +show create table mysql.general_log; +Table Create Table +general_log CREATE TABLE `general_log` ( + `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext, + `thread_id` int(11) DEFAULT NULL, + `server_id` int(11) DEFAULT NULL, + `command_type` varchar(64) DEFAULT NULL, + `argument` mediumtext +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='General log' +show create table mysql.slow_log; +Table Create Table +slow_log CREATE TABLE `slow_log` ( + `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext NOT NULL, + `query_time` time NOT NULL, + `lock_time` time NOT NULL, + `rows_sent` int(11) NOT NULL, + `rows_examined` int(11) NOT NULL, + `db` varchar(512) DEFAULT NULL, + `last_insert_id` int(11) DEFAULT NULL, + `insert_id` int(11) DEFAULT NULL, + `server_id` int(11) DEFAULT NULL, + `sql_text` mediumtext NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Slow log' +set global general_log='ON'; +set global slow_query_log='ON'; +select * from mysql.general_log; +event_time user_host thread_id server_id command_type argument +TIMESTAMP USER_HOST THREAD_ID 1 Query set names utf8 +TIMESTAMP USER_HOST THREAD_ID 1 Query create table bug16905 (s char(15) character set utf8 default 'пусто') +TIMESTAMP USER_HOST THREAD_ID 1 Query insert into bug16905 values ('новое') +TIMESTAMP USER_HOST THREAD_ID 1 Query select * from mysql.general_log +TIMESTAMP USER_HOST THREAD_ID 1 Query drop table bug16905 +TIMESTAMP USER_HOST THREAD_ID 1 Query truncate table mysql.slow_log +TIMESTAMP USER_HOST THREAD_ID 1 Query set session long_query_time=1 +TIMESTAMP USER_HOST THREAD_ID 1 Query select sleep(2) +TIMESTAMP USER_HOST THREAD_ID 1 Query select * from mysql.slow_log +TIMESTAMP USER_HOST THREAD_ID 1 Query alter table mysql.general_log engine=myisam +TIMESTAMP USER_HOST THREAD_ID 1 Query alter table mysql.slow_log engine=myisam +TIMESTAMP USER_HOST THREAD_ID 1 Query drop table mysql.general_log +TIMESTAMP USER_HOST THREAD_ID 1 Query drop table mysql.slow_log +TIMESTAMP USER_HOST THREAD_ID 1 Query set global general_log='OFF' +TIMESTAMP USER_HOST THREAD_ID 1 Query set global slow_query_log='ON' +TIMESTAMP USER_HOST THREAD_ID 1 Query select * from mysql.general_log +flush logs; +lock tables mysql.general_log WRITE; +ERROR HY000: You can't write-lock a log table. Only read access is possible. +lock tables mysql.slow_log WRITE; +ERROR HY000: You can't write-lock a log table. Only read access is possible. +lock tables mysql.general_log READ; +ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead. +lock tables mysql.slow_log READ; +ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead. +lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL; +unlock tables; +set global general_log='OFF'; +set global slow_query_log='OFF'; +alter table mysql.slow_log engine=ndb; +ERROR HY000: One can use only CSV and MyISAM engines for the log tables +alter table mysql.slow_log engine=innodb; +ERROR HY000: One can use only CSV and MyISAM engines for the log tables +alter table mysql.slow_log engine=archive; +ERROR HY000: One can use only CSV and MyISAM engines for the log tables +alter table mysql.slow_log engine=blackhole; +ERROR HY000: One can use only CSV and MyISAM engines for the log tables +drop table mysql.slow_log; +drop table mysql.general_log; +drop table mysql.general_log; +ERROR 42S02: Unknown table 'general_log' +drop table mysql.slow_log; +ERROR 42S02: Unknown table 'slow_log' +use mysql; +CREATE TABLE `general_log` ( +`event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +ON UPDATE CURRENT_TIMESTAMP, +`user_host` mediumtext, +`thread_id` int(11) DEFAULT NULL, +`server_id` int(11) DEFAULT NULL, +`command_type` varchar(64) DEFAULT NULL, +`argument` mediumtext +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log'; +CREATE TABLE `slow_log` ( +`start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +ON UPDATE CURRENT_TIMESTAMP, +`user_host` mediumtext NOT NULL, +`query_time` time NOT NULL, +`lock_time` time NOT NULL, +`rows_sent` int(11) NOT NULL, +`rows_examined` int(11) NOT NULL, +`db` varchar(512) DEFAULT NULL, +`last_insert_id` int(11) DEFAULT NULL, +`insert_id` int(11) DEFAULT NULL, +`server_id` int(11) DEFAULT NULL, +`sql_text` mediumtext NOT NULL +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log'; +set global general_log='ON'; +set global slow_query_log='ON'; +use test; diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test index 5b79e5e4625..df88b13a225 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -171,6 +171,139 @@ select sleep(2); --replace_column 1 TIMESTAMP 2 USER_HOST 3 QUERY_TIME select * from mysql.slow_log; +# +# Bug #18559 log tables cannot change engine, and gets deadlocked when +# dropping w/ log on +# + +# check that appropriate error messages are given when one attempts to alter +# or drop a log tables, while corresponding logs are enabled +--error ER_CANT_ALTER_LOG_TABLE +alter table mysql.general_log engine=myisam; +--error ER_CANT_ALTER_LOG_TABLE +alter table mysql.slow_log engine=myisam; + +--error ER_CANT_DROP_LOG_TABLE +drop table mysql.general_log; +--error ER_CANT_DROP_LOG_TABLE +drop table mysql.slow_log; + +# check that one can alter log tables to MyISAM +set global general_log='OFF'; + +# cannot convert another log table +--error ER_CANT_ALTER_LOG_TABLE +alter table mysql.slow_log engine=myisam; + +# alter both tables +set global slow_query_log='OFF'; +# check that both tables use CSV engine +show create table mysql.general_log; +show create table mysql.slow_log; + +alter table mysql.general_log engine=myisam; +alter table mysql.slow_log engine=myisam; + +# check that the tables were converted +show create table mysql.general_log; +show create table mysql.slow_log; + +# enable log tables and chek that new tables indeed work +set global general_log='ON'; +set global slow_query_log='ON'; + +--replace_column 1 TIMESTAMP 2 USER_HOST 3 THREAD_ID +select * from mysql.general_log; + +# check that flush of myisam-based log tables work fine +flush logs; + +# check locking of myisam-based log tables + +--error ER_CANT_WRITE_LOCK_LOG_TABLE +lock tables mysql.general_log WRITE; + +--error ER_CANT_WRITE_LOCK_LOG_TABLE +lock tables mysql.slow_log WRITE; + +# +# This attemts to get TL_READ_NO_INSERT lock, which is incompatible with +# TL_WRITE_CONCURRENT_INSERT. This should fail. We issue this error as log +# tables are always opened and locked by the logger. +# + +--error ER_CANT_READ_LOCK_LOG_TABLE +lock tables mysql.general_log READ; + +--error ER_CANT_READ_LOCK_LOG_TABLE +lock tables mysql.slow_log READ; + +# +# This call should result in TL_READ lock on the log table. This is ok and +# should pass. +# + +lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL; + +unlock tables; + +# check that we can drop them +set global general_log='OFF'; +set global slow_query_log='OFF'; + +# check that alter table doesn't work for other engines +--error ER_BAD_LOG_ENGINE +alter table mysql.slow_log engine=ndb; +--error ER_BAD_LOG_ENGINE +alter table mysql.slow_log engine=innodb; +--error ER_BAD_LOG_ENGINE +alter table mysql.slow_log engine=archive; +--error ER_BAD_LOG_ENGINE +alter table mysql.slow_log engine=blackhole; + +drop table mysql.slow_log; +drop table mysql.general_log; + +# check that table share cleanup is performed correctly (double drop) + +--error ER_BAD_TABLE_ERROR +drop table mysql.general_log; +--error ER_BAD_TABLE_ERROR +drop table mysql.slow_log; + +# recreate tables and enable logs + +use mysql; + +CREATE TABLE `general_log` ( + `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP + ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext, + `thread_id` int(11) DEFAULT NULL, + `server_id` int(11) DEFAULT NULL, + `command_type` varchar(64) DEFAULT NULL, + `argument` mediumtext +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log'; + +CREATE TABLE `slow_log` ( + `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP + ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext NOT NULL, + `query_time` time NOT NULL, + `lock_time` time NOT NULL, + `rows_sent` int(11) NOT NULL, + `rows_examined` int(11) NOT NULL, + `db` varchar(512) DEFAULT NULL, + `last_insert_id` int(11) DEFAULT NULL, + `insert_id` int(11) DEFAULT NULL, + `server_id` int(11) DEFAULT NULL, + `sql_text` mediumtext NOT NULL +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log'; + +set global general_log='ON'; +set global slow_query_log='ON'; +use test; + # kill all connections disconnect con1; disconnect con2; 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))) { diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 6bd8447720c..1b5098a7519 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -817,27 +817,9 @@ bool ha_tina::check_if_locking_is_allowed(uint sql_command, uint count, bool called_by_logger_thread) { - /* - 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_FLUSH && - type & REFRESH_LOG) && - !called_by_logger_thread && - (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; - } + if (!called_by_logger_thread) + return check_if_log_table_locking_is_allowed(sql_command, type, table); + return TRUE; } diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c index c1ed29c4734..93fe4ed5d52 100644 --- a/storage/myisam/mi_extra.c +++ b/storage/myisam/mi_extra.c @@ -366,6 +366,11 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) pthread_mutex_unlock(&share->intern_lock); #endif break; + case HA_EXTRA_MARK_AS_LOG_TABLE: + pthread_mutex_lock(&share->intern_lock); + share->is_log_table= TRUE; + pthread_mutex_unlock(&share->intern_lock); + break; case HA_EXTRA_KEY_CACHE: case HA_EXTRA_NO_KEY_CACHE: default: diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c index b61c1af24da..1675c596860 100644 --- a/storage/myisam/mi_open.c +++ b/storage/myisam/mi_open.c @@ -489,6 +489,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) share->data_file_type = DYNAMIC_RECORD; my_afree((gptr) disk_cache); mi_setup_functions(share); + share->is_log_table= FALSE; #ifdef THREAD thr_lock_init(&share->lock); VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST)); diff --git a/storage/myisam/mi_write.c b/storage/myisam/mi_write.c index 9ab8753f6d7..f16d9471afe 100644 --- a/storage/myisam/mi_write.c +++ b/storage/myisam/mi_write.c @@ -163,6 +163,18 @@ int mi_write(MI_INFO *info, byte *record) (*info->invalidator)(info->filename); info->invalidator=0; } + + /* + Update status of the table. We need to do so after each row write + for the log tables, as we want the new row to become visible to + other threads as soon as possible. We lock mutex here to follow + pthread memory visibility rules. + */ + pthread_mutex_lock(&share->intern_lock); + if (share->is_log_table) + mi_update_status((void*) info); + pthread_mutex_unlock(&share->intern_lock); + allow_break(); /* Allow SIGHUP & SIGINT */ DBUG_RETURN(0); diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h index baab34b4b67..765e26dc74d 100644 --- a/storage/myisam/myisamdef.h +++ b/storage/myisam/myisamdef.h @@ -201,6 +201,9 @@ typedef struct st_mi_isam_share { /* Shared between opens */ uint blocksize; /* blocksize of keyfile */ myf write_flag; enum data_file_type data_file_type; + /* Below flag is needed to make log tables work with concurrent insert */ + my_bool is_log_table; + my_bool changed, /* If changed since lock */ global_changed, /* If changed since open */ not_flushed, From 5431ecb593b1eff9d71b629b638d65458d286a4d Mon Sep 17 00:00:00 2001 From: "petr/cps@mysql.com/owlet." <> Date: Tue, 8 Aug 2006 12:03:24 +0400 Subject: [PATCH 4/4] Fix windows pushbuild failure: the bug occured because we didn't check for NULL value of the lex_create_info->db_type pointer. The pointer is NULL in the case, when the engine name is unknown to the server. This happens with NDB on Windows. --- sql/sql_table.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3e218f7d33e..5325758fd12 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5043,8 +5043,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, /* 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 || /* unknown engine */ !(lex_create_info->db_type->db_type == DB_TYPE_MYISAM || - lex_create_info->db_type->db_type == DB_TYPE_CSV_DB)) + lex_create_info->db_type->db_type == DB_TYPE_CSV_DB))) { my_error(ER_BAD_LOG_ENGINE, MYF(0)); DBUG_RETURN(TRUE);