diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index c61dd2247ee..8b0a5ea6a20 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -72,3 +72,149 @@ 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; +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..97c83310b4d 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -171,6 +171,149 @@ 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; + +# +# 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/ha_myisam.cc b/sql/ha_myisam.cc index 2acc1f4ed7d..565010a1889 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 0804f23f51e..fbccfe7fa46 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1423,6 +1423,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 ddcd6f860a7..201a2f1980a 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/mysqld.cc b/sql/mysqld.cc index a8fcee4cce3..087613c6b7c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2771,6 +2771,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)); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a5fefc38c59..64cf018e03b 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5843,3 +5843,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_base.cc b/sql/sql_base.cc index e40b9721911..dbe7f5b5083 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) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 945fac83ff2..5325758fd12 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)) @@ -5003,6 +5015,43 @@ 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 || /* unknown 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,