summaryrefslogtreecommitdiff
path: root/sql/log.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/log.cc')
-rw-r--r--sql/log.cc1293
1 files changed, 799 insertions, 494 deletions
diff --git a/sql/log.cc b/sql/log.cc
index 5a17ef817d0..cdae7885046 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -37,14 +37,13 @@
#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;
+MYSQL_BIN_LOG mysql_bin_log;
ulong sync_binlog_counter= 0;
+static Muted_query_log_event invisible_commit;
+
static bool test_if_number(const char *str,
long *res, bool allow_wildcards);
static int binlog_init();
@@ -63,6 +62,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!
@@ -71,11 +77,17 @@ sql_print_message_func sql_print_message_handlers[3] =
struct binlog_trx_data {
bool empty() const
{
+#ifdef HAVE_ROW_BASED_REPLICATION
return pending == NULL && my_b_tell(&trans_log) == 0;
+#else
+ return my_b_tell(&trans_log) == 0;
+#endif
}
binlog_trx_data() {}
IO_CACHE trans_log; // The transaction cache
+#ifdef HAVE_ROW_BASED_REPLICATION
Rows_log_event *pending; // The pending binrows event
+#endif
};
handlerton binlog_hton;
@@ -86,8 +98,8 @@ handlerton binlog_hton;
SYNOPSIS
open_log_table()
- log_type type of the log table to open: QUERY_LOG_GENERAL
- or QUERY_LOG_SLOW
+ log_table_type type of the log table to open: QUERY_LOG_GENERAL
+ or QUERY_LOG_SLOW
DESCRIPTION
@@ -102,14 +114,14 @@ handlerton binlog_hton;
TRUE - error occured
*/
-bool Log_to_csv_event_handler::open_log_table(uint log_type)
+bool Log_to_csv_event_handler::open_log_table(uint log_table_type)
{
THD *log_thd, *curr= current_thd;
TABLE_LIST *table;
bool error= FALSE;
DBUG_ENTER("open_log_table");
- switch (log_type) {
+ switch (log_table_type) {
case QUERY_LOG_GENERAL:
log_thd= general_log_thd;
table= &general_log;
@@ -222,8 +234,8 @@ Log_to_csv_event_handler::~Log_to_csv_event_handler()
SYNOPSIS
reopen_log_table()
- log_type type of the log table to open: QUERY_LOG_GENERAL
- or QUERY_LOG_SLOW
+ log_table_type type of the log table to open: QUERY_LOG_GENERAL
+ or QUERY_LOG_SLOW
DESCRIPTION
@@ -240,18 +252,20 @@ Log_to_csv_event_handler::~Log_to_csv_event_handler()
TRUE - open_log_table() returned an error
*/
-bool Log_to_csv_event_handler::reopen_log_table(uint log_type)
+bool Log_to_csv_event_handler::reopen_log_table(uint log_table_type)
{
/* don't open the log table, if it wasn't enabled during startup */
if (!logger.is_log_tables_initialized)
return FALSE;
- return open_log_table(log_type);
+ return open_log_table(log_table_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;
}
@@ -313,9 +327,9 @@ bool Log_to_csv_event_handler::
table->field[1]->store(user_host, user_host_len, client_cs);
table->field[1]->set_notnull();
- table->field[2]->store((longlong) thread_id);
+ table->field[2]->store((longlong) thread_id, TRUE);
table->field[2]->set_notnull();
- table->field[3]->store((longlong) server_id);
+ table->field[3]->store((longlong) server_id, TRUE);
table->field[3]->set_notnull();
table->field[4]->store(command_type, command_type_len, client_cs);
table->field[4]->set_notnull();
@@ -395,13 +409,13 @@ bool Log_to_csv_event_handler::
if (query_start_arg)
{
/* fill in query_time field */
- table->field[2]->store(query_time);
+ table->field[2]->store(query_time, TRUE);
/* lock_time */
- table->field[3]->store(lock_time);
+ table->field[3]->store(lock_time, TRUE);
/* rows_sent */
- table->field[4]->store((longlong) thd->sent_row_count);
+ table->field[4]->store((longlong) thd->sent_row_count, TRUE);
/* rows_examined */
- table->field[5]->store((longlong) thd->examined_row_count);
+ table->field[5]->store((longlong) thd->examined_row_count, TRUE);
}
else
{
@@ -420,18 +434,18 @@ bool Log_to_csv_event_handler::
if (thd->last_insert_id_used)
{
- table->field[7]->store((longlong) thd->current_insert_id);
+ table->field[7]->store((longlong) thd->current_insert_id, TRUE);
table->field[7]->set_notnull();
}
/* set value if we do an insert on autoincrement column */
if (thd->insert_id_used)
{
- table->field[8]->store((longlong) thd->last_insert_id);
+ table->field[8]->store((longlong) thd->last_insert_id, TRUE);
table->field[8]->set_notnull();
}
- table->field[9]->store((longlong) server_id);
+ table->field[9]->store((longlong) server_id, TRUE);
table->field[9]->set_notnull();
/* sql_text */
@@ -505,10 +519,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 +540,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.reopen_file();
+ if (opt_slow_log)
+ mysql_slow_log.reopen_file();
}
/*
@@ -582,9 +598,9 @@ void LOGGER::cleanup_end()
}
-void LOGGER::close_log_table(uint log_type, bool lock_in_use)
+void LOGGER::close_log_table(uint log_table_type, bool lock_in_use)
{
- table_log_handler->close_log_table(log_type, lock_in_use);
+ table_log_handler->close_log_table(log_table_type, lock_in_use);
}
@@ -624,9 +640,9 @@ void LOGGER::init_log_tables()
}
-bool LOGGER::reopen_log_table(uint log_type)
+bool LOGGER::reopen_log_table(uint log_table_type)
{
- return table_log_handler->reopen_log_table(log_type);
+ return table_log_handler->reopen_log_table(log_table_type);
}
@@ -647,10 +663,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 +676,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 +746,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 +825,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 +933,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_slow_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,
@@ -961,9 +1090,9 @@ int LOGGER::set_handlers(uint error_log_printer,
SYNOPSIS
close_log_table()
- log_type type of the log table to close: QUERY_LOG_GENERAL
- or QUERY_LOG_SLOW
- lock_in_use Set to TRUE if the caller owns LOCK_open. FALSE otherwise.
+ log_table_type type of the log table to close: QUERY_LOG_GENERAL
+ or QUERY_LOG_SLOW
+ lock_in_use Set to TRUE if the caller owns LOCK_open. FALSE otherwise.
DESCRIPTION
@@ -973,7 +1102,7 @@ int LOGGER::set_handlers(uint error_log_printer,
*/
void Log_to_csv_event_handler::
- close_log_table(uint log_type, bool lock_in_use)
+ close_log_table(uint log_table_type, bool lock_in_use)
{
THD *log_thd, *curr= current_thd;
TABLE_LIST *table;
@@ -981,7 +1110,7 @@ void Log_to_csv_event_handler::
if (!logger.is_log_tables_initialized)
return; /* do nothing */
- switch (log_type) {
+ switch (log_table_type) {
case QUERY_LOG_GENERAL:
log_thd= general_log_thd;
table= &general_log;
@@ -1022,7 +1151,7 @@ void Log_to_csv_event_handler::
/*
this function is mostly a placeholder.
- conceptually, binlog initialization (now mostly done in MYSQL_LOG::open)
+ conceptually, binlog initialization (now mostly done in MYSQL_BIN_LOG::open)
should be moved here.
*/
@@ -1061,7 +1190,9 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, Log_event *end_ev)
int error=0;
IO_CACHE *trans_log= &trx_data->trans_log;
- if (end_ev)
+
+ /* NULL denotes ROLLBACK with nothing to replicate */
+ if (end_ev != NULL)
{
/*
We can always end the statement when ending a transaction since
@@ -1074,6 +1205,7 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, Log_event *end_ev)
#endif
error= mysql_bin_log.write(thd, trans_log, end_ev);
}
+#ifdef HAVE_ROW_BASED_REPLICATION
else
{
#ifdef HAVE_ROW_BASED_REPLICATION
@@ -1093,6 +1225,7 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, Log_event *end_ev)
transaction cache.
*/
mysql_bin_log.update_table_map_version();
+#endif
statistic_increment(binlog_cache_use, &LOCK_status);
if (trans_log->disk_writes != 0)
@@ -1111,7 +1244,7 @@ static int binlog_prepare(THD *thd, bool all)
do nothing.
just pretend we can do 2pc, so that MySQL won't
switch to 1pc.
- real work will be done in MYSQL_LOG::log()
+ real work will be done in MYSQL_BIN_LOG::log()
*/
return 0;
}
@@ -1127,12 +1260,17 @@ static int binlog_commit(THD *thd, bool all)
if (trx_data->empty())
{
- // we're here because trans_log was flushed in MYSQL_LOG::log()
+ // we're here because trans_log was flushed in MYSQL_BIN_LOG::log()
DBUG_RETURN(0);
}
- Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE);
- qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
- DBUG_RETURN(binlog_end_trans(thd, trx_data, &qev));
+ if (all)
+ {
+ Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE);
+ qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
+ DBUG_RETURN(binlog_end_trans(thd, trx_data, &qev));
+ }
+ else
+ DBUG_RETURN(binlog_end_trans(thd, trx_data, &invisible_commit));
}
static int binlog_rollback(THD *thd, bool all)
@@ -1367,12 +1505,119 @@ static int find_uniq_filename(char *name)
}
+void MYSQL_LOG::init(enum_log_type log_type_arg,
+ enum cache_type io_cache_type_arg)
+{
+ DBUG_ENTER("MYSQL_LOG::init");
+ log_type= log_type_arg;
+ io_cache_type= io_cache_type_arg;
+ DBUG_PRINT("info",("log_type: %d", log_type));
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Open a (new) log file.
+
+ SYNOPSIS
+ open()
+
+ log_name The name of the log to open
+ log_type_arg The type of the log. E.g. LOG_NORMAL
+ new_name The new name for the logfile. This is only needed
+ when the method is used to open the binlog file.
+ io_cache_type_arg The type of the IO_CACHE to use for this log file
+
+ DESCRIPTION
+ Open the logfile, init IO_CACHE and write startup messages
+ (in case of general and slow query logs).
+
+ RETURN VALUES
+ 0 ok
+ 1 error
+*/
+
+bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
+ const char *new_name, enum cache_type io_cache_type_arg)
+{
+ char buff[FN_REFLEN];
+ File file= -1;
+ int open_flags= O_CREAT | O_BINARY;
+ DBUG_ENTER("MYSQL_LOG::open");
+ DBUG_PRINT("enter", ("log_type: %d", (int) log_type_arg));
+
+ write_error= 0;
+
+ init(log_type_arg, io_cache_type_arg);
+
+ if (!(name= my_strdup(log_name, MYF(MY_WME))))
+ {
+ name= (char *)log_name; // for the error message
+ goto err;
+ }
+
+ if (new_name)
+ strmov(log_file_name, new_name);
+ else if (generate_new_name(log_file_name, name))
+ goto err;
+
+ if (io_cache_type == SEQ_READ_APPEND)
+ open_flags |= O_RDWR | O_APPEND;
+ else
+ open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND);
+
+ db[0]= 0;
+
+ if ((file= my_open(log_file_name, open_flags,
+ MYF(MY_WME | ME_WAITTANG))) < 0 ||
+ init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
+ my_tell(file, MYF(MY_WME)), 0,
+ MYF(MY_WME | MY_NABP |
+ ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0))))
+ goto err;
+
+ if (log_type == LOG_NORMAL)
+ {
+ char *end;
+ int len=my_snprintf(buff, sizeof(buff), "%s, Version: %s. "
+#ifdef EMBEDDED_LIBRARY
+ "embedded library\n", my_progname, server_version
+#elif __NT__
+ "started with:\nTCP Port: %d, Named Pipe: %s\n",
+ my_progname, server_version, mysqld_port,
+ mysqld_unix_port
+#else
+ "started with:\nTcp port: %d Unix socket: %s\n",
+ my_progname, server_version, mysqld_port,
+ mysqld_unix_port
+#endif
+ );
+ end= strnmov(buff + len, "Time Id Command Argument\n",
+ sizeof(buff) - len);
+ if (my_b_write(&log_file, (byte*) buff, (uint) (end-buff)) ||
+ flush_io_cache(&log_file))
+ goto err;
+ }
+
+ log_state= LOG_OPENED;
+ DBUG_RETURN(0);
+
+err:
+ sql_print_error("Could not use %s for logging (error %d). \
+Turning logging off for the whole duration of the MySQL server process. \
+To turn it on again: fix the cause, \
+shutdown the MySQL server and restart it.", name, errno);
+ if (file >= 0)
+ my_close(file, MYF(0));
+ end_io_cache(&log_file);
+ safeFree(name);
+ log_state= LOG_CLOSED;
+ DBUG_RETURN(1);
+}
+
MYSQL_LOG::MYSQL_LOG()
- :bytes_written(0), last_time(0), query_start(0), name(0),
- prepared_xids(0), log_type(LOG_CLOSED), file_id(1), open_count(1),
- write_error(FALSE), inited(FALSE), need_start_event(TRUE),
- m_table_map_version(0),
- description_event_for_exec(0), description_event_for_queue(0)
+ : name(0), log_type(LOG_UNKNOWN), log_state(LOG_CLOSED), write_error(FALSE),
+ inited(FALSE)
{
/*
We don't want to initialize LOCK_Log here as such initialization depends on
@@ -1380,9 +1625,54 @@ MYSQL_LOG::MYSQL_LOG()
called only in main(). Doing initialization here would make it happen
before main().
*/
- index_file_name[0] = 0;
- bzero((char*) &log_file,sizeof(log_file));
- bzero((char*) &index_file, sizeof(index_file));
+ bzero((char*) &log_file, sizeof(log_file));
+}
+
+void MYSQL_LOG::init_pthread_objects()
+{
+ DBUG_ASSERT(inited == 0);
+ inited= 1;
+ (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
+}
+
+/*
+ Close the log file
+
+ SYNOPSIS
+ close()
+ exiting Bitmask. For the slow and general logs the only used bit is
+ LOG_CLOSE_TO_BE_OPENED. This is used if we intend to call
+ open at once after close.
+
+ NOTES
+ One can do an open on the object at once after doing a close.
+ The internal structures are not freed until cleanup() is called
+*/
+
+void MYSQL_LOG::close(uint exiting)
+{ // One can't set log_type here!
+ DBUG_ENTER("MYSQL_LOG::close");
+ DBUG_PRINT("enter",("exiting: %d", (int) exiting));
+ if (log_state == LOG_OPENED)
+ {
+ end_io_cache(&log_file);
+
+ if (my_sync(log_file.file, MYF(MY_WME)) && ! write_error)
+ {
+ write_error= 1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ }
+
+ if (my_close(log_file.file, MYF(MY_WME)) && ! write_error)
+ {
+ write_error= 1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ }
+ }
+
+ log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
+ safeFree(name);
+ DBUG_VOID_RETURN;
}
/* this is called only once */
@@ -1393,12 +1683,8 @@ void MYSQL_LOG::cleanup()
if (inited)
{
inited= 0;
- close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
- delete description_event_for_queue;
- delete description_event_for_exec;
(void) pthread_mutex_destroy(&LOCK_log);
- (void) pthread_mutex_destroy(&LOCK_index);
- (void) pthread_cond_destroy(&update_cond);
+ close(0);
}
DBUG_VOID_RETURN;
}
@@ -1406,8 +1692,8 @@ void MYSQL_LOG::cleanup()
int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
{
- fn_format(new_name,log_name,mysql_data_home,"",4);
- if (log_type != LOG_NORMAL)
+ fn_format(new_name, log_name, mysql_data_home, "", 4);
+ if (log_type == LOG_BIN)
{
if (!fn_ext(log_name)[0])
{
@@ -1422,33 +1708,287 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
}
-void MYSQL_LOG::init(enum_log_type log_type_arg,
- enum cache_type io_cache_type_arg,
- bool no_auto_events_arg,
- ulong max_size_arg)
+/*
+ Reopen the log file
+
+ SYNOPSIS
+ reopen_file()
+
+ DESCRIPTION
+ Reopen the log file. The method is used during FLUSH LOGS
+ and locks LOCK_log mutex
+*/
+
+
+void MYSQL_QUERY_LOG::reopen_file()
{
- DBUG_ENTER("MYSQL_LOG::init");
- log_type = log_type_arg;
- io_cache_type = io_cache_type_arg;
- no_auto_events = no_auto_events_arg;
- max_size=max_size_arg;
- DBUG_PRINT("info",("log_type: %d max_size: %lu", log_type, max_size));
+ char *save_name;
+
+ DBUG_ENTER("MYSQL_LOG::reopen_file");
+ if (!is_open())
+ {
+ DBUG_PRINT("info",("log is closed"));
+ DBUG_VOID_RETURN;
+ }
+
+ pthread_mutex_lock(&LOCK_log);
+
+ save_name= name;
+ name= 0; // Don't free name
+ close(LOG_CLOSE_TO_BE_OPENED);
+
+ /*
+ Note that at this point, log_state != LOG_CLOSED (important for is_open()).
+ */
+
+ open(save_name, log_type, 0, io_cache_type);
+ my_free(save_name, MYF(0));
+
+ pthread_mutex_unlock(&LOCK_log);
+
DBUG_VOID_RETURN;
}
-void MYSQL_LOG::init_pthread_objects()
+/*
+ Write a command to traditional general log file
+
+ SYNOPSIS
+ write()
+
+ event_time command start timestamp
+ user_host the pointer to the string with user@host info
+ user_host_len length of the user_host string. this is computed once
+ and passed to all general log event handlers
+ thread_id Id of the thread, issued a query
+ command_type the type of the command being logged
+ command_type_len the length of the string above
+ sql_text the very text of the query being executed
+ sql_text_len the length of sql_text string
+
+ DESCRIPTION
+
+ Log given command to to normal (not rotable) log file
+
+ RETURN
+ FASE - OK
+ TRUE - error occured
+*/
+
+bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host,
+ uint user_host_len, int thread_id,
+ const char *command_type, uint command_type_len,
+ const char *sql_text, uint sql_text_len)
{
- DBUG_ASSERT(inited == 0);
- inited= 1;
- (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
- (void) pthread_cond_init(&update_cond, 0);
+ char buff[32];
+ uint length= 0;
+ char time_buff[MAX_TIME_SIZE];
+ struct tm start;
+ uint time_buff_len= 0;
+
+ /* Test if someone closed between the is_open test and lock */
+ if (is_open())
+ {
+ /* Note that my_b_write() assumes it knows the length for this */
+ if (event_time != last_time)
+ {
+ last_time= event_time;
+
+ localtime_r(&event_time, &start);
+
+ time_buff_len= my_snprintf(time_buff, MAX_TIME_SIZE,
+ "%02d%02d%02d %2d:%02d:%02d",
+ start.tm_year % 100, start.tm_mon + 1,
+ start.tm_mday, start.tm_hour,
+ start.tm_min, start.tm_sec);
+
+ if (my_b_write(&log_file, (byte*) &time_buff, time_buff_len))
+ goto err;
+ }
+ else
+ if (my_b_write(&log_file, (byte*) "\t\t" ,2) < 0)
+ goto err;
+
+ /* command_type, thread_id */
+ length= my_snprintf(buff, 32, "%5ld ", thread_id);
+
+ if (my_b_write(&log_file, (byte*) buff, length))
+ goto err;
+
+ if (my_b_write(&log_file, (byte*) command_type, command_type_len))
+ goto err;
+
+ if (my_b_write(&log_file, (byte*) "\t", 1))
+ goto err;
+
+ /* sql_text */
+ if (my_b_write(&log_file, (byte*) sql_text, sql_text_len))
+ goto err;
+
+ if (my_b_write(&log_file, (byte*) "\n", 1) ||
+ flush_io_cache(&log_file))
+ goto err;
+ }
+
+ return FALSE;
+err:
+
+ if (!write_error)
+ {
+ write_error= 1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ }
+ return TRUE;
}
+
+/*
+ Log a query to the traditional slow log file
+
+ SYNOPSIS
+ write()
+
+ thd THD of the query
+ current_time current timestamp
+ query_start_arg command start timestamp
+ user_host the pointer to the string with user@host info
+ user_host_len length of the user_host string. this is computed once
+ and passed to all general log event handlers
+ query_time Amount of time the query took to execute (in seconds)
+ lock_time Amount of time the query was locked (in seconds)
+ is_command The flag, which determines, whether the sql_text is a
+ query or an administrator command.
+ sql_text the very text of the query or administrator command
+ processed
+ sql_text_len the length of sql_text string
+
+ DESCRIPTION
+
+ Log a query to the slow log file.
+
+ RETURN
+ FALSE - OK
+ TRUE - error occured
+*/
+
+bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
+ time_t query_start_arg, const char *user_host,
+ uint user_host_len, longlong query_time,
+ longlong lock_time, bool is_command,
+ const char *sql_text, uint sql_text_len)
+{
+ bool error= 0;
+ DBUG_ENTER("MYSQL_QUERY_LOG::write");
+
+ if (!is_open())
+ DBUG_RETURN(0);
+
+ if (is_open())
+ { // Safety agains reopen
+ int tmp_errno= 0;
+ char buff[80], *end;
+ uint buff_len;
+ end= buff;
+
+ if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
+ {
+ Security_context *sctx= thd->security_ctx;
+ if (current_time != last_time)
+ {
+ last_time= current_time;
+ struct tm start;
+ localtime_r(&current_time, &start);
+
+ buff_len= my_snprintf(buff, sizeof buff,
+ "# Time: %02d%02d%02d %2d:%02d:%02d\n",
+ start.tm_year % 100, start.tm_mon + 1,
+ start.tm_mday, start.tm_hour,
+ start.tm_min, start.tm_sec);
+
+ /* Note that my_b_write() assumes it knows the length for this */
+ if (my_b_write(&log_file, (byte*) buff, buff_len))
+ tmp_errno= errno;
+ }
+ if (my_b_printf(&log_file, "# User@Host: ", sizeof("# User@Host: ") - 1)
+ != sizeof("# User@Host: ") - 1)
+ tmp_errno= errno;
+ if (my_b_printf(&log_file, user_host, user_host_len) != user_host_len)
+ tmp_errno= errno;
+ if (my_b_write(&log_file, (byte*) "\n", 1))
+ tmp_errno= errno;
+ }
+ /* For slow query log */
+ if (my_b_printf(&log_file,
+ "# Query_time: %lu Lock_time: %lu"
+ " Rows_sent: %lu Rows_examined: %lu\n",
+ (ulong) query_time, (ulong) lock_time,
+ (ulong) thd->sent_row_count,
+ (ulong) thd->examined_row_count) == (uint) -1)
+ tmp_errno= errno;
+ if (thd->db && strcmp(thd->db, db))
+ { // Database changed
+ if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
+ tmp_errno= errno;
+ strmov(db,thd->db);
+ }
+ if (thd->last_insert_id_used)
+ {
+ end=strmov(end, ",last_insert_id=");
+ end=longlong10_to_str((longlong) thd->current_insert_id, end, -10);
+ }
+ // Save value if we do an insert.
+ if (thd->insert_id_used)
+ {
+ if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
+ {
+ end=strmov(end,",insert_id=");
+ end=longlong10_to_str((longlong) thd->last_insert_id, end, -10);
+ }
+ }
+
+ /*
+ This info used to show up randomly, depending on whether the query
+ checked the query start time or not. now we always write current
+ timestamp to the slow log
+ */
+ end= strmov(end, ",timestamp=");
+ end= int10_to_str((long) current_time, end, 10);
+
+ if (end != buff)
+ {
+ *end++=';';
+ *end='\n';
+ if (my_b_write(&log_file, (byte*) "SET ", 4) ||
+ my_b_write(&log_file, (byte*) buff + 1, (uint) (end-buff)))
+ tmp_errno= errno;
+ }
+ if (is_command)
+ {
+ end= strxmov(buff, "# administrator command: ", NullS);
+ buff_len= (ulong) (end - buff);
+ my_b_write(&log_file, (byte*) buff, buff_len);
+ }
+ if (my_b_write(&log_file, (byte*) sql_text, sql_text_len) ||
+ my_b_write(&log_file, (byte*) ";\n",2) ||
+ flush_io_cache(&log_file))
+ tmp_errno= errno;
+ if (tmp_errno)
+ {
+ error= 1;
+ if (! write_error)
+ {
+ write_error= 1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, error);
+ }
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+
const char *MYSQL_LOG::generate_name(const char *log_name,
- const char *suffix,
- bool strip_ext, char *buff)
+ const char *suffix,
+ bool strip_ext, char *buff)
{
if (!log_name || !log_name[0])
{
@@ -1456,23 +1996,79 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
TODO: The following should be using fn_format(); We just need to
first change fn_format() to cut the file name if it's too long.
*/
- strmake(buff,glob_hostname,FN_REFLEN-5);
- strmov(fn_ext(buff),suffix);
+ strmake(buff, glob_hostname, FN_REFLEN - 5);
+ strmov(fn_ext(buff), suffix);
return (const char *)buff;
}
// get rid of extension if the log is binary to avoid problems
if (strip_ext)
{
- char *p = fn_ext(log_name);
- uint length=(uint) (p-log_name);
- strmake(buff,log_name,min(length,FN_REFLEN));
+ char *p= fn_ext(log_name);
+ uint length= (uint) (p - log_name);
+ strmake(buff, log_name, min(length, FN_REFLEN));
return (const char*)buff;
}
return log_name;
}
-bool MYSQL_LOG::open_index_file(const char *index_file_name_arg,
+
+MYSQL_BIN_LOG::MYSQL_BIN_LOG()
+ :bytes_written(0), prepared_xids(0), file_id(1), open_count(1),
+ need_start_event(TRUE), m_table_map_version(0),
+ description_event_for_exec(0), description_event_for_queue(0)
+{
+ /*
+ We don't want to initialize locks here as such initialization depends on
+ safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
+ called only in main(). Doing initialization here would make it happen
+ before main().
+ */
+ index_file_name[0] = 0;
+ bzero((char*) &index_file, sizeof(index_file));
+}
+
+/* this is called only once */
+
+void MYSQL_BIN_LOG::cleanup()
+{
+ DBUG_ENTER("cleanup");
+ if (inited)
+ {
+ inited= 0;
+ close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
+ delete description_event_for_queue;
+ delete description_event_for_exec;
+ (void) pthread_mutex_destroy(&LOCK_log);
+ (void) pthread_mutex_destroy(&LOCK_index);
+ (void) pthread_cond_destroy(&update_cond);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/* Init binlog-specific vars */
+void MYSQL_BIN_LOG::init(bool no_auto_events_arg, ulong max_size_arg)
+{
+ DBUG_ENTER("MYSQL_BIN_LOG::init");
+ no_auto_events= no_auto_events_arg;
+ max_size= max_size_arg;
+ DBUG_PRINT("info",("max_size: %lu", max_size));
+ DBUG_VOID_RETURN;
+}
+
+
+void MYSQL_BIN_LOG::init_pthread_objects()
+{
+ DBUG_ASSERT(inited == 0);
+ inited= 1;
+ (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
+ (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
+ (void) pthread_cond_init(&update_cond, 0);
+}
+
+
+bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
const char *log_name)
{
File index_file_nr= -1;
@@ -1509,10 +2105,10 @@ bool MYSQL_LOG::open_index_file(const char *index_file_name_arg,
/*
- Open a (new) log file.
+ Open a (new) binlog file.
DESCRIPTION
- - If binary logs, also open the index file and register the new
+ - Open the log file and the index file. Register the new
file name in it
- When calling this when the file is in use, you must have a locks
on LOCK_log and LOCK_index.
@@ -1522,94 +2118,32 @@ bool MYSQL_LOG::open_index_file(const char *index_file_name_arg,
1 error
*/
-bool MYSQL_LOG::open(const char *log_name,
- enum_log_type log_type_arg,
- const char *new_name,
- enum cache_type io_cache_type_arg,
- bool no_auto_events_arg,
- ulong max_size_arg,
- bool null_created_arg)
+bool MYSQL_BIN_LOG::open(const char *log_name,
+ enum_log_type log_type_arg,
+ const char *new_name,
+ enum cache_type io_cache_type_arg,
+ bool no_auto_events_arg,
+ ulong max_size_arg,
+ bool null_created_arg)
{
char buff[FN_REFLEN];
File file= -1;
int open_flags = O_CREAT | O_BINARY;
- DBUG_ENTER("MYSQL_LOG::open");
+ DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
- last_time=query_start=0;
write_error=0;
- init(log_type_arg,io_cache_type_arg,no_auto_events_arg,max_size_arg);
+ /* open the main log file */
+ if (MYSQL_LOG::open(log_name, log_type_arg, new_name, io_cache_type_arg))
+ DBUG_RETURN(1); /* all warnings issued */
- if (!(name=my_strdup(log_name,MYF(MY_WME))))
- {
- name= (char *)log_name; // for the error message
- goto err;
- }
- if (new_name)
- strmov(log_file_name,new_name);
- else if (generate_new_name(log_file_name, name))
- goto err;
+ init(no_auto_events_arg, max_size_arg);
- if (io_cache_type == SEQ_READ_APPEND)
- open_flags |= O_RDWR | O_APPEND;
- else
- open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND);
-
- db[0]=0;
open_count++;
- if ((file=my_open(log_file_name,open_flags,
- MYF(MY_WME | ME_WAITTANG))) < 0 ||
- init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
- my_tell(file,MYF(MY_WME)), 0,
- MYF(MY_WME | MY_NABP |
- ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0))))
- goto err;
- switch (log_type) {
- case LOG_NORMAL:
- {
- char *end;
- int len=my_snprintf(buff, sizeof(buff), "%s, Version: %s. "
-#ifdef EMBEDDED_LIBRARY
- "embedded library\n", my_progname, server_version
-#elif __NT__
- "started with:\nTCP Port: %d, Named Pipe: %s\n",
- my_progname, server_version, mysqld_port, mysqld_unix_port
-#else
- "started with:\nTcp port: %d Unix socket: %s\n",
- my_progname,server_version,mysqld_port,mysqld_unix_port
-#endif
- );
- end=strnmov(buff+len,"Time Id Command Argument\n",
- sizeof(buff)-len);
- if (my_b_write(&log_file, (byte*) buff,(uint) (end-buff)) ||
- flush_io_cache(&log_file))
- goto err;
- break;
- }
- case LOG_NEW:
- {
- uint len;
- time_t skr=time(NULL);
- struct tm tm_tmp;
-
- localtime_r(&skr,&tm_tmp);
- len= my_snprintf(buff,sizeof(buff),
- "# %s, Version: %s at %02d%02d%02d %2d:%02d:%02d\n",
- my_progname,server_version,
- tm_tmp.tm_year % 100,
- tm_tmp.tm_mon+1,
- tm_tmp.tm_mday,
- tm_tmp.tm_hour,
- tm_tmp.tm_min,
- tm_tmp.tm_sec);
- if (my_b_write(&log_file, (byte*) buff, len) ||
- flush_io_cache(&log_file))
- goto err;
- break;
- }
- case LOG_BIN:
+ DBUG_ASSERT(log_type == LOG_BIN);
+
{
bool write_file_name_to_index_file=0;
@@ -1700,13 +2234,9 @@ bool MYSQL_LOG::open(const char *log_name,
my_sync(index_file.file, MYF(MY_WME)))
goto err;
}
- break;
- }
- case LOG_CLOSED: // Impossible
- case LOG_TO_BE_OPENED:
- DBUG_ASSERT(1);
- break;
}
+ log_state= LOG_OPENED;
+
DBUG_RETURN(0);
err:
@@ -1719,12 +2249,12 @@ shutdown the MySQL server and restart it.", name, errno);
end_io_cache(&log_file);
end_io_cache(&index_file);
safeFree(name);
- log_type= LOG_CLOSED;
+ log_state= LOG_CLOSED;
DBUG_RETURN(1);
}
-int MYSQL_LOG::get_current_log(LOG_INFO* linfo)
+int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
{
pthread_mutex_lock(&LOCK_log);
strmake(linfo->log_file_name, log_file_name, sizeof(linfo->log_file_name)-1);
@@ -1811,7 +2341,7 @@ err:
LOG_INFO_IO Got IO error while reading file
*/
-int MYSQL_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
+int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
bool need_lock)
{
int error= 0;
@@ -1885,7 +2415,7 @@ int MYSQL_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
LOG_INFO_IO Got IO error while reading file
*/
-int MYSQL_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
+int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
{
int error= 0;
uint length;
@@ -1933,12 +2463,11 @@ err:
1 error
*/
-bool MYSQL_LOG::reset_logs(THD* thd)
+bool MYSQL_BIN_LOG::reset_logs(THD* thd)
{
LOG_INFO linfo;
bool error=0;
const char* save_name;
- enum_log_type save_log_type;
DBUG_ENTER("reset_logs");
ha_reset_logs(thd);
@@ -1960,7 +2489,6 @@ bool MYSQL_LOG::reset_logs(THD* thd)
/* Save variables so that we can reopen the log */
save_name=name;
name=0; // Protect against free
- save_log_type=log_type;
close(LOG_CLOSE_TO_BE_OPENED);
/* First delete all old log files */
@@ -1973,19 +2501,18 @@ bool MYSQL_LOG::reset_logs(THD* thd)
for (;;)
{
- my_delete(linfo.log_file_name, MYF(MY_WME));
+ my_delete_allow_opened(linfo.log_file_name, MYF(MY_WME));
if (find_next_log(&linfo, 0))
break;
}
/* Start logging with a new file */
close(LOG_CLOSE_INDEX);
- my_delete(index_file_name, MYF(MY_WME)); // Reset (open will update)
+ my_delete_allow_opened(index_file_name, MYF(MY_WME)); // Reset (open will update)
if (!thd->slave_thread)
need_start_event=1;
if (!open_index_file(index_file_name, 0))
- open(save_name, save_log_type, 0,
- io_cache_type, no_auto_events, max_size, 0);
+ open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0);
my_free((gptr) save_name, MYF(0));
err:
@@ -2033,7 +2560,7 @@ err:
#ifdef HAVE_REPLICATION
-int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included)
+int MYSQL_BIN_LOG::purge_first_log(struct st_relay_log_info* rli, bool included)
{
int error;
DBUG_ENTER("purge_first_log");
@@ -2109,7 +2636,7 @@ err:
Update log index_file
*/
-int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
+int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
{
if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
return LOG_INFO_IO;
@@ -2142,7 +2669,7 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
LOG_INFO_EOF to_log not found
*/
-int MYSQL_LOG::purge_logs(const char *to_log,
+int MYSQL_BIN_LOG::purge_logs(const char *to_log,
bool included,
bool need_mutex,
bool need_update_threads,
@@ -2228,7 +2755,7 @@ err:
LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
*/
-int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
+int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
{
int error;
LOG_INFO log_info;
@@ -2287,7 +2814,7 @@ err:
If file name will be longer then FN_REFLEN it will be truncated
*/
-void MYSQL_LOG::make_log_name(char* buf, const char* log_ident)
+void MYSQL_BIN_LOG::make_log_name(char* buf, const char* log_ident)
{
uint dir_len = dirname_length(log_file_name);
if (dir_len > FN_REFLEN)
@@ -2301,29 +2828,48 @@ void MYSQL_LOG::make_log_name(char* buf, const char* log_ident)
Check if we are writing/reading to the given log file
*/
-bool MYSQL_LOG::is_active(const char *log_file_name_arg)
+bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
{
return !strcmp(log_file_name, log_file_name_arg);
}
/*
+ Wrappers around new_file_impl to avoid using argument
+ to control locking. The argument 1) less readable 2) breaks
+ incapsulation 3) allows external access to the class without
+ a lock (which is not possible with private new_file_without_locking
+ method).
+*/
+
+void MYSQL_BIN_LOG::new_file()
+{
+ new_file_impl(1);
+}
+
+
+void MYSQL_BIN_LOG::new_file_without_locking()
+{
+ new_file_impl(0);
+}
+
+
+/*
Start writing to a new log file or reopen the old file
SYNOPSIS
- new_file()
+ new_file_impl()
need_lock Set to 1 if caller has not locked LOCK_log
NOTE
The new file name is stored last in the index file
*/
-void MYSQL_LOG::new_file(bool need_lock)
+void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
{
char new_name[FN_REFLEN], *new_name_ptr, *old_name;
- enum_log_type save_log_type;
- DBUG_ENTER("MYSQL_LOG::new_file");
+ DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
if (!is_open())
{
DBUG_PRINT("info",("log is closed"));
@@ -2389,12 +2935,11 @@ void MYSQL_LOG::new_file(bool need_lock)
signal_update();
}
old_name=name;
- save_log_type=log_type;
name=0; // Don't free name
close(LOG_CLOSE_TO_BE_OPENED);
/*
- Note that at this point, log_type != LOG_CLOSED (important for is_open()).
+ Note that at this point, log_state != LOG_CLOSED (important for is_open()).
*/
/*
@@ -2406,7 +2951,7 @@ void MYSQL_LOG::new_file(bool need_lock)
trigger temp tables deletion on slaves.
*/
- open(old_name, save_log_type, new_name_ptr,
+ open(old_name, log_type, new_name_ptr,
io_cache_type, no_auto_events, max_size, 1);
my_free(old_name,MYF(0));
@@ -2419,11 +2964,11 @@ end:
}
-bool MYSQL_LOG::append(Log_event* ev)
+bool MYSQL_BIN_LOG::append(Log_event* ev)
{
bool error = 0;
pthread_mutex_lock(&LOCK_log);
- DBUG_ENTER("MYSQL_LOG::append");
+ DBUG_ENTER("MYSQL_BIN_LOG::append");
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
/*
@@ -2438,7 +2983,7 @@ bool MYSQL_LOG::append(Log_event* ev)
bytes_written+= ev->data_written;
DBUG_PRINT("info",("max_size: %lu",max_size));
if ((uint) my_b_append_tell(&log_file) > max_size)
- new_file(0);
+ new_file_without_locking();
err:
pthread_mutex_unlock(&LOCK_log);
@@ -2447,10 +2992,10 @@ err:
}
-bool MYSQL_LOG::appendv(const char* buf, uint len,...)
+bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
{
bool error= 0;
- DBUG_ENTER("MYSQL_LOG::appendv");
+ DBUG_ENTER("MYSQL_BIN_LOG::appendv");
va_list(args);
va_start(args,len);
@@ -2468,7 +3013,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
DBUG_PRINT("info",("max_size: %lu",max_size));
if ((uint) my_b_append_tell(&log_file) > max_size)
- new_file(0);
+ new_file_without_locking();
err:
if (!error)
@@ -2477,99 +3022,7 @@ err:
}
-/*
- Write a command to traditional general log file
-
- SYNOPSIS
- write()
-
- event_time command start timestamp
- user_host the pointer to the string with user@host info
- user_host_len length of the user_host string. this is computed once
- and passed to all general log event handlers
- thread_id Id of the thread, issued a query
- command_type the type of the command being logged
- command_type_len the length of the string above
- sql_text the very text of the query being executed
- sql_text_len the length of sql_text string
-
- DESCRIPTION
-
- Log given command to to normal (not rotable) log file
-
- RETURN
- FASE - OK
- TRUE - error occured
-*/
-
-bool MYSQL_LOG::write(time_t event_time, const char *user_host,
- uint user_host_len, int thread_id,
- const char *command_type, uint command_type_len,
- const char *sql_text, uint sql_text_len)
-{
- char buff[32];
- uint length= 0;
- char time_buff[MAX_TIME_SIZE];
- struct tm start;
- uint time_buff_len= 0;
-
- /* Test if someone closed between the is_open test and lock */
- if (is_open())
- {
- /* Note that my_b_write() assumes it knows the length for this */
- if (event_time != last_time)
- {
- last_time= event_time;
-
- localtime_r(&event_time, &start);
-
- time_buff_len= my_snprintf(time_buff, MAX_TIME_SIZE,
- "%02d%02d%02d %2d:%02d:%02d",
- start.tm_year % 100, start.tm_mon + 1,
- start.tm_mday, start.tm_hour,
- start.tm_min, start.tm_sec);
-
- if (my_b_write(&log_file, (byte*) &time_buff, time_buff_len))
- goto err;
- }
- else
- if (my_b_write(&log_file, (byte*) "\t\t" ,2) < 0)
- goto err;
-
- /* command_type, thread_id */
- length= my_snprintf(buff, 32, "%5ld ", thread_id);
-
- if (my_b_write(&log_file, (byte*) buff, length))
- goto err;
-
- if (my_b_write(&log_file, (byte*) command_type, command_type_len))
- goto err;
-
- if (my_b_write(&log_file, (byte*) "\t", 1))
- goto err;
-
- /* sql_text */
- if (my_b_write(&log_file, (byte*) sql_text, sql_text_len))
- goto err;
-
- if (my_b_write(&log_file, (byte*) "\n", 1) ||
- flush_io_cache(&log_file))
- goto err;
- }
-
- return FALSE;
-err:
-
- if (!write_error)
- {
- write_error= 1;
- sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
- }
- return TRUE;
-}
-
-
-bool MYSQL_LOG::flush_and_sync()
+bool MYSQL_BIN_LOG::flush_and_sync()
{
int err=0, fd=log_file.file;
safe_mutex_assert_owner(&LOCK_log);
@@ -2583,7 +3036,7 @@ bool MYSQL_LOG::flush_and_sync()
return err;
}
-void MYSQL_LOG::start_union_events(THD *thd)
+void MYSQL_BIN_LOG::start_union_events(THD *thd)
{
DBUG_ASSERT(!thd->binlog_evt_union.do_union);
thd->binlog_evt_union.do_union= TRUE;
@@ -2592,20 +3045,19 @@ void MYSQL_LOG::start_union_events(THD *thd)
thd->binlog_evt_union.first_query_id= thd->query_id;
}
-void MYSQL_LOG::stop_union_events(THD *thd)
+void MYSQL_BIN_LOG::stop_union_events(THD *thd)
{
DBUG_ASSERT(thd->binlog_evt_union.do_union);
thd->binlog_evt_union.do_union= FALSE;
}
-bool MYSQL_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
+bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
{
return (thd->binlog_evt_union.do_union &&
query_id_param >= thd->binlog_evt_union.first_query_id);
}
-#ifdef HAVE_ROW_BASED_REPLICATION
/*
These functions are placed in this file since they need access to
binlog_hton, which has internal linkage.
@@ -2641,6 +3093,7 @@ int THD::binlog_setup_trx_data()
engine has registered for the transaction.
*/
+#ifdef HAVE_ROW_BASED_REPLICATION
int THD::binlog_write_table_map(TABLE *table, bool is_trans)
{
int error;
@@ -2705,9 +3158,10 @@ THD::binlog_set_pending_rows_event(Rows_log_event* ev)
(either cached binlog if transaction, or disk binlog). Sets a new pending
event.
*/
-int MYSQL_LOG::flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event)
+int MYSQL_BIN_LOG::
+ flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event)
{
- DBUG_ENTER("MYSQL_LOG::flush_and_set_pending_rows_event(event)");
+ DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)");
DBUG_ASSERT(thd->current_stmt_binlog_row_based && mysql_bin_log.is_open());
DBUG_PRINT("enter", ("event=%p", event));
@@ -2791,11 +3245,11 @@ int MYSQL_LOG::flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event)
Write an event to the binary log
*/
-bool MYSQL_LOG::write(Log_event *event_info)
+bool MYSQL_BIN_LOG::write(Log_event *event_info)
{
THD *thd= event_info->thd;
bool error= 1;
- DBUG_ENTER("MYSQL_LOG::write(Log_event *)");
+ DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
if (thd->binlog_evt_union.do_union)
{
@@ -2818,9 +3272,9 @@ bool MYSQL_LOG::write(Log_event *event_info)
we are inside a stored function, we do not end the statement since
this will close all tables on the slave.
*/
+#ifdef HAVE_ROW_BASED_REPLICATION
bool const end_stmt=
thd->prelocked_mode && thd->lex->requires_prelocking();
-#ifdef HAVE_ROW_BASED_REPLICATION
thd->binlog_flush_pending_rows_event(end_stmt);
#endif /*HAVE_ROW_BASED_REPLICATION*/
@@ -2871,7 +3325,6 @@ bool MYSQL_LOG::write(Log_event *event_info)
(binlog_trx_data*) thd->ha_data[binlog_hton.slot];
IO_CACHE *trans_log= &trx_data->trans_log;
bool trans_log_in_use= my_b_tell(trans_log) != 0;
-
if (event_info->get_cache_stmt() && !trans_log_in_use)
trans_register_ha(thd,
(thd->options &
@@ -3015,14 +3468,14 @@ bool general_log_print(THD *thd, enum enum_server_command command,
return error;
}
-void MYSQL_LOG::rotate_and_purge(uint flags)
+void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
{
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
pthread_mutex_lock(&LOCK_log);
if ((flags & RP_FORCE_ROTATE) ||
(my_b_tell(&log_file) >= (my_off_t) max_size))
{
- new_file(0);
+ new_file_without_locking();
#ifdef HAVE_REPLICATION
if (expire_logs_days)
{
@@ -3036,7 +3489,7 @@ void MYSQL_LOG::rotate_and_purge(uint flags)
pthread_mutex_unlock(&LOCK_log);
}
-uint MYSQL_LOG::next_file_id()
+uint MYSQL_BIN_LOG::next_file_id()
{
uint res;
pthread_mutex_lock(&LOCK_log);
@@ -3067,11 +3520,14 @@ uint MYSQL_LOG::next_file_id()
that the same updates are run on the slave.
*/
-bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
+bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
{
- DBUG_ENTER("MYSQL_LOG::write(THD *, IO_CACHE *, Log_event *)");
+ DBUG_ENTER("MYSQL_BIN_LOG::write(THD *, IO_CACHE *, Log_event *)");
VOID(pthread_mutex_lock(&LOCK_log));
+ /* NULL would represent nothing to replicate after ROLLBACK */
+ DBUG_ASSERT(commit_event != NULL);
+
if (likely(is_open())) // Should always be true
{
uint length;
@@ -3165,148 +3621,6 @@ err:
/*
- Log a query to the traditional slow log file
-
- SYNOPSIS
- write()
-
- thd THD of the query
- current_time current timestamp
- query_start_arg command start timestamp
- user_host the pointer to the string with user@host info
- user_host_len length of the user_host string. this is computed once
- and passed to all general log event handlers
- query_time Amount of time the query took to execute (in seconds)
- lock_time Amount of time the query was locked (in seconds)
- is_command The flag, which determines, whether the sql_text is a
- query or an administrator command.
- sql_text the very text of the query or administrator command
- processed
- sql_text_len the length of sql_text string
-
- DESCRIPTION
-
- Log a query to the slow log file.
-
- RETURN
- FALSE - OK
- TRUE - error occured
-*/
-
-bool MYSQL_LOG::write(THD *thd, time_t current_time, time_t query_start_arg,
- const char *user_host, uint user_host_len,
- longlong query_time, longlong lock_time, bool is_command,
- const char *sql_text, uint sql_text_len)
-{
- bool error= 0;
- DBUG_ENTER("MYSQL_LOG::write");
-
- if (!is_open())
- DBUG_RETURN(0);
-
- if (is_open())
- { // Safety agains reopen
- int tmp_errno= 0;
- char buff[80], *end;
- uint buff_len;
- end= buff;
-
- if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
- {
- Security_context *sctx= thd->security_ctx;
- if (current_time != last_time)
- {
- last_time= current_time;
- struct tm start;
- localtime_r(&current_time, &start);
-
- buff_len= my_snprintf(buff, sizeof buff,
- "# Time: %02d%02d%02d %2d:%02d:%02d\n",
- start.tm_year % 100, start.tm_mon + 1,
- start.tm_mday, start.tm_hour,
- start.tm_min, start.tm_sec);
-
- /* Note that my_b_write() assumes it knows the length for this */
- if (my_b_write(&log_file, (byte*) buff, buff_len))
- tmp_errno=errno;
- }
- if (my_b_printf(&log_file, "# User@Host: ", sizeof("# User@Host: ") - 1))
- tmp_errno=errno;
- if (my_b_printf(&log_file, user_host, user_host_len))
- tmp_errno=errno;
- if (my_b_write(&log_file, (byte*) "\n", 1))
- tmp_errno=errno;
- }
- /* For slow query log */
- if (my_b_printf(&log_file,
- "# Query_time: %lu Lock_time: %lu"
- " Rows_sent: %lu Rows_examined: %lu\n",
- (ulong) query_time, (ulong) lock_time,
- (ulong) thd->sent_row_count,
- (ulong) thd->examined_row_count) == (uint) -1)
- tmp_errno=errno;
- if (thd->db && strcmp(thd->db,db))
- { // Database changed
- if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
- tmp_errno=errno;
- strmov(db,thd->db);
- }
- if (thd->last_insert_id_used)
- {
- end=strmov(end,",last_insert_id=");
- end=longlong10_to_str((longlong) thd->current_insert_id,end,-10);
- }
- // Save value if we do an insert.
- if (thd->insert_id_used)
- {
- if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
- {
- end=strmov(end,",insert_id=");
- end=longlong10_to_str((longlong) thd->last_insert_id,end,-10);
- }
- }
-
- /*
- This info used to show up randomly, depending on whether the query
- checked the query start time or not. now we always write current
- timestamp to the slow log
- */
- end= strmov(end, ",timestamp=");
- end= int10_to_str((long) current_time, end, 10);
-
- if (end != buff)
- {
- *end++=';';
- *end='\n';
- if (my_b_write(&log_file, (byte*) "SET ",4) ||
- my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff)))
- tmp_errno=errno;
- }
- if (is_command)
- {
- end= strxmov(buff, "# administrator command: ", NullS);
- buff_len= (ulong) (end - buff);
- my_b_write(&log_file, (byte*) buff, buff_len);
- }
- if (my_b_write(&log_file, (byte*) sql_text, sql_text_len) ||
- my_b_write(&log_file, (byte*) ";\n",2) ||
- flush_io_cache(&log_file))
- tmp_errno=errno;
- if (tmp_errno)
- {
- error=1;
- if (! write_error)
- {
- write_error=1;
- sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
- }
- }
- }
- DBUG_RETURN(error);
-}
-
-
-/*
Wait until we get a signal that the binary log has been updated
SYNOPSIS
@@ -3322,7 +3636,7 @@ bool MYSQL_LOG::write(THD *thd, time_t current_time, time_t query_start_arg,
THD::enter_cond() (see NOTES in sql_class.h).
*/
-void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave)
+void MYSQL_BIN_LOG::wait_for_update(THD* thd, bool is_slave)
{
const char *old_msg;
DBUG_ENTER("wait_for_update");
@@ -3355,11 +3669,11 @@ void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave)
The internal structures are not freed until cleanup() is called
*/
-void MYSQL_LOG::close(uint exiting)
+void MYSQL_BIN_LOG::close(uint exiting)
{ // One can't set log_type here!
- DBUG_ENTER("MYSQL_LOG::close");
+ DBUG_ENTER("MYSQL_BIN_LOG::close");
DBUG_PRINT("enter",("exiting: %d", (int) exiting));
- if (log_type != LOG_CLOSED && log_type != LOG_TO_BE_OPENED)
+ if (log_state == LOG_OPENED)
{
#ifdef HAVE_REPLICATION
if (log_type == LOG_BIN && !no_auto_events &&
@@ -3371,7 +3685,6 @@ void MYSQL_LOG::close(uint exiting)
signal_update();
}
#endif /* HAVE_REPLICATION */
- end_io_cache(&log_file);
/* don't pwrite in a file opened with O_APPEND - it doesn't work */
if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
@@ -3381,16 +3694,8 @@ void MYSQL_LOG::close(uint exiting)
my_pwrite(log_file.file, &flags, 1, offset, MYF(0));
}
- if (my_sync(log_file.file,MYF(MY_WME)) && ! write_error)
- {
- write_error=1;
- sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
- }
- if (my_close(log_file.file,MYF(MY_WME)) && ! write_error)
- {
- write_error=1;
- sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
- }
+ /* this will cleanup IO_CACHE, sync and close the file */
+ MYSQL_LOG::close(exiting);
}
/*
@@ -3407,13 +3712,13 @@ void MYSQL_LOG::close(uint exiting)
sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
}
}
- log_type= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
+ log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
safeFree(name);
DBUG_VOID_RETURN;
}
-void MYSQL_LOG::set_max_size(ulong max_size_arg)
+void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
{
/*
We need to take locks, otherwise this may happen:
@@ -3422,7 +3727,7 @@ void MYSQL_LOG::set_max_size(ulong max_size_arg)
uses the old_max_size argument, so max_size_arg has been overwritten and
it's like if the SET command was never run.
*/
- DBUG_ENTER("MYSQL_LOG::set_max_size");
+ DBUG_ENTER("MYSQL_BIN_LOG::set_max_size");
pthread_mutex_lock(&LOCK_log);
if (is_open())
max_size= max_size_arg;
@@ -3571,9 +3876,9 @@ bool flush_error_log()
return result;
}
-void MYSQL_LOG::signal_update()
+void MYSQL_BIN_LOG::signal_update()
{
- DBUG_ENTER("MYSQL_LOG::signal_update");
+ DBUG_ENTER("MYSQL_BIN_LOG::signal_update");
pthread_cond_broadcast(&update_cond);
DBUG_VOID_RETURN;
}
@@ -4176,7 +4481,7 @@ int TC_LOG::using_heuristic_recover()
}
/****** transaction coordinator log for 2pc - binlog() based solution ******/
-#define TC_LOG_BINLOG MYSQL_LOG
+#define TC_LOG_BINLOG MYSQL_BIN_LOG
/*
TODO keep in-memory list of prepared transactions