summaryrefslogtreecommitdiff
path: root/sql/lock.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/lock.cc')
-rw-r--r--sql/lock.cc105
1 files changed, 79 insertions, 26 deletions
diff --git a/sql/lock.cc b/sql/lock.cc
index e713990bd58..946a089fadc 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -68,10 +68,6 @@
table_handler->external_lock(thd, F_UNLCK) for each table that was locked,
excluding one that caused failure. That means handler must cleanup itself
in case external_lock() fails.
-
- @todo
- Change to use my_malloc() ONLY when using LOCK TABLES command or when
- we are forced to use mysql_lock_merge.
*/
#include <my_global.h>
@@ -83,6 +79,7 @@
#include "sql_parse.h" // is_log_table_write_query
#include "sql_acl.h" // SUPER_ACL
#include <hash.h>
+#include "wsrep_mysqld.h"
/**
@defgroup Locking Locking
@@ -265,19 +262,24 @@ void reset_lock_data(MYSQL_LOCK *sql_lock, bool unlock)
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
{
MYSQL_LOCK *sql_lock;
+ uint gld_flags= GET_LOCK_STORE_LOCKS;
DBUG_ENTER("mysql_lock_tables(tables)");
if (lock_tables_check(thd, tables, count, flags))
DBUG_RETURN(NULL);
- if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS)))
+ if (!(thd->variables.option_bits & OPTION_TABLE_LOCK))
+ gld_flags|= GET_LOCK_ON_THD;
+
+ if (! (sql_lock= get_lock_data(thd, tables, count, gld_flags)))
DBUG_RETURN(NULL);
if (mysql_lock_tables(thd, sql_lock, flags))
{
/* Clear the lock type of all lock data to avoid reusage. */
reset_lock_data(sql_lock, 1);
- my_free(sql_lock);
+ if (!(gld_flags & GET_LOCK_ON_THD))
+ my_free(sql_lock);
sql_lock= 0;
}
DBUG_RETURN(sql_lock);
@@ -304,8 +306,8 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags)
PSI_stage_info org_stage;
DBUG_ENTER("mysql_lock_tables(sql_lock)");
- thd->enter_stage(&stage_system_lock, &org_stage, __func__, __FILE__,
- __LINE__);
+ thd->backup_stage(&org_stage);
+ THD_STAGE_INFO(thd, stage_system_lock);
if (sql_lock->table_count && lock_external(thd, sql_lock->table,
sql_lock->table_count))
goto end;
@@ -315,6 +317,7 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags)
/* Copy the lock data array. thr_multi_lock() reorders its contents. */
memmove(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
sql_lock->lock_count * sizeof(*sql_lock->locks));
+
/* Lock on the copied half of the lock data array. */
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
sql_lock->lock_count,
@@ -330,7 +333,10 @@ end:
{
thd->send_kill_message();
if (!rc)
+ {
mysql_unlock_tables(thd, sql_lock, 0);
+ THD_STAGE_INFO(thd, stage_after_table_lock);
+ }
rc= 1;
}
else if (rc > 1)
@@ -378,9 +384,18 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
}
+void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
+{
+ mysql_unlock_tables(thd, sql_lock,
+ thd->variables.option_bits & OPTION_TABLE_LOCK);
+}
+
+
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
{
DBUG_ENTER("mysql_unlock_tables");
+ THD_STAGE_INFO(thd, stage_unlocking_tables);
+
if (sql_lock->table_count)
unlock_external(thd, sql_lock->table, sql_lock->table_count);
if (sql_lock->lock_count)
@@ -398,9 +413,10 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
{
- MYSQL_LOCK *sql_lock;
- if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK)))
- mysql_unlock_tables(thd, sql_lock, 1);
+ MYSQL_LOCK *sql_lock=
+ get_lock_data(thd, table, count, GET_LOCK_UNLOCK | GET_LOCK_ON_THD);
+ if (sql_lock)
+ mysql_unlock_tables(thd, sql_lock, 0);
}
@@ -547,11 +563,10 @@ void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
MYSQL_LOCK *locked;
DBUG_ENTER("mysql_lock_abort");
- if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
+ if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK | GET_LOCK_ON_THD)))
{
for (uint i=0; i < locked->lock_count; i++)
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
- my_free(locked);
}
DBUG_VOID_RETURN;
}
@@ -575,7 +590,7 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
bool result= FALSE;
DBUG_ENTER("mysql_lock_abort_for_thread");
- if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
+ if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK | GET_LOCK_ON_THD)))
{
for (uint i=0; i < locked->lock_count; i++)
{
@@ -583,7 +598,6 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
table->in_use->thread_id))
result= TRUE;
}
- my_free(locked);
}
DBUG_RETURN(result);
}
@@ -701,7 +715,6 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
TABLE **to, **table_buf;
DBUG_ENTER("get_lock_data");
- DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
DBUG_PRINT("info", ("count %d", count));
for (i=lock_count=table_count=0 ; i < count ; i++)
@@ -722,11 +735,12 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
update the table values. So the second part of the array is copied
from the first part immediately before calling thr_multi_lock().
*/
- if (!(sql_lock= (MYSQL_LOCK*)
- my_malloc(sizeof(*sql_lock) +
- sizeof(THR_LOCK_DATA*) * lock_count * 2 +
- sizeof(table_ptr) * table_count,
- MYF(0))))
+ size_t amount= sizeof(*sql_lock) +
+ sizeof(THR_LOCK_DATA*) * lock_count * 2 +
+ sizeof(table_ptr) * table_count;
+ if (!(sql_lock= (MYSQL_LOCK*) (flags & GET_LOCK_ON_THD ?
+ thd->alloc(amount) :
+ my_malloc(amount, MYF(0)))))
DBUG_RETURN(0);
locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
to= table_buf= sql_lock->table= (TABLE**) (locks + lock_count * 2);
@@ -745,9 +759,9 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT);
locks_start= locks;
locks= table->file->store_lock(thd, locks,
- (flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
- lock_type);
- if (flags & GET_LOCK_STORE_LOCKS)
+ (flags & GET_LOCK_ACTION_MASK) == GET_LOCK_UNLOCK ? TL_IGNORE :
+ lock_type);
+ if ((flags & GET_LOCK_ACTION_MASK) == GET_LOCK_STORE_LOCKS)
{
table->lock_position= (uint) (to - table_buf);
table->lock_data_start= (uint) (locks_start - locks_buf);
@@ -812,7 +826,7 @@ bool lock_schema_name(THD *thd, const char *db)
if (thd->locked_tables_mode)
{
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
- ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
+ ER_THD(thd, ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
return TRUE;
}
@@ -868,7 +882,7 @@ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type,
if (thd->locked_tables_mode)
{
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
- ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
+ ER_THD(thd, ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
return TRUE;
}
@@ -1053,6 +1067,13 @@ void Global_read_lock::unlock_global_read_lock(THD *thd)
{
thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
m_mdl_blocks_commits_lock= NULL;
+#ifdef WITH_WSREP
+ if (WSREP_ON)
+ {
+ wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
+ wsrep->resume(wsrep);
+ }
+#endif /* WITH_WSREP */
}
thd->mdl_context.release_lock(m_mdl_global_shared_lock);
m_mdl_global_shared_lock= NULL;
@@ -1085,9 +1106,22 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
If we didn't succeed lock_global_read_lock(), or if we already suceeded
make_global_read_lock_block_commit(), do nothing.
*/
+
if (m_state != GRL_ACQUIRED)
DBUG_RETURN(0);
+#ifdef WITH_WSREP
+ if (WSREP_ON && m_mdl_blocks_commits_lock)
+ {
+ WSREP_DEBUG("GRL was in block commit mode when entering "
+ "make_global_read_lock_block_commit");
+ thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
+ m_mdl_blocks_commits_lock= NULL;
+ wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
+ wsrep->resume(wsrep);
+ }
+#endif /* WITH_WSREP */
+
mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED, MDL_EXPLICIT);
if (thd->mdl_context.acquire_lock(&mdl_request,
@@ -1097,6 +1131,25 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
m_mdl_blocks_commits_lock= mdl_request.ticket;
m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT;
+#ifdef WITH_WSREP
+ if (WSREP_ON)
+ {
+ long long ret = wsrep->pause(wsrep);
+ if (ret >= 0)
+ {
+ wsrep_locked_seqno= ret;
+ }
+ else if (ret != -ENOSYS) /* -ENOSYS - no provider */
+ {
+ WSREP_ERROR("Failed to pause provider: %lld (%s)", -ret, strerror(-ret));
+
+ DBUG_ASSERT(m_mdl_blocks_commits_lock == NULL);
+ wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ }
+#endif /* WITH_WSREP */
DBUG_RETURN(FALSE);
}