diff options
author | Alexander Nozdrin <alik@sun.com> | 2010-01-18 23:19:19 +0300 |
---|---|---|
committer | Alexander Nozdrin <alik@sun.com> | 2010-01-18 23:19:19 +0300 |
commit | dedfdb490ba528ddf3f9155a4fb6f0b3728df149 (patch) | |
tree | d38210df12297fa40d9edbf59cbb72329a4ccad4 /sql/log.cc | |
parent | 7917f0852f57ff0fecb80f561eccd674a4e1866d (diff) | |
parent | dccf2acceab7a3ed125c0d9c11330fe5f6898a1f (diff) | |
download | mariadb-git-dedfdb490ba528ddf3f9155a4fb6f0b3728df149.tar.gz |
Manual merge from mysql-next-mr.
Conflicts:
- sql/sql_plugin.cc
Diffstat (limited to 'sql/log.cc')
-rw-r--r-- | sql/log.cc | 1536 |
1 files changed, 873 insertions, 663 deletions
diff --git a/sql/log.cc b/sql/log.cc index dd5a041290a..7d5d5f9e176 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -138,18 +138,22 @@ sql_print_message_func sql_print_message_handlers[3] = sql_print_error }; - /** - Create the name of the default general log file - + Create the name of the log specified. + + This method forms a new path + file name for the + log specified in @c name. + @param[IN] buff Location for building new string. - @param[IN] log_ext The extension for the file (e.g .log) - @returns Pointer to a new string containing the name + @param[IN] name Name of the log file. + @param[IN] log_ext The extension for the log (e.g. .log). + + @returns Pointer to new string containing the name. */ -char *make_default_log_name(char *buff,const char* log_ext) +char *make_log_name(char *buff, const char *name, const char* log_ext) { - strmake(buff, default_logfile_name, FN_REFLEN-5); - return fn_format(buff, buff, mysql_data_home, log_ext, + strmake(buff, name, FN_REFLEN-5); + return fn_format(buff, buff, mysql_real_data_home, log_ext, MYF(MY_UNPACK_FILENAME|MY_REPLACE_EXT)); } @@ -164,24 +168,24 @@ char *make_default_log_name(char *buff,const char* log_ext) class Mutex_sentry { public: - Mutex_sentry(pthread_mutex_t *mutex) + Mutex_sentry(mysql_mutex_t *mutex) : m_mutex(mutex) { if (m_mutex) - pthread_mutex_lock(mutex); + mysql_mutex_lock(mutex); } ~Mutex_sentry() { if (m_mutex) - pthread_mutex_unlock(m_mutex); + mysql_mutex_unlock(m_mutex); #ifndef DBUG_OFF m_mutex= 0; #endif } private: - pthread_mutex_t *m_mutex; + mysql_mutex_t *m_mutex; // It's not allowed to copy this object in any way Mutex_sentry(Mutex_sentry const&); @@ -189,115 +193,155 @@ private: }; /* - Helper class to store binary log transaction data. + Helper classes to store non-transactional and transactional data + before copying it to the binary log. */ -class binlog_trx_data { +class binlog_cache_data +{ public: - binlog_trx_data() - : at_least_one_stmt_committed(0), incident(FALSE), m_pending(0), - before_stmt_pos(MY_OFF_T_UNDEF) + binlog_cache_data(): m_pending(0), before_stmt_pos (MY_OFF_T_UNDEF), + incident(FALSE) { - trans_log.end_of_file= max_binlog_cache_size; + cache_log.end_of_file= max_binlog_cache_size; } - ~binlog_trx_data() + ~binlog_cache_data() { - DBUG_ASSERT(pending() == NULL); - close_cached_file(&trans_log); + DBUG_ASSERT(empty()); + close_cached_file(&cache_log); } - my_off_t position() const { - return my_b_tell(&trans_log); + bool empty() const + { + return pending() == NULL && my_b_tell(&cache_log) == 0; } - bool empty() const + Rows_log_event *pending() const { - return pending() == NULL && my_b_tell(&trans_log) == 0; + return m_pending; } - /* - Truncate the transaction cache to a certain position. This - includes deleting the pending event. - */ - void truncate(my_off_t pos) + void set_pending(Rows_log_event *const pending) { - DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos)); - DBUG_PRINT("info", ("before_stmt_pos=%lu", (ulong) pos)); - if (pending()) - { - delete pending(); - } - set_pending(0); - reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0); - trans_log.end_of_file= max_binlog_cache_size; - if (pos < before_stmt_pos) - before_stmt_pos= MY_OFF_T_UNDEF; + m_pending= pending; + } - /* - The only valid positions that can be truncated to are at the - beginning of a statement. We are relying on this fact to be able - to set the at_least_one_stmt_committed flag correctly. In other word, if - we are truncating to the beginning of the transaction cache, - there will be no statements in the cache, otherwhise, we will - have at least one statement in the transaction cache. - */ - at_least_one_stmt_committed= (pos > 0); + void set_incident(void) + { + incident= TRUE; + } + + bool has_incident(void) + { + return(incident); } - /* - Reset the entire contents of the transaction cache, emptying it - completely. - */ - void reset() { - if (!empty()) - truncate(0); - before_stmt_pos= MY_OFF_T_UNDEF; + void reset() + { + truncate(0); incident= FALSE; - trans_log.end_of_file= max_binlog_cache_size; + before_stmt_pos= MY_OFF_T_UNDEF; + cache_log.end_of_file= max_binlog_cache_size; DBUG_ASSERT(empty()); } - Rows_log_event *pending() const + my_off_t get_byte_position() const { - return m_pending; + return my_b_tell(&cache_log); } - void set_pending(Rows_log_event *const pending) + my_off_t get_prev_position() { - m_pending= pending; + return(before_stmt_pos); } - IO_CACHE trans_log; // The transaction cache - - void set_incident(void) + void set_prev_position(my_off_t pos) { - incident= TRUE; + before_stmt_pos= pos; } - bool has_incident(void) + void restore_prev_position() { - return(incident); + truncate(before_stmt_pos); } - /** - Boolean that is true if there is at least one statement in the - transaction cache. + void restore_savepoint(my_off_t pos) + { + truncate(pos); + if (pos < before_stmt_pos) + before_stmt_pos= MY_OFF_T_UNDEF; + } + + /* + Cache to store data before copying it to the binary log. */ - bool at_least_one_stmt_committed; - bool incident; + IO_CACHE cache_log; private: /* - Pending binrows event. This event is the event where the rows are - currently written. + Pending binrows event. This event is the event where the rows are currently + written. */ Rows_log_event *m_pending; -public: /* Binlog position before the start of the current statement. */ my_off_t before_stmt_pos; + + /* + This indicates that some events did not get into the cache and most likely + it is corrupted. + */ + bool incident; + + /* + It truncates the cache to a certain position. This includes deleting the + pending event. + */ + void truncate(my_off_t pos) + { + DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos)); + if (pending()) + { + delete pending(); + set_pending(0); + } + reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, 0); + cache_log.end_of_file= max_binlog_cache_size; + } + + binlog_cache_data& operator=(const binlog_cache_data& info); + binlog_cache_data(const binlog_cache_data& info); +}; + +class binlog_cache_mngr { +public: + binlog_cache_mngr() {} + + void reset_cache(binlog_cache_data* cache_data) + { + cache_data->reset(); + } + + binlog_cache_data* get_binlog_cache_data(bool is_transactional) + { + return (is_transactional ? &trx_cache : &stmt_cache); + } + + IO_CACHE* get_binlog_cache_log(bool is_transactional) + { + return (is_transactional ? &trx_cache.cache_log : &stmt_cache.cache_log); + } + + binlog_cache_data stmt_cache; + + binlog_cache_data trx_cache; + +private: + + binlog_cache_mngr& operator=(const binlog_cache_mngr& info); + binlog_cache_mngr(const binlog_cache_mngr& info); }; handlerton *binlog_hton; @@ -420,8 +464,8 @@ bool Log_to_csv_event_handler:: */ save_time_zone_used= thd->time_zone_used; - save_thd_options= thd->options; - thd->options&= ~OPTION_BIN_LOG; + save_thd_options= thd->variables.option_bits; + thd->variables.option_bits&= ~OPTION_BIN_LOG; bzero(& table_list, sizeof(TABLE_LIST)); table_list.alias= table_list.table_name= GENERAL_LOG_NAME.str; @@ -433,7 +477,7 @@ bool Log_to_csv_event_handler:: table_list.db_length= MYSQL_SCHEMA_NAME.length; /* - 1) open_performance_schema_table generates an error of the + 1) open_log_table generates an error of the table can not be opened or is corrupted. 2) "INSERT INTO general_log" can generate warning sometimes. @@ -446,8 +490,7 @@ bool Log_to_csv_event_handler:: thd->push_internal_handler(& error_handler); need_pop= TRUE; - if (!(table= open_performance_schema_table(thd, & table_list, - & open_tables_backup))) + if (!(table= open_log_table(thd, &table_list, &open_tables_backup))) goto err; need_close= TRUE; @@ -527,9 +570,9 @@ err: if (need_pop) thd->pop_internal_handler(); if (need_close) - close_performance_schema_table(thd, & open_tables_backup); + close_log_table(thd, &open_tables_backup); - thd->options= save_thd_options; + thd->variables.option_bits= save_thd_options; thd->time_zone_used= save_time_zone_used; return result; } @@ -597,8 +640,7 @@ bool Log_to_csv_event_handler:: table_list.db= MYSQL_SCHEMA_NAME.str; table_list.db_length= MYSQL_SCHEMA_NAME.length; - if (!(table= open_performance_schema_table(thd, & table_list, - & open_tables_backup))) + if (!(table= open_log_table(thd, &table_list, &open_tables_backup))) goto err; need_close= TRUE; @@ -723,7 +765,7 @@ err: table->file->ha_release_auto_increment(); } if (need_close) - close_performance_schema_table(thd, & open_tables_backup); + close_log_table(thd, &open_tables_backup); thd->time_zone_used= save_time_zone_used; DBUG_RETURN(result); } @@ -757,12 +799,11 @@ int Log_to_csv_event_handler:: table_list.db= MYSQL_SCHEMA_NAME.str; table_list.db_length= MYSQL_SCHEMA_NAME.length; - table= open_performance_schema_table(thd, & table_list, - & open_tables_backup); + table= open_log_table(thd, &table_list, &open_tables_backup); if (table) { result= 0; - close_performance_schema_table(thd, & open_tables_backup); + close_log_table(thd, &open_tables_backup); } else result= 1; @@ -838,10 +879,10 @@ bool Log_to_file_event_handler::init() if (!is_initialized) { if (opt_slow_log) - mysql_slow_log.open_slow_log(sys_var_slow_log_path.value); + mysql_slow_log.open_slow_log(opt_slow_logname); if (opt_log) - mysql_log.open_query_log(sys_var_general_log_path.value); + mysql_log.open_query_log(opt_logname); is_initialized= TRUE; } @@ -898,7 +939,7 @@ bool LOGGER::error_log_print(enum loglevel level, const char *format, void LOGGER::cleanup_base() { DBUG_ASSERT(inited == 1); - rwlock_destroy(&LOCK_logger); + mysql_rwlock_destroy(&LOCK_logger); if (table_log_handler) { table_log_handler->cleanup(); @@ -943,7 +984,7 @@ void LOGGER::init_base() init_error_log(LOG_FILE); file_log_handler->init_pthread_objects(); - my_rwlock_init(&LOCK_logger, NULL); + mysql_rwlock_init(key_rwlock_LOCK_logger, &LOCK_logger); } @@ -977,6 +1018,54 @@ bool LOGGER::flush_logs(THD *thd) } +/** + Close and reopen the slow log (with locks). + + @returns FALSE. +*/ +bool LOGGER::flush_slow_log() +{ + /* + Now we lock logger, as nobody should be able to use logging routines while + log tables are closed + */ + logger.lock_exclusive(); + + /* Reopen slow log file */ + if (opt_slow_log) + file_log_handler->get_mysql_slow_log()->reopen_file(); + + /* End of log flush */ + logger.unlock(); + + return 0; +} + + +/** + Close and reopen the general log (with locks). + + @returns FALSE. +*/ +bool LOGGER::flush_general_log() +{ + /* + Now we lock logger, as nobody should be able to use logging routines while + log tables are closed + */ + logger.lock_exclusive(); + + /* Reopen general log file */ + if (opt_log) + file_log_handler->get_mysql_log()->reopen_file(); + + /* End of log flush */ + logger.unlock(); + + return 0; +} + + /* Log slow query with all enabled log event handlers @@ -1202,7 +1291,7 @@ bool LOGGER::activate_log_handler(THD* thd, uint log_type) { file_log= file_log_handler->get_mysql_slow_log(); - file_log->open_slow_log(sys_var_slow_log_path.value); + file_log->open_slow_log(opt_slow_logname); if (table_log_handler->activate_log(thd, QUERY_LOG_SLOW)) { /* Error printed by open table in activate_log() */ @@ -1221,7 +1310,7 @@ bool LOGGER::activate_log_handler(THD* thd, uint log_type) { file_log= file_log_handler->get_mysql_log(); - file_log->open_query_log(sys_var_general_log_path.value); + file_log->open_query_log(opt_logname); if (table_log_handler->activate_log(thd, QUERY_LOG_GENERAL)) { /* Error printed by open table in activate_log() */ @@ -1305,26 +1394,6 @@ int LOGGER::set_handlers(uint error_log_printer, return 0; } -/** - This function checks if a transactional talbe was updated by the - current statement. - - @param thd The client thread that executed the current statement. - @return - @c true if a transactional table was updated, @false otherwise. -*/ -static bool stmt_has_updated_trans_table(THD *thd) -{ - Ha_trx_info *ha_info; - - for (ha_info= thd->transaction.stmt.ha_list; ha_info && ha_info->is_started(); ha_info= ha_info->next()) - { - if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) - return (TRUE); - } - return (FALSE); -} - /* Save position of binary log transaction cache. @@ -1347,10 +1416,10 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos) DBUG_ASSERT(pos != NULL); if (thd_get_ha_data(thd, binlog_hton) == NULL) thd->binlog_setup_trx_data(); - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); DBUG_ASSERT(mysql_bin_log.is_open()); - *pos= trx_data->position(); + *pos= cache_mngr->trx_cache.get_byte_position(); DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos)); DBUG_VOID_RETURN; } @@ -1381,9 +1450,9 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos) /* Only true if binlog_trans_log_savepos() wasn't called before */ DBUG_ASSERT(pos != ~(my_off_t) 0); - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); - trx_data->truncate(pos); + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + cache_mngr->trx_cache.restore_savepoint(pos); DBUG_VOID_RETURN; } @@ -1412,115 +1481,127 @@ int binlog_init(void *p) static int binlog_close_connection(handlerton *hton, THD *thd) { - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); - DBUG_ASSERT(trx_data->empty()); + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + DBUG_ASSERT(cache_mngr->trx_cache.empty() && cache_mngr->stmt_cache.empty()); thd_set_ha_data(thd, binlog_hton, NULL); - trx_data->~binlog_trx_data(); - my_free((uchar*)trx_data, MYF(0)); + cache_mngr->~binlog_cache_mngr(); + my_free((uchar*)cache_mngr, MYF(0)); return 0; } -/* - End a transaction. +/** + This function flushes a transactional cache upon commit/rollback. - SYNOPSIS - binlog_end_trans() + @param thd The thread whose transaction should be flushed + @param cache_mngr Pointer to the cache data to be flushed + @param end_ev The end event either commit/rollback. - thd The thread whose transaction should be ended - trx_data Pointer to the transaction data to use - end_ev The end event to use, or NULL - all True if the entire transaction should be ended, false if - only the statement transaction should be ended. + @return + nonzero if an error pops up when flushing the transactional cache. +*/ +static int +binlog_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, + Log_event *end_ev) +{ + DBUG_ENTER("binlog_flush_trx_cache"); + int error=0; + IO_CACHE *cache_log= &cache_mngr->trx_cache.cache_log; - DESCRIPTION + /* + This function handles transactional changes and as such + this flag equals to true. + */ + bool const is_transactional= TRUE; - End the currently open transaction. The transaction can be either - a real transaction (if 'all' is true) or a statement transaction - (if 'all' is false). + if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional)) + DBUG_RETURN(1); + /* + Doing a commit or a rollback including non-transactional tables, + i.e., ending a transaction where we might write the transaction + cache to the binary log. + + We can always end the statement when ending a transaction since + transactions are not allowed inside stored functions. If they + were, we would have to ensure that we're not ending a statement + inside a stored function. + */ + error= mysql_bin_log.write(thd, &cache_mngr->trx_cache.cache_log, end_ev, + cache_mngr->trx_cache.has_incident()); + cache_mngr->reset_cache(&cache_mngr->trx_cache); - If 'end_ev' is NULL, the transaction is a rollback of only - transactional tables, so the transaction cache will be truncated - to either just before the last opened statement transaction (if - 'all' is false), or reset completely (if 'all' is true). - */ + /* + We need to step the table map version after writing the + transaction cache to disk. + */ + mysql_bin_log.update_table_map_version(); + statistic_increment(binlog_cache_use, &LOCK_status); + if (cache_log->disk_writes != 0) + { + statistic_increment(binlog_cache_disk_use, &LOCK_status); + cache_log->disk_writes= 0; + } + + DBUG_ASSERT(cache_mngr->trx_cache.empty()); + DBUG_RETURN(error); +} + +/** + This function truncates the transactional cache upon committing or rolling + back either a transaction or a statement. + + @param thd The thread whose transaction should be flushed + @param cache_mngr Pointer to the cache data to be flushed + @param all @c true means truncate the transaction, otherwise the + statement must be truncated. + + @return + nonzero if an error pops up when truncating the transactional cache. +*/ static int -binlog_end_trans(THD *thd, binlog_trx_data *trx_data, - Log_event *end_ev, bool all) +binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all) { - DBUG_ENTER("binlog_end_trans"); + DBUG_ENTER("binlog_truncate_trx_cache"); int error=0; - IO_CACHE *trans_log= &trx_data->trans_log; - DBUG_PRINT("enter", ("transaction: %s end_ev: 0x%lx", - all ? "all" : "stmt", (long) end_ev)); - DBUG_PRINT("info", ("thd->options={ %s%s}", - FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), - FLAGSTR(thd->options, OPTION_BEGIN))); + /* + This function handles transactional changes and as such this flag + equals to true. + */ + bool const is_transactional= TRUE; + DBUG_PRINT("info", ("thd->options={ %s%s}, transaction: %s", + FLAGSTR(thd->variables.option_bits, OPTION_NOT_AUTOCOMMIT), + FLAGSTR(thd->variables.option_bits, OPTION_BEGIN), + all ? "all" : "stmt")); /* - NULL denotes ROLLBACK with nothing to replicate: i.e., rollback of - only transactional tables. If the transaction contain changes to - any non-transactiona tables, we need write the transaction and log - a ROLLBACK last. + If rolling back an entire transaction or a single statement not + inside a transaction, we reset the transaction cache. */ - if (end_ev != NULL) + thd->binlog_remove_pending_rows_event(TRUE, is_transactional); + if (all || !thd->in_multi_stmt_transaction()) { - if (thd->binlog_flush_pending_rows_event(TRUE)) - DBUG_RETURN(1); - /* - Doing a commit or a rollback including non-transactional tables, - i.e., ending a transaction where we might write the transaction - cache to the binary log. - - We can always end the statement when ending a transaction since - transactions are not allowed inside stored functions. If they - were, we would have to ensure that we're not ending a statement - inside a stored function. - */ - error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev, - trx_data->has_incident()); - trx_data->reset(); + if (cache_mngr->trx_cache.has_incident()) + error= mysql_bin_log.write_incident(thd, TRUE); - /* - We need to step the table map version after writing the - transaction cache to disk. - */ - mysql_bin_log.update_table_map_version(); - statistic_increment(binlog_cache_use, &LOCK_status); - if (trans_log->disk_writes != 0) - { - statistic_increment(binlog_cache_disk_use, &LOCK_status); - trans_log->disk_writes= 0; - } + cache_mngr->reset_cache(&cache_mngr->trx_cache); + + thd->clear_binlog_table_maps(); } + /* + If rolling back a statement in a transaction, we truncate the + transaction cache to remove the statement. + */ else - { - /* - If rolling back an entire transaction or a single statement not - inside a transaction, we reset the transaction cache. - - If rolling back a statement in a transaction, we truncate the - transaction cache to remove the statement. - */ - thd->binlog_remove_pending_rows_event(TRUE); - if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) - { - if (trx_data->has_incident()) - error= mysql_bin_log.write_incident(thd, TRUE); - trx_data->reset(); - } - else // ...statement - trx_data->truncate(trx_data->before_stmt_pos); + cache_mngr->trx_cache.restore_prev_position(); - /* - We need to step the table map version on a rollback to ensure - that a new table map event is generated instead of the one that - was written to the thrown-away transaction cache. - */ - mysql_bin_log.update_table_map_version(); - } + /* + We need to step the table map version on a rollback to ensure that a new + table map event is generated instead of the one that was written to the + thrown-away transaction cache. + */ + mysql_bin_log.update_table_map_version(); - DBUG_ASSERT(thd->binlog_get_pending_rows_event() == NULL); + DBUG_ASSERT(thd->binlog_get_pending_rows_event(is_transactional) == NULL); DBUG_RETURN(error); } @@ -1536,10 +1617,56 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all) } /** + This function flushes the non-transactional to the binary log upon + committing or rolling back a statement. + + @param thd The thread whose transaction should be flushed + @param cache_mngr Pointer to the cache data to be flushed + + @return + nonzero if an error pops up when flushing the non-transactional cache. +*/ +static int +binlog_flush_stmt_cache(THD *thd, binlog_cache_mngr *cache_mngr) +{ + int error= 0; + DBUG_ENTER("binlog_flush_stmt_cache"); + /* + If we are flushing the statement cache, it means that the changes get + through otherwise the cache is empty and this routine should not be called. + */ + DBUG_ASSERT(cache_mngr->stmt_cache.has_incident() == FALSE); + /* + This function handles non-transactional changes and as such this flag equals + to false. + */ + bool const is_transactional= FALSE; + IO_CACHE *cache_log= &cache_mngr->stmt_cache.cache_log; + thd->binlog_flush_pending_rows_event(TRUE, is_transactional); + Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0); + if ((error= mysql_bin_log.write(thd, cache_log, &qev, + cache_mngr->stmt_cache.has_incident()))) + DBUG_RETURN(error); + cache_mngr->reset_cache(&cache_mngr->stmt_cache); + + /* + We need to step the table map version after writing the + transaction cache to disk. + */ + mysql_bin_log.update_table_map_version(); + statistic_increment(binlog_cache_use, &LOCK_status); + if (cache_log->disk_writes != 0) + { + statistic_increment(binlog_cache_disk_use, &LOCK_status); + cache_log->disk_writes= 0; + } + DBUG_RETURN(error); +} + +/** This function is called once after each statement. - It has the responsibility to flush the transaction cache to the - binlog file on commits. + It has the responsibility to flush the caches to the binary log on commits. @param hton The binlog handlerton. @param thd The client thread that executes the transaction. @@ -1552,57 +1679,53 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) { int error= 0; DBUG_ENTER("binlog_commit"); - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + bool const in_transaction= thd->in_multi_stmt_transaction(); + + DBUG_PRINT("debug", + ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", + all, + YESNO(in_transaction), + YESNO(thd->transaction.all.modified_non_trans_table), + YESNO(thd->transaction.stmt.modified_non_trans_table))); - if (trx_data->empty()) + if (!cache_mngr->stmt_cache.empty()) { - // we're here because trans_log was flushed in MYSQL_BIN_LOG::log_xid() - trx_data->reset(); + binlog_flush_stmt_cache(thd, cache_mngr); + } + + if (cache_mngr->trx_cache.empty()) + { + /* + we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid() + */ + cache_mngr->reset_cache(&cache_mngr->trx_cache); DBUG_RETURN(0); } /* We commit the transaction if: - - We are not in a transaction and committing a statement, or - - - We are in a transaction and a full transaction is committed - - Otherwise, we accumulate the statement + - We are in a transaction and a full transaction is committed. + Otherwise, we accumulate the changes. */ - ulonglong const in_transaction= - thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN); - DBUG_PRINT("debug", - ("all: %d, empty: %s, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", - all, - YESNO(trx_data->empty()), - YESNO(in_transaction), - YESNO(thd->transaction.all.modified_non_trans_table), - YESNO(thd->transaction.stmt.modified_non_trans_table))); - if (!in_transaction || all || - (!all && !trx_data->at_least_one_stmt_committed && - !stmt_has_updated_trans_table(thd) && - thd->transaction.stmt.modified_non_trans_table)) + if (!in_transaction || all) { - Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, 0); - error= binlog_end_trans(thd, trx_data, &qev, all); + Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0); + error= binlog_flush_trx_cache(thd, cache_mngr, &qev); } - trx_data->at_least_one_stmt_committed = my_b_tell(&trx_data->trans_log) > 0; - + /* + This is part of the stmt rollback. + */ if (!all) - trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt commit + cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); DBUG_RETURN(error); } /** - This function is called when a transaction involving a transactional - table is rolled back. - - It has the responsibility to flush the transaction cache to the - binlog file. However, if the transaction does not involve - non-transactional tables, nothing needs to be logged. + This function is called when a transaction or a statement is rolled back. @param hton The binlog handlerton. @param thd The client thread that executes the transaction. @@ -1615,18 +1738,38 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) { DBUG_ENTER("binlog_rollback"); int error=0; - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); - - if (trx_data->empty()) { - trx_data->reset(); - DBUG_RETURN(0); - } + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", YESNO(all), YESNO(thd->transaction.all.modified_non_trans_table), YESNO(thd->transaction.stmt.modified_non_trans_table))); + + /* + If an incident event is set we do not flush the content of the statement + cache because it may be corrupted. + */ + if (cache_mngr->stmt_cache.has_incident()) + { + mysql_bin_log.write_incident(thd, TRUE); + cache_mngr->reset_cache(&cache_mngr->stmt_cache); + } + else if (!cache_mngr->stmt_cache.empty()) + { + binlog_flush_stmt_cache(thd, cache_mngr); + } + + if (cache_mngr->trx_cache.empty()) + { + /* + we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid() + */ + cache_mngr->reset_cache(&cache_mngr->trx_cache); + DBUG_RETURN(0); + } + + if (mysql_bin_log.check_write_error(thd)) { /* @@ -1637,52 +1780,46 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) */ DBUG_ASSERT(!all); /* - We reach this point if either only transactional tables were modified or - the effect of a statement that did not get into the binlog needs to be - rolled back. In the latter case, if a statement changed non-transactional - tables or had the OPTION_KEEP_LOG associated, we write an incident event - to the binlog in order to stop slaves and notify users that some changes - on the master did not get into the binlog and slaves will be inconsistent. - On the other hand, if a statement is transactional, we just safely roll it - back. + We reach this point if the effect of a statement did not properly get into + a cache and need to be rolled back. */ - if ((thd->transaction.stmt.modified_non_trans_table || - (thd->options & OPTION_KEEP_LOG)) && - mysql_bin_log.check_write_error(thd)) - trx_data->set_incident(); - error= binlog_end_trans(thd, trx_data, 0, all); + error= binlog_truncate_trx_cache(thd, cache_mngr, all); } else - { - /* - We flush the cache with a rollback, wrapped in a beging/rollback if: - . aborting a transaction that modified a non-transactional table; + { + /* + We flush the cache wrapped in a beging/rollback if: + . aborting a transcation that modified a non-transactional table or; . aborting a statement that modified both transactional and - non-transactional tables but which is not in the boundaries of any - transaction or there was no early change; + non-transctional tables but which is not in the boundaries of any + transaction; . the OPTION_KEEP_LOG is activate. */ - if ((all && thd->transaction.all.modified_non_trans_table) || + if (thd->variables.binlog_format == BINLOG_FORMAT_STMT && + ((all && thd->transaction.all.modified_non_trans_table) || (!all && thd->transaction.stmt.modified_non_trans_table && - !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) || - (!all && thd->transaction.stmt.modified_non_trans_table && - !trx_data->at_least_one_stmt_committed && - thd->current_stmt_binlog_row_based) || - ((thd->options & OPTION_KEEP_LOG))) + !thd->in_multi_stmt_transaction()) || + (thd->variables.option_bits & OPTION_KEEP_LOG))) { - Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0); - error= binlog_end_trans(thd, trx_data, &qev, all); + Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0); + error= binlog_flush_trx_cache(thd, cache_mngr, &qev); } /* Otherwise, we simply truncate the cache as there is no change on non-transactional tables as follows. */ - else if ((all && !thd->transaction.all.modified_non_trans_table) || - (!all && !thd->transaction.stmt.modified_non_trans_table)) - error= binlog_end_trans(thd, trx_data, 0, all); + else if (all || (!all && + (!thd->transaction.stmt.modified_non_trans_table || + !thd->in_multi_stmt_transaction() || + thd->variables.binlog_format != BINLOG_FORMAT_STMT))) + error= binlog_truncate_trx_cache(thd, cache_mngr, all); } + + /* + This is part of the stmt rollback. + */ if (!all) - trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt rollback + cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); DBUG_RETURN(error); } @@ -1758,7 +1895,8 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); int const error= thd->binlog_query(THD::STMT_QUERY_TYPE, - thd->query(), thd->query_length(), TRUE, FALSE, errcode); + thd->query(), thd->query_length(), TRUE, FALSE, FALSE, + errcode); DBUG_RETURN(error); } @@ -1772,12 +1910,13 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) from the SAVEPOINT command. */ if (unlikely(thd->transaction.all.modified_non_trans_table || - (thd->options & OPTION_KEEP_LOG))) + (thd->variables.option_bits & OPTION_KEEP_LOG))) { int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); int error= thd->binlog_query(THD::STMT_QUERY_TYPE, - thd->query(), thd->query_length(), TRUE, FALSE, errcode); + thd->query(), thd->query_length(), TRUE, FALSE, FALSE, + errcode); DBUG_RETURN(error); } binlog_trans_log_truncate(thd, *(my_off_t*)sv); @@ -1811,8 +1950,9 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg) File file; DBUG_ENTER("open_binlog"); - if ((file = my_open(log_file_name, O_RDONLY | O_BINARY | O_SHARE, - MYF(MY_WME))) < 0) + if ((file= mysql_file_open(key_file_binlog, + log_file_name, O_RDONLY | O_BINARY | O_SHARE, + MYF(MY_WME))) < 0) { sql_print_error("Failed to open log (file '%s', errno %d)", log_file_name, my_errno); @@ -1834,7 +1974,7 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg) err: if (file >= 0) { - my_close(file,MYF(0)); + mysql_file_close(file, MYF(0)); end_io_cache(log); } DBUG_RETURN(-1); @@ -1948,7 +2088,7 @@ updating the index files.", max_found); */ if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN)) { - sql_print_error("Log filename too large: %s%s (%lu). \ + sql_print_error("Log filename too large: %s%s (%zu). \ Please fix this by archiving old logs and updating the \ index files.", name, ext_buf, (strlen(ext_buf) + (end - name))); error= 1; @@ -2044,10 +2184,11 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, db[0]= 0; - if ((file= my_open(log_file_name, open_flags, - MYF(MY_WME | ME_WAITTANG))) < 0 || + if ((file= mysql_file_open(key_file_MYSQL_LOG, + 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, + mysql_file_tell(file, MYF(MY_WME)), 0, MYF(MY_WME | MY_NABP | ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0)))) goto err; @@ -2085,7 +2226,7 @@ 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)); + mysql_file_close(file, MYF(0)); end_io_cache(&log_file); safeFree(name); log_state= LOG_CLOSED; @@ -2109,7 +2250,7 @@ void MYSQL_LOG::init_pthread_objects() { DBUG_ASSERT(inited == 0); inited= 1; - (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW); } /* @@ -2134,13 +2275,13 @@ void MYSQL_LOG::close(uint exiting) { end_io_cache(&log_file); - if (my_sync(log_file.file, MYF(MY_WME)) && ! write_error) + if (mysql_file_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) + if (mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error) { write_error= 1; sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); @@ -2160,7 +2301,7 @@ void MYSQL_LOG::cleanup() if (inited) { inited= 0; - (void) pthread_mutex_destroy(&LOCK_log); + mysql_mutex_destroy(&LOCK_log); close(0); } DBUG_VOID_RETURN; @@ -2215,7 +2356,7 @@ void MYSQL_QUERY_LOG::reopen_file() DBUG_VOID_RETURN; } - pthread_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_log); save_name= name; name= 0; // Don't free name @@ -2228,7 +2369,7 @@ void MYSQL_QUERY_LOG::reopen_file() open(save_name, log_type, 0, io_cache_type); my_free(save_name, MYF(0)); - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); DBUG_VOID_RETURN; } @@ -2270,7 +2411,7 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host, struct tm start; uint time_buff_len= 0; - (void) pthread_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_log); /* Test if someone closed between the is_open test and lock */ if (is_open()) @@ -2319,7 +2460,7 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host, goto err; } - (void) pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); return FALSE; err: @@ -2328,7 +2469,7 @@ err: write_error= 1; sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); } - (void) pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); return TRUE; } @@ -2371,11 +2512,11 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, bool error= 0; DBUG_ENTER("MYSQL_QUERY_LOG::write"); - (void) pthread_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_log); if (!is_open()) { - (void) pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); DBUG_RETURN(0); } @@ -2484,7 +2625,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, } } } - (void) pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); DBUG_RETURN(error); } @@ -2546,9 +2687,9 @@ void MYSQL_BIN_LOG::cleanup() 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); + mysql_mutex_destroy(&LOCK_log); + mysql_mutex_destroy(&LOCK_index); + mysql_cond_destroy(&update_cond); } DBUG_VOID_RETURN; } @@ -2569,9 +2710,9 @@ 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); + mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_BINLOG_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW); + mysql_cond_init(key_BINLOG_update_cond, &update_cond, 0); } @@ -2594,23 +2735,25 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, } fn_format(index_file_name, index_file_name_arg, mysql_data_home, ".index", opt); - if ((index_file_nr= my_open(index_file_name, - O_RDWR | O_CREAT | O_BINARY , - MYF(MY_WME))) < 0 || - my_sync(index_file_nr, MYF(MY_WME)) || + if ((index_file_nr= mysql_file_open(key_file_binlog_index, + index_file_name, + O_RDWR | O_CREAT | O_BINARY, + MYF(MY_WME))) < 0 || + mysql_file_sync(index_file_nr, MYF(MY_WME)) || init_io_cache(&index_file, index_file_nr, IO_SIZE, WRITE_CACHE, - my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)), - 0, MYF(MY_WME | MY_WAIT_IF_FULL)) || + mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)), + 0, MYF(MY_WME | MY_WAIT_IF_FULL)) || DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0)) { /* TODO: all operations creating/deleting the index file or a log, should call my_sync_dir() or my_sync_dir_by_file() to be durable. - TODO: file creation should be done with my_create() not my_open(). + TODO: file creation should be done with mysql_file_create() + not mysql_file_open(). */ if (index_file_nr >= 0) - my_close(index_file_nr,MYF(0)); + mysql_file_close(index_file_nr, MYF(0)); return TRUE; } @@ -2774,7 +2917,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, bytes_written+= description_event_for_queue->data_written; } if (flush_io_cache(&log_file) || - my_sync(log_file.file, MYF(MY_WME))) + mysql_file_sync(log_file.file, MYF(MY_WME))) goto err; if (write_file_name_to_index_file) @@ -2795,7 +2938,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, strlen(log_file_name)) || my_b_write(&index_file, (uchar*) "\n", 1) || flush_io_cache(&index_file) || - my_sync(index_file.file, MYF(MY_WME))) + mysql_file_sync(index_file.file, MYF(MY_WME))) goto err; #ifdef HAVE_REPLICATION @@ -2822,7 +2965,7 @@ 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)); + mysql_file_close(file, MYF(0)); end_io_cache(&log_file); end_io_cache(&index_file); safeFree(name); @@ -2833,9 +2976,9 @@ shutdown the MySQL server and restart it.", name, errno); int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo) { - pthread_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_log); int ret = raw_get_current_log(linfo); - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); return ret; } @@ -2875,19 +3018,20 @@ static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset) for (;; offset+= bytes_read) { - (void) my_seek(file, offset, MY_SEEK_SET, MYF(0)); - if ((bytes_read= (int) my_read(file, io_buf, sizeof(io_buf), MYF(MY_WME))) + mysql_file_seek(file, offset, MY_SEEK_SET, MYF(0)); + if ((bytes_read= (int) mysql_file_read(file, io_buf, sizeof(io_buf), + MYF(MY_WME))) < 0) goto err; if (!bytes_read) break; // end of file - (void) my_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0)); - if (my_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP))) + mysql_file_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0)); + if (mysql_file_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP))) goto err; } /* The following will either truncate the file or fill the end with \n' */ - if (my_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) || - my_sync(file, MYF(MY_WME))) + if (mysql_file_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) || + mysql_file_sync(file, MYF(MY_WME))) goto err; /* Reset data in old index cache */ @@ -2936,8 +3080,8 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, move from under our feet */ if (need_lock) - pthread_mutex_lock(&LOCK_index); - safe_mutex_assert_owner(&LOCK_index); + mysql_mutex_lock(&LOCK_index); + mysql_mutex_assert_owner(&LOCK_index); /* As the file is flushed, we can't get an error here */ (void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0); @@ -2971,7 +3115,7 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, } if (need_lock) - pthread_mutex_unlock(&LOCK_index); + mysql_mutex_unlock(&LOCK_index); DBUG_RETURN(error); } @@ -3007,8 +3151,8 @@ int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock) char *fname= linfo->log_file_name; if (need_lock) - pthread_mutex_lock(&LOCK_index); - safe_mutex_assert_owner(&LOCK_index); + mysql_mutex_lock(&LOCK_index); + mysql_mutex_assert_owner(&LOCK_index); /* As the file is flushed, we can't get an error here */ (void) reinit_io_cache(&index_file, READ_CACHE, linfo->index_file_offset, 0, @@ -3025,7 +3169,7 @@ int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock) err: if (need_lock) - pthread_mutex_unlock(&LOCK_index); + mysql_mutex_unlock(&LOCK_index); return error; } @@ -3060,8 +3204,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) We need to get both locks to be sure that no one is trying to write to the index log file. */ - pthread_mutex_lock(&LOCK_log); - pthread_mutex_lock(&LOCK_index); + mysql_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_index); /* The following mutex is needed to ensure that no threads call @@ -3069,7 +3213,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) thread. If the transaction involved MyISAM tables, it should go into binlog even on rollback. */ - pthread_mutex_lock(&LOCK_thread_count); + mysql_mutex_lock(&LOCK_thread_count); /* Save variables so that we can reopen the log */ save_name=name; @@ -3162,9 +3306,9 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) err: if (error == 1) name= const_cast<char*>(save_name); - pthread_mutex_unlock(&LOCK_thread_count); - pthread_mutex_unlock(&LOCK_index); - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_thread_count); + mysql_mutex_unlock(&LOCK_index); + mysql_mutex_unlock(&LOCK_log); DBUG_RETURN(error); } @@ -3218,7 +3362,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) DBUG_ASSERT(rli->slave_running == 1); DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name)); - pthread_mutex_lock(&LOCK_index); + mysql_mutex_lock(&LOCK_index); to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0)); /* @@ -3262,19 +3406,19 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) DBUG_EXECUTE_IF("crash_before_purge_logs", abort();); - pthread_mutex_lock(&rli->log_space_lock); + mysql_mutex_lock(&rli->log_space_lock); rli->relay_log.purge_logs(to_purge_if_included, included, 0, 0, &rli->log_space_total); // Tell the I/O thread to take the relay_log_space_limit into account rli->ignore_log_space_limit= 0; - pthread_mutex_unlock(&rli->log_space_lock); + mysql_mutex_unlock(&rli->log_space_lock); /* Ok to broadcast after the critical region as there is no risk of the mutex being destroyed by this thread later - this helps save context switches */ - pthread_cond_broadcast(&rli->log_space_cond); + mysql_cond_broadcast(&rli->log_space_cond); /* * Need to update the log pos because purge logs has been called @@ -3296,7 +3440,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) err: my_free(to_purge_if_included, MYF(0)); - pthread_mutex_unlock(&LOCK_index); + mysql_mutex_unlock(&LOCK_index); DBUG_RETURN(error); } @@ -3336,7 +3480,7 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads LOG_INFO_EOF to_log not found LOG_INFO_EMFILE too many files opened LOG_INFO_FATAL if any other than ENOENT error from - my_stat() or my_delete() + mysql_file_stat() or mysql_file_delete() */ int MYSQL_BIN_LOG::purge_logs(const char *to_log, @@ -3353,7 +3497,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, DBUG_PRINT("info",("to_log= %s",to_log)); if (need_mutex) - pthread_mutex_lock(&LOCK_index); + mysql_mutex_lock(&LOCK_index); if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) { sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not " @@ -3416,7 +3560,7 @@ err: DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", abort();); if (need_mutex) - pthread_mutex_unlock(&LOCK_index); + mysql_mutex_unlock(&LOCK_index); DBUG_RETURN(error); } @@ -3555,7 +3699,7 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space, /* Get rid of the trailing '\n' */ log_info.log_file_name[length-1]= 0; - if (!my_stat(log_info.log_file_name, &s, MYF(0))) + if (!mysql_file_stat(key_file_binlog, log_info.log_file_name, &s, MYF(0))) { if (my_errno == ENOENT) { @@ -3569,7 +3713,7 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space, ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), log_info.log_file_name); } - sql_print_information("Failed to execute my_stat on file '%s'", + sql_print_information("Failed to execute mysql_file_stat on file '%s'", log_info.log_file_name); my_errno= 0; } @@ -3707,7 +3851,7 @@ err: @retval LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated LOG_INFO_FATAL if any other than ENOENT error from - my_stat() or my_delete() + mysql_file_stat() or mysql_file_delete() */ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) @@ -3720,7 +3864,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) DBUG_ENTER("purge_logs_before_date"); - pthread_mutex_lock(&LOCK_index); + mysql_mutex_lock(&LOCK_index); to_log[0]= 0; if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/))) @@ -3730,7 +3874,8 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) !is_active(log_info.log_file_name) && !log_in_use(log_info.log_file_name)) { - if (!my_stat(log_info.log_file_name, &stat_area, MYF(0))) + if (!mysql_file_stat(key_file_binlog, + log_info.log_file_name, &stat_area, MYF(0))) { if (my_errno == ENOENT) { @@ -3779,7 +3924,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) error= (to_log[0] ? purge_logs(to_log, 1, 0, 1, (ulonglong *) 0) : 0); err: - pthread_mutex_unlock(&LOCK_index); + mysql_mutex_unlock(&LOCK_index); DBUG_RETURN(error); } #endif /* HAVE_REPLICATION */ @@ -3855,11 +4000,11 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) } if (need_lock) - pthread_mutex_lock(&LOCK_log); - pthread_mutex_lock(&LOCK_index); + mysql_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_index); - safe_mutex_assert_owner(&LOCK_log); - safe_mutex_assert_owner(&LOCK_index); + mysql_mutex_assert_owner(&LOCK_log); + mysql_mutex_assert_owner(&LOCK_index); /* if binlog is used as tc log, be sure all xids are "unlogged", @@ -3873,12 +4018,12 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) if (prepared_xids) { tc_log_page_waits++; - pthread_mutex_lock(&LOCK_prep_xids); + mysql_mutex_lock(&LOCK_prep_xids); while (prepared_xids) { DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids)); - pthread_cond_wait(&COND_prep_xids, &LOCK_prep_xids); + mysql_cond_wait(&COND_prep_xids, &LOCK_prep_xids); } - pthread_mutex_unlock(&LOCK_prep_xids); + mysql_mutex_unlock(&LOCK_prep_xids); } /* Reuse old name if not binlog and not update log */ @@ -3938,8 +4083,8 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) end: if (need_lock) - pthread_mutex_unlock(&LOCK_log); - pthread_mutex_unlock(&LOCK_index); + mysql_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_index); DBUG_VOID_RETURN; } @@ -3948,7 +4093,7 @@ end: bool MYSQL_BIN_LOG::append(Log_event* ev) { bool error = 0; - pthread_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_log); DBUG_ENTER("MYSQL_BIN_LOG::append"); DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); @@ -3969,7 +4114,7 @@ bool MYSQL_BIN_LOG::append(Log_event* ev) new_file_without_locking(); err: - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); signal_update(); // Safe as we don't call close DBUG_RETURN(error); } @@ -3984,7 +4129,7 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...) DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); - safe_mutex_assert_owner(&LOCK_log); + mysql_mutex_assert_owner(&LOCK_log); do { if (my_b_append(&log_file,(uchar*) buf,len)) @@ -4011,14 +4156,14 @@ bool MYSQL_BIN_LOG::flush_and_sync(bool *synced) int err=0, fd=log_file.file; if (synced) *synced= 0; - safe_mutex_assert_owner(&LOCK_log); + mysql_mutex_assert_owner(&LOCK_log); if (flush_io_cache(&log_file)) return 1; uint sync_period= get_sync_period(); if (sync_period && ++sync_counter >= sync_period) { sync_counter= 0; - err=my_sync(fd, MYF(MY_WME)); + err= mysql_file_sync(fd, MYF(MY_WME)); if (synced) *synced= 1; } @@ -4055,27 +4200,67 @@ bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param) int THD::binlog_setup_trx_data() { DBUG_ENTER("THD::binlog_setup_trx_data"); - binlog_trx_data *trx_data= - (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); + binlog_cache_mngr *cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton); - if (trx_data) + if (cache_mngr) DBUG_RETURN(0); // Already set up - trx_data= (binlog_trx_data*) my_malloc(sizeof(binlog_trx_data), MYF(MY_ZEROFILL)); - if (!trx_data || - open_cached_file(&trx_data->trans_log, mysql_tmpdir, + cache_mngr= (binlog_cache_mngr*) my_malloc(sizeof(binlog_cache_mngr), MYF(MY_ZEROFILL)); + if (!cache_mngr || + open_cached_file(&cache_mngr->stmt_cache.cache_log, mysql_tmpdir, + LOG_PREFIX, binlog_cache_size, MYF(MY_WME)) || + open_cached_file(&cache_mngr->trx_cache.cache_log, mysql_tmpdir, LOG_PREFIX, binlog_cache_size, MYF(MY_WME))) { - my_free((uchar*)trx_data, MYF(MY_ALLOW_ZERO_PTR)); + my_free((uchar*)cache_mngr, MYF(MY_ALLOW_ZERO_PTR)); DBUG_RETURN(1); // Didn't manage to set it up } - thd_set_ha_data(this, binlog_hton, trx_data); + thd_set_ha_data(this, binlog_hton, cache_mngr); - trx_data= new (thd_get_ha_data(this, binlog_hton)) binlog_trx_data; + cache_mngr= new (thd_get_ha_data(this, binlog_hton)) binlog_cache_mngr; DBUG_RETURN(0); } +/** + This function checks if a transactional talbe was updated by the + current transaction. + + @param thd The client thread that executed the current statement. + @return + @c true if a transactional table was updated, @false otherwise. +*/ +bool +trans_has_updated_trans_table(THD* thd) +{ + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + + return (cache_mngr ? my_b_tell (&cache_mngr->trx_cache.cache_log) : 0); +} + +/** + This function checks if a transactional talbe was updated by the + current statement. + + @param thd The client thread that executed the current statement. + @return + @c true if a transactional table was updated, @false otherwise. +*/ +bool +stmt_has_updated_trans_table(THD *thd) +{ + Ha_trx_info *ha_info; + + for (ha_info= thd->transaction.stmt.ha_list; ha_info; ha_info= ha_info->next()) + { + if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) + return (TRUE); + } + return (FALSE); +} + /* Function to start a statement and optionally a transaction for the binary log. @@ -4089,11 +4274,10 @@ int THD::binlog_setup_trx_data() - Start a transaction if not in autocommit mode or if a BEGIN statement has been seen. - - Start a statement transaction to allow us to truncate the binary - log. + - Start a statement transaction to allow us to truncate the cache. - Save the currrent binlog position so that we can roll back the - statement by truncating the transaction log. + statement by truncating the cache. We only update the saved position if the old one was undefined, the reason is that there are some cases (e.g., for CREATE-SELECT) @@ -4107,18 +4291,18 @@ int THD::binlog_setup_trx_data() void THD::binlog_start_trans_and_stmt() { - binlog_trx_data *trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); + binlog_cache_mngr *cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton); DBUG_ENTER("binlog_start_trans_and_stmt"); - DBUG_PRINT("enter", ("trx_data: 0x%lx trx_data->before_stmt_pos: %lu", - (long) trx_data, - (trx_data ? (ulong) trx_data->before_stmt_pos : + DBUG_PRINT("enter", ("cache_mngr: %p cache_mngr->trx_cache.get_prev_position(): %lu", + cache_mngr, + (cache_mngr ? (ulong) cache_mngr->trx_cache.get_prev_position() : (ulong) 0))); - if (trx_data == NULL || - trx_data->before_stmt_pos == MY_OFF_T_UNDEF) + if (cache_mngr == NULL || + cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF) { this->binlog_set_stmt_begin(); - if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + if (variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trans_register_ha(this, TRUE, binlog_hton); trans_register_ha(this, FALSE, binlog_hton); /* @@ -4136,27 +4320,35 @@ THD::binlog_start_trans_and_stmt() } void THD::binlog_set_stmt_begin() { - binlog_trx_data *trx_data= - (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); + binlog_cache_mngr *cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton); /* - The call to binlog_trans_log_savepos() might create the trx_data + The call to binlog_trans_log_savepos() might create the cache_mngr structure, if it didn't exist before, so we save the position into an auto variable and then write it into the transaction - data for the binary log (i.e., trx_data). + data for the binary log (i.e., cache_mngr). */ my_off_t pos= 0; binlog_trans_log_savepos(this, &pos); - trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); - trx_data->before_stmt_pos= pos; + cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton); + cache_mngr->trx_cache.set_prev_position(pos); } -/* - Write a table map to the binary log. - */ - -int THD::binlog_write_table_map(TABLE *table, bool is_trans) +/** + This function writes a table map to the binary log. + Note that in order to keep the signature uniform with related methods, + we use a redundant parameter to indicate whether a transactional table + was changed or not. + + @param table a pointer to the table. + @param is_transactional @c true indicates a transactional table, + otherwise @c false a non-transactional. + @return + nonzero if an error pops up when writing the table map event. +*/ +int THD::binlog_write_table_map(TABLE *table, bool is_transactional) { int error; DBUG_ENTER("THD::binlog_write_table_map"); @@ -4165,19 +4357,21 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans) table->s->table_map_id)); /* Pre-conditions */ - DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open()); + DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); - Table_map_log_event::flag_set const - flags= Table_map_log_event::TM_NO_FLAGS; - Table_map_log_event - the_event(this, table, table->s->table_map_id, is_trans, flags); + the_event(this, table, table->s->table_map_id, is_transactional); - if (is_trans && binlog_table_maps == 0) + if (binlog_table_maps == 0) binlog_start_trans_and_stmt(); - if ((error= mysql_bin_log.write(&the_event))) + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton); + + IO_CACHE *file= cache_mngr->get_binlog_cache_log(is_transactional); + + if ((error= the_event.write(file))) DBUG_RETURN(error); binlog_table_maps++; @@ -4185,144 +4379,163 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans) DBUG_RETURN(0); } +/** + This function retrieves a pending row event from a cache which is + specified through the parameter @c is_transactional. Respectively, when it + is @c true, the pending event is returned from the transactional cache. + Otherwise from the non-transactional cache. + + @param is_transactional @c true indicates a transactional cache, + otherwise @c false a non-transactional. + @return + The row event if any. +*/ Rows_log_event* -THD::binlog_get_pending_rows_event() const +THD::binlog_get_pending_rows_event(bool is_transactional) const { - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); + Rows_log_event* rows= NULL; + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton); + /* - This is less than ideal, but here's the story: If there is no - trx_data, prepare_pending_rows_event() has never been called - (since the trx_data is set up there). In that case, we just return - NULL. + This is less than ideal, but here's the story: If there is no cache_mngr, + prepare_pending_rows_event() has never been called (since the cache_mngr + is set up there). In that case, we just return NULL. */ - return trx_data ? trx_data->pending() : NULL; + if (cache_mngr) + { + binlog_cache_data *cache_data= + cache_mngr->get_binlog_cache_data(is_transactional); + + rows= cache_data->pending(); + } + return (rows); } +/** + This function stores a pending row event into a cache which is specified + through the parameter @c is_transactional. Respectively, when it is @c + true, the pending event is stored into the transactional cache. Otherwise + into the non-transactional cache. + + @param evt a pointer to the row event. + @param is_transactional @c true indicates a transactional cache, + otherwise @c false a non-transactional. +*/ void -THD::binlog_set_pending_rows_event(Rows_log_event* ev) +THD::binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional) { if (thd_get_ha_data(this, binlog_hton) == NULL) binlog_setup_trx_data(); - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton); - DBUG_ASSERT(trx_data); - trx_data->set_pending(ev); + DBUG_ASSERT(cache_mngr); + + binlog_cache_data *cache_data= + cache_mngr->get_binlog_cache_data(is_transactional); + + cache_data->set_pending(ev); } /** - Remove the pending rows event, discarding any outstanding rows. - - If there is no pending rows event available, this is effectively a + This function removes the pending rows event, discarding any outstanding + rows. If there is no pending rows event available, this is effectively a no-op. - */ + + @param thd a pointer to the user thread. + @param is_transactional @c true indicates a transactional cache, + otherwise @c false a non-transactional. +*/ int -MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd) +MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd, bool is_transactional) { DBUG_ENTER("MYSQL_BIN_LOG::remove_pending_rows_event"); - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); - DBUG_ASSERT(trx_data); + DBUG_ASSERT(cache_mngr); - if (Rows_log_event* pending= trx_data->pending()) + binlog_cache_data *cache_data= + cache_mngr->get_binlog_cache_data(is_transactional); + + if (Rows_log_event* pending= cache_data->pending()) { delete pending; - trx_data->set_pending(NULL); + cache_data->set_pending(NULL); } DBUG_RETURN(0); } /* - Moves the last bunch of rows from the pending Rows event to the binlog - (either cached binlog if transaction, or disk binlog). Sets a new pending - event. + Moves the last bunch of rows from the pending Rows event to a cache (either + transactional cache if is_transaction is @c true, or the non-transactional + cache otherwise. Sets a new pending event. + + @param thd a pointer to the user thread. + @param evt a pointer to the row event. + @param is_transactional @c true indicates a transactional cache, + otherwise @c false a non-transactional. */ int MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, - Rows_log_event* event) + Rows_log_event* event, + bool is_transactional) { DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)"); DBUG_ASSERT(mysql_bin_log.is_open()); DBUG_PRINT("enter", ("event: 0x%lx", (long) event)); int error= 0; + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); + DBUG_ASSERT(cache_mngr); - DBUG_ASSERT(trx_data); + binlog_cache_data *cache_data= + cache_mngr->get_binlog_cache_data(is_transactional); - DBUG_PRINT("info", ("trx_data->pending(): 0x%lx", (long) trx_data->pending())); + DBUG_PRINT("info", ("cache_mngr->pending(): 0x%lx", (long) cache_data->pending())); - if (Rows_log_event* pending= trx_data->pending()) + if (Rows_log_event* pending= cache_data->pending()) { - IO_CACHE *file= &log_file; - - /* - Decide if we should write to the log file directly or to the - transaction log. - */ - if (pending->get_cache_stmt() || my_b_tell(&trx_data->trans_log)) - file= &trx_data->trans_log; - - /* - If we are writing to the log file directly, we could avoid - locking the log. This does not work since we need to step the - m_table_map_version below, and that change has to be protected - by the LOCK_log mutex. - */ - pthread_mutex_lock(&LOCK_log); + IO_CACHE *file= &cache_data->cache_log; /* - Write pending event to log file or transaction cache + Write pending event to the cache. */ if (pending->write(file)) { - pthread_mutex_unlock(&LOCK_log); set_write_error(thd); + if (check_write_error(thd) && cache_data && + thd->transaction.stmt.modified_non_trans_table) + cache_data->set_incident(); DBUG_RETURN(1); } /* We step the table map version if we are writing an event - representing the end of a statement. We do this regardless of - wheather we write to the transaction cache or to directly to the - file. - - In an ideal world, we could avoid stepping the table map version - if we were writing to a transaction cache, since we could then - reuse the table map that was written earlier in the transaction - cache. This does not work since STMT_END_F implies closing all - table mappings on the slave side. + representing the end of a statement. + In an ideal world, we could avoid stepping the table map version, + since we could then reuse the table map that was written earlier + in the cache. This does not work since STMT_END_F implies closing + all table mappings on the slave side. + TODO: Find a solution so that table maps does not have to be written several times within a transaction. - */ + */ if (pending->get_flags(Rows_log_event::STMT_END_F)) ++m_table_map_version; delete pending; - - if (file == &log_file) - { - error= flush_and_sync(0); - if (!error) - { - signal_update(); - rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); - } - } - - pthread_mutex_unlock(&LOCK_log); } - thd->binlog_set_pending_rows_event(event); + thd->binlog_set_pending_rows_event(event, is_transactional); DBUG_RETURN(error); } @@ -4336,6 +4549,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) THD *thd= event_info->thd; bool error= 1; DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)"); + binlog_cache_data *cache_data= 0; if (thd->binlog_evt_union.do_union) { @@ -4344,27 +4558,22 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) We will log the function call to the binary log on function exit */ thd->binlog_evt_union.unioned_events= TRUE; - thd->binlog_evt_union.unioned_events_trans |= event_info->cache_stmt; + thd->binlog_evt_union.unioned_events_trans |= + event_info->use_trans_cache(); DBUG_RETURN(0); } /* - Flush the pending rows event to the transaction cache or to the - log file. Since this function potentially aquire the LOCK_log - mutex, we do this before aquiring the LOCK_log mutex in this - function. - We only end the statement if we are in a top-level statement. If we are inside a stored function, we do not end the statement since this will close all tables on the slave. */ bool const end_stmt= thd->prelocked_mode && thd->lex->requires_prelocking(); - if (thd->binlog_flush_pending_rows_event(end_stmt)) + if (thd->binlog_flush_pending_rows_event(end_stmt, + event_info->use_trans_cache())) DBUG_RETURN(error); - pthread_mutex_lock(&LOCK_log); - /* In most cases this is only called if 'is_open()' is true; in fact this is mostly called if is_open() *was* true a few instructions before, but it @@ -4372,7 +4581,6 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) */ if (likely(is_open())) { - IO_CACHE *file= &log_file; #ifdef HAVE_REPLICATION /* In the future we need to add to the following if tests like @@ -4380,68 +4588,71 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) binlog_[wild_]{do|ignore}_table?" (WL#1049)" */ const char *local_db= event_info->get_db(); - if ((thd && !(thd->options & OPTION_BIN_LOG)) || - (!binlog_filter->db_ok(local_db))) - { - pthread_mutex_unlock(&LOCK_log); + if ((thd && !(thd->variables.option_bits & OPTION_BIN_LOG)) || + !binlog_filter->db_ok(local_db)) DBUG_RETURN(0); - } #endif /* HAVE_REPLICATION */ - /* - Should we write to the binlog cache or to the binlog on disk? - Write to the binlog cache if: - - it is already not empty (meaning we're in a transaction; note that the - present event could be about a non-transactional table, but still we need - to write to the binlog cache in that case to handle updates to mixed - trans/non-trans table types the best possible in binlogging) - - or if the event asks for it (cache_stmt == TRUE). - */ - if (opt_using_transactions && thd) + IO_CACHE *file= NULL; + + if (event_info->use_direct_logging()) + { + file= &log_file; + mysql_mutex_lock(&LOCK_log); + } + else { if (thd->binlog_setup_trx_data()) goto err; - binlog_trx_data *const trx_data= - (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); - IO_CACHE *trans_log= &trx_data->trans_log; - my_off_t trans_log_pos= my_b_tell(trans_log); - if (event_info->get_cache_stmt() || trans_log_pos != 0 || - stmt_has_updated_trans_table(thd)) + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + + /* + If we are about to use write rows, we just need to check the type of + the event (either transactional or non-transactional) in order to + choose the cache. + */ + if (thd->is_current_stmt_binlog_format_row()) { - DBUG_PRINT("info", ("Using trans_log: cache: %d, trans_log_pos: %lu", - event_info->get_cache_stmt(), - (ulong) trans_log_pos)); - thd->binlog_start_trans_and_stmt(); - file= trans_log; + file= cache_mngr->get_binlog_cache_log(event_info->use_trans_cache()); + cache_data= cache_mngr->get_binlog_cache_data(event_info->use_trans_cache()); } /* - TODO as Mats suggested, for all the cases above where we write to - trans_log, it sounds unnecessary to lock LOCK_log. We should rather - test first if we want to write to trans_log, and if not, lock - LOCK_log. + However, if we are about to write statements we need to consider other + things. We use the non-transactional cache when: + + . the transactional cache is empty which means that there were no + early statement on behalf of the transaction. + . the respective event is tagged as non-transactional. */ - } + else if (cache_mngr->trx_cache.empty() && + !event_info->use_trans_cache()) + { + file= &cache_mngr->stmt_cache.cache_log; + cache_data= &cache_mngr->stmt_cache; + } + else + { + file= &cache_mngr->trx_cache.cache_log; + cache_data= &cache_mngr->trx_cache; + } + thd->binlog_start_trans_and_stmt(); + } DBUG_PRINT("info",("event type: %d",event_info->get_type_code())); /* - No check for auto events flag here - this write method should - never be called if auto-events are enabled - */ - - /* - 1. Write first log events which describe the 'run environment' - of the SQL command - */ + No check for auto events flag here - this write method should + never be called if auto-events are enabled. - /* - If row-based binlogging, Insert_id, Rand and other kind of "setting - context" events are not needed. + Write first log events which describe the 'run environment' + of the SQL command. If row-based binlogging, Insert_id, Rand + and other kind of "setting context" events are not needed. */ if (thd) { - if (!thd->current_stmt_binlog_row_based) + if (!thd->is_current_stmt_binlog_format_row()) { if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt) { @@ -4487,39 +4698,48 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) } /* - Write the SQL command - */ - - if (event_info->write(file) || + Write the event. + */ + if (event_info->write(file) || DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0)) goto err; - if (file == &log_file) // we are writing to the real log (disk) + error= 0; + +err: + if (event_info->use_direct_logging()) { - bool synced= 0; - if (flush_and_sync(&synced)) - goto err; + if (!error) + { + bool synced; + if ((error= flush_and_sync(&synced))) + goto unlock; - if (RUN_HOOK(binlog_storage, after_flush, - (thd, log_file_name, file->pos_in_file, synced))) { - sql_print_error("Failed to run 'after_flush' hooks"); - goto err; + if ((error= RUN_HOOK(binlog_storage, after_flush, + (thd, log_file_name, file->pos_in_file, synced)))) + { + sql_print_error("Failed to run 'after_flush' hooks"); + goto unlock; + } + signal_update(); + rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); } - - signal_update(); - rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); +unlock: + mysql_mutex_unlock(&LOCK_log); } - error=0; -err: if (error) + { set_write_error(thd); + if (check_write_error(thd) && cache_data && + thd->transaction.stmt.modified_non_trans_table) + cache_data->set_incident(); + } } if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F) ++m_table_map_version; - pthread_mutex_unlock(&LOCK_log); DBUG_RETURN(error); } @@ -4549,7 +4769,7 @@ bool LOGGER::log_command(THD *thd, enum enum_server_command command) */ if (*general_log_handler_list && (what_to_log & (1L << (uint) command))) { - if ((thd->options & OPTION_LOG_OFF) + if ((thd->variables.option_bits & OPTION_LOG_OFF) #ifndef NO_EMBEDDED_ACCESS_CHECKS && (sctx->master_access & SUPER_ACL) #endif @@ -4599,7 +4819,7 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags) bool check_purge= false; #endif if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)) - pthread_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_log); if ((flags & RP_FORCE_ROTATE) || (my_b_tell(&log_file) >= (my_off_t) max_size)) { @@ -4609,7 +4829,7 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags) #endif } if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)) - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); #ifdef HAVE_REPLICATION /* @@ -4628,9 +4848,9 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags) uint MYSQL_BIN_LOG::next_file_id() { uint res; - pthread_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_log); res = file_id++; - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); return res; } @@ -4642,7 +4862,7 @@ uint MYSQL_BIN_LOG::next_file_id() write_cache() cache Cache to write to the binary log lock_log True if the LOCK_log mutex should be aquired, false otherwise - sync_log True if the log should be flushed and sync:ed + sync_log True if the log should be flushed and synced DESCRIPTION Write the contents of the cache to the binary log. The cache will @@ -4814,7 +5034,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) Incident incident= INCIDENT_LOST_EVENTS; Incident_log_event ev(thd, incident, write_error_msg); if (lock) - pthread_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_log); error= ev.write(&log_file); if (lock) { @@ -4823,7 +5043,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) signal_update(); rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); } - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); } DBUG_RETURN(error); } @@ -4856,10 +5076,7 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident) { DBUG_ENTER("MYSQL_BIN_LOG::write(THD *, IO_CACHE *, Log_event *)"); - pthread_mutex_lock(&LOCK_log); - - /* NULL would represent nothing to replicate after ROLLBACK */ - DBUG_ASSERT(commit_event != NULL); + mysql_mutex_lock(&LOCK_log); DBUG_ASSERT(is_open()); if (likely(is_open())) // Should always be true @@ -4875,19 +5092,9 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, transaction is either a BEGIN..COMMIT block or a single statement in autocommit mode. */ - Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, TRUE, 0); - - /* - Now this Query_log_event has artificial log_pos 0. It must be - adjusted to reflect the real position in the log. Not doing it - would confuse the slave: it would prevent this one from - knowing where he is in the master's binlog, which would result - in wrong positions being shown to the user, MASTER_POS_WAIT - undue waiting etc. - */ + Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE, TRUE, 0); if (qinfo.write(&log_file)) goto err; - DBUG_EXECUTE_IF("crash_before_writing_xid", { if ((write_error= write_cache(cache, false, true))) @@ -4938,14 +5145,14 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, */ if (commit_event && commit_event->get_type_code() == XID_EVENT) { - pthread_mutex_lock(&LOCK_prep_xids); + mysql_mutex_lock(&LOCK_prep_xids); prepared_xids++; - pthread_mutex_unlock(&LOCK_prep_xids); + mysql_mutex_unlock(&LOCK_prep_xids); } else rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); } - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); DBUG_RETURN(0); @@ -4955,7 +5162,7 @@ err: write_error= 1; sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); } - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); DBUG_RETURN(1); } @@ -4977,10 +5184,10 @@ void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd) DBUG_ENTER("wait_for_update_relay_log"); old_msg= thd->enter_cond(&update_cond, &LOCK_log, - "Slave has read all relay log; " + "Slave has read all relay log; " "waiting for the slave I/O " "thread to update it" ); - pthread_cond_wait(&update_cond, &LOCK_log); + mysql_cond_wait(&update_cond, &LOCK_log); thd->exit_cond(old_msg); DBUG_VOID_RETURN; } @@ -5011,10 +5218,10 @@ int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd, "Master has sent all binlog to slave; " "waiting for binlog to be updated"); if (!timeout) - pthread_cond_wait(&update_cond, &LOCK_log); + mysql_cond_wait(&update_cond, &LOCK_log); else - ret= pthread_cond_timedwait(&update_cond, &LOCK_log, - const_cast<struct timespec *>(timeout)); + ret= mysql_cond_timedwait(&update_cond, &LOCK_log, + const_cast<struct timespec *>(timeout)); DBUG_RETURN(ret); } @@ -5054,16 +5261,16 @@ void MYSQL_BIN_LOG::close(uint exiting) if (log_file.type == WRITE_CACHE && log_type == LOG_BIN) { my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET; - my_off_t org_position= my_tell(log_file.file, MYF(0)); + my_off_t org_position= mysql_file_tell(log_file.file, MYF(0)); uchar flags= 0; // clearing LOG_EVENT_BINLOG_IN_USE_F - my_pwrite(log_file.file, &flags, 1, offset, MYF(0)); + mysql_file_pwrite(log_file.file, &flags, 1, offset, MYF(0)); /* Restore position so that anything we have in the IO_cache is written to the correct position. - We need the seek here, as my_pwrite() is not guaranteed to keep the + We need the seek here, as mysql_file_pwrite() is not guaranteed to keep the original position on system that doesn't support pwrite(). */ - my_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0)); + mysql_file_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0)); } /* this will cleanup IO_CACHE, sync and close the file */ @@ -5078,7 +5285,7 @@ void MYSQL_BIN_LOG::close(uint exiting) if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file)) { end_io_cache(&index_file); - if (my_close(index_file.file, MYF(0)) < 0 && ! write_error) + if (mysql_file_close(index_file.file, MYF(0)) < 0 && ! write_error) { write_error= 1; sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno); @@ -5100,10 +5307,10 @@ void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg) it's like if the SET command was never run. */ DBUG_ENTER("MYSQL_BIN_LOG::set_max_size"); - pthread_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_log); if (is_open()) max_size= max_size_arg; - pthread_mutex_unlock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); DBUG_VOID_RETURN; } @@ -5175,7 +5382,7 @@ bool flush_error_log() char err_renamed[FN_REFLEN], *end; end= strmake(err_renamed,log_error_file,FN_REFLEN-5); strmov(end, "-old"); - pthread_mutex_lock(&LOCK_error_log); + mysql_mutex_lock(&LOCK_error_log); #ifdef __WIN__ char err_temp[FN_REFLEN+5]; /* @@ -5183,7 +5390,7 @@ bool flush_error_log() the current error file. */ strxmov(err_temp, err_renamed,"-tmp",NullS); - (void) my_delete(err_temp, MYF(0)); + my_delete(err_temp, MYF(0)); if (freopen(err_temp,"a+",stdout)) { int fd; @@ -5192,27 +5399,27 @@ bool flush_error_log() freopen(err_temp,"a+",stderr); setbuf(stderr, NULL); - (void) my_delete(err_renamed, MYF(0)); - my_rename(log_error_file,err_renamed,MYF(0)); + my_delete(err_renamed, MYF(0)); + my_rename(log_error_file, err_renamed, MYF(0)); if (freopen(log_error_file,"a+",stdout)) { freopen(log_error_file,"a+",stderr); setbuf(stderr, NULL); } - if ((fd = my_open(err_temp, O_RDONLY, MYF(0))) >= 0) + if ((fd= my_open(err_temp, O_RDONLY, MYF(0))) >= 0) { - while ((bytes= my_read(fd, buf, IO_SIZE, MYF(0))) && + while ((bytes= mysql_file_read(fd, buf, IO_SIZE, MYF(0))) && bytes != MY_FILE_ERROR) my_fwrite(stderr, buf, bytes, MYF(0)); - my_close(fd, MYF(0)); + mysql_file_close(fd, MYF(0)); } - (void) my_delete(err_temp, MYF(0)); + my_delete(err_temp, MYF(0)); } else result= 1; #else - my_rename(log_error_file,err_renamed,MYF(0)); + my_rename(log_error_file, err_renamed, MYF(0)); if (freopen(log_error_file,"a+",stdout)) { FILE *reopen; @@ -5222,7 +5429,7 @@ bool flush_error_log() else result= 1; #endif - pthread_mutex_unlock(&LOCK_error_log); + mysql_mutex_unlock(&LOCK_error_log); } return result; } @@ -5231,7 +5438,7 @@ void MYSQL_BIN_LOG::signal_update() { DBUG_ENTER("MYSQL_BIN_LOG::signal_update"); signal_cnt++; - pthread_cond_broadcast(&update_cond); + mysql_cond_broadcast(&update_cond); DBUG_VOID_RETURN; } @@ -5297,7 +5504,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer) DBUG_ENTER("print_buffer_to_file"); DBUG_PRINT("enter",("buffer: %s", buffer)); - pthread_mutex_lock(&LOCK_error_log); + mysql_mutex_lock(&LOCK_error_log); skr= my_time(0); localtime_r(&skr, &tm_tmp); @@ -5316,7 +5523,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer) fflush(stderr); - pthread_mutex_unlock(&LOCK_error_log); + mysql_mutex_unlock(&LOCK_error_log); DBUG_VOID_RETURN; } @@ -5440,17 +5647,18 @@ int TC_LOG_MMAP::open(const char *opt_name) DBUG_ASSERT(TC_LOG_PAGE_SIZE % tc_log_page_size == 0); fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME); - if ((fd= my_open(logname, O_RDWR, MYF(0))) < 0) + if ((fd= mysql_file_open(key_file_tclog, logname, O_RDWR, MYF(0))) < 0) { if (my_errno != ENOENT) goto err; if (using_heuristic_recover()) return 1; - if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0) + if ((fd= mysql_file_create(key_file_tclog, logname, CREATE_MODE, + O_RDWR, MYF(MY_WME))) < 0) goto err; inited=1; file_length= opt_tc_log_size; - if (my_chsize(fd, file_length, 0, MYF(MY_WME))) + if (mysql_file_chsize(fd, file_length, 0, MYF(MY_WME))) goto err; } else @@ -5464,7 +5672,7 @@ int TC_LOG_MMAP::open(const char *opt_name) "--tc-heuristic-recover is used"); goto err; } - file_length= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE)); + file_length= mysql_file_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE)); if (file_length == MY_FILEPOS_ERROR || file_length % tc_log_page_size) goto err; } @@ -5488,8 +5696,8 @@ int TC_LOG_MMAP::open(const char *opt_name) pg->next=pg+1; pg->waiters=0; pg->state=POOL; - pthread_mutex_init(&pg->lock, MY_MUTEX_INIT_FAST); - pthread_cond_init (&pg->cond, 0); + mysql_mutex_init(key_PAGE_lock, &pg->lock, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_PAGE_cond, &pg->cond, 0); pg->start=(my_xid *)(data + i*tc_log_page_size); pg->end=(my_xid *)(pg->start + tc_log_page_size); pg->size=pg->free=tc_log_page_size/sizeof(my_xid); @@ -5508,11 +5716,11 @@ int TC_LOG_MMAP::open(const char *opt_name) my_msync(fd, data, tc_log_page_size, MS_SYNC); inited=5; - pthread_mutex_init(&LOCK_sync, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&LOCK_active, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&LOCK_pool, MY_MUTEX_INIT_FAST); - pthread_cond_init(&COND_active, 0); - pthread_cond_init(&COND_pool, 0); + mysql_mutex_init(key_LOCK_sync, &LOCK_sync, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_active, &LOCK_active, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_pool, &LOCK_pool, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_active, &COND_active, 0); + mysql_cond_init(key_COND_pool, &COND_pool, 0); inited=6; @@ -5546,7 +5754,7 @@ void TC_LOG_MMAP::get_active_from_pool() int best_free; if (syncing) - pthread_mutex_lock(&LOCK_pool); + mysql_mutex_lock(&LOCK_pool); do { @@ -5579,7 +5787,7 @@ void TC_LOG_MMAP::get_active_from_pool() pool_last=*best_p; if (syncing) - pthread_mutex_unlock(&LOCK_pool); + mysql_mutex_unlock(&LOCK_pool); } /** @@ -5594,7 +5802,7 @@ int TC_LOG_MMAP::overflow() let's check the behaviour of tc_log_page_waits first */ tc_log_page_waits++; - pthread_cond_wait(&COND_pool, &LOCK_pool); + mysql_cond_wait(&COND_pool, &LOCK_pool); return 1; // always return 1 } @@ -5631,7 +5839,7 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) PAGE *p; ulong cookie; - pthread_mutex_lock(&LOCK_active); + mysql_mutex_lock(&LOCK_active); /* if active page is full - just wait... @@ -5641,14 +5849,14 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) unlog() does not signal COND_active. */ while (unlikely(active && active->free == 0)) - pthread_cond_wait(&COND_active, &LOCK_active); + mysql_cond_wait(&COND_active, &LOCK_active); /* no active page ? take one from the pool */ if (active == 0) get_active_from_pool(); p=active; - pthread_mutex_lock(&p->lock); + mysql_mutex_lock(&p->lock); /* searching for an empty slot */ while (*p->ptr) @@ -5664,9 +5872,9 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) p->state= DIRTY; /* to sync or not to sync - this is the question */ - pthread_mutex_unlock(&LOCK_active); - pthread_mutex_lock(&LOCK_sync); - pthread_mutex_unlock(&p->lock); + mysql_mutex_unlock(&LOCK_active); + mysql_mutex_lock(&LOCK_sync); + mysql_mutex_unlock(&p->lock); if (syncing) { // somebody's syncing. let's wait @@ -5676,24 +5884,24 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) as p->state may be not DIRTY when we come here */ while (p->state == DIRTY && syncing) - pthread_cond_wait(&p->cond, &LOCK_sync); + mysql_cond_wait(&p->cond, &LOCK_sync); p->waiters--; err= p->state == ERROR; if (p->state != DIRTY) // page was synced { if (p->waiters == 0) - pthread_cond_signal(&COND_pool); // in case somebody's waiting - pthread_mutex_unlock(&LOCK_sync); + mysql_cond_signal(&COND_pool); // in case somebody's waiting + mysql_mutex_unlock(&LOCK_sync); goto done; // we're done } } // page was not synced! do it now DBUG_ASSERT(active == p && syncing == 0); - pthread_mutex_lock(&LOCK_active); + mysql_mutex_lock(&LOCK_active); syncing=p; // place is vacant - take it active=0; // page is not active anymore - pthread_cond_broadcast(&COND_active); // in case somebody's waiting - pthread_mutex_unlock(&LOCK_active); - pthread_mutex_unlock(&LOCK_sync); + mysql_cond_broadcast(&COND_active); // in case somebody's waiting + mysql_mutex_unlock(&LOCK_active); + mysql_mutex_unlock(&LOCK_sync); err= sync(); done: @@ -5713,20 +5921,20 @@ int TC_LOG_MMAP::sync() err= my_msync(fd, syncing->start, 1, MS_SYNC); /* page is synced. let's move it to the pool */ - pthread_mutex_lock(&LOCK_pool); + mysql_mutex_lock(&LOCK_pool); pool_last->next=syncing; pool_last=syncing; syncing->next=0; syncing->state= err ? ERROR : POOL; - pthread_cond_broadcast(&syncing->cond); // signal "sync done" - pthread_cond_signal(&COND_pool); // in case somebody's waiting - pthread_mutex_unlock(&LOCK_pool); + mysql_cond_broadcast(&syncing->cond); // signal "sync done" + mysql_cond_signal(&COND_pool); // in case somebody's waiting + mysql_mutex_unlock(&LOCK_pool); /* marking 'syncing' slot free */ - pthread_mutex_lock(&LOCK_sync); + mysql_mutex_lock(&LOCK_sync); syncing=0; - pthread_cond_signal(&active->cond); // wake up a new syncer - pthread_mutex_unlock(&LOCK_sync); + mysql_cond_signal(&active->cond); // wake up a new syncer + mysql_mutex_unlock(&LOCK_sync); return err; } @@ -5744,15 +5952,15 @@ void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) DBUG_ASSERT(x >= p->start && x < p->end); *x=0; - pthread_mutex_lock(&p->lock); + mysql_mutex_lock(&p->lock); p->free++; DBUG_ASSERT(p->free <= p->size); set_if_smaller(p->ptr, x); if (p->free == p->size) // the page is completely empty statistic_decrement(tc_log_cur_pages_used, &LOCK_status); if (p->waiters == 0) // the page is in pool and ready to rock - pthread_cond_signal(&COND_pool); // ping ... for overflow() - pthread_mutex_unlock(&p->lock); + mysql_cond_signal(&COND_pool); // ping ... for overflow() + mysql_mutex_unlock(&p->lock); } void TC_LOG_MMAP::close() @@ -5760,29 +5968,29 @@ void TC_LOG_MMAP::close() uint i; switch (inited) { case 6: - pthread_mutex_destroy(&LOCK_sync); - pthread_mutex_destroy(&LOCK_active); - pthread_mutex_destroy(&LOCK_pool); - pthread_cond_destroy(&COND_pool); + mysql_mutex_destroy(&LOCK_sync); + mysql_mutex_destroy(&LOCK_active); + mysql_mutex_destroy(&LOCK_pool); + mysql_cond_destroy(&COND_pool); case 5: - data[0]='A'; // garble the first (signature) byte, in case my_delete fails + data[0]='A'; // garble the first (signature) byte, in case mysql_file_delete fails case 4: for (i=0; i < npages; i++) { if (pages[i].ptr == 0) break; - pthread_mutex_destroy(&pages[i].lock); - pthread_cond_destroy(&pages[i].cond); + mysql_mutex_destroy(&pages[i].lock); + mysql_cond_destroy(&pages[i].cond); } case 3: my_free((uchar*)pages, MYF(0)); case 2: my_munmap((char*)data, (size_t)file_length); case 1: - my_close(fd, MYF(0)); + mysql_file_close(fd, MYF(0)); } if (inited>=5) // cannot do in the switch because of Windows - my_delete(logname, MYF(MY_WME)); + mysql_file_delete(key_file_tclog, logname, MYF(MY_WME)); inited=0; } @@ -5887,8 +6095,9 @@ int TC_LOG_BINLOG::open(const char *opt_name) DBUG_ASSERT(total_ha_2pc > 1); DBUG_ASSERT(opt_name && opt_name[0]); - pthread_mutex_init(&LOCK_prep_xids, MY_MUTEX_INIT_FAST); - pthread_cond_init (&COND_prep_xids, 0); + mysql_mutex_init(key_BINLOG_LOCK_prep_xids, + &LOCK_prep_xids, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_BINLOG_COND_prep_xids, &COND_prep_xids, 0); if (!my_b_inited(&index_file)) { @@ -5954,7 +6163,7 @@ int TC_LOG_BINLOG::open(const char *opt_name) delete ev; end_io_cache(&log); - my_close(file, MYF(MY_WME)); + mysql_file_close(file, MYF(MY_WME)); if (error) goto err; @@ -5968,8 +6177,8 @@ err: void TC_LOG_BINLOG::close() { DBUG_ASSERT(prepared_xids==0); - pthread_mutex_destroy(&LOCK_prep_xids); - pthread_cond_destroy (&COND_prep_xids); + mysql_mutex_destroy(&LOCK_prep_xids); + mysql_cond_destroy(&COND_prep_xids); } /** @@ -5985,24 +6194,25 @@ int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid) { DBUG_ENTER("TC_LOG_BINLOG::log"); Xid_log_event xle(thd, xid); - binlog_trx_data *trx_data= - (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); + binlog_cache_mngr *cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); /* We always commit the entire transaction when writing an XID. Also note that the return value is inverted. */ - DBUG_RETURN(!binlog_end_trans(thd, trx_data, &xle, TRUE)); + DBUG_RETURN(!binlog_flush_stmt_cache(thd, cache_mngr) && + !binlog_flush_trx_cache(thd, cache_mngr, &xle)); } void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) { - pthread_mutex_lock(&LOCK_prep_xids); + mysql_mutex_lock(&LOCK_prep_xids); DBUG_ASSERT(prepared_xids > 0); if (--prepared_xids == 0) { DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids)); - pthread_cond_signal(&COND_prep_xids); + mysql_cond_signal(&COND_prep_xids); } - pthread_mutex_unlock(&LOCK_prep_xids); + mysql_mutex_unlock(&LOCK_prep_xids); rotate_and_purge(0); // as ::write() did not rotate } |