diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/mdl.cc | 53 | ||||
-rw-r--r-- | sql/mdl.h | 2 | ||||
-rw-r--r-- | sql/sql_base.cc | 21 | ||||
-rw-r--r-- | sql/sql_class.cc | 10 | ||||
-rw-r--r-- | sql/sql_class.h | 8 |
5 files changed, 72 insertions, 22 deletions
diff --git a/sql/mdl.cc b/sql/mdl.cc index 28d2006b023..37699f1847b 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -17,6 +17,7 @@ #include "sql_class.h" #include "debug_sync.h" #include "sql_array.h" +#include "rpl_rli.h" #include <hash.h> #include <mysqld_error.h> #include <mysql/plugin.h> @@ -442,6 +443,7 @@ public: virtual void notify_conflicting_locks(MDL_context *ctx) = 0; virtual bitmap_t hog_lock_types_bitmap() const = 0; + bool check_if_conflicting_replication_locks(MDL_context *ctx); /** List of granted tickets for this lock. */ Ticket_list m_granted; @@ -2290,6 +2292,44 @@ void MDL_scoped_lock::notify_conflicting_locks(MDL_context *ctx) } } +/** + Check if there is any conflicting lock that could cause this thread + to wait for another thread which is not ready to commit. + This is always an error, as the upper level of parallel replication + should not allow a scheduling of a conflicting DDL until all earlier + transactions has commited. + + This function is only called for a slave using parallel replication + and trying to get an exclusive lock for the table. +*/ + +bool MDL_lock::check_if_conflicting_replication_locks(MDL_context *ctx) +{ + Ticket_iterator it(m_granted); + MDL_ticket *conflicting_ticket; + + while ((conflicting_ticket= it++)) + { + if (conflicting_ticket->get_ctx() != ctx) + { + MDL_context *conflicting_ctx= conflicting_ticket->get_ctx(); + + /* + If the conflicting thread is another parallel replication + thread for the same master and it's not in commit stage, then + the current transaction has started too early and something is + seriously wrong. + */ + if (conflicting_ctx->get_thd()->rgi_slave && + conflicting_ctx->get_thd()->rgi_slave->rli == + ctx->get_thd()->rgi_slave->rli && + !conflicting_ctx->get_thd()->rgi_slave->did_mark_start_commit) + return 1; // Fatal error + } + } + return 0; +} + /** Acquire one lock with waiting for conflicting locks to go away if needed. @@ -2355,6 +2395,19 @@ MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout) if (lock->needs_notification(ticket) && lock_wait_timeout) lock->notify_conflicting_locks(this); + /* + Ensure that if we are trying to get an exclusive lock for a slave + running parallel replication, then we are not blocked by another + parallel slave thread that is not committed. This should never happen as + the parallel replication scheduler should never schedule a DDL while + DML's are still running. + */ + DBUG_ASSERT((mdl_request->type != MDL_INTENTION_EXCLUSIVE && + mdl_request->type != MDL_EXCLUSIVE) || + !(get_thd()->rgi_slave && + get_thd()->rgi_slave->is_parallel_exec && + lock->check_if_conflicting_replication_locks(this))); + mysql_prlock_unlock(&lock->m_rwlock); will_wait_for(ticket); diff --git a/sql/mdl.h b/sql/mdl.h index c4d792acd29..13de60284da 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -910,7 +910,6 @@ private: */ MDL_wait_for_subgraph *m_waiting_for; private: - THD *get_thd() const { return m_owner->get_thd(); } MDL_ticket *find_ticket(MDL_request *mdl_req, enum_mdl_duration *duration); void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel); @@ -919,6 +918,7 @@ private: MDL_ticket **out_ticket); public: + THD *get_thd() const { return m_owner->get_thd(); } void find_deadlock(); ulong get_thread_id() const { return thd_get_thread_id(get_thd()); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fc1d716667e..21a004c4ec6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -648,7 +648,6 @@ bool close_cached_connection_tables(THD *thd, LEX_STRING *connection) static void mark_temp_tables_as_free_for_reuse(THD *thd) { - rpl_group_info *rgi_slave; DBUG_ENTER("mark_temp_tables_as_free_for_reuse"); if (thd->query_id == 0) @@ -657,9 +656,7 @@ static void mark_temp_tables_as_free_for_reuse(THD *thd) DBUG_VOID_RETURN; } - rgi_slave=thd->rgi_slave; - if ((!rgi_slave && thd->temporary_tables) || - (rgi_slave && unlikely(rgi_slave->rli->save_temporary_tables))) + if (thd->have_temporary_tables()) { thd->lock_temporary_tables(); for (TABLE *table= thd->temporary_tables ; table ; table= table->next) @@ -667,15 +664,7 @@ static void mark_temp_tables_as_free_for_reuse(THD *thd) if ((table->query_id == thd->query_id) && ! table->open_by_handler) mark_tmp_table_for_reuse(table); } - thd->unlock_temporary_tables(); - if (rgi_slave) - { - /* - Temporary tables are shared with other by sql execution threads. - As a safety messure, clear the pointer to the common area. - */ - thd->temporary_tables= 0; - } + thd->unlock_temporary_tables(1); } DBUG_VOID_RETURN; } @@ -1643,7 +1632,7 @@ TABLE *find_temporary_table(THD *thd, break; } } - thd->unlock_temporary_tables(); + thd->unlock_temporary_tables(0); return result; } @@ -1746,7 +1735,7 @@ void close_temporary_table(THD *thd, TABLE *table, thread_safe_decrement32(&slave_open_temp_tables, &thread_running_lock); table->in_use= 0; // No statistics } - thd->unlock_temporary_tables(); + thd->unlock_temporary_tables(0); close_temporary(table, free_share, delete_table); DBUG_VOID_RETURN; } @@ -5705,7 +5694,7 @@ TABLE *open_table_uncached(THD *thd, handlerton *hton, { thread_safe_increment32(&slave_open_temp_tables, &thread_running_lock); } - thd->unlock_temporary_tables(); + thd->unlock_temporary_tables(0); } tmp_table->pos_in_table_list= 0; DBUG_PRINT("tmptable", ("opened table: '%s'.'%s' 0x%lx", tmp_table->s->db.str, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1ee5e4b4113..94462924686 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6477,10 +6477,18 @@ void THD::rgi_lock_temporary_tables() temporary_tables= rgi_slave->rli->save_temporary_tables; } -void THD::rgi_unlock_temporary_tables() +void THD::rgi_unlock_temporary_tables(bool clear) { rgi_slave->rli->save_temporary_tables= temporary_tables; mysql_mutex_unlock(&rgi_slave->rli->data_lock); + if (clear) + { + /* + Temporary tables are shared with other by sql execution threads. + As a safety messure, clear the pointer to the common area. + */ + temporary_tables= 0; + } } bool THD::rgi_have_temporary_tables() diff --git a/sql/sql_class.h b/sql/sql_class.h index 46eeeceb112..9da3387e75f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3778,7 +3778,7 @@ private: /* Protect against add/delete of temporary tables in parallel replication */ void rgi_lock_temporary_tables(); - void rgi_unlock_temporary_tables(); + void rgi_unlock_temporary_tables(bool clear); bool rgi_have_temporary_tables(); public: /* @@ -3802,15 +3802,15 @@ public: if (rgi_slave) rgi_lock_temporary_tables(); } - inline void unlock_temporary_tables() + inline void unlock_temporary_tables(bool clear) { if (rgi_slave) - rgi_unlock_temporary_tables(); + rgi_unlock_temporary_tables(clear); } inline bool have_temporary_tables() { return (temporary_tables || - (rgi_slave && rgi_have_temporary_tables())); + (rgi_slave && unlikely(rgi_have_temporary_tables()))); } }; |