summaryrefslogtreecommitdiff
path: root/sql/sql_class.h
diff options
context:
space:
mode:
authorunknown <knielsen@knielsen-hq.org>2013-11-01 09:17:06 +0100
committerunknown <knielsen@knielsen-hq.org>2013-11-01 09:17:06 +0100
commitcb86ce60b9bade5ae7712d8f3f74668208ee3fd2 (patch)
treedaff81c02baa6c2581d6abe3d746b8f35ee44f32 /sql/sql_class.h
parentf4d5d849fd3b526d38ca6eb083fd0b290eb0eda7 (diff)
parent39df665a3332bd9bfb2529419f534a49cfac388c (diff)
downloadmariadb-git-cb86ce60b9bade5ae7712d8f3f74668208ee3fd2.tar.gz
Merge MDEV-4506: Parallel replication into 10.0-base.
Diffstat (limited to 'sql/sql_class.h')
-rw-r--r--sql/sql_class.h158
1 files changed, 157 insertions, 1 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 13a3adf5909..de3357212a3 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -47,6 +47,7 @@
class Reprepare_observer;
class Relay_log_info;
+struct rpl_group_info;
class Rpl_filter;
class Query_log_event;
@@ -1556,6 +1557,120 @@ private:
};
+/*
+ Class to facilitate the commit of one transactions waiting for the commit of
+ another transaction to complete first.
+
+ This is used during (parallel) replication, to allow different transactions
+ to be applied in parallel, but still commit in order.
+
+ The transaction that wants to wait for a prior commit must first register
+ to wait with register_wait_for_prior_commit(waitee). Such registration
+ must be done holding the waitee->LOCK_wait_commit, to prevent the other
+ THD from disappearing during the registration.
+
+ Then during commit, if a THD is registered to wait, it will call
+ wait_for_prior_commit() as part of ha_commit_trans(). If no wait is
+ registered, or if the waitee for has already completed commit, then
+ wait_for_prior_commit() returns immediately.
+
+ And when a THD that may be waited for has completed commit (more precisely
+ commit_ordered()), then it must call wakeup_subsequent_commits() to wake
+ up any waiters. Note that this must be done at a point that is guaranteed
+ to be later than any waiters registering themselves. It is safe to call
+ wakeup_subsequent_commits() multiple times, as waiters are removed from
+ registration as part of the wakeup.
+
+ The reason for separate register and wait calls is that this allows to
+ register the wait early, at a point where the waited-for THD is known to
+ exist. And then the actual wait can be done much later, where the
+ waited-for THD may have been long gone. By registering early, the waitee
+ can signal before disappearing.
+*/
+struct wait_for_commit
+{
+ /*
+ The LOCK_wait_commit protects the fields subsequent_commits_list and
+ wakeup_subsequent_commits_running (for a waitee), and the flag
+ waiting_for_commit and associated COND_wait_commit (for a waiter).
+ */
+ mysql_mutex_t LOCK_wait_commit;
+ mysql_cond_t COND_wait_commit;
+ /* List of threads that did register_wait_for_prior_commit() on us. */
+ wait_for_commit *subsequent_commits_list;
+ /* Link field for entries in subsequent_commits_list. */
+ wait_for_commit *next_subsequent_commit;
+ /* Our waitee, if we did register_wait_for_prior_commit(), else NULL. */
+ wait_for_commit *waitee;
+ /*
+ Generic pointer for use by the transaction coordinator to optimise the
+ waiting for improved group commit.
+
+ Currently used by binlog TC to signal that a waiter is ready to commit, so
+ that the waitee can grab it and group commit it directly. It is free to be
+ used by another transaction coordinator for similar purposes.
+ */
+ void *opaque_pointer;
+ /*
+ The waiting_for_commit flag is cleared when a waiter has been woken
+ up. The COND_wait_commit condition is signalled when this has been
+ cleared.
+ */
+ bool waiting_for_commit;
+ /* The wakeup error code from the waitee. 0 means no error. */
+ int wakeup_error;
+ /*
+ Flag set when wakeup_subsequent_commits_running() is active, see comments
+ on that function for details.
+ */
+ bool wakeup_subsequent_commits_running;
+
+ void register_wait_for_prior_commit(wait_for_commit *waitee);
+ int wait_for_prior_commit()
+ {
+ /*
+ Quick inline check, to avoid function call and locking in the common case
+ where no wakeup is registered, or a registered wait was already signalled.
+ */
+ if (waiting_for_commit)
+ return wait_for_prior_commit2();
+ else
+ return wakeup_error;
+ }
+ void wakeup_subsequent_commits(int wakeup_error)
+ {
+ /*
+ Do the check inline, so only the wakeup case takes the cost of a function
+ call for every commmit.
+
+ Note that the check is done without locking. It is the responsibility of
+ the user of the wakeup facility to ensure that no waiters can register
+ themselves after the last call to wakeup_subsequent_commits().
+
+ This avoids having to take another lock for every commit, which would be
+ pointless anyway - even if we check under lock, there is nothing to
+ prevent a waiter from arriving just after releasing the lock.
+ */
+ if (subsequent_commits_list)
+ wakeup_subsequent_commits2(wakeup_error);
+ }
+ void unregister_wait_for_prior_commit()
+ {
+ if (waiting_for_commit)
+ unregister_wait_for_prior_commit2();
+ }
+
+ void wakeup(int wakeup_error);
+
+ int wait_for_prior_commit2();
+ void wakeup_subsequent_commits2(int wakeup_error);
+ void unregister_wait_for_prior_commit2();
+
+ wait_for_commit();
+ ~wait_for_commit();
+};
+
+
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
class THD;
@@ -1590,8 +1705,9 @@ public:
/* Used to execute base64 coded binlog events in MySQL server */
Relay_log_info* rli_fake;
+ rpl_group_info* rgi_fake;
/* Slave applier execution context */
- Relay_log_info* rli_slave;
+ rpl_group_info* rgi_slave;
/* Used to SLAVE SQL thread */
Rpl_filter* rpl_filter;
@@ -3207,6 +3323,25 @@ public:
void wait_for_wakeup_ready();
/* Wake this thread up from wait_for_wakeup_ready(). */
void signal_wakeup_ready();
+
+ wait_for_commit *wait_for_commit_ptr;
+ int wait_for_prior_commit()
+ {
+ if (wait_for_commit_ptr)
+ {
+ int err= wait_for_commit_ptr->wait_for_prior_commit();
+ if (err)
+ my_error(ER_PRIOR_COMMIT_FAILED, MYF(0));
+ return err;
+ }
+ return 0;
+ }
+ void wakeup_subsequent_commits(int wakeup_error)
+ {
+ if (wait_for_commit_ptr)
+ wait_for_commit_ptr->wakeup_subsequent_commits(wakeup_error);
+ }
+
private:
/** The current internal error handler for this thread, or NULL. */
@@ -3260,6 +3395,27 @@ private:
bool wakeup_ready;
mysql_mutex_t LOCK_wakeup_ready;
mysql_cond_t COND_wakeup_ready;
+
+ /* Protect against add/delete of temporary tables in parallel replication */
+ void rgi_lock_temporary_tables();
+ void rgi_unlock_temporary_tables();
+ bool rgi_have_temporary_tables();
+public:
+ inline void lock_temporary_tables()
+ {
+ if (rgi_slave)
+ rgi_lock_temporary_tables();
+ }
+ inline void unlock_temporary_tables()
+ {
+ if (rgi_slave)
+ rgi_unlock_temporary_tables();
+ }
+ inline bool have_temporary_tables()
+ {
+ return (temporary_tables ||
+ (rgi_slave && rgi_have_temporary_tables()));
+ }
};