1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

Merge various replication-related patches into MariaDB 5.3:

- MWL#116 Group commit
 - MWL#136 Enhancements for START TRANSACTION WITH CONSISTENT SNAPSHOT
 - MWL#47 Annotate_rows_log_event
 - MWL#163 innodb_release_locks_early
 - Percona patch enhancing row-based replication for tables with no primary key
This commit is contained in:
unknown
2011-04-08 09:39:33 +02:00
105 changed files with 7078 additions and 905 deletions

View File

@@ -79,6 +79,8 @@ TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"",
static TYPELIB known_extensions= {0,"known_exts", NULL, NULL};
uint known_extensions_id= 0;
static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans,
bool is_real_trans);
static plugin_ref ha_default_plugin(THD *thd)
@@ -1077,7 +1079,7 @@ ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
*/
int ha_commit_trans(THD *thd, bool all)
{
int error= 0, cookie= 0;
int error= 0, cookie;
/*
'all' means that this is either an explicit commit issued by
user, or an implicit commit issued by a DDL.
@@ -1092,7 +1094,8 @@ int ha_commit_trans(THD *thd, bool all)
*/
bool is_real_trans= all || thd->transaction.all.ha_list == 0;
Ha_trx_info *ha_info= trans->ha_list;
my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
bool need_prepare_ordered, need_commit_ordered;
my_xid xid;
DBUG_ENTER("ha_commit_trans");
/* Just a random warning to test warnings pushed during autocommit. */
@@ -1131,89 +1134,114 @@ int ha_commit_trans(THD *thd, bool all)
DBUG_RETURN(2);
}
#ifdef USING_TRANSACTIONS
if (ha_info)
if (!ha_info)
{
uint rw_ha_count;
bool rw_trans;
DBUG_EXECUTE_IF("crash_commit_before", DBUG_SUICIDE(););
/* Close all cursors that can not survive COMMIT */
if (is_real_trans) /* not a statement commit */
thd->stmt_map.close_transient_cursors();
rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
/* rw_trans is TRUE when we in a transaction changing data */
rw_trans= is_real_trans && (rw_ha_count > 0);
if (rw_trans &&
wait_if_global_read_lock(thd, 0, 0))
{
ha_rollback_trans(thd, all);
DBUG_RETURN(1);
}
if (rw_trans &&
opt_readonly &&
!(thd->security_ctx->master_access & SUPER_ACL) &&
!thd->slave_thread)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
ha_rollback_trans(thd, all);
error= 1;
goto end;
}
if (!trans->no_2pc && (rw_ha_count > 1))
{
for (; ha_info && !error; ha_info= ha_info->next())
{
int err;
handlerton *ht= ha_info->ht();
/*
Do not call two-phase commit if this particular
transaction is read-only. This allows for simpler
implementation in engines that are always read-only.
*/
if (! ha_info->is_trx_read_write())
continue;
/*
Sic: we know that prepare() is not NULL since otherwise
trans->no_2pc would have been set.
*/
if ((err= ht->prepare(ht, thd, all)))
{
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
error= 1;
}
status_var_increment(thd->status_var.ha_prepare_count);
}
DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
if (error || (is_real_trans && xid &&
(error= !(cookie= tc_log->log_xid(thd, xid)))))
{
ha_rollback_trans(thd, all);
error= 1;
goto end;
}
DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
}
error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
if (cookie)
if(tc_log->unlog(cookie, xid))
{
error= 2;
goto end;
}
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
end:
if (rw_trans)
start_waiting_global_read_lock(thd);
/* Free resources and perform other cleanup even for 'empty' transactions. */
if (is_real_trans)
thd->transaction.cleanup();
DBUG_RETURN(0);
}
/* Free resources and perform other cleanup even for 'empty' transactions. */
else if (is_real_trans)
thd->transaction.cleanup();
DBUG_EXECUTE_IF("crash_commit_before", DBUG_SUICIDE(););
/* Close all cursors that can not survive COMMIT */
if (is_real_trans) /* not a statement commit */
thd->stmt_map.close_transient_cursors();
uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
/* rw_trans is TRUE when we in a transaction changing data */
bool rw_trans= is_real_trans && (rw_ha_count > 0);
if (rw_trans &&
wait_if_global_read_lock(thd, 0, 0))
{
ha_rollback_trans(thd, all);
DBUG_RETURN(1);
}
if (rw_trans &&
opt_readonly &&
!(thd->security_ctx->master_access & SUPER_ACL) &&
!thd->slave_thread)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
goto err;
}
if (trans->no_2pc || (rw_ha_count <= 1))
{
error= ha_commit_one_phase(thd, all);
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
goto end;
}
need_prepare_ordered= FALSE;
need_commit_ordered= FALSE;
xid= thd->transaction.xid_state.xid.get_my_xid();
for (Ha_trx_info *hi= ha_info; hi; hi= hi->next())
{
int err;
handlerton *ht= hi->ht();
/*
Do not call two-phase commit if this particular
transaction is read-only. This allows for simpler
implementation in engines that are always read-only.
*/
if (! hi->is_trx_read_write())
continue;
/*
Sic: we know that prepare() is not NULL since otherwise
trans->no_2pc would have been set.
*/
err= ht->prepare(ht, thd, all);
status_var_increment(thd->status_var.ha_prepare_count);
if (err)
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
if (err)
goto err;
need_prepare_ordered|= (ht->prepare_ordered != NULL);
need_commit_ordered|= (ht->commit_ordered != NULL);
}
DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
if (!is_real_trans)
{
error= commit_one_phase_2(thd, all, trans, is_real_trans);
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
goto end;
}
cookie= tc_log->log_and_order(thd, xid, all, need_prepare_ordered,
need_commit_ordered);
if (!cookie)
goto err;
DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0;
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
if (tc_log->unlog(cookie, xid))
{
error= 2; /* Error during commit */
goto end;
}
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
goto end;
/* Come here if error and we need to rollback. */
err:
error= 1; /* Transaction was rolled back */
ha_rollback_trans(thd, all);
end:
if (rw_trans)
start_waiting_global_read_lock(thd);
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
@@ -1224,7 +1252,6 @@ end:
*/
int ha_commit_one_phase(THD *thd, bool all)
{
int error=0;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
/*
"real" is a nick name for a transaction for which a commit will
@@ -1234,8 +1261,16 @@ int ha_commit_one_phase(THD *thd, bool all)
enclosing 'all' transaction is rolled back.
*/
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
DBUG_ENTER("ha_commit_one_phase");
DBUG_RETURN(commit_one_phase_2(thd, all, trans, is_real_trans));
}
static int
commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
{
int error= 0;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
DBUG_ENTER("commit_one_phase_2");
#ifdef USING_TRANSACTIONS
if (ha_info)
{
@@ -1852,7 +1887,16 @@ int ha_start_consistent_snapshot(THD *thd)
{
bool warn= true;
/*
Holding the LOCK_commit_ordered mutex ensures that we get the same
snapshot for all engines (including the binary log). This allows us
among other things to do backups with
START TRANSACTION WITH CONSISTENT SNAPSHOT and
have a consistent binlog position.
*/
pthread_mutex_lock(&LOCK_commit_ordered);
plugin_foreach(thd, snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &warn);
pthread_mutex_unlock(&LOCK_commit_ordered);
/*
Same idea as when one wants to CREATE TABLE in one engine which does not
@@ -4622,7 +4666,8 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
/** @brief
Write table maps for all (manually or automatically) locked tables
to the binary log.
to the binary log. Also, if binlog_annotate_rows_events is ON,
write Annotate_rows event before the first table map.
SYNOPSIS
write_locked_table_maps()
@@ -4659,6 +4704,9 @@ static int write_locked_table_maps(THD *thd)
locks[0]= thd->extra_lock;
locks[1]= thd->lock;
locks[2]= thd->locked_tables;
my_bool with_annotate= thd->variables.binlog_annotate_rows_events &&
thd->query() && thd->query_length();
for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
{
MYSQL_LOCK const *const lock= locks[i];
@@ -4676,7 +4724,8 @@ static int write_locked_table_maps(THD *thd)
check_table_binlog_row_based(thd, table))
{
int const has_trans= table->file->has_transactions();
int const error= thd->binlog_write_table_map(table, has_trans);
int const error= thd->binlog_write_table_map(table, has_trans,
&with_annotate);
/*
If an error occurs, it is the responsibility of the caller to
roll back the transaction.