summaryrefslogtreecommitdiff
path: root/sql/sql_base.cc
diff options
context:
space:
mode:
authorKonstantin Osipov <kostja@sun.com>2010-03-16 00:20:20 +0300
committerKonstantin Osipov <kostja@sun.com>2010-03-16 00:20:20 +0300
commit09b7a0d11540495dd6fc9cf7ec0d2c81fd630f83 (patch)
tree3d24b829164a0567d0a3259fe6a86f4234031a42 /sql/sql_base.cc
parenta45162d4e33152255132ec642ba7cfc60b5df1e1 (diff)
parent7116431a8a089e2f32d756073968951760d629cf (diff)
downloadmariadb-git-09b7a0d11540495dd6fc9cf7ec0d2c81fd630f83.tar.gz
A post-review fix for type-aware metadata locks.
DDL no longer aborts mysql_lock_tables(), and hence we no longer need to support need_reopen flag of this call. Remove the flag, and all the code in the server that was responsible for handling the case when it was set. This allowed to simplify: open_and_lock_tables_derived(), the delayed thread, multi-update. Rename MYSQL_LOCK_IGNORE_FLUSH to MYSQL_OPEN_IGNORE_FLUSH, since we now only support this flag in open_table(). Rename MYSQL_LOCK_PERF_SCHEMA to MYSQL_LOCK_LOG_TABLE, to avoid confusion. Move the wait for the global read lock for cases when we do updates in SELECT f1() or DO (UPDATE) to open_table() from mysql_lock_tables(). When waiting for the read lock, we could raise need_reopen flag, which is no longer present in mysql_lock_tables(). Since the block responsible for waiting for GRL was moved, MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK was renamed to MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK. mysql-test/r/mdl_sync.result: Update test results (see comments for mdl_sync.test). mysql-test/t/mdl_sync.test: Update tests: an abort mysql_lock_tables() called for an INSERT no longer auto-closes SQL HANDLERS, since it no longer leads to back-off and retry. sql/ha_ndbcluster_binlog.cc: Remove unused variables. sql/lock.cc: Remove support for need_reopen parameter of mysql_lock_tables(). Update comments. sql/log_event_old.cc: Remove the loop responsible for handling need_reopen out parameter of mysql_lock_tables(). sql/mysql_priv.h: Update open and lock tables flag names. sql/share/errmsg-utf8.txt: Add a new error message to report when thr_multi_lock() is aborted. sql/sql_base.cc: Update comments. Rename MYSQL_LOCK_IGNORE_FLUSH to MYSQL_OPEN_IGNORE_FLUSH. sql/sql_class.h: Remove unused code. sql/sql_db.cc: Remove an unused bit of code. sql/sql_handler.cc: For backward compatibility, we still want to back off and retry when a call to mysql_lock_tables() is aborted from within an SQL HANDLER. Write an internal error handler to support the case. sql/sql_insert.cc: Call mysql_lock_tables() no longer has need_reopen out parameter. Simplify the code by removing the crud that took care of it. MYSQL_LOCK_IGNORE_FLUSH is now only supported by open_tables(). sql/sql_show.cc: Rename MYSQL_LOCK_IGNORE_FLUSH to MYSQL_OPEN_IGNORE_FLUSH sql/sql_table.cc: Remove an unused parameter. sql/sql_update.cc: Remove the need_reopen loop from multi-update. We no also longer need to cleanup the parse tree in case when mysql_lock_tables() is aborted and thus an infinite source of multi-update bugs is gone. sql/tztime.cc: Rename MYSQL_LOCK_IGNORE_FLUSH to MYSQL_OPEN_IGNORE_FLUSH, since from now on this flag is only supported by open_table().
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r--sql/sql_base.cc147
1 files changed, 67 insertions, 80 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b4c9aa576d0..a85a863abd9 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2421,7 +2421,7 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
required to remedy problem appeared during attempt
to open table.
flags Bitmap of flags to modify how open works:
- MYSQL_LOCK_IGNORE_FLUSH - Open table even if
+ MYSQL_OPEN_IGNORE_FLUSH - Open table even if
someone has done a flush or there is a pending
exclusive metadata lock requests against it
(i.e. request high priority metadata lock).
@@ -2480,6 +2480,31 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
TMP_TABLE_KEY_EXTRA);
/*
+ We need this to work for all tables, including temporary
+ tables, for backwards compatibility. But not under LOCK
+ TABLES, since under LOCK TABLES one can't use a non-prelocked
+ table. This code only works for updates done inside DO/SELECT
+ f1() statements, normal DML is handled by means of
+ sql_command_flags.
+ */
+ if (global_read_lock && table_list->lock_type >= TL_WRITE_ALLOW_WRITE &&
+ ! (flags & MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK) &&
+ ! thd->locked_tables_mode)
+ {
+ /*
+ Someone has issued FLUSH TABLES WITH READ LOCK and we want
+ a write lock. Wait until the lock is gone.
+ */
+ if (thd->global_read_lock.wait_if_global_read_lock(thd, 1, 1))
+ DBUG_RETURN(TRUE);
+
+ if (thd->version != refresh_version)
+ {
+ (void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC);
+ DBUG_RETURN(TRUE);
+ }
+ }
+ /*
Unless requested otherwise, try to resolve this table in the list
of temporary tables of this thread. In MySQL temporary tables
are always thread-local and "shadow" possible base tables with the
@@ -2680,7 +2705,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (!thd->open_tables)
thd->version=refresh_version;
else if ((thd->version != refresh_version) &&
- ! (flags & MYSQL_LOCK_IGNORE_FLUSH))
+ ! (flags & MYSQL_OPEN_IGNORE_FLUSH))
{
/* Someone did a refresh while thread was opening tables */
mysql_mutex_unlock(&LOCK_open);
@@ -2811,7 +2836,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (share->version != refresh_version)
{
- if (!(flags & MYSQL_LOCK_IGNORE_FLUSH))
+ if (!(flags & MYSQL_OPEN_IGNORE_FLUSH))
{
/*
We already have an MDL lock. But we have encountered an old
@@ -3293,7 +3318,6 @@ bool
Locked_tables_list::reopen_tables(THD *thd)
{
Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT);
- bool lt_refresh_unused;
size_t reopen_count= 0;
MYSQL_LOCK *lock;
MYSQL_LOCK *merged_lock;
@@ -3333,7 +3357,7 @@ Locked_tables_list::reopen_tables(THD *thd)
break something else.
*/
lock= mysql_lock_tables(thd, m_reopen_array, reopen_count,
- MYSQL_OPEN_REOPEN, &lt_refresh_unused);
+ MYSQL_OPEN_REOPEN);
thd->in_lock_tables= 0;
if (lock == NULL || (merged_lock=
mysql_lock_merge(thd->lock, lock)) == NULL)
@@ -5061,7 +5085,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
TABLE *table;
Open_table_context ot_ctx(thd, (lock_flags & MYSQL_LOCK_IGNORE_TIMEOUT) ?
LONG_TIMEOUT : thd->variables.lock_wait_timeout);
- bool refresh;
bool error;
DBUG_ENTER("open_ltable");
@@ -5073,8 +5096,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
/* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= FRMTYPE_TABLE;
-retry:
- while ((error= open_table(thd, table_list, thd->mem_root, &ot_ctx, 0)) &&
+ while ((error= open_table(thd, table_list, thd->mem_root, &ot_ctx, lock_flags)) &&
ot_ctx.can_recover_from_failed_open())
{
/*
@@ -5120,18 +5142,9 @@ retry:
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1,
- lock_flags, &refresh)))
+ lock_flags)))
{
- if (refresh)
- {
- close_thread_tables(thd);
- table_list->table= NULL;
- table_list->mdl_request.ticket= NULL;
- thd->mdl_context.rollback_to_savepoint(ot_ctx.start_of_statement_svp());
- goto retry;
- }
- else
- table= 0;
+ table= 0;
}
}
}
@@ -5168,42 +5181,27 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
Prelocking_strategy *prelocking_strategy)
{
uint counter;
- bool need_reopen;
- /*
- Remember the set of metadata locks which this connection
- managed to acquire before the start of the current statement.
- It can be either transaction-scope locks, or HANDLER locks,
- or LOCK TABLES locks. If mysql_lock_tables() fails with
- need_reopen request, we'll use it to instruct
- close_tables_for_reopen() to release all locks of this
- statement.
- */
- MDL_ticket *start_of_statement_svp= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("open_and_lock_tables");
DBUG_PRINT("enter", ("derived handling: %d", derived));
- for ( ; ; )
- {
- if (open_tables(thd, &tables, &counter, flags, prelocking_strategy))
- DBUG_RETURN(TRUE);
- DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", {
- const char *old_proc_info= thd->proc_info;
- thd->proc_info= "DBUG sleep";
- my_sleep(6000000);
- thd->proc_info= old_proc_info;});
-
- if (!lock_tables(thd, tables, counter, flags,
- &need_reopen))
- break;
- if (!need_reopen)
- DBUG_RETURN(TRUE);
- close_tables_for_reopen(thd, &tables, start_of_statement_svp);
- }
+ if (open_tables(thd, &tables, &counter, flags, prelocking_strategy))
+ DBUG_RETURN(TRUE);
+
+ DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", {
+ const char *old_proc_info= thd->proc_info;
+ thd->proc_info= "DBUG sleep";
+ my_sleep(6000000);
+ thd->proc_info= old_proc_info;});
+
+ if (lock_tables(thd, tables, counter, flags))
+ DBUG_RETURN(TRUE);
+
if (derived &&
(mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
(thd->fill_derived_tables() &&
mysql_handle_derived(thd->lex, &mysql_derived_filling))))
DBUG_RETURN(TRUE); /* purecov: inspected */
+
DBUG_RETURN(FALSE);
}
@@ -5216,7 +5214,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
thd - thread handler
tables - list of tables for open
flags - bitmap of flags to modify how the tables will be open:
- MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
+ MYSQL_OPEN_IGNORE_FLUSH - open table even if someone has
done a flush or namelock on it.
RETURN
@@ -5261,37 +5259,28 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
}
-/*
- Lock all tables in list
+/**
+ Lock all tables in a list.
- SYNOPSIS
- lock_tables()
- thd Thread handler
- tables Tables to lock
- count Number of opened tables
- flags Options (see mysql_lock_tables() for details)
- need_reopen Out parameter which if TRUE indicates that some
- tables were dropped or altered during this call
- and therefore invoker should reopen tables and
- try to lock them once again (in this case
- lock_tables() will also return error).
+ @param thd Thread handler
+ @param tables Tables to lock
+ @param count Number of opened tables
+ @param flags Options (see mysql_lock_tables() for details)
- NOTES
- You can't call lock_tables twice, as this would break the dead-lock-free
- handling thr_lock gives us. You most always get all needed locks at
- once.
+ You can't call lock_tables() while holding thr_lock locks, as
+ this would break the dead-lock-free handling thr_lock gives us.
+ You must always get all needed locks at once.
- If query for which we are calling this function marked as requiring
- prelocking, this function will change locked_tables_mode to
- LTM_PRELOCKED.
+ If the query for which we are calling this function is marked as
+ requiring prelocking, this function will change
+ locked_tables_mode to LTM_PRELOCKED.
- RETURN VALUES
- 0 ok
- -1 Error
+ @retval FALSE Success.
+ @retval TRUE A lock wait timeout, deadlock or out of memory.
*/
bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
- uint flags, bool *need_reopen)
+ uint flags)
{
TABLE_LIST *table;
@@ -5302,7 +5291,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
*/
DBUG_ASSERT(thd->locked_tables_mode <= LTM_LOCK_TABLES ||
!thd->lex->requires_prelocking());
- *need_reopen= FALSE;
if (!tables && !thd->lex->requires_prelocking())
DBUG_RETURN(thd->decide_logging_format(tables));
@@ -5347,7 +5335,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
DEBUG_SYNC(thd, "before_lock_tables_takes_lock");
if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start),
- flags, need_reopen)))
+ flags)))
DBUG_RETURN(TRUE);
DEBUG_SYNC(thd, "after_lock_tables_takes_lock");
@@ -8869,7 +8857,7 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
thd->reset_n_backup_open_tables_state(backup);
if (open_and_lock_tables(thd, table_list, FALSE,
- MYSQL_LOCK_IGNORE_FLUSH |
+ MYSQL_OPEN_IGNORE_FLUSH |
MYSQL_LOCK_IGNORE_TIMEOUT))
{
lex->restore_backup_query_tables_list(&query_tables_list_backup);
@@ -8957,11 +8945,11 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
TABLE *
open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup)
{
- uint flags= ( MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
+ uint flags= ( MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |
- MYSQL_LOCK_IGNORE_FLUSH |
+ MYSQL_OPEN_IGNORE_FLUSH |
MYSQL_LOCK_IGNORE_TIMEOUT |
- MYSQL_LOCK_PERF_SCHEMA);
+ MYSQL_LOCK_LOG_TABLE);
TABLE *table;
/* Save value that is changed in mysql_lock_tables() */
ulonglong save_utime_after_lock= thd->utime_after_lock;
@@ -8989,8 +8977,7 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup)
open tables cannot be accepted when restoring the open tables
state.
*/
- if (thd->killed)
- close_thread_tables(thd);
+ close_thread_tables(thd);
thd->restore_backup_open_tables_state(backup);
}