summaryrefslogtreecommitdiff
path: root/sql/mdl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/mdl.cc')
-rw-r--r--sql/mdl.cc53
1 files changed, 53 insertions, 0 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);