From 0c4e184bdec77d15d055c868aea04d504bd5ae5d Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 19 Jun 2006 18:30:55 +0500 Subject: [PATCH] WL#3015: Logging Improvements - No Restarts(ver N4) Added slow_query_log & general_log global upadatable variables. Added slow-query-log & general-log startup options. Added log_output, general_log_file, slow_query_log_file global updatable variables. mysql-test/r/show_check.result: WL#3015: Logging Improvements - No Restarts result fix sql/log.cc: WL#3015: Logging Improvements - No Restarts added methods to LOGGER class void deactivate_log_handlers(THD* thd, uint log_type); bool activate_log_handlers(THD* thd, uint log_type); added methods to Log_to_file_event_handler: TABLE_LIST *get_mysql_slow_log() TABLE_LIST *get_mysql_log() sql/log.h: WL#3015: Logging Improvements - No Restarts added methods to LOGGER class void deactivate_log_handlers(THD* thd, uint log_type); bool activate_log_handlers(THD* thd, uint log_type); added methods to Log_to_file_event_handler: TABLE_LIST *get_mysql_slow_log() TABLE_LIST *get_mysql_log() sql/mysql_priv.h: WL#3015: Logging Improvements - No Restarts sql/mysqld.cc: WL#3015: Logging Improvements - No Restarts added 'slow-query-log' & 'general-log' options sql/set_var.cc: WL#3015: Logging Improvements - No Restarts added 'slow_query_log' & 'general_log' updatable variables added 'log_output', 'general_log_file', 'slow_query_log_file' updatable variables sql/set_var.h: WL#3015: Logging Improvements - No Restarts new class sys_var_log_state new class sys_var_log_output sql/share/errmsg.txt: WL#3015: Logging Improvements - No Restarts added error message sql/sql_delete.cc: WL#3015: Logging Improvements - No Restarts 'truncate table slow_log|general', keep status of logs --- mysql-test/r/log_state.result | 155 +++++++++++++++++++++ mysql-test/r/show_check.result | 22 ++- mysql-test/t/log_state-master.opt | 1 + mysql-test/t/log_state.test | 122 +++++++++++++++++ sql/log.cc | 193 +++++++++++++++++++++----- sql/log.h | 19 ++- sql/mysql_priv.h | 8 +- sql/mysqld.cc | 38 +++++- sql/set_var.cc | 216 ++++++++++++++++++++++++++++++ sql/set_var.h | 36 ++++- sql/share/errmsg.txt | 2 + sql/sql_delete.cc | 10 +- 12 files changed, 757 insertions(+), 65 deletions(-) create mode 100644 mysql-test/r/log_state.result create mode 100644 mysql-test/t/log_state-master.opt create mode 100644 mysql-test/t/log_state.test diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result new file mode 100644 index 00000000000..df81f05fea5 --- /dev/null +++ b/mysql-test/r/log_state.result @@ -0,0 +1,155 @@ +set global general_log= OFF; +truncate table mysql.general_log; +truncate table mysql.slow_log; +show global variables +where Variable_name = 'log' or Variable_name = 'log_slow_queries' or +Variable_name = 'general_log' or Variable_name = 'slow_query_log'; +Variable_name Value +general_log OFF +log OFF +log_slow_queries OFF +slow_query_log OFF +flush logs; +set global general_log= ON; +create table t1(f1 int); +select * from mysql.general_log; +event_time user_host thread_id server_id command_type argument +TIMESTAMP root[root] @ localhost [] # 1 Query create table t1(f1 int) +TIMESTAMP root[root] @ localhost [] # 1 Query select * from mysql.general_log +set global general_log= OFF; +drop table t1; +select * from mysql.general_log; +event_time user_host thread_id server_id command_type argument +TIMESTAMP root[root] @ localhost [] # 1 Query create table t1(f1 int) +TIMESTAMP root[root] @ localhost [] # 1 Query select * from mysql.general_log +TIMESTAMP root[root] @ localhost [] # 1 Query set global general_log= OFF +set global general_log= ON; +flush logs; +show global variables +where Variable_name = 'log' or Variable_name = 'log_slow_queries' or +Variable_name = 'general_log' or Variable_name = 'slow_query_log'; +Variable_name Value +general_log ON +log ON +log_slow_queries OFF +slow_query_log OFF +set session long_query_time=1; +select sleep(2); +sleep(2) +0 +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 +set global slow_query_log= ON; +set session long_query_time=1; +select sleep(2); +sleep(2) +0 +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, root[root] @ localhost [] USER_HOST, QUERY_TIME 1 0 test 0 0 1 select sleep(2) +show global variables +where Variable_name = 'log' or Variable_name = 'log_slow_queries' or +Variable_name = 'general_log' or Variable_name = 'slow_query_log'; +Variable_name Value +general_log ON +log ON +log_slow_queries ON +slow_query_log ON +set global general_log= ON; +set global general_log= OFF; +set global general_log= OFF; +set global slow_query_log= ON; +set global slow_query_log= OFF; +set global slow_query_log= OFF; +set global general_log= ON; +truncate table mysql.general_log; +create table t1(f1 int); +drop table t1; +select * from mysql.general_log; +event_time user_host thread_id server_id command_type argument +TIMESTAMP root[root] @ localhost [] # 1 Query create table t1(f1 int) +TIMESTAMP root[root] @ localhost [] # 1 Query drop table t1 +TIMESTAMP root[root] @ localhost [] # 1 Query select * from mysql.general_log +set global general_log= OFF; +truncate table mysql.general_log; +select * from mysql.general_log; +event_time user_host thread_id server_id command_type argument +set global general_log= ON; +show global variables +where Variable_name = 'log' or Variable_name = 'log_slow_queries' or +Variable_name = 'general_log' or Variable_name = 'slow_query_log'; +Variable_name Value +general_log ON +log ON +log_slow_queries OFF +slow_query_log OFF +show variables like 'general_log_file'; +Variable_name Value +general_log_file # +show variables like 'slow_query_log_file'; +Variable_name Value +slow_query_log_file # +show variables like 'log_output'; +Variable_name Value +log_output FILE,TABLE +set global general_log_file='/not exiting path/log.master'; +ERROR 42000: Variable 'general_log_file' can't be set to the value of '/not exiting path/log.master' +set global general_log_file='/tmp'; +ERROR 42000: Variable 'general_log_file' can't be set to the value of '/tmp' +set global general_log_file=''; +ERROR 42000: Variable 'general_log_file' can't be set to the value of '' +show variables like 'general_log_file'; +Variable_name Value +general_log_file # +set global general_log= OFF; +set global general_log_file='/tmp/log.master'; +set global general_log= ON; +create table t1(f1 int); +drop table t1; +set global general_log= OFF; +set global general_log_file=default; +set global general_log= ON; +create table t1(f1 int); +drop table t1; +show variables like 'general_log_file'; +Variable_name Value +general_log_file # +show variables like 'slow_query_log_file'; +Variable_name Value +slow_query_log_file # +set global general_log= default; +set global slow_query_log= default; +set global general_log_file= default; +set global slow_query_log_file= default; +show variables like 'general_log'; +Variable_name Value +general_log OFF +show variables like 'slow_query_log'; +Variable_name Value +slow_query_log OFF +set global general_log=ON; +set global log_output=default; +show variables like 'log_output'; +Variable_name Value +log_output TABLE +set global general_log=OFF; +set global log_output=FILE; +truncate table mysql.general_log; +show variables like 'log_output'; +Variable_name Value +log_output FILE +set global general_log=ON; +create table t1(f1 int); +select * from mysql.general_log; +event_time user_host thread_id server_id command_type argument +set global general_log=OFF; +set global log_output="FILE,TABLE"; +show variables like 'log_output'; +Variable_name Value +log_output FILE,TABLE +set global general_log=ON; +drop table t1; +select * from mysql.general_log; +event_time user_host thread_id server_id command_type argument +TIMESTAMP root[root] @ localhost [] # 1 Query drop table t1 +TIMESTAMP root[root] @ localhost [] # 1 Query select * from mysql.general_log diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 5dcb8b2afd6..154bd99a7f3 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -148,14 +148,12 @@ flush tables; show open tables; Database Table In_use Name_locked mysql general_log 1 0 -mysql slow_log 1 0 create table t1(n int); insert into t1 values (1); show open tables; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 test t1 0 0 +mysql general_log 1 0 drop table t1; create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" ENGINE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed; show create table t1; @@ -568,23 +566,21 @@ SELECT 1 FROM mysql.db, mysql.proc, mysql.user, mysql.time_zone, mysql.time_zone 1 SHOW OPEN TABLES; Database Table In_use Name_locked -mysql proc 0 0 +mysql db 0 0 test urkunde 0 0 mysql time_zone 0 0 -mysql db 0 0 -test txt1 0 0 -mysql slow_log 1 0 -test tyt2 0 0 mysql general_log 1 0 +test txt1 0 0 +mysql proc 0 0 +test tyt2 0 0 mysql user 0 0 mysql time_zone_name 0 0 SHOW OPEN TABLES FROM mysql; Database Table In_use Name_locked -mysql proc 0 0 -mysql time_zone 0 0 mysql db 0 0 -mysql slow_log 1 0 +mysql time_zone 0 0 mysql general_log 1 0 +mysql proc 0 0 mysql user 0 0 mysql time_zone_name 0 0 SHOW OPEN TABLES FROM mysql LIKE 'u%'; @@ -598,16 +594,14 @@ test tyt2 0 0 mysql time_zone_name 0 0 SHOW OPEN TABLES LIKE '%o%'; Database Table In_use Name_locked -mysql proc 0 0 mysql time_zone 0 0 -mysql slow_log 1 0 mysql general_log 1 0 +mysql proc 0 0 mysql time_zone_name 0 0 FLUSH TABLES; SHOW OPEN TABLES; Database Table In_use Name_locked mysql general_log 1 0 -mysql slow_log 1 0 DROP TABLE txt1; DROP TABLE tyt2; DROP TABLE urkunde; diff --git a/mysql-test/t/log_state-master.opt b/mysql-test/t/log_state-master.opt new file mode 100644 index 00000000000..445c6223d47 --- /dev/null +++ b/mysql-test/t/log_state-master.opt @@ -0,0 +1 @@ +--log-output=TABLE,FILE --log --general-log=0 --log-slow-queries --slow-query-log=0 diff --git a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test new file mode 100644 index 00000000000..d3dec841dc1 --- /dev/null +++ b/mysql-test/t/log_state.test @@ -0,0 +1,122 @@ +-- source include/not_embedded.inc +--source include/have_csv.inc + +--disable_ps_protocol +set global general_log= OFF; +truncate table mysql.general_log; +truncate table mysql.slow_log; +show global variables +where Variable_name = 'log' or Variable_name = 'log_slow_queries' or +Variable_name = 'general_log' or Variable_name = 'slow_query_log'; +flush logs; +set global general_log= ON; +create table t1(f1 int); +--replace_column 1 TIMESTAMP 3 # +select * from mysql.general_log; +set global general_log= OFF; +drop table t1; +--replace_column 1 TIMESTAMP 3 # +select * from mysql.general_log; +set global general_log= ON; +flush logs; +show global variables +where Variable_name = 'log' or Variable_name = 'log_slow_queries' or +Variable_name = 'general_log' or Variable_name = 'slow_query_log'; + +connect (con1,localhost,root,,); +connection con1; +set session long_query_time=1; +select sleep(2); +--replace_column 1 TIMESTAMP, 3 USER_HOST, 4 QUERY_TIME +select * from mysql.slow_log; +connection default; + +set global slow_query_log= ON; +connection con1; +set session long_query_time=1; +select sleep(2); +--replace_column 1 TIMESTAMP, 3 USER_HOST, 4 QUERY_TIME +select * from mysql.slow_log; +disconnect con1; +connection default; +show global variables +where Variable_name = 'log' or Variable_name = 'log_slow_queries' or +Variable_name = 'general_log' or Variable_name = 'slow_query_log'; + +set global general_log= ON; +set global general_log= OFF; +set global general_log= OFF; +set global slow_query_log= ON; +set global slow_query_log= OFF; +set global slow_query_log= OFF; + +set global general_log= ON; +truncate table mysql.general_log; +create table t1(f1 int); +drop table t1; +--replace_column 1 TIMESTAMP 3 # +select * from mysql.general_log; +set global general_log= OFF; +truncate table mysql.general_log; +--replace_column 1 TIMESTAMP 3 # +select * from mysql.general_log; +set global general_log= ON; +show global variables +where Variable_name = 'log' or Variable_name = 'log_slow_queries' or +Variable_name = 'general_log' or Variable_name = 'slow_query_log'; + +--replace_column 2 # +show variables like 'general_log_file'; +--replace_column 2 # +show variables like 'slow_query_log_file'; +show variables like 'log_output'; + +--error 1231 +set global general_log_file='/not exiting path/log.master'; +--error 1231 +set global general_log_file='/tmp'; +--error 1231 +set global general_log_file=''; +--replace_column 2 # +show variables like 'general_log_file'; +set global general_log= OFF; +set global general_log_file='/tmp/log.master'; +set global general_log= ON; +create table t1(f1 int); +drop table t1; +set global general_log= OFF; +set global general_log_file=default; +set global general_log= ON; +create table t1(f1 int); +drop table t1; +--replace_column 2 # +show variables like 'general_log_file'; +--replace_column 2 # +show variables like 'slow_query_log_file'; + +set global general_log= default; +set global slow_query_log= default; +set global general_log_file= default; +set global slow_query_log_file= default; +show variables like 'general_log'; +show variables like 'slow_query_log'; +set global general_log=ON; +set global log_output=default; +show variables like 'log_output'; +set global general_log=OFF; +set global log_output=FILE; +truncate table mysql.general_log; +show variables like 'log_output'; +set global general_log=ON; +create table t1(f1 int); +--replace_column 1 TIMESTAMP 3 # +select * from mysql.general_log; +set global general_log=OFF; +set global log_output="FILE,TABLE"; +show variables like 'log_output'; +set global general_log=ON; +drop table t1; +--replace_column 1 TIMESTAMP 3 # +select * from mysql.general_log; + +--enable_ps_protocol diff --git a/sql/log.cc b/sql/log.cc index 5a17ef817d0..c6c63ceb929 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -37,9 +37,6 @@ #define MAX_USER_HOST_SIZE 512 #define MAX_TIME_SIZE 32 -/* we need this for log files intialization */ -extern char *opt_logname, *opt_slow_logname; - LOGGER logger; MYSQL_LOG mysql_bin_log; @@ -63,6 +60,13 @@ sql_print_message_func sql_print_message_handlers[3] = }; +char *make_default_log_name(char *buff,const char* log_ext) +{ + strmake(buff, glob_hostname, FN_REFLEN-5); + return fn_format(buff, buff, mysql_data_home, log_ext, + MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT)); +} + /* This is a POD. Please keep it that way! @@ -250,8 +254,10 @@ bool Log_to_csv_event_handler::reopen_log_table(uint log_type) void Log_to_csv_event_handler::cleanup() { - close_log_table(QUERY_LOG_GENERAL, FALSE); - close_log_table(QUERY_LOG_SLOW, FALSE); + if (opt_log) + close_log_table(QUERY_LOG_GENERAL, FALSE); + if (opt_slow_log) + close_log_table(QUERY_LOG_SLOW, FALSE); logger.is_log_tables_initialized= FALSE; } @@ -505,10 +511,10 @@ bool Log_to_file_event_handler::init() if (!is_initialized) { if (opt_slow_log) - mysql_slow_log.open_slow_log(opt_slow_logname); + mysql_slow_log.open_slow_log(sys_var_slow_log_path.value); if (opt_log) - mysql_log.open_query_log(opt_logname); + mysql_log.open_query_log(sys_var_general_log_path.value); is_initialized= TRUE; } @@ -526,8 +532,10 @@ void Log_to_file_event_handler::cleanup() void Log_to_file_event_handler::flush() { /* reopen log files */ - mysql_log.new_file(1); - mysql_slow_log.new_file(1); + if (opt_log) + mysql_log.new_file(1); + if (opt_slow_log) + mysql_slow_log.new_file(1); } /* @@ -647,10 +655,7 @@ bool LOGGER::flush_logs(THD *thd) close_general_log.db= (char*) "mysql"; close_general_log.db_length= 5; - /* reopen log files */ - file_log_handler->flush(); - - /* flush tables, in the case they are enabled */ + /* lock tables, in the case they are enabled */ if (logger.is_log_tables_initialized) { /* @@ -663,23 +668,29 @@ bool LOGGER::flush_logs(THD *thd) Here we use one of the logger handler THD's. Simply because it seems appropriate. */ - lock_and_wait_for_table_name(table_log_handler->general_log_thd, - &close_slow_log); - lock_and_wait_for_table_name(table_log_handler->general_log_thd, - &close_general_log); + if (opt_slow_log) + lock_and_wait_for_table_name(table_log_handler->general_log_thd, + &close_slow_log); + if (opt_log) + lock_and_wait_for_table_name(table_log_handler->general_log_thd, + &close_general_log); + } - /* - Deny others from logging to general and slow log, - while reopening tables. - */ - logger.lock(); + /* + Deny others from logging to general and slow log, + while reopening tables. + */ + logger.lock(); + /* reopen log files */ + file_log_handler->flush(); + + /* flush tables, in the case they are enabled */ + if (logger.is_log_tables_initialized) table_log_handler->flush(table_log_handler->general_log_thd, &close_slow_log, &close_general_log); - - /* end of log tables flush */ - logger.unlock(); - } + /* end of log flush */ + logger.unlock(); return FALSE; } @@ -727,6 +738,11 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, return 0; lock(); + if (!opt_slow_log) + { + unlock(); + return 0; + } /* fill in user_host value: the format is "%s[%s] @ %s [%s]" */ user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE, @@ -801,6 +817,11 @@ bool LOGGER::general_log_print(THD *thd, enum enum_server_command command, id=0; /* Log from connect handler */ lock(); + if (!opt_log) + { + unlock(); + return 0; + } time_t current_time= time(NULL); user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE, @@ -904,26 +925,126 @@ void LOGGER::init_general_log(uint general_log_printer) } +bool LOGGER::activate_log_handler(THD* thd, uint log_type) +{ + bool res= 0; + lock(); + switch (log_type) { + case QUERY_LOG_SLOW: + if (!opt_slow_log) + { + if ((res= reopen_log_table(log_type))) + goto err; + file_log_handler->get_mysql_slow_log()-> + open_query_log(sys_var_slow_log_path.value); + init_slow_log(log_output_options); + opt_slow_log= TRUE; + } + break; + case QUERY_LOG_GENERAL: + if (!opt_log) + { + if ((res= reopen_log_table(log_type))) + goto err; + file_log_handler->get_mysql_log()-> + open_query_log(sys_var_general_log_path.value); + init_general_log(log_output_options); + opt_log= TRUE; + } + break; + default: + DBUG_ASSERT(0); + } +err: + unlock(); + return res; +} + + +void LOGGER::deactivate_log_handler(THD *thd, uint log_type) +{ + TABLE_LIST *table_list; + my_bool *tmp_opt= 0; + MYSQL_LOG *file_log; + THD *log_thd; + + switch (log_type) { + case QUERY_LOG_SLOW: + table_list= &table_log_handler->slow_log; + tmp_opt= &opt_slow_log; + file_log= file_log_handler->get_mysql_slow_log(); + log_thd= table_log_handler->slow_log_thd; + break; + case QUERY_LOG_GENERAL: + table_list= &table_log_handler->general_log; + tmp_opt= &opt_log; + file_log= file_log_handler->get_mysql_log(); + log_thd= table_log_handler->general_log_thd; + break; + default: + DBUG_ASSERT(0); + } + + if (!(*tmp_opt)) + return; + + if (is_log_tables_initialized) + lock_and_wait_for_table_name(log_thd, table_list); + lock(); + + if (is_log_tables_initialized) + { + VOID(pthread_mutex_lock(&LOCK_open)); + close_log_table(log_type, TRUE); + table_list->table= 0; + query_cache_invalidate3(log_thd, table_list, 0); + unlock_table_name(log_thd, table_list); + VOID(pthread_mutex_unlock(&LOCK_open)); + } + file_log->close(0); + *tmp_opt= FALSE; + unlock(); +} + + bool Log_to_csv_event_handler::flush(THD *thd, TABLE_LIST *close_slow_log, TABLE_LIST *close_general_log) { VOID(pthread_mutex_lock(&LOCK_open)); - close_log_table(QUERY_LOG_GENERAL, TRUE); - close_log_table(QUERY_LOG_SLOW, TRUE); - close_general_log->next_local= close_slow_log; - query_cache_invalidate3(thd, close_general_log, 0); - unlock_table_name(thd, close_slow_log); - unlock_table_name(thd, close_general_log); + if (opt_log) + { + close_log_table(QUERY_LOG_GENERAL, TRUE); + query_cache_invalidate3(thd, close_general_log, 0); + unlock_table_name(thd, close_general_log); + } + if (opt_slow_log) + { + close_log_table(QUERY_LOG_SLOW, TRUE); + query_cache_invalidate3(thd, close_slow_log, 0); + unlock_table_name(thd, close_slow_log); + } VOID(pthread_mutex_unlock(&LOCK_open)); - return reopen_log_table(QUERY_LOG_SLOW) || - reopen_log_table(QUERY_LOG_GENERAL); + /* + we use | and not || here, to ensure that both reopen_log_table + are called, even if the first one fails + */ + if ((opt_slow_log && reopen_log_table(QUERY_LOG_SLOW)) | + (opt_log && reopen_log_table(QUERY_LOG_GENERAL))) + return 1; + return 0; } /* the parameters are unused for the log tables */ bool Log_to_csv_event_handler::init() { - /* we always open log tables. even if the logging is disabled */ - return (open_log_table(QUERY_LOG_GENERAL) || open_log_table(QUERY_LOG_SLOW)); + /* + we use | and not || here, to ensure that both open_log_table + are called, even if the first one fails + */ + if ((opt_log && open_log_table(QUERY_LOG_GENERAL)) | + (opt_slow_log && open_log_table(QUERY_LOG_SLOW))) + return 1; + return 0; } int LOGGER::set_handlers(uint error_log_printer, diff --git a/sql/log.h b/sql/log.h index 03d5466e549..49aae15feee 100644 --- a/sql/log.h +++ b/sql/log.h @@ -438,6 +438,8 @@ public: CHARSET_INFO *client_cs); void flush(); void init_pthread_objects(); + MYSQL_LOG *get_mysql_slow_log() { return &mysql_slow_log; } + MYSQL_LOG *get_mysql_log() { return &mysql_log; } }; @@ -510,8 +512,21 @@ public: void init_error_log(uint error_log_printer); void init_slow_log(uint slow_log_printer); void init_general_log(uint general_log_printer); - }; - + void deactivate_log_handler(THD* thd, uint log_type); + bool activate_log_handler(THD* thd, uint log_type); + MYSQL_LOG *get_slow_log_file_handler() + { + if (file_log_handler) + return file_log_handler->get_mysql_slow_log(); + return NULL; + } + MYSQL_LOG *get_log_file_handler() + { + if (file_log_handler) + return file_log_handler->get_mysql_log(); + return NULL; + } +}; enum enum_binlog_format { BINLOG_FORMAT_STMT= 0, // statement-based diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3d499b67519..83cbb383aef 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1167,6 +1167,7 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db, void remove_db_from_cache(const char *db); void flush_tables(); bool is_equal(const LEX_STRING *a, const LEX_STRING *b); +char *make_default_log_name(char *buff,const char* log_ext); #ifdef WITH_PARTITION_STORAGE_ENGINE uint fast_alter_partition_table(THD *thd, TABLE *table, @@ -1514,7 +1515,9 @@ extern bool opt_endinfo, using_udf_functions; extern my_bool locked_in_memory; extern bool opt_using_transactions, mysqld_embedded; extern bool using_update_log, opt_large_files, server_id_supplied; -extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log; +extern bool opt_update_log, opt_bin_log, opt_error_log; +extern my_bool opt_log, opt_slow_log; +extern uint log_output_options; extern my_bool opt_log_queries_not_using_indexes; extern bool opt_disable_networking, opt_skip_show_db; extern my_bool opt_character_set_client_handshake; @@ -1536,6 +1539,8 @@ extern my_bool opt_enable_shared_memory; extern char *default_tz_name; extern my_bool opt_large_pages; extern uint opt_large_page_size; +extern char *opt_logname, *opt_slow_logname; +extern const char *log_output_str; extern MYSQL_LOG mysql_bin_log; extern LOGGER logger; @@ -1582,6 +1587,7 @@ extern TABLE *unused_tables; extern const char* any_db; extern struct my_option my_long_options[]; extern const LEX_STRING view_type; +extern TYPELIB log_output_typelib; /* optional things, have_* variables */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 56c3b1857a8..2ec62e741b9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -302,16 +302,15 @@ arg_cmp_func Arg_comparator::comparator_matrix[5][2] = {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}, {&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal}}; -const char *log_output_names[] = -{ "NONE", "FILE", "TABLE", NullS}; +const char *log_output_names[] = { "NONE", "FILE", "TABLE", NullS}; +static const unsigned int log_output_names_len[]= { 4, 4, 5, 0 }; TYPELIB log_output_typelib= {array_elements(log_output_names)-1,"", - log_output_names, NULL}; + log_output_names, + (unsigned int *) log_output_names_len}; /* static variables */ /* the default log output is log tables */ -static const char *log_output_str= "TABLE"; -static ulong log_output_options= LOG_TABLE; static bool lower_case_table_names_used= 0; static bool volatile select_thread_in_use, signal_thread_in_use; static bool volatile ready_to_exit; @@ -342,7 +341,9 @@ static my_bool opt_sync_bdb_logs; /* Global variables */ -bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; +bool opt_update_log, opt_bin_log; +my_bool opt_log, opt_slow_log; +uint log_output_options; my_bool opt_log_queries_not_using_indexes= 0; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; @@ -520,6 +521,7 @@ ulong thread_id=1L,current_pid; ulong slow_launch_threads = 0, sync_binlog_period; ulong expire_logs_days = 0; ulong rpl_recovery_rank=0; +const char *log_output_str= "TABLE"; double log_10[32]; /* 10 potences */ time_t start_time; @@ -1229,6 +1231,8 @@ void clean_up(bool print_message) free_defaults(defaults_argv); my_free(sys_init_connect.value, MYF(MY_ALLOW_ZERO_PTR)); my_free(sys_init_slave.value, MYF(MY_ALLOW_ZERO_PTR)); + my_free(sys_var_general_log_path.value, MYF(MY_ALLOW_ZERO_PTR)); + my_free(sys_var_slow_log_path.value, MYF(MY_ALLOW_ZERO_PTR)); free_tmpdir(&mysql_tmpdir_list); #ifdef HAVE_REPLICATION my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR)); @@ -2607,6 +2611,7 @@ static bool init_global_datetime_format(timestamp_type format_type, static int init_common_variables(const char *conf_file_name, int argc, char **argv, const char **groups) { + char buff[FN_REFLEN]; umask(((~my_umask) & 0666)); my_decimal_set_zero(&decimal_zero); // set decimal_zero constant; tzset(); // Set tzname @@ -2763,6 +2768,16 @@ static int init_common_variables(const char *conf_file_name, int argc, else sys_init_slave.value=my_strdup("",MYF(0)); + if (!opt_logname) + opt_logname= make_default_log_name(buff, ".log"); + sys_var_general_log_path.value= my_strdup(opt_logname, MYF(0)); + sys_var_general_log_path.value_length= strlen(opt_logname); + + if (!opt_slow_logname) + opt_slow_logname= make_default_log_name(buff, "-slow.log"); + sys_var_slow_log_path.value= my_strdup(opt_slow_logname, MYF(0)); + sys_var_slow_log_path.value_length= strlen(opt_slow_logname); + if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1)) return 1; if (my_database_names_init()) @@ -4815,7 +4830,9 @@ enum options_mysqld OPT_TABLE_LOCK_WAIT_TIMEOUT, OPT_PLUGIN_DIR, OPT_LOG_OUTPUT, - OPT_PORT_OPEN_TIMEOUT + OPT_PORT_OPEN_TIMEOUT, + OPT_GENERAL_LOG, + OPT_SLOW_LOG }; @@ -5044,6 +5061,9 @@ Disable with --skip-bdb (will save memory).", "Set up signals usable for debugging", (gptr*) &opt_debugging, (gptr*) &opt_debugging, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"general-log", OPT_GENERAL_LOG, + "Enable|disable general log", (gptr*) &opt_log, + (gptr*) &opt_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_LARGE_PAGES {"large-pages", OPT_ENABLE_LARGE_PAGES, "Enable support for large pages. \ Disable with --skip-large-pages.", @@ -5613,6 +5633,9 @@ replicating a LOAD DATA INFILE command.", "Tells the slave thread to continue replication when a query returns an error from the provided list.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"slow-query-log", OPT_SLOW_LOG, + "Enable|disable slow query log", (gptr*) &opt_slow_log, + (gptr*) &opt_slow_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"socket", OPT_SOCKET, "Socket file to use for connection.", (gptr*) &mysqld_unix_port, (gptr*) &mysqld_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -6922,6 +6945,7 @@ static void mysql_init_variables(void) opt_skip_slave_start= opt_reckless_slave = 0; mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0; opt_log= opt_update_log= opt_slow_log= 0; + log_output_options= find_bit_type(log_output_str, &log_output_typelib); opt_bin_log= 0; opt_disable_networking= opt_skip_show_db=0; opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0; diff --git a/sql/set_var.cc b/sql/set_var.cc index 53b4b395c37..79de4dd7c16 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -55,6 +55,7 @@ #include #include #include +#include #include "event_scheduler.h" @@ -164,6 +165,11 @@ static byte *get_error_count(THD *thd); static byte *get_warning_count(THD *thd); static byte *get_prepared_stmt_count(THD *thd); static byte *get_tmpdir(THD *thd); +static int sys_check_log_path(THD *thd, set_var *var); +static bool sys_update_general_log_path(THD *thd, set_var * var); +static void sys_default_general_log_path(THD *thd, enum_var_type type); +static bool sys_update_slow_log_path(THD *thd, set_var * var); +static void sys_default_slow_log_path(THD *thd, enum_var_type type); /* Variable definition list @@ -679,6 +685,22 @@ sys_var_have_variable sys_have_row_based_replication("have_row_based_replication /* Global read-only variable describing server license */ sys_var_const_str sys_license("license", STRINGIFY_ARG(LICENSE)); +/* Global variables which enable|disable logging */ +sys_var_log_state sys_var_general_log("general_log", &opt_log, + QUERY_LOG_GENERAL); +sys_var_log_state sys_var_slow_query_log("slow_query_log", &opt_slow_log, + QUERY_LOG_SLOW); +sys_var_str sys_var_general_log_path("general_log_file", sys_check_log_path, + sys_update_general_log_path, + sys_default_general_log_path, + opt_logname); +sys_var_str sys_var_slow_log_path("slow_query_log_file", sys_check_log_path, + sys_update_slow_log_path, + sys_default_slow_log_path, + opt_slow_logname); +sys_var_log_output sys_var_log_output_state("log_output", &log_output_options, + &log_output_typelib, 0); + #ifdef HAVE_REPLICATION static int show_slave_skip_errors(THD *thd, SHOW_VAR *var, char *buff) { @@ -777,6 +799,8 @@ SHOW_VAR init_vars[]= { {"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG}, {"ft_query_expansion_limit",(char*) &ft_query_expansion_limit, SHOW_LONG}, {"ft_stopword_file", (char*) &ft_stopword_file, SHOW_CHAR_PTR}, + {sys_var_general_log.name, (char*) &opt_log, SHOW_MY_BOOL}, + {sys_var_general_log_path.name, (char*) &sys_var_general_log_path, SHOW_SYS}, {sys_group_concat_max_len.name, (char*) &sys_group_concat_max_len, SHOW_SYS}, {sys_have_archive_db.name, (char*) &have_archive_db, SHOW_HAVE}, {sys_have_berkeley_db.name, (char*) &have_berkeley_db, SHOW_HAVE}, @@ -854,6 +878,7 @@ SHOW_VAR init_vars[]= { {"log_bin", (char*) &opt_bin_log, SHOW_BOOL}, {sys_trust_function_creators.name,(char*) &sys_trust_function_creators, SHOW_SYS}, {"log_error", (char*) log_error_file, SHOW_CHAR}, + {sys_var_log_output_state.name, (char*) &sys_var_log_output_state, SHOW_SYS}, {sys_log_queries_not_using_indexes.name, (char*) &sys_log_queries_not_using_indexes, SHOW_SYS}, #ifdef HAVE_REPLICATION @@ -977,6 +1002,8 @@ SHOW_VAR init_vars[]= { {sys_slave_trans_retries.name,(char*) &sys_slave_trans_retries, SHOW_SYS}, #endif {sys_slow_launch_time.name, (char*) &sys_slow_launch_time, SHOW_SYS}, + {sys_var_slow_query_log.name, (char*) &opt_slow_log, SHOW_MY_BOOL}, + {sys_var_slow_log_path.name, (char*) &sys_var_slow_log_path, SHOW_SYS}, #ifdef HAVE_SYS_UN_H {"socket", (char*) &mysqld_unix_port, SHOW_CHAR_PTR}, #endif @@ -2509,6 +2536,195 @@ end: } +bool sys_var_log_state::update(THD *thd, set_var *var) +{ + bool res= 0; + pthread_mutex_lock(&LOCK_global_system_variables); + if (!var->save_result.ulong_value) + logger.deactivate_log_handler(thd, log_type); + else + { + if ((res= logger.activate_log_handler(thd, log_type))) + { + my_error(ER_CANT_ACTIVATE_LOG, MYF(0), + log_type == QUERY_LOG_GENERAL ? "general" : + "slow query"); + goto err; + } + } +err: + pthread_mutex_unlock(&LOCK_global_system_variables); + return res; +} + +void sys_var_log_state::set_default(THD *thd, enum_var_type type) +{ + pthread_mutex_lock(&LOCK_global_system_variables); + logger.deactivate_log_handler(thd, log_type); + pthread_mutex_unlock(&LOCK_global_system_variables); +} + + +static int sys_check_log_path(THD *thd, set_var *var) +{ + char path[FN_REFLEN]; + MY_STAT f_stat; + const char *var_path= var->value->str_value.ptr(); + bzero(&f_stat, sizeof(MY_STAT)); + + (void) unpack_filename(path, var_path); + if (my_stat(path, &f_stat, MYF(0))) + { + /* Check if argument is a file and we have 'write' permission */ + if (!MY_S_ISREG(f_stat.st_mode) || + !(f_stat.st_mode & MY_S_IWRITE)) + return -1; + } + else + { + /* + Check if directory exists and + we have permission to create file & write to file + */ + (void) dirname_part(path, var_path); + if (my_access(path, (F_OK|W_OK))) + return -1; + } + return 0; +} + + +bool update_sys_var_str_path(THD *thd, sys_var_str *var_str, + set_var *var, const char *log_ext, + bool log_state, uint log_type) +{ + MYSQL_LOG *file_log; + char buff[FN_REFLEN]; + char *res= 0, *old_value=(char *)(var ? var->value->str_value.ptr() : 0); + bool result= 0; + uint str_length= (var ? var->value->str_value.length() : 0); + + switch (log_type) { + case QUERY_LOG_SLOW: + file_log= logger.get_slow_log_file_handler(); + break; + case QUERY_LOG_GENERAL: + file_log= logger.get_log_file_handler(); + break; + default: + DBUG_ASSERT(0); + } + + if (!old_value) + { + old_value= make_default_log_name(buff, log_ext); + str_length= strlen(old_value); + } + if (!(res= my_strndup((byte*)old_value, str_length, MYF(MY_FAE+MY_WME)))) + { + result= 1; + goto err; + } + + pthread_mutex_lock(&LOCK_global_system_variables); + logger.lock(); + + if (file_log && log_state) + file_log->close(0); + old_value= var_str->value; + var_str->value= res; + var_str->value_length= str_length; + my_free(old_value, MYF(MY_ALLOW_ZERO_PTR)); + if (file_log && log_state) + file_log->open_query_log(sys_var_general_log_path.value); + + logger.unlock(); + pthread_mutex_unlock(&LOCK_global_system_variables); + +err: + return result; +} + + +static bool sys_update_general_log_path(THD *thd, set_var * var) +{ + return update_sys_var_str_path(thd, &sys_var_general_log_path, + var, ".log", opt_log, QUERY_LOG_GENERAL); +} + + +static void sys_default_general_log_path(THD *thd, enum_var_type type) +{ + (void) update_sys_var_str_path(thd, &sys_var_general_log_path, + 0, ".log", opt_log, QUERY_LOG_GENERAL); +} + + +static bool sys_update_slow_log_path(THD *thd, set_var * var) +{ + return update_sys_var_str_path(thd, &sys_var_slow_log_path, + var, "-slow.log", opt_slow_log, + QUERY_LOG_SLOW); +} + + +static void sys_default_slow_log_path(THD *thd, enum_var_type type) +{ + (void) update_sys_var_str_path(thd, &sys_var_slow_log_path, + 0, "-slow.log", opt_slow_log, + QUERY_LOG_SLOW); +} + + +bool sys_var_log_output::update(THD *thd, set_var *var) +{ + pthread_mutex_lock(&LOCK_global_system_variables); + logger.lock(); + logger.init_slow_log(var->save_result.ulong_value); + logger.init_general_log(var->save_result.ulong_value); + *value= var->save_result.ulong_value; + logger.unlock(); + pthread_mutex_unlock(&LOCK_global_system_variables); + return 0; +} + + +void sys_var_log_output::set_default(THD *thd, enum_var_type type) +{ + pthread_mutex_lock(&LOCK_global_system_variables); + logger.lock(); + logger.init_slow_log(LOG_TABLE); + logger.init_general_log(LOG_TABLE); + *value= LOG_TABLE; + logger.unlock(); + pthread_mutex_unlock(&LOCK_global_system_variables); +} + + +byte *sys_var_log_output::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) +{ + char buff[256]; + String tmp(buff, sizeof(buff), &my_charset_latin1); + ulong length; + ulong val= *value; + + tmp.length(0); + for (uint i= 0; val; val>>= 1, i++) + { + if (val & 1) + { + tmp.append(log_output_typelib.type_names[i], + log_output_typelib.type_lengths[i]); + tmp.append(','); + } + } + + if ((length= tmp.length())) + length--; + return (byte*) thd->strmake(tmp.ptr(), length); +} + + /***************************************************************************** Functions to handle SET NAMES and SET CHARACTER SET *****************************************************************************/ diff --git a/sql/set_var.h b/sql/set_var.h index 1049b154d47..2793f60f763 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -262,7 +262,7 @@ public: class sys_var_enum :public sys_var { - uint *value; + uint *value; TYPELIB *enum_names; public: sys_var_enum(const char *name_arg, uint *value_arg, @@ -772,6 +772,38 @@ public: }; +class sys_var_log_state :public sys_var_bool_ptr +{ + uint log_type; +public: + sys_var_log_state(const char *name_arg, my_bool *value_arg, uint log_type_arg) + :sys_var_bool_ptr(name_arg, value_arg), log_type(log_type_arg) {} + bool update(THD *thd, set_var *var); + void set_default(THD *thd, enum_var_type type); +}; + + +class sys_var_log_output :public sys_var +{ + uint *value; + TYPELIB *enum_names; +public: + sys_var_log_output(const char *name_arg, uint *value_arg, + TYPELIB *typelib, sys_after_update_func func) + :sys_var(name_arg,func), value(value_arg), enum_names(typelib) + {} + bool check(THD *thd, set_var *var) + { + return check_set(thd, var, enum_names); + } + bool update(THD *thd, set_var *var); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); + bool check_update_type(Item_result type) { return 0; } + void set_default(THD *thd, enum_var_type type); + SHOW_TYPE type() { return SHOW_CHAR; } +}; + + /* Variable that you can only read from */ class sys_var_readonly: public sys_var @@ -1068,6 +1100,8 @@ CHARSET_INFO *get_old_charset_by_name(const char *old_name); gptr find_named(I_List *list, const char *name, uint length, NAMED_LIST **found); +extern sys_var_str sys_var_general_log_path, sys_var_slow_log_path; + /* key_cache functions */ KEY_CACHE *get_key_cache(LEX_STRING *cache_name); KEY_CACHE *get_or_create_key_cache(const char *name, uint length); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index ae5ddd31475..317ec5fc420 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5832,3 +5832,5 @@ ER_EVENT_SET_VAR_ERROR ER_PARTITION_MERGE_ERROR eng "MyISAM Merge handler cannot be used in partitioned tables" swe "MyISAM Merge kan inte anändas i en partitionerad tabell" +ER_CANT_ACTIVATE_LOG + eng "Cannot activate '%-.64s' log." diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index dd4748bc15c..7609c0eb495 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -931,7 +931,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) /* close log tables in use */ if (!my_strcasecmp(system_charset_info, table_list->db, "mysql")) { - if (!my_strcasecmp(system_charset_info, table_list->table_name, + if (opt_log && + !my_strcasecmp(system_charset_info, table_list->table_name, "general_log")) { lock_logger= 1; @@ -940,7 +941,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) closed_log_tables= closed_log_tables | QUERY_LOG_GENERAL; } else - if (!my_strcasecmp(system_charset_info, table_list->table_name, + if (opt_slow_log && + !my_strcasecmp(system_charset_info, table_list->table_name, "slow_log")) { lock_logger= 1; @@ -981,10 +983,10 @@ end: unlock_table_name(thd, table_list); VOID(pthread_mutex_unlock(&LOCK_open)); - if (closed_log_tables & QUERY_LOG_SLOW) + if (opt_slow_log && (closed_log_tables & QUERY_LOG_SLOW)) logger.reopen_log_table(QUERY_LOG_SLOW); - if (closed_log_tables & QUERY_LOG_GENERAL) + if (opt_log && (closed_log_tables & QUERY_LOG_GENERAL)) logger.reopen_log_table(QUERY_LOG_GENERAL); if (lock_logger) logger.unlock();