1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Backport of:

----------------------------------------------------------
revno: 2630.4.26
committer: Konstantin Osipov <konstantin@mysql.com>
branch nick: mysql-6.0-prelocked_mode-to-push
timestamp: Fri 2008-06-06 23:19:04 +0400
message:
  WL#3726: work on review comments.
  Remove thd->locked_tables. Always store MYSQL_LOCK instances in
  thd->lock.
  Rename thd->prelocked_mode to thd->locked_tables_mode.
  Use thd->locked_tables_mode to determine if we
  are under LOCK TABLES. Update the code to not assume that
  if thd->lock is set, LOCK TABLES mode is off.
  Review comments.


sql/ha_ndbcluster_binlog.cc:
  Don't unlock the lock under LOCK TABLES (safety).
sql/handler.cc:
  There is no thd->locked_tables any more.
  Update comments.
sql/lock.cc:
  There is no thd->locked_tables any more.
sql/log.cc:
  Rename thd->prelocked_mode to thd->locked_tables_mode.
sql/set_var.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
sql/sp_head.cc:
  Rename thd->prelocked_mode to thd->locked_tables_mode.
sql/sql_base.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
  Remove thd->locked_tables.
sql/sql_cache.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
sql/sql_class.cc:
  Avoid code duplication.
  Do not release the table locks prematurely if we're under LOCK TABLES.
  Use thd->locked_tables_mode instead of thd->locked_tables.
sql/sql_class.h:
  Remove thd->locked_tables.
  Make prelocked mode a kind of LOCK TABLES mode.
  Update comments.
sql/sql_cursor.cc:
  Update comments.
sql/sql_insert.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
  Rename thd->prelocked_mode to thd->locked_tables_mode.
sql/sql_load.cc:
  Rename thd->prelocked_mode to thd->locked_tables_mode.
sql/sql_parse.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
  Remove thd->locked_tables.
sql/sql_partition.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
sql/sql_rename.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
sql/sql_select.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
sql/sql_table.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
sql/sql_trigger.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
sql/sql_update.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
sql/sql_view.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
storage/myisam/ha_myisam.cc:
  Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
This commit is contained in:
Konstantin Osipov
2009-12-01 17:39:03 +03:00
parent 1b078b3f2d
commit 5969dcda21
22 changed files with 208 additions and 213 deletions

View File

@ -1025,7 +1025,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock,
DBUG_ASSERT(!have_lock);
pthread_mutex_unlock(&LOCK_open);
if (thd->locked_tables)
if (thd->locked_tables_mode)
{
/*
If we are under LOCK TABLES we need to reopen tables without
@ -1141,7 +1141,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock,
}
err_with_reopen:
if (thd->locked_tables)
if (thd->locked_tables_mode)
{
pthread_mutex_lock(&LOCK_open);
/*
@ -1375,7 +1375,6 @@ void close_thread_tables(THD *thd,
bool skip_mdl)
{
TABLE *table;
prelocked_mode_type prelocked_mode= thd->prelocked_mode;
DBUG_ENTER("close_thread_tables");
#ifdef EXTRA_DEBUG
@ -1433,11 +1432,12 @@ void close_thread_tables(THD *thd,
Reset transaction state, but only if we're not inside a
sub-statement of a prelocked statement.
*/
if (! prelocked_mode || thd->lex->requires_prelocking())
if (thd->locked_tables_mode <= LTM_LOCK_TABLES ||
thd->lex->requires_prelocking())
thd->transaction.stmt.reset();
}
if (thd->locked_tables || prelocked_mode)
if (thd->locked_tables_mode)
{
/* Ensure we are calling ha_reset() for all used tables */
@ -1447,7 +1447,7 @@ void close_thread_tables(THD *thd,
We are under simple LOCK TABLES or we're inside a sub-statement
of a prelocked statement, so should not do anything else.
*/
if (!prelocked_mode || !thd->lex->requires_prelocking())
if (! thd->lex->requires_prelocking())
DBUG_VOID_RETURN;
/*
@ -1455,18 +1455,19 @@ void close_thread_tables(THD *thd,
so we have to leave the prelocked mode now with doing implicit
UNLOCK TABLES if needed.
*/
DBUG_PRINT("info",("thd->prelocked_mode= NON_PRELOCKED"));
thd->prelocked_mode= NON_PRELOCKED;
if (thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
thd->locked_tables_mode= LTM_LOCK_TABLES;
if (prelocked_mode == PRELOCKED_UNDER_LOCK_TABLES)
if (thd->locked_tables_mode == LTM_LOCK_TABLES)
DBUG_VOID_RETURN;
thd->locked_tables_mode= LTM_NONE;
thd->options&= ~OPTION_TABLE_LOCK;
/*
Note that we are leaving prelocked mode so we don't need
to care about THD::locked_tables_root.
*/
thd->lock= thd->locked_tables;
thd->locked_tables= 0;
/* Fallthrough */
}
@ -1501,16 +1502,6 @@ void close_thread_tables(THD *thd,
mdl_remove_all_locks(&thd->mdl_context);
}
if (prelocked_mode == PRELOCKED)
{
/*
If we are here then we are leaving normal prelocked mode, so it is
good idea to turn off OPTION_TABLE_LOCK flag.
*/
DBUG_ASSERT(thd->lex->requires_prelocking());
thd->options&= ~(OPTION_TABLE_LOCK);
}
DBUG_VOID_RETURN;
}
@ -1951,9 +1942,10 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list)
Try to locate the table in the list of thd->temporary_tables.
If the table is found:
- if the table is being used by some outer statement, fail.
- if the table is in thd->locked_tables, unlock it and
remove it from the list of locked tables. Currently only transactional
temporary tables are present in the locked_tables list.
- if the table is locked with LOCK TABLES or by prelocking,
unlock it and remove it from the list of locked tables
(THD::lock). Currently only transactional temporary tables
are locked.
- Close the temporary table, remove its .FRM
- remove the table from the list of temporary tables
@ -1992,7 +1984,7 @@ int drop_temporary_table(THD *thd, TABLE_LIST *table_list)
If LOCK TABLES list is not empty and contains this table,
unlock the table and remove the table from this list.
*/
mysql_lock_remove(thd, thd->locked_tables, table, FALSE);
mysql_lock_remove(thd, thd->lock, table, FALSE);
close_temporary_table(thd, table, 1, 1);
DBUG_RETURN(0);
}
@ -2265,7 +2257,7 @@ bool close_cached_table(THD *thd, TABLE *table)
DBUG_RETURN(TRUE);
/* Close lock if this is not got with LOCK TABLES */
if (thd->lock)
if (! thd->locked_tables_mode)
{
mysql_unlock_tables(thd, thd->lock);
thd->lock=0; // Start locked threads
@ -2318,8 +2310,8 @@ void unlink_open_table(THD *thd, TABLE *find, bool unlock)
if (list->s->table_cache_key.length == key_length &&
!memcmp(list->s->table_cache_key.str, key, key_length))
{
if (unlock && thd->locked_tables)
mysql_lock_remove(thd, thd->locked_tables,
if (unlock && thd->locked_tables_mode)
mysql_lock_remove(thd, thd->lock,
list->parent ? list->parent : list, TRUE);
/* Prepare MERGE table for close. Close parent if necessary. */
@ -2690,7 +2682,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
open not pre-opened tables in pre-locked/LOCK TABLES mode.
TODO: move this block into a separate function.
*/
if (thd->locked_tables || thd->prelocked_mode)
if (thd->locked_tables_mode)
{ // Using table locks
TABLE *best_table= 0;
int best_distance= INT_MIN;
@ -2705,7 +2697,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
*/
if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
table->query_id != thd->query_id && /* skip tables already used */
!(thd->prelocked_mode && table->query_id) &&
(thd->locked_tables_mode == LTM_LOCK_TABLES ||
table->query_id == 0) &&
!table->parent)
{
int distance= ((int) table->reginfo.lock_type -
@ -2788,7 +2781,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
so we may only end up here if the table did not exist when
locked tables list was created.
*/
if (thd->prelocked_mode == PRELOCKED)
if (thd->locked_tables_mode == LTM_PRELOCKED)
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
else
my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
@ -3329,7 +3322,7 @@ void close_data_files_and_leave_as_placeholders(THD *thd, const char *db,
safe_mutex_assert_owner(&LOCK_open);
if (thd->lock)
if (! thd->locked_tables_mode)
{
/*
If we are not under LOCK TABLES we should have only one table
@ -3344,7 +3337,7 @@ void close_data_files_and_leave_as_placeholders(THD *thd, const char *db,
if (!strcmp(table->s->table_name.str, table_name) &&
!strcmp(table->s->db.str, db))
{
if (thd->locked_tables)
if (thd->locked_tables_mode)
{
if (table->parent)
{
@ -3354,11 +3347,11 @@ void close_data_files_and_leave_as_placeholders(THD *thd, const char *db,
the parent and close it. OTOH in most cases a MERGE table
won't have multiple children with the same db.table_name.
*/
mysql_lock_remove(thd, thd->locked_tables, table->parent, TRUE);
mysql_lock_remove(thd, thd->lock, table->parent, TRUE);
close_handle_and_leave_table_as_placeholder(table->parent);
}
else
mysql_lock_remove(thd, thd->locked_tables, table, TRUE);
mysql_lock_remove(thd, thd->lock, table, TRUE);
}
table->s->version= 0;
close_handle_and_leave_table_as_placeholder(table);
@ -3554,7 +3547,7 @@ bool reopen_tables(THD *thd, bool get_locks)
if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables),
flags, &not_used)))
{
thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock);
thd->lock= mysql_lock_merge(thd->lock, lock);
}
else
{
@ -3587,17 +3580,22 @@ void unlock_locked_tables(THD *thd)
DBUG_ASSERT(!thd->in_sub_stmt &&
!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
if (thd->locked_tables)
{
thd->lock= thd->locked_tables;
thd->locked_tables=0;
close_thread_tables(thd);
/*
After closing tables we can free memory used for storing lock
request objects for metadata locks
*/
free_root(&thd->locked_tables_root, MYF(MY_MARK_BLOCKS_FREE));
}
/*
Sic: we must be careful to not close open tables if
we're not in LOCK TABLES mode: unlock_locked_tables() is
sometimes called implicitly, expecting no effect on
open tables, e.g. from begin_trans().
*/
if (thd->locked_tables_mode != LTM_LOCK_TABLES)
return;
thd->locked_tables_mode= LTM_NONE;
close_thread_tables(thd);
/*
After closing tables we can free memory used for storing lock
request objects for metadata locks
*/
free_root(&thd->locked_tables_root, MYF(MY_MARK_BLOCKS_FREE));
}
@ -4494,11 +4492,6 @@ thr_lock_type read_lock_type_for_table(THD *thd, TABLE *table)
prelocking it won't do such precaching and will simply reuse table list
which is already built.
If any table has a trigger and start->trg_event_map is non-zero
the final lock will end up in thd->locked_tables, otherwise, the
lock will be placed in thd->lock. See also comments in
st_lex::set_trg_event_type_for_tables().
RETURN
0 - OK
-1 - error
@ -4543,10 +4536,10 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
If we are not already executing prelocked statement and don't have
statement for which table list for prelocking is already built, let
us cache routines and try to build such table list.
*/
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
!thd->lex->requires_prelocking() &&
thd->lex->uses_stored_routines())
{
bool first_no_prelocking, need_prelocking;
@ -4759,7 +4752,8 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
If we lock table for reading we won't update it so there is no need to
process its triggers since they never will be activated.
*/
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
!thd->lex->requires_prelocking() &&
tables->trg_event_map && tables->table->triggers &&
tables->lock_type >= TL_WRITE_ALLOW_WRITE)
{
@ -4780,7 +4774,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
}
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode)
{
if (tables->lock_type == TL_WRITE_DEFAULT)
tables->table->reginfo.lock_type= thd->update_lock_default;
@ -4803,10 +4797,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
DBUG_PRINT("tcache", ("is parent: %d is child: %d",
test(tables->table->child_l),
test(tables->parent_l)));
DBUG_PRINT("tcache", ("in lock tables: %d in prelock mode: %d",
test(thd->locked_tables), test(thd->prelocked_mode)));
if (((!thd->locked_tables && !thd->prelocked_mode) ||
tables->table->s->tmp_table) &&
if ((!thd->locked_tables_mode || tables->table->s->tmp_table) &&
((tables->table->child_l &&
add_merge_table_list(tables)) ||
(tables->parent_l &&
@ -4822,7 +4813,8 @@ process_view_routines:
Again we may need cache all routines used by this view and add
tables used by them to table list.
*/
if (tables->view && !thd->prelocked_mode &&
if (tables->view &&
thd->locked_tables_mode <= LTM_LOCK_TABLES &&
!thd->lex->requires_prelocking() &&
tables->view->uses_stored_routines())
{
@ -4996,7 +4988,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
DBUG_ENTER("open_ltable");
/* should not be used in a prelocked_mode context, see NOTE above */
DBUG_ASSERT(!thd->prelocked_mode);
DBUG_ASSERT(thd->locked_tables_mode < LTM_PRELOCKED);
thd_proc_info(thd, "Opening table");
thd->current_tablenr= 0;
@ -5033,7 +5025,7 @@ retry:
table_list->lock_type= lock_type;
table_list->table= table;
table->grant= table_list->grant;
if (thd->locked_tables)
if (thd->locked_tables_mode)
{
if (check_lock_and_start_stmt(thd, table, lock_type))
table= 0;
@ -5355,9 +5347,9 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables)
handling thr_lock gives us. You most always get all needed locks at
once.
If query for which we are calling this function marked as requring
prelocking, this function will do implicit LOCK TABLES and change
thd::prelocked_mode accordingly.
If query for which we are calling this function marked as requiring
prelocking, this function will change locked_tables_mode to
LTM_PRELOCKED.
RETURN VALUES
0 ok
@ -5374,22 +5366,24 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count,
We can't meet statement requiring prelocking if we already
in prelocked mode.
*/
DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking());
DBUG_ASSERT(thd->locked_tables_mode <= LTM_LOCK_TABLES ||
!thd->lex->requires_prelocking());
*need_reopen= FALSE;
if (!tables && !thd->lex->requires_prelocking())
DBUG_RETURN(decide_logging_format(thd, tables));
/*
We need this extra check for thd->prelocked_mode because we want to avoid
attempts to lock tables in substatements. Checking for thd->locked_tables
is not enough in some situations. For example for SP containing
Check for thd->locked_tables_mode to avoid a redundant
and harmful attempt to lock the already locked tables again.
Checking for thd->lock is not enough in some situations. For example,
if a stored function contains
"drop table t3; create temporary t3 ..; insert into t3 ...;"
thd->locked_tables may be 0 after drop tables, and without this extra
check insert will try to lock temporary table t3, that will lead
to memory leak...
thd->lock may be 0 after drop tables, whereas locked_tables_mode
is still on. In this situation an attempt to lock temporary
table t3 will lead to a memory leak.
*/
if (!thd->locked_tables && !thd->prelocked_mode)
if (! thd->locked_tables_mode)
{
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
TABLE **start,**ptr;
@ -5443,15 +5437,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count,
We just have done implicit LOCK TABLES, and now we have
to emulate first open_and_lock_tables() after it.
Note that "LOCK TABLES" can also be marked as requiring prelocking
(e.g. if one locks view which uses functions). We should not emulate
such open_and_lock_tables() in this case. We also should not set
THD::prelocked_mode or first close_thread_tables() call will do
"UNLOCK TABLES".
*/
thd->locked_tables= thd->lock;
thd->lock= 0;
thd->in_lock_tables=0;
thd->in_lock_tables= 0;
/*
When open_and_lock_tables() is called for a single table out of
@ -5474,8 +5461,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count,
This was an attempt to enter prelocked mode so there is no
need to care about THD::locked_tables_root here.
*/
mysql_unlock_tables(thd, thd->locked_tables);
thd->locked_tables= 0;
mysql_unlock_tables(thd, thd->lock);
thd->options&= ~(OPTION_TABLE_LOCK);
DBUG_RETURN(-1);
}
@ -5486,8 +5472,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count,
and was marked as occupied during open_tables() as free for reuse.
*/
mark_real_tables_as_free_for_reuse(first_not_own);
DBUG_PRINT("info",("prelocked_mode= PRELOCKED"));
thd->prelocked_mode= PRELOCKED;
DBUG_PRINT("info",("locked_tables_mode= PRELOCKED"));
thd->locked_tables_mode= LTM_PRELOCKED;
}
}
else
@ -5512,7 +5498,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count,
In a stored function or trigger we should ensure that we won't change
a table that is already used by the calling statement.
*/
if (thd->prelocked_mode &&
if (thd->locked_tables_mode >= LTM_PRELOCKED &&
table->lock_type >= TL_WRITE_ALLOW_WRITE)
{
for (TABLE* opentab= thd->open_tables; opentab; opentab= opentab->next)
@ -5540,8 +5526,9 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count,
if (thd->lex->requires_prelocking())
{
mark_real_tables_as_free_for_reuse(first_not_own);
DBUG_PRINT("info", ("thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES"));
thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES;
DBUG_PRINT("info",
("thd->locked_tables_mode= LTM_PRELOCKED_UNDER_LOCK_TABLES"));
thd->locked_tables_mode= LTM_PRELOCKED_UNDER_LOCK_TABLES;
}
}