Commit f477e66e authored by Konstantin Osipov's avatar Konstantin Osipov

Backport of:

------------------------------------------------------------
revno: 2617.23.18
committer: Davi Arnaut <Davi.Arnaut@Sun.COM>
branch nick: 4284-6.0
timestamp: Mon 2009-03-02 18:18:26 -0300
message:
Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order
WL#4284: Transactional DDL locking

This is a prerequisite patch:

These changes are intended to split lock requests from granted
locks and to allow the memory and lifetime of granted locks to
be managed within the MDL subsystem. Furthermore, tickets can
now be shared and therefore are used to satisfy multiple lock
requests, but only shared locks can be recursive.

The problem is that the MDL subsystem morphs lock requests into
granted locks locks but does not manage the memory and lifetime
of lock requests, and hence, does not manage the memory of
granted locks either. This can be problematic because it puts the
burden of tracking references on the users of the subsystem and
it can't be easily done in transactional contexts where the locks
have to be kept around for the duration of a transaction.

Another issue is that recursive locks (when the context trying to
acquire a lock already holds a lock on the same object) requires
that each time the lock is granted, a unique lock request/granted
lock structure structure must be kept around until the lock is
released. This can lead to memory leaks in transactional contexts
as locks taken during the transaction should only be released at
the end of the transaction. This also leads to unnecessary wake
ups (broadcasts) in the MDL subsystem if the context still holds
a equivalent of the lock being released.

These issues are exacerbated due to the fact that WL#4284 low-level
design says that the implementation should "2) Store metadata locks
in transaction memory root, rather than statement memory root" but
this is not possible because a memory root, as implemented in mysys,
requires all objects allocated from it to be freed all at once.

This patch combines review input and significant code contributions
from Konstantin Osipov (kostja) and Dmitri Lenev (dlenev).


mysql-test/r/mdl_sync.result:
  Add test case result.
mysql-test/t/mdl_sync.test:
  Add test case for shared lock upgrade case.
sql/event_db_repository.cc:
  Rename mdl_alloc_lock to mdl_request_alloc.
sql/ha_ndbcluster_binlog.cc:
  Use new function names to initialize MDL lock requests.
sql/lock.cc:
  Rename MDL functions.
sql/log_event.cc:
  The MDL request now holds the table and database name data (MDL_KEY).
sql/mdl.cc:
  Move the MDL key to the MDL_LOCK structure in order to make the
  object suitable for allocation from a fixed-size allocator. This
  allows the simplification of the lists in the MDL_LOCK object,
  which now are just two, one for granted tickets and other for
  waiting (upgraders) tickets.
  
  Recursive requests for a shared lock on the same object can now
  be granted using the same lock ticket. This schema is only used
  for shared locks because that the only case that matters. This
  is used to avoid waste of resources in case a context (connection)
  already holds a shared lock on a object.
sql/mdl.h:
  Introduce a metadata lock object key which is used  to uniquely
  identify lock objects.
  
  Separate the structure used to represent pending lock requests
  from the structure used to represent granted metadata locks.
  
  Rename functions used to manipulate locks requests in order to
  have a more consistent function naming schema.
sql/sp_head.cc:
  Rename mdl_alloc_lock to mdl_request_alloc.
sql/sql_acl.cc:
  Rename alloc_mdl_locks to alloc_mdl_requests.
sql/sql_base.cc:
  Various changes to accommodate that lock requests are separated
  from lock tickets (granted locks).
sql/sql_class.h:
  Last acquired lock before the savepoint was set.
sql/sql_delete.cc:
  Various changes to accommodate that lock requests are separated
  from lock tickets (granted locks).
sql/sql_handler.cc:
  Various changes to accommodate that lock requests are separated
  from lock tickets (granted locks).
sql/sql_insert.cc:
  Rename alloc_mdl_locks to alloc_mdl_requests.
sql/sql_parse.cc:
  Rename alloc_mdl_locks to alloc_mdl_requests.
sql/sql_plist.h:
  Typedef for iterator type.
sql/sql_plugin.cc:
  Rename alloc_mdl_locks to alloc_mdl_requests.
sql/sql_servers.cc:
  Rename alloc_mdl_locks to alloc_mdl_requests.
sql/sql_show.cc:
  Various changes to accommodate that lock requests are separated
  from lock tickets (granted locks).
sql/sql_table.cc:
  Various changes to accommodate that lock requests are separated
  from lock tickets (granted locks).
sql/sql_trigger.cc:
  Save reference to the lock ticket so it can be downgraded later.
sql/sql_udf.cc:
  Rename alloc_mdl_locks to alloc_mdl_requests.
sql/table.cc:
  Rename mdl_alloc_lock to mdl_request_alloc.
sql/table.h:
  Separate MDL lock requests from lock tickets (granted locks).
storage/myisammrg/ha_myisammrg.cc:
  Rename alloc_mdl_locks to alloc_mdl_requests.
parent 62ed4904
SET DEBUG_SYNC= 'RESET';
drop table if exists t1,t2,t3;
create table t1 (i int);
create table t2 (i int);
connection: default
lock tables t2 read;
connection: con1
set debug_sync='mdl_upgrade_shared_lock_to_exclusive SIGNAL parked WAIT_FOR go';
alter table t1 rename t3;
connection: default
set debug_sync= 'now WAIT_FOR parked';
connection: con2
set debug_sync='mdl_acquire_exclusive_locks_wait SIGNAL go';
drop table t1,t2;
connection: con1
connection: default
unlock tables;
connection: con2
ERROR 42S02: Unknown table 't1'
drop table t3;
SET DEBUG_SYNC= 'RESET';
#
# We need the Debug Sync Facility.
#
--source include/have_debug_sync.inc
# Clean up resources used in this test case.
--disable_warnings
SET DEBUG_SYNC= 'RESET';
--enable_warnings
#
# Test the case of when a exclusive lock request waits for a
# shared lock being upgraded to a exclusive lock.
#
connect (con1,localhost,root,,test,,);
connect (con2,localhost,root,,test,,);
connect (con3,localhost,root,,test,,);
connection default;
--disable_warnings
drop table if exists t1,t2,t3;
--enable_warnings
create table t1 (i int);
create table t2 (i int);
--echo connection: default
lock tables t2 read;
connection con1;
--echo connection: con1
set debug_sync='mdl_upgrade_shared_lock_to_exclusive SIGNAL parked WAIT_FOR go';
--send alter table t1 rename t3
connection default;
--echo connection: default
set debug_sync= 'now WAIT_FOR parked';
connection con2;
--echo connection: con2
set debug_sync='mdl_acquire_exclusive_locks_wait SIGNAL go';
--send drop table t1,t2
connection con1;
--echo connection: con1
--reap
connection default;
--echo connection: default
unlock tables;
connection con2;
--echo connection: con2
--error ER_BAD_TABLE_ERROR
--reap
connection default;
drop table t3;
disconnect con1;
disconnect con2;
disconnect con3;
# Clean up resources used in this test case.
--disable_warnings
SET DEBUG_SYNC= 'RESET';
--enable_warnings
......@@ -555,7 +555,7 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
DBUG_ENTER("Event_db_repository::open_event_table");
tables.init_one_table("mysql", 5, "event", 5, "event", lock_type);
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
if (simple_open_n_lock_tables(thd, &tables))
{
......@@ -1110,7 +1110,7 @@ Event_db_repository::check_system_tables(THD *thd)
/* Check mysql.db */
tables.init_one_table("mysql", 5, "db", 2, "db", TL_READ);
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
if (simple_open_n_lock_tables(thd, &tables))
{
......@@ -1128,7 +1128,7 @@ Event_db_repository::check_system_tables(THD *thd)
}
/* Check mysql.user */
tables.init_one_table("mysql", 5, "user", 4, "user", TL_READ);
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
if (simple_open_n_lock_tables(thd, &tables))
{
......@@ -1149,7 +1149,7 @@ Event_db_repository::check_system_tables(THD *thd)
}
/* Check mysql.event */
tables.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
if (simple_open_n_lock_tables(thd, &tables))
{
......
......@@ -140,8 +140,7 @@ static Uint64 *p_latest_trans_gci= 0;
*/
static TABLE *ndb_binlog_index= 0;
static TABLE_LIST binlog_tables;
static MDL_LOCK_DATA binlog_mdl_lock_data;
static char binlog_mdlkey[MAX_MDLKEY_LENGTH];
static MDL_LOCK_REQUEST binlog_mdl_lock_request;
/*
Helper functions
......@@ -2343,9 +2342,8 @@ static int open_ndb_binlog_index(THD *thd, TABLE **ndb_binlog_index)
tables->alias= tables->table_name= reptable;
tables->lock_type= TL_WRITE;
thd->proc_info= "Opening " NDB_REP_DB "." NDB_REP_TABLE;
mdl_init_lock(&binlog_mdl_lock_data, binlog_mdlkey, 0, tables->db,
tables->table_name);
tables->mdl_lock_data= &binlog_mdl_lock_data;
mdl_request_init(&binlog_mdl_lock_request, 0, tables->db, tables->table_name);
tables->mdl_lock_request= &binlog_mdl_lock_request;
tables->required_type= FRMTYPE_TABLE;
uint counter;
thd->clear_error();
......
......@@ -953,24 +953,24 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
bool lock_table_names(THD *thd, TABLE_LIST *table_list)
{
TABLE_LIST *lock_table;
MDL_LOCK_DATA *mdl_lock_data;
MDL_LOCK_REQUEST *mdl_lock_req;
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
{
if (!(mdl_lock_data= mdl_alloc_lock(0, lock_table->db,
lock_table->table_name,
thd->mem_root)))
mdl_lock_req= mdl_request_alloc(0, lock_table->db, lock_table->table_name,
thd->mem_root);
if (!mdl_lock_req)
goto end;
mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE);
mdl_add_lock(&thd->mdl_context, mdl_lock_data);
lock_table->mdl_lock_data= mdl_lock_data;
mdl_request_set_type(mdl_lock_req, MDL_EXCLUSIVE);
mdl_request_add(&thd->mdl_context, mdl_lock_req);
lock_table->mdl_lock_request= mdl_lock_req;
}
if (mdl_acquire_exclusive_locks(&thd->mdl_context))
goto end;
return 0;
end:
mdl_remove_all_locks(&thd->mdl_context);
mdl_request_remove_all(&thd->mdl_context);
return 1;
}
......@@ -986,8 +986,8 @@ end:
void unlock_table_names(THD *thd)
{
DBUG_ENTER("unlock_table_names");
mdl_release_locks(&thd->mdl_context);
mdl_remove_all_locks(&thd->mdl_context);
mdl_ticket_release_all(&thd->mdl_context);
mdl_request_remove_all(&thd->mdl_context);
DBUG_VOID_RETURN;
}
......
......@@ -8059,8 +8059,8 @@ Table_map_log_event::~Table_map_log_event()
int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
{
RPL_TABLE_LIST *table_list;
char *db_mem, *tname_mem, *mdlkey;
MDL_LOCK_DATA *mdl_lock_data;
char *db_mem, *tname_mem;
MDL_LOCK_REQUEST *mdl_lock_request;
size_t dummy_len;
void *memory;
DBUG_ENTER("Table_map_log_event::do_apply_event(Relay_log_info*)");
......@@ -8075,8 +8075,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
&table_list, (uint) sizeof(RPL_TABLE_LIST),
&db_mem, (uint) NAME_LEN + 1,
&tname_mem, (uint) NAME_LEN + 1,
&mdl_lock_data, sizeof(MDL_LOCK_DATA),
&mdlkey, MAX_MDLKEY_LENGTH,
&mdl_lock_request, sizeof(MDL_LOCK_REQUEST),
NullS)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
......@@ -8089,9 +8088,9 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
table_list->updating= 1;
strmov(table_list->db, rpl_filter->get_rewrite_db(m_dbnam, &dummy_len));
strmov(table_list->table_name, m_tblnam);
mdl_init_lock(mdl_lock_data, mdlkey, 0, table_list->db,
table_list->table_name);
table_list->mdl_lock_data= mdl_lock_data;
mdl_request_init(mdl_lock_request, 0, table_list->db,
table_list->table_name);
table_list->mdl_lock_request= mdl_lock_request;
int error= 0;
......
This diff is collapsed.
This diff is collapsed.
......@@ -3981,10 +3981,10 @@ sp_head::add_used_tables_to_table_list(THD *thd,
table->prelocking_placeholder= 1;
table->belong_to_view= belong_to_view;
table->trg_event_map= stab->trg_event_map;
table->mdl_lock_data= mdl_alloc_lock(0, table->db, table->table_name,
thd->locked_tables_root ?
thd->locked_tables_root :
thd->mem_root);
table->mdl_lock_request= mdl_request_alloc(0, table->db, table->table_name,
thd->locked_tables_root ?
thd->locked_tables_root :
thd->mem_root);
/* Everyting else should be zeroed */
......@@ -4026,9 +4026,10 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
table->lock_type= locktype;
table->select_lex= lex->current_select;
table->cacheable_table= 1;
table->mdl_lock_data= mdl_alloc_lock(0, table->db, table->table_name,
thd->locked_tables_root ?
thd->locked_tables_root : thd->mem_root);
table->mdl_lock_request= mdl_request_alloc(0, table->db, table->table_name,
thd->locked_tables_root ?
thd->locked_tables_root :
thd->mem_root);
lex->add_to_query_tables(table);
return table;
......
......@@ -693,7 +693,7 @@ my_bool acl_reload(THD *thd)
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
tables[0].skip_temporary= tables[1].skip_temporary=
tables[2].skip_temporary= TRUE;
alloc_mdl_locks(tables, thd->mem_root);
alloc_mdl_requests(tables, thd->mem_root);
if (simple_open_n_lock_tables(thd, tables))
{
......@@ -1598,7 +1598,7 @@ bool change_password(THD *thd, const char *host, const char *user,
bzero((char*) &tables, sizeof(tables));
tables.alias= tables.table_name= (char*) "user";
tables.db= (char*) "mysql";
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
#ifdef HAVE_REPLICATION
/*
......@@ -3110,7 +3110,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
? tables+2 : 0);
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
alloc_mdl_locks(tables, thd->mem_root);
alloc_mdl_requests(tables, thd->mem_root);
/*
This statement will be replicated as a statement, even when using
......@@ -3328,7 +3328,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
tables[0].next_local= tables[0].next_global= tables+1;
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
tables[0].db=tables[1].db=(char*) "mysql";
alloc_mdl_locks(tables, thd->mem_root);
alloc_mdl_requests(tables, thd->mem_root);
/*
This statement will be replicated as a statement, even when using
......@@ -3467,7 +3467,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
tables[0].next_local= tables[0].next_global= tables+1;
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
tables[0].db=tables[1].db=(char*) "mysql";
alloc_mdl_locks(tables, thd->mem_root);
alloc_mdl_requests(tables, thd->mem_root);
/*
This statement will be replicated as a statement, even when using
......@@ -3801,7 +3801,7 @@ static my_bool grant_reload_procs_priv(THD *thd)
table.db= (char *) "mysql";
table.lock_type= TL_READ;
table.skip_temporary= 1;
alloc_mdl_locks(&table, thd->mem_root);
alloc_mdl_requests(&table, thd->mem_root);
if (simple_open_n_lock_tables(thd, &table))
{
......@@ -3868,7 +3868,7 @@ my_bool grant_reload(THD *thd)
tables[0].next_local= tables[0].next_global= tables+1;
tables[0].lock_type= tables[1].lock_type= TL_READ;
tables[0].skip_temporary= tables[1].skip_temporary= TRUE;
alloc_mdl_locks(tables, thd->mem_root);
alloc_mdl_requests(tables, thd->mem_root);
/*
To avoid deadlocks we should obtain table locks before
......@@ -5215,7 +5215,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
(tables+4)->lock_type= TL_WRITE;
tables->db= (tables+1)->db= (tables+2)->db=
(tables+3)->db= (tables+4)->db= (char*) "mysql";
alloc_mdl_locks(tables, thd->mem_root);
alloc_mdl_requests(tables, thd->mem_root);
#ifdef HAVE_REPLICATION
/*
......
This diff is collapsed.
......@@ -779,6 +779,8 @@ struct st_savepoint {
char *name;
uint length;
Ha_trx_info *ha_list;
/** Last acquired lock before this savepoint was set. */
MDL_LOCK_TICKET *mdl_savepoint;
};
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY};
......
......@@ -1100,7 +1100,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
TABLE *table;
bool error;
uint path_length;
MDL_LOCK_DATA *mdl_lock_data= 0;
MDL_LOCK_REQUEST *mdl_lock_request= NULL;
DBUG_ENTER("mysql_truncate");
bzero((char*) &create_info,sizeof(create_info));
......@@ -1175,13 +1175,13 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
tries to get table enging and therefore accesses table in some way
without holding any kind of meta-data lock.
*/
mdl_lock_data= mdl_alloc_lock(0, table_list->db, table_list->table_name,
thd->mem_root);
mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE);
mdl_add_lock(&thd->mdl_context, mdl_lock_data);
mdl_lock_request= mdl_request_alloc(0, table_list->db,
table_list->table_name, thd->mem_root);
mdl_request_set_type(mdl_lock_request, MDL_EXCLUSIVE);
mdl_request_add(&thd->mdl_context, mdl_lock_request);
if (mdl_acquire_exclusive_locks(&thd->mdl_context))
{
mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
mdl_request_remove(&thd->mdl_context, mdl_lock_request);
DBUG_RETURN(TRUE);
}
pthread_mutex_lock(&LOCK_open);
......@@ -1212,18 +1212,18 @@ end:
write_bin_log(thd, TRUE, thd->query(), thd->query_length());
my_ok(thd); // This should return record count
}
if (mdl_lock_data)
if (mdl_lock_request)
{
mdl_release_lock(&thd->mdl_context, mdl_lock_data);
mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
mdl_ticket_release(&thd->mdl_context, mdl_lock_request->ticket);
mdl_request_remove(&thd->mdl_context, mdl_lock_request);
}
}
else if (error)
{
if (mdl_lock_data)
if (mdl_lock_request)
{
mdl_release_lock(&thd->mdl_context, mdl_lock_data);
mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
mdl_ticket_release(&thd->mdl_context, mdl_lock_request->ticket);
mdl_request_remove(&thd->mdl_context, mdl_lock_request);
}
}
DBUG_RETURN(error);
......
......@@ -125,7 +125,7 @@ static void mysql_ha_hash_free(TABLE_LIST *tables)
static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables)
{
TABLE **table_ptr;
MDL_LOCK_DATA *mdl_lock_data;
MDL_LOCK_TICKET *mdl_lock_ticket;
/*
Though we could take the table pointer from hash_tables->table,
......@@ -141,7 +141,7 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables)
if (*table_ptr)
{
(*table_ptr)->file->ha_index_or_rnd_end();
mdl_lock_data= (*table_ptr)->mdl_lock_data;
mdl_lock_ticket= (*table_ptr)->mdl_lock_ticket;
pthread_mutex_lock(&LOCK_open);
if (close_thread_table(thd, table_ptr))
{
......@@ -149,8 +149,8 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables)
broadcast_refresh();
}
pthread_mutex_unlock(&LOCK_open);
mdl_release_lock(&thd->handler_mdl_context, mdl_lock_data);
mdl_remove_lock(&thd->handler_mdl_context, mdl_lock_data);
mdl_ticket_release(&thd->handler_mdl_context, mdl_lock_ticket);
mdl_request_remove(&thd->handler_mdl_context, tables->mdl_lock_request);
}
else if (tables->table)
{
......@@ -190,12 +190,12 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables)
bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
{
TABLE_LIST *hash_tables = NULL;
MDL_LOCK_DATA *mdl_lock_data;
char *db, *name, *alias, *mdlkey;
char *db, *name, *alias;
uint dblen, namelen, aliaslen, counter;
int error;
TABLE *backup_open_tables;
MDL_CONTEXT backup_mdl_context;
MDL_LOCK_REQUEST *mdl_lock_request;
DBUG_ENTER("mysql_ha_open");
DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d",
tables->db, tables->table_name, tables->alias,
......@@ -246,8 +246,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
&db, (uint) dblen,
&name, (uint) namelen,
&alias, (uint) aliaslen,
&mdl_lock_data, sizeof(MDL_LOCK_DATA),
&mdlkey, MAX_MDLKEY_LENGTH,
&mdl_lock_request, sizeof(MDL_LOCK_REQUEST),
NullS)))
{
DBUG_PRINT("exit",("ERROR"));
......@@ -261,8 +260,8 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
memcpy(hash_tables->db, tables->db, dblen);
memcpy(hash_tables->table_name, tables->table_name, namelen);
memcpy(hash_tables->alias, tables->alias, aliaslen);
mdl_init_lock(mdl_lock_data, mdlkey, 0, db, name);
hash_tables->mdl_lock_data= mdl_lock_data;
mdl_request_init(mdl_lock_request, 0, db, name);
hash_tables->mdl_lock_request= mdl_lock_request;
/* add to hash */
if (my_hash_insert(&thd->handler_tables_hash, (uchar*) hash_tables))
......@@ -801,11 +800,11 @@ void mysql_ha_flush(THD *thd)
{
hash_tables= (TABLE_LIST*) my_hash_element(&thd->handler_tables_hash, i);
/*
TABLE::mdl_lock_data is 0 for temporary tables so we need extra check.
TABLE::mdl_lock_ticket is 0 for temporary tables so we need extra check.
*/
if (hash_tables->table &&
(hash_tables->table->mdl_lock_data &&
mdl_has_pending_conflicting_lock(hash_tables->table->mdl_lock_data) ||
(hash_tables->table->mdl_lock_ticket &&
mdl_has_pending_conflicting_lock(hash_tables->table->mdl_lock_ticket) ||
hash_tables->table->needs_reopen()))
mysql_ha_close_table(thd, hash_tables);
}
......
......@@ -2399,7 +2399,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
thd->lex->set_stmt_unsafe();
thd->set_current_stmt_binlog_row_based_if_mixed();
alloc_mdl_locks(&di->table_list, thd->mem_root);
alloc_mdl_requests(&di->table_list, thd->mem_root);
if (di->open_and_lock_table())
goto err;
......
......@@ -1115,7 +1115,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
select_lex.table_list.link_in_list((uchar*) &table_list,
(uchar**) &table_list.next_local);
thd->lex->add_to_query_tables(&table_list);
alloc_mdl_locks(&table_list, thd->mem_root);
alloc_mdl_requests(&table_list, thd->mem_root);
/* switch on VIEW optimisation: do not fill temporary tables */
thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
......@@ -3324,7 +3324,7 @@ end_with_restore_list:
!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
goto error;
alloc_mdl_locks(all_tables, thd->locked_tables_list.locked_tables_root());
alloc_mdl_requests(all_tables, thd->locked_tables_list.locked_tables_root());
thd->options|= OPTION_TABLE_LOCK;
thd->in_lock_tables=1;
......@@ -5977,9 +5977,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->next_name_resolution_table= NULL;
/* Link table in global list (all used tables) */
lex->add_to_query_tables(ptr);
ptr->mdl_lock_data= mdl_alloc_lock(0 , ptr->db, ptr->table_name,
thd->locked_tables_root ?
thd->locked_tables_root : thd->mem_root);
ptr->mdl_lock_request=
mdl_request_alloc(0, ptr->db, ptr->table_name, thd->locked_tables_root ?
thd->locked_tables_root : thd->mem_root);
DBUG_RETURN(ptr);
}
......
......@@ -90,6 +90,7 @@ public:
#ifndef _lint
friend class I_P_List_iterator<T, B>;
#endif
typedef I_P_List_iterator<T, B> Iterator;
};
......
......@@ -1366,7 +1366,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
tables.alias= tables.table_name= (char*)"plugin";
tables.lock_type= TL_READ;
tables.db= new_thd->db;
alloc_mdl_locks(&tables, tmp_root);
alloc_mdl_requests(&tables, tmp_root);
#ifdef EMBEDDED_LIBRARY
/*
......@@ -1660,7 +1660,7 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
if (check_table_access(thd, INSERT_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
/* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table = open_ltable(thd, &tables, TL_WRITE, 0)))
......@@ -1735,7 +1735,7 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
bzero(&tables, sizeof(tables));
tables.db= (char *)"mysql";
tables.table_name= tables.alias= (char *)"plugin";
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
/* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE, 0)))
......
......@@ -234,7 +234,7 @@ bool servers_reload(THD *thd)
tables[0].alias= tables[0].table_name= (char*) "servers";
tables[0].db= (char*) "mysql";
tables[0].lock_type= TL_READ;
alloc_mdl_locks(tables, thd->mem_root);
alloc_mdl_requests(tables, thd->mem_root);
if (simple_open_n_lock_tables(thd, tables))
{
......@@ -365,7 +365,7 @@ insert_server(THD *thd, FOREIGN_SERVER *server)
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
tables.alias= tables.table_name= (char*) "servers";
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
/* need to open before acquiring THR_LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE, 0)))
......@@ -584,7 +584,7 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
tables.alias= tables.table_name= (char*) "servers";
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
rw_wrlock(&THR_LOCK_servers);
......@@ -709,7 +709,7 @@ int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered)
bzero((char*) &tables, sizeof(tables));
tables.db= (char*)"mysql";
tables.alias= tables.table_name= (char*)"servers";
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
if (!(table= open_ltable(thd, &tables, TL_WRITE, 0)))
{
......
......@@ -3050,12 +3050,8 @@ uint get_table_open_method(TABLE_LIST *tables,
Acquire high priority share metadata lock on a table.
@param thd Thread context.
@param mdl_lock_data Pointer to memory to be used for MDL_LOCK_DATA
@param mdl_lock_req Pointer to memory to be used for MDL_LOCK_REQUEST
object for a lock request.
@param mdlkey Pointer to the buffer for key for the lock request
(should be at least strlen(db) + strlen(name) + 2
bytes, or, if the lengths are not known,
MAX_MDLKEY_LENGTH)
@param table Table list element for the table
@note This is an auxiliary function to be used in cases when we want to
......@@ -3069,23 +3065,23 @@ uint get_table_open_method(TABLE_LIST *tables,
*/
static bool
acquire_high_prio_shared_mdl_lock(THD *thd, MDL_LOCK_DATA *mdl_lock_data,
char *mdlkey, TABLE_LIST *table)
acquire_high_prio_shared_mdl_lock(THD *thd, MDL_LOCK_REQUEST *mdl_lock_req,
TABLE_LIST *table)
{
bool retry;
mdl_init_lock(mdl_lock_data, mdlkey, 0, table->db, table->table_name);
table->mdl_lock_data= mdl_lock_data;
mdl_add_lock(&thd->mdl_context, mdl_lock_data);
mdl_set_lock_type(mdl_lock_data, MDL_SHARED_HIGH_PRIO);
mdl_request_init(mdl_lock_req, 0, table->db, table->table_name);
table->mdl_lock_request= mdl_lock_req;
mdl_request_add(&thd->mdl_context, mdl_lock_req);
mdl_request_set_type(mdl_lock_req, MDL_SHARED_HIGH_PRIO);
while (1)
{
if (mdl_acquire_shared_lock(&thd->mdl_context, mdl_lock_data, &retry))
if (mdl_acquire_shared_lock(&thd->mdl_context, mdl_lock_req, &retry))
{
if (!retry || mdl_wait_for_locks(&thd->mdl_context))
{
mdl_remove_all_locks(&thd->mdl_context);
mdl_request_remove_all(&thd->mdl_context);
return TRUE;
}
continue;
......@@ -3127,8 +3123,7 @@ static int fill_schema_table_from_frm(THD *thd,TABLE *table,
char key[MAX_DBKEY_LENGTH];
uint key_length;
char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1];
MDL_LOCK_DATA mdl_lock_data;
char mdlkey[MAX_MDLKEY_LENGTH];
MDL_LOCK_REQUEST mdl_lock_request;
bzero((char*) &table_list, sizeof(TABLE_LIST));
bzero((char*) &tbl, sizeof(TABLE));
......@@ -3158,8 +3153,7 @@ static int fill_schema_table_from_frm(THD *thd,TABLE *table,
simply obtaining internal lock of data-dictionary (ATM it
is LOCK_open) instead of obtaning full-blown metadata lock.
*/
if (acquire_high_prio_shared_mdl_lock(thd, &mdl_lock_data, mdlkey,
&table_list))
if (acquire_high_prio_shared_mdl_lock(thd, &mdl_lock_request, &table_list))
{
/*
Some error occured (most probably we have been killed while
......@@ -3220,8 +3214,8 @@ err_unlock:
pthread_mutex_unlock(&LOCK_open);
err:
mdl_release_lock(&thd->mdl_context, &mdl_lock_data);
mdl_remove_lock(&thd->mdl_context, &mdl_lock_data);
mdl_ticket_release(&thd->mdl_context, mdl_lock_request.ticket);
mdl_request_remove(&thd->mdl_context, &mdl_lock_request);
thd->clear_error();
return res;
}
......@@ -7317,7 +7311,7 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name)
uint num_tables; /* NOTE: unused, only to pass to open_tables(). */
alloc_mdl_locks(lst, thd->mem_root);
alloc_mdl_requests(lst, thd->mem_root);
if (open_tables(thd, &lst, &num_tables, 0))
{
......
This diff is collapsed.
......@@ -329,6 +329,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
String stmt_query;
bool need_start_waiting= FALSE;
bool lock_upgrade_done= FALSE;
MDL_LOCK_TICKET *mdl_lock_ticket= NULL;
DBUG_ENTER("mysql_create_or_drop_trigger");
......@@ -451,8 +452,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
if (!(tables->table= find_write_locked_table(thd->open_tables, tables->db,
tables->table_name)))
goto end;
/* Later on we will need it to downgrade the lock */
tables->mdl_lock_data= tables->table->mdl_lock_data;
}
else
{
......@@ -465,6 +464,9 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
}
table= tables->table;
/* Later on we will need it to downgrade the lock */
mdl_lock_ticket= table->mdl_lock_ticket;
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
goto end;
......@@ -511,8 +513,7 @@ end:
TABLE instance created by open_n_lock_single_table() and metadata lock.
*/
if (thd->locked_tables_mode && tables && lock_upgrade_done)
mdl_downgrade_exclusive_lock(&thd->mdl_context,
tables->mdl_lock_data);
mdl_downgrade_exclusive_lock(&thd->mdl_context, mdl_lock_ticket);
if (need_start_waiting)
start_waiting_global_read_lock(thd);
......
......@@ -142,7 +142,7 @@ void udf_init()
tables.alias= tables.table_name= (char*) "func";
tables.lock_type = TL_READ;
tables.db= db;
alloc_mdl_locks(&tables, new_thd->mem_root);
alloc_mdl_requests(&tables, new_thd->mem_root);
if (simple_open_n_lock_tables(new_thd, &tables))
{
......@@ -486,7 +486,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
bzero((char*) &tables,sizeof(tables));
tables.db= (char*) "mysql";
tables.table_name= tables.alias= (char*) "func";
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
/* Allow creation of functions even if we can't open func table */
if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
goto err;
......@@ -565,7 +565,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
bzero((char*) &tables,sizeof(tables));
tables.db=(char*) "mysql";
tables.table_name= tables.alias= (char*) "func";
alloc_mdl_locks(&tables, thd->mem_root);
alloc_mdl_requests(&tables, thd->mem_root);
if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
goto err;
table->use_all_columns();
......
......@@ -4811,12 +4811,11 @@ size_t max_row_length(TABLE *table, const uchar *data)
objects for all elements of table list.
*/
void alloc_mdl_locks(TABLE_LIST *table_list, MEM_ROOT *root)
void alloc_mdl_requests(TABLE_LIST *table_list, MEM_ROOT *root)
{
for ( ; table_list ; table_list= table_list->next_global)
table_list->mdl_lock_data= mdl_alloc_lock(0, table_list->db,
table_list->table_name,
root);
table_list->mdl_lock_request=
mdl_request_alloc(0, table_list->db, table_list->table_name, root);
}
......
......@@ -30,7 +30,8 @@ class st_select_lex;
class partition_info;
class COND_EQUAL;
class Security_context;
struct MDL_LOCK_DATA;
struct MDL_LOCK_REQUEST;
struct MDL_LOCK_TICKET;
/*************************************************************************/
......@@ -813,7 +814,7 @@ public:
partition_info *part_info; /* Partition related information */
bool no_partitions_used; /* If true, all partitions have been pruned away */
#endif
MDL_LOCK_DATA *mdl_lock_data;
MDL_LOCK_TICKET *mdl_lock_ticket;
bool fill_item_list(List<Item> *item_list) const;
void reset_item_list(List<Item> *item_list) const;
......@@ -1416,7 +1417,7 @@ struct TABLE_LIST
uint table_open_method;
enum enum_schema_table_state schema_table_state;
MDL_LOCK_DATA *mdl_lock_data;
MDL_LOCK_REQUEST *mdl_lock_request;
void calc_md5(char *buffer);
void set_underlying_merge();
......@@ -1785,6 +1786,6 @@ static inline void dbug_tmp_restore_column_maps(MY_BITMAP *read_set,
size_t max_row_length(TABLE *table, const uchar *data);
void alloc_mdl_locks(TABLE_LIST *table_list, MEM_ROOT *root);
void alloc_mdl_requests(TABLE_LIST *table_list, MEM_ROOT *root);
#endif /* TABLE_INCLUDED */
......@@ -434,16 +434,15 @@ int ha_myisammrg::add_children_list(void)
/* Copy select_lex. Used in unique_table() at least. */
child_l->select_lex= parent_l->select_lex;
child_l->mdl_lock_data= NULL; /* Safety, if alloc_mdl_locks fails. */
child_l->mdl_lock_request= NULL; /* Safety, if alloc_mdl_requests fails. */
/* Break when this was the last child. */
if (&child_l->next_global == this->children_last_l)
break;
}
alloc_mdl_locks(children_l,
thd->locked_tables_root ? thd->locked_tables_root :
thd->mem_root);
alloc_mdl_requests(children_l, thd->locked_tables_root ?
thd->locked_tables_root : thd->mem_root);
/* Insert children into the table list. */
if (parent_l->next_global)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment