summaryrefslogtreecommitdiff
path: root/sql/log.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/log.cc')
-rw-r--r--sql/log.cc153
1 files changed, 86 insertions, 67 deletions
diff --git a/sql/log.cc b/sql/log.cc
index 1b8cd52ebb0..cbbe294387b 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1452,11 +1452,6 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
trx_data->has_incident());
trx_data->reset();
- /*
- 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)
{
@@ -1482,13 +1477,6 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
}
else // ...statement
trx_data->truncate(trx_data->before_stmt_pos);
-
- /*
- 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);
@@ -1534,28 +1522,23 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
}
/*
- We commit the transaction if:
-
- - We are not in a transaction and committing a statement, or
+ We flush the cache if:
- - We are in a transaction and a full transaction is committed
+ - we are committing a transaction or;
+ - no statement was committed before and just non-transactional
+ tables were updated.
- Otherwise, we accumulate the statement
+ Otherwise, we collect 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: %d, empty: %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 (ending_trans(thd, all) ||
+ (trans_has_no_stmt_committed(thd, all) &&
+ !stmt_has_updated_trans_table(thd) && stmt_has_updated_non_trans_table(thd)))
{
Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, 0);
error= binlog_end_trans(thd, trx_data, &qev, all);
@@ -1618,7 +1601,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
On the other hand, if a statement is transactional, we just safely roll it
back.
*/
- if ((thd->transaction.stmt.modified_non_trans_table ||
+ if ((stmt_has_updated_non_trans_table(thd) ||
(thd->options & OPTION_KEEP_LOG)) &&
mysql_bin_log.check_write_error(thd))
trx_data->set_incident();
@@ -1627,20 +1610,19 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool 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 with a rollback, wrapped in a begin/rollback if:
+ . aborting a transaction that modified a non-transactional table or
+ the OPTION_KEEP_LOG is activate.
. 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;
- . the OPTION_KEEP_LOG is activate.
*/
- if ((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)))
+ if ((ending_trans(thd, all) &&
+ (trans_has_updated_non_trans_table(thd) ||
+ (thd->options & OPTION_KEEP_LOG))) ||
+ (trans_has_no_stmt_committed(thd, all) &&
+ stmt_has_updated_non_trans_table(thd) &&
+ thd->current_stmt_binlog_row_based))
{
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0);
error= binlog_end_trans(thd, trx_data, &qev, all);
@@ -1649,8 +1631,8 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
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))
+ else if (ending_trans(thd, all) ||
+ (!(thd->options & OPTION_KEEP_LOG) && !stmt_has_updated_non_trans_table(thd)))
error= binlog_end_trans(thd, trx_data, 0, all);
}
if (!all)
@@ -1747,7 +1729,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
non-transactional table. Otherwise, truncate the binlog cache starting
from the SAVEPOINT command.
*/
- if (unlikely(thd->transaction.all.modified_non_trans_table ||
+ if (unlikely(trans_has_updated_non_trans_table(thd) ||
(thd->options & OPTION_KEEP_LOG)))
{
String log_query;
@@ -2471,7 +2453,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
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),
+ need_start_event(TRUE),
is_relay_log(0),
description_event_for_exec(0), description_event_for_queue(0)
{
@@ -3985,6 +3967,67 @@ bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
query_id_param >= thd->binlog_evt_union.first_query_id);
}
+/**
+ This function checks if a transaction, either a multi-statement
+ or a single statement transaction is about to commit or not.
+
+ @param thd The client thread that executed the current statement.
+ @param all Committing a transaction (i.e. TRUE) or a statement
+ (i.e. FALSE).
+ @return
+ @c true if committing a transaction, otherwise @c false.
+*/
+bool ending_trans(const THD* thd, const bool all)
+{
+ return (all || (!all && !(thd->options &
+ (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))));
+}
+
+/**
+ This function checks if a non-transactional table was updated by
+ the current transaction.
+
+ @param thd The client thread that executed the current statement.
+ @return
+ @c true if a non-transactional table was updated, @c false
+ otherwise.
+*/
+bool trans_has_updated_non_trans_table(const THD* thd)
+{
+ return (thd->transaction.all.modified_non_trans_table ||
+ thd->transaction.stmt.modified_non_trans_table);
+}
+
+/**
+ This function checks if any statement was committed and cached.
+
+ @param thd The client thread that executed the current statement.
+ @param all Committing a transaction (i.e. TRUE) or a statement
+ (i.e. FALSE).
+ @return
+ @c true if at a statement was committed and cached, @c false
+ otherwise.
+*/
+bool trans_has_no_stmt_committed(const THD* thd, bool all)
+{
+ binlog_trx_data *const trx_data=
+ (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+
+ return (!all && !trx_data->at_least_one_stmt_committed);
+}
+
+/**
+ This function checks if a non-transactional table was updated by the
+ current statement.
+
+ @param thd The client thread that executed the current statement.
+ @return
+ @c true if a non-transactional table was updated, @c false otherwise.
+*/
+bool stmt_has_updated_non_trans_table(const THD* thd)
+{
+ return (thd->transaction.stmt.modified_non_trans_table);
+}
/*
These functions are placed in this file since they need access to
@@ -4117,7 +4160,6 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans)
DBUG_RETURN(error);
binlog_table_maps++;
- table->s->table_map_version= mysql_bin_log.table_map_version();
DBUG_RETURN(0);
}
@@ -4208,10 +4250,8 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
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.
+ If we are not writing to the log file directly, we could avoid
+ locking the log.
*/
pthread_mutex_lock(&LOCK_log);
@@ -4225,24 +4265,6 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
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.
-
- 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)
@@ -4456,9 +4478,6 @@ err:
set_write_error(thd);
}
- if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
- ++m_table_map_version;
-
pthread_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
}