#At file:///opt/local/work/6.0-46224-1/ based on revid:holyfoot@stripped
3699 Konstantin Osipov 2009-11-10
A prerequisite patch for the fix for Bug#46224
"HANDLER statements within a transaction might lead to deadlocks".
Introduce a notion of a sentinel to MDL_context. A sentinel
is a ticket that separates all tickets in the context into two
groups: before and after it. Currently we can have (and need) only
one designated sentinel -- it separates all locks taken by LOCK
TABLE or HANDLER statement, which must survive COMMIT and ROLLBACK
and all other locks, which must be released at COMMIT and ROLLBACK.
The tricky part is maintaining the sentinel up to date when
someone release its corresponding ticket. This can happen, e.g.
if someone issues DROP TABLE under LOCK TABLES (generally,
see all calls to release_all_locks_for_name()).
MDL_context::release_ticket() is modified to take care for it.
modified:
sql/log_event.cc
sql/mdl.cc
sql/mdl.h
sql/rpl_injector.cc
sql/rpl_rli.cc
sql/set_var.cc
sql/slave.cc
sql/sql_acl.cc
sql/sql_base.cc
sql/sql_class.h
sql/sql_parse.cc
sql/sql_servers.cc
sql/sql_table.cc
sql/transaction.cc
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2009-10-27 10:00:21 +0000
+++ b/sql/log_event.cc 2009-11-09 22:35:07 +0000
@@ -5321,8 +5321,7 @@ int Xid_log_event::do_apply_event(Relay_
if (!(res= trans_commit(thd)))
{
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
}
return res;
}
=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc 2009-10-25 13:41:27 +0000
+++ b/sql/mdl.cc 2009-11-09 22:35:07 +0000
@@ -187,6 +187,7 @@ void MDL_context::init(THD *thd_arg)
{
m_has_global_shared_lock= FALSE;
m_thd= thd_arg;
+ m_lt_or_ha_sentinel= NULL;
/*
FIXME: In reset_n_backup_open_tables_state,
we abuse "init" as a reset, i.e. call it on an already
@@ -234,6 +235,7 @@ void MDL_context::backup_and_reset(MDL_c
m_tickets.swap(backup->m_tickets);
backup->m_has_global_shared_lock= m_has_global_shared_lock;
+ backup->m_lt_or_ha_sentinel= m_lt_or_ha_sentinel;
/*
When the main context is swapped out, one can not take
the global shared lock, and one can not rely on it:
@@ -241,6 +243,7 @@ void MDL_context::backup_and_reset(MDL_c
a temporary hack to support ad-hoc opening of system tables.
*/
m_has_global_shared_lock= FALSE;
+ m_lt_or_ha_sentinel= NULL;
}
@@ -255,6 +258,7 @@ void MDL_context::restore_from_backup(MD
m_tickets.swap(backup->m_tickets);
m_has_global_shared_lock= backup->m_has_global_shared_lock;
+ m_lt_or_ha_sentinel= backup->m_lt_or_ha_sentinel;
}
@@ -284,6 +288,7 @@ void MDL_context::merge(MDL_context *src
an SQL handler. We never acquire the global shared lock there.
*/
DBUG_ASSERT(! src->m_has_global_shared_lock);
+ DBUG_ASSERT(! src->m_lt_or_ha_sentinel);
}
@@ -1280,6 +1285,9 @@ void MDL_context::release_ticket(MDL_tic
safe_mutex_assert_owner(&LOCK_mdl);
+ if (ticket == m_lt_or_ha_sentinel)
+ m_lt_or_ha_sentinel= ticket->next_in_context;
+
m_tickets.remove(ticket);
switch (ticket->m_type)
@@ -1317,14 +1325,21 @@ void MDL_context::release_ticket(MDL_tic
/**
- Release all locks associated with the context.
+ Release all locks associated with the context. If the sentinel
+ is not NULL, do not release locks before and including the
+ sentinel.
+
+ This function is used to:
+ - back off in case of a lock conflict.
+ - release all locks in the end of a transaction
+ - rollback to a savepoint
- This function is used to back off in case of a lock conflict.
- It is also used to release shared locks in the end of an SQL
- statement.
+ The sentinel semantics is used to support LOCK TABLES
+ mode, and HANDLER statements: locks taken by these statement
+ survive COMMIT, ROLLBACK, ROLLBACK TO SAVEPOINT.
*/
-void MDL_context::release_all_locks()
+void MDL_context::release_all_locks_after(MDL_ticket *sentinel)
{
MDL_ticket *ticket;
Ticket_iterator it(m_tickets);
@@ -1336,7 +1351,7 @@ void MDL_context::release_all_locks()
DBUG_VOID_RETURN;
pthread_mutex_lock(&LOCK_mdl);
- while ((ticket= it++))
+ while ((ticket= it++) && ticket != sentinel)
{
DBUG_PRINT("info", ("found lock to release ticket=%p", ticket));
release_ticket(ticket);
@@ -1345,8 +1360,6 @@ void MDL_context::release_all_locks()
pthread_cond_broadcast(&COND_mdl);
pthread_mutex_unlock(&LOCK_mdl);
- m_tickets.empty();
-
DBUG_VOID_RETURN;
}
@@ -1593,19 +1606,34 @@ void *MDL_ticket::get_cached_object()
void MDL_context::rollback_to_savepoint(MDL_ticket *mdl_savepoint)
{
- MDL_ticket *ticket;
- Ticket_iterator it(m_tickets);
DBUG_ENTER("MDL_context::rollback_to_savepoint");
- while ((ticket= it++))
- {
- /* Stop when lock was acquired before this savepoint. */
- if (ticket == mdl_savepoint)
- break;
- release_lock(ticket);
- }
+ release_all_locks_after(mdl_savepoint);
DBUG_VOID_RETURN;
}
+void MDL_context::commit_transaction()
+{
+ DBUG_ENTER("MDL_context::commit_or_rollback_transaction");
+ release_all_locks_after(m_lt_or_ha_sentinel);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Should be used only when we know for sure
+ we're not under LOCK TABLES.
+*/
+
+void MDL_context::release_all_locks()
+{
+ DBUG_ENTER("MDL_context::release_all_locks");
+ DBUG_ASSERT(m_lt_or_ha_sentinel == NULL);
+
+ release_all_locks_after(m_lt_or_ha_sentinel);
+ m_lt_or_ha_sentinel= NULL;
+
+ DBUG_VOID_RETURN;
+}
=== modified file 'sql/mdl.h'
--- a/sql/mdl.h 2009-10-12 09:08:34 +0000
+++ b/sql/mdl.h 2009-11-09 22:35:07 +0000
@@ -339,7 +339,6 @@ public:
bool wait_for_locks(MDL_request_list *requests);
- void release_all_locks();
void release_all_locks_for_name(MDL_ticket *ticket);
void release_lock(MDL_ticket *ticket);
void release_global_shared_lock();
@@ -360,16 +359,36 @@ public:
return m_tickets.head();
}
+ void set_lt_or_ha_sentinel()
+ {
+ DBUG_ASSERT(m_lt_or_ha_sentinel == NULL);
+ m_lt_or_ha_sentinel= mdl_savepoint();
+ }
+
+ void clear_lt_or_ha_sentinel()
+ {
+ m_lt_or_ha_sentinel= NULL;
+ }
+
+ void commit_transaction();
+ void release_all_locks();
void rollback_to_savepoint(MDL_ticket *mdl_savepoint);
inline THD *get_thd() const { return m_thd; }
private:
Ticket_list m_tickets;
bool m_has_global_shared_lock;
+ /**
+ When entering LOCK TABLES mode, remember the last taken
+ metadata lock. COMMIT/ROLLBACK must preserve these metadata
+ locks.
+ */
+ MDL_ticket *m_lt_or_ha_sentinel;
THD *m_thd;
private:
void release_ticket(MDL_ticket *ticket);
MDL_ticket *find_ticket(MDL_request *mdl_req);
+ void release_all_locks_after(MDL_ticket *sentinel);
};
=== modified file 'sql/rpl_injector.cc'
--- a/sql/rpl_injector.cc 2009-03-06 22:17:00 +0000
+++ b/sql/rpl_injector.cc 2009-11-09 22:35:07 +0000
@@ -86,8 +86,7 @@ int injector::transaction::commit()
if (!trans_commit(m_thd))
{
close_thread_tables(m_thd);
- if (!m_thd->locked_tables_mode)
- m_thd->mdl_context.release_all_locks();
+ m_thd->mdl_context.commit_transaction();
}
DBUG_RETURN(0);
}
@@ -99,8 +98,7 @@ int injector::transaction::rollback()
if (!trans_rollback(m_thd))
{
close_thread_tables(m_thd);
- if (!m_thd->locked_tables_mode)
- m_thd->mdl_context.release_all_locks();
+ m_thd->mdl_context.commit_transaction();
}
DBUG_RETURN(0);
}
=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc 2009-10-26 14:02:26 +0000
+++ b/sql/rpl_rli.cc 2009-11-09 22:35:07 +0000
@@ -922,8 +922,8 @@ void Relay_log_info::cleanup_context(THD
}
m_table_map.clear_tables();
slave_close_thread_tables(thd);
- if (error && !thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ if (error)
+ thd->mdl_context.commit_transaction();
clear_flag(IN_STMT);
/*
Cleanup for the flags that have been set at do_apply_event.
=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc 2009-10-27 10:03:00 +0000
+++ b/sql/set_var.cc 2009-11-09 22:35:07 +0000
@@ -3758,8 +3758,7 @@ static bool set_option_autocommit(THD *t
return TRUE;
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
}
if (var->save_result.ulong_value != 0)
=== modified file 'sql/slave.cc'
--- a/sql/slave.cc 2009-10-26 14:02:26 +0000
+++ b/sql/slave.cc 2009-11-09 22:35:07 +0000
@@ -2570,8 +2570,8 @@ static int exec_relay_log_event(THD* thd
exec_res= 0;
trans_rollback(thd);
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ DBUG_ASSERT(! thd->locked_tables_mode);
+ thd->mdl_context.commit_transaction();
/* chance for concurrent connection to get more locks */
safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
(CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);
=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc 2009-10-25 13:41:27 +0000
+++ b/sql/sql_acl.cc 2009-11-09 22:35:07 +0000
@@ -741,8 +741,7 @@ my_bool acl_reload(THD *thd)
end:
trans_commit_implicit(thd);
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
DBUG_RETURN(return_val);
}
@@ -3900,8 +3899,7 @@ my_bool grant_reload(THD *thd)
rw_unlock(&LOCK_grant);
trans_commit_implicit(thd);
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
/*
It is OK failing to load procs_priv table because we may be
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2009-10-25 13:41:27 +0000
+++ b/sql/sql_base.cc 2009-11-09 22:35:07 +0000
@@ -1472,7 +1472,7 @@ void close_thread_tables(THD *thd)
if (thd->locked_tables_mode == LTM_LOCK_TABLES)
DBUG_VOID_RETURN;
- thd->locked_tables_mode= LTM_NONE;
+ thd->leave_locked_tables_mode();
/* Fallthrough */
}
@@ -1502,16 +1502,21 @@ void close_thread_tables(THD *thd)
if (thd->open_tables)
close_open_tables(thd);
- /*
- Defer the release of metadata locks until the current transaction
- is either committed or rolled back. This prevents other statements
- from modifying the table for the entire duration of this transaction.
- This provides commitment ordering for guaranteeing serializability
- across multiple transactions.
- */
- if (!thd->in_multi_stmt_transaction() ||
- (thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
+ if (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)
+ {
thd->mdl_context.release_all_locks();
+ }
+ else if (! thd->in_multi_stmt_transaction())
+ {
+ /*
+ Defer the release of metadata locks until the current transaction
+ is either committed or rolled back. This prevents other statements
+ from modifying the table for the entire duration of this transaction.
+ This provides commitment ordering for guaranteeing serializability
+ across multiple transactions.
+ */
+ thd->mdl_context.commit_transaction();
+ }
DBUG_VOID_RETURN;
}
@@ -3087,7 +3092,7 @@ Locked_tables_list::init_locked_tables(T
return TRUE;
}
}
- thd->locked_tables_mode= LTM_LOCK_TABLES;
+ thd->enter_locked_tables_mode(LTM_LOCK_TABLES);
return FALSE;
}
@@ -3126,7 +3131,7 @@ Locked_tables_list::unlock_locked_tables
*/
table_list->table->pos_in_locked_tables= NULL;
}
- thd->locked_tables_mode= LTM_NONE;
+ thd->leave_locked_tables_mode();
close_thread_tables(thd);
}
@@ -4648,11 +4653,10 @@ retry:
{
/*
Even though we have failed to open table we still need to
- call release_all_locks() to release metadata locks which
+ call release_all_locks_after() to release metadata locks which
might have been acquired successfully.
*/
- if (! thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.release_all_locks();
table_list->mdl_request.ticket= 0;
if (ot_ctx.recover_from_failed_open_table_attempt(thd, table_list))
break;
@@ -4703,8 +4707,7 @@ retry:
close_thread_tables(thd);
table_list->table= NULL;
table_list->mdl_request.ticket= NULL;
- if (! thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.release_all_locks();
goto retry;
}
}
@@ -5121,7 +5124,7 @@ bool lock_tables(THD *thd, TABLE_LIST *t
*/
mark_real_tables_as_free_for_reuse(first_not_own);
DBUG_PRINT("info",("locked_tables_mode= LTM_PRELOCKED"));
- thd->locked_tables_mode= LTM_PRELOCKED;
+ thd->enter_locked_tables_mode(LTM_PRELOCKED);
}
}
else
@@ -5223,8 +5226,7 @@ void close_tables_for_reopen(THD *thd, T
for (tmp= first_not_own_table; tmp; tmp= tmp->next_global)
tmp->mdl_request.ticket= NULL;
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
}
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2009-10-28 15:45:46 +0000
+++ b/sql/sql_class.h 2009-11-09 22:35:07 +0000
@@ -963,7 +963,6 @@ public:
lower level routines, which would otherwise miss that lock.
*/
MYSQL_LOCK *extra_lock;
-
/*
Enum enum_locked_tables_mode and locked_tables_mode member are
used to indicate whether the so-called "locked tables mode" is on,
@@ -1040,6 +1039,17 @@ public:
mdl_context.init(thd);
handler_mdl_context.init(thd);
}
+ void enter_locked_tables_mode(enum_locked_tables_mode mode_arg)
+ {
+ DBUG_ASSERT(locked_tables_mode == LTM_NONE);
+ mdl_context.set_lt_or_ha_sentinel();
+ locked_tables_mode= mode_arg;
+ }
+ void leave_locked_tables_mode()
+ {
+ locked_tables_mode= LTM_NONE;
+ mdl_context.clear_lt_or_ha_sentinel();
+ }
};
/**
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2009-10-29 21:33:17 +0000
+++ b/sql/sql_parse.cc 2009-11-09 22:35:07 +0000
@@ -1240,8 +1240,7 @@ bool dispatch_command(enum enum_server_c
if (trans_commit_implicit(thd))
break;
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
if (check_global_access(thd,RELOAD_ACL))
break;
general_log_print(thd, command, NullS);
@@ -1271,8 +1270,7 @@ bool dispatch_command(enum enum_server_c
if (trans_commit_implicit(thd))
break;
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
my_ok(thd);
break;
}
@@ -2042,8 +2040,7 @@ mysql_execute_command(THD *thd)
goto error;
/* Close tables and release metadata locks. */
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
}
/*
@@ -3582,7 +3579,7 @@ end_with_restore_list:
if (thd->options & OPTION_TABLE_LOCK)
{
trans_commit_implicit(thd);
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
thd->options&= ~(OPTION_TABLE_LOCK);
}
if (thd->global_read_lock)
@@ -3639,7 +3636,7 @@ end_with_restore_list:
if (trans_commit_implicit(thd))
goto error;
/* release transactional metadata locks. */
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
if (lex->protect_against_global_read_lock &&
wait_if_global_read_lock(thd, 0, 1))
goto error;
@@ -3675,7 +3672,7 @@ end_with_restore_list:
*/
close_thread_tables(thd);
DBUG_ASSERT(!thd->locked_tables_mode);
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
thd->options&= ~(OPTION_TABLE_LOCK);
}
else
@@ -4168,8 +4165,7 @@ end_with_restore_list:
thd->locked_tables_mode == LTM_LOCK_TABLES);
if (trans_commit(thd))
goto error;
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
/* Begin transaction with the same isolation level. */
if (lex->tx_chain && trans_begin(thd))
goto error;
@@ -4184,8 +4180,7 @@ end_with_restore_list:
thd->locked_tables_mode == LTM_LOCK_TABLES);
if (trans_rollback(thd))
goto error;
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
/* Begin transaction with the same isolation level. */
if (lex->tx_chain && trans_begin(thd))
goto error;
@@ -4582,8 +4577,7 @@ create_sp_error:
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sp_automatic_privileges && !opt_noacl &&
@@ -4731,15 +4725,13 @@ create_sp_error:
case SQLCOM_XA_COMMIT:
if (trans_xa_commit(thd))
goto error;
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
my_ok(thd);
break;
case SQLCOM_XA_ROLLBACK:
if (trans_xa_rollback(thd))
goto error;
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
my_ok(thd);
break;
case SQLCOM_XA_RECOVER:
@@ -4896,8 +4888,7 @@ finish:
trans_commit_implicit(thd);
/* Close tables and release metadata locks. */
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
thd->stmt_da->can_overwrite_status= FALSE;
}
=== modified file 'sql/sql_servers.cc'
--- a/sql/sql_servers.cc 2009-10-12 09:08:34 +0000
+++ b/sql/sql_servers.cc 2009-11-09 22:35:07 +0000
@@ -247,8 +247,7 @@ bool servers_reload(THD *thd)
end:
trans_commit_implicit(thd);
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
DBUG_PRINT("info", ("unlocking servers_cache"));
rw_unlock(&THR_LOCK_servers);
DBUG_RETURN(return_val);
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2009-10-26 12:51:43 +0000
+++ b/sql/sql_table.cc 2009-11-09 22:35:07 +0000
@@ -4678,8 +4678,7 @@ static bool mysql_admin_table(THD* thd,
trans_commit_stmt(thd);
trans_commit(thd);
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
lex->reset_query_tables_list(FALSE);
table->table=0; // For query cache
if (protocol->write())
@@ -4731,8 +4730,7 @@ static bool mysql_admin_table(THD* thd,
trans_rollback_stmt(thd);
trans_rollback(thd);
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
result_code= mysql_recreate_table(thd, table);
reenable_binlog(thd);
@@ -4848,8 +4846,7 @@ send_result_message:
trans_commit_stmt(thd);
trans_commit(thd);
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
DEBUG_SYNC(thd, "ha_admin_try_alter");
protocol->store(STRING_WITH_LEN("note"), system_charset_info);
protocol->store(STRING_WITH_LEN(
@@ -4875,8 +4872,7 @@ send_result_message:
trans_commit_stmt(thd);
trans_commit(thd);
close_thread_tables(thd);
- if (!thd->locked_tables_mode)
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
if (!result_code) // recreation went ok
{
/* Clear the ticket released in close_thread_tables(). */
=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc 2009-06-30 08:03:05 +0000
+++ b/sql/transaction.cc 2009-11-09 22:35:07 +0000
@@ -103,7 +103,7 @@ bool trans_begin(THD *thd, uint flags)
Release transactional metadata locks only after the
transaction has been committed.
*/
- thd->mdl_context.release_all_locks();
+ thd->mdl_context.commit_transaction();
thd->options|= OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
@@ -341,6 +341,10 @@ bool trans_savepoint(THD *thd, LEX_STRIN
Remember the last acquired lock before the savepoint was set.
This is used as a marker to only release locks acquired after
the setting of this savepoint.
+ Note: this works just fine if we're under LOCK TABLES,
+ since mdl_savepoint() is guaranteed to be beyond
+ the last locked table. This allows to release some
+ locks acquired during LOCK TABLES.
*/
newsv->mdl_savepoint = thd->mdl_context.mdl_savepoint();
@@ -388,8 +392,10 @@ bool trans_rollback_to_savepoint(THD *th
thd->transaction.savepoints= sv;
- /* Release metadata locks that were acquired during this savepoint unit. */
- if (!res && !thd->locked_tables_mode)
+ /*
+ Release metadata locks that were acquired during this savepoint unit.
+ */
+ if (!res)
thd->mdl_context.rollback_to_savepoint(sv->mdl_savepoint);
DBUG_RETURN(test(res));
Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20091109223507-leeftwr9mt6b0yxm.bundle
| Thread |
|---|
| • bzr commit into mysql-6.0-codebase-bugfixing branch (kostja:3699)Bug#46224 | Konstantin Osipov | 9 Nov |