From: Andrei Elkin Date: November 21 2012 7:49am Subject: bzr push into mysql-trunk branch (andrei.elkin:5055 to 5056) List-Archive: http://lists.mysql.com/commits/145340 Message-Id: <201211210749.qAL7nheB027394@mysql1000.dsl.inet.fi> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 5056 Andrei Elkin 2012-11-21 [merge] merge from 5.6 bugfixing branch. modified: sql/binlog.cc sql/binlog.h sql/sql_class.h 5055 Sunny Bains 2012-11-21 [merge] Merge from mysql-5.6. modified: storage/innobase/include/trx0purge.h storage/innobase/srv/srv0srv.cc storage/innobase/trx/trx0purge.cc === modified file 'sql/binlog.cc' --- a/sql/binlog.cc revid:sunny.bains@stripped +++ b/sql/binlog.cc revid:andrei.elkin@stripped @@ -1334,6 +1334,16 @@ Stage_manager::enroll_for(StageID stage, if (!leader) { mysql_mutex_lock(&m_lock_done); +#ifndef DBUG_OFF + /* + Leader can be awaiting all-clear to preempt follower's execution. + With setting the status the follower ensures it won't execute anything + including thread-specific code. + */ + thd->transaction.flags.ready_preempt= 1; + if (leader_await_preempt_status) + mysql_cond_signal(&m_cond_preempt); +#endif while (thd->transaction.flags.pending) mysql_cond_wait(&m_cond_done, &m_lock_done); mysql_mutex_unlock(&m_lock_done); @@ -1361,6 +1371,22 @@ THD *Stage_manager::Mutex_queue::fetch_a DBUG_RETURN(result); } +#ifndef DBUG_OFF +void Stage_manager::clear_preempt_status(THD *head) +{ + DBUG_ASSERT(head); + + mysql_mutex_lock(&m_lock_done); + while(!head->transaction.flags.ready_preempt) + { + leader_await_preempt_status= true; + mysql_cond_wait(&m_cond_preempt, &m_lock_done); + } + leader_await_preempt_status= false; + mysql_mutex_unlock(&m_lock_done); +} +#endif + /** Write a rollback record of the transaction to the binary log. @@ -6005,6 +6031,9 @@ MYSQL_BIN_LOG::process_commit_stage_queu { mysql_mutex_assert_owner(&LOCK_commit); Thread_excursion excursion(thd); +#ifndef DBUG_OFF + thd->transaction.flags.ready_preempt= 1; // formality by the leader +#endif for (THD *head= first ; head ; head = head->next_to_commit) { DBUG_PRINT("debug", ("Thread ID: %lu, commit_error: %d, flags.pending: %s", @@ -6018,6 +6047,9 @@ MYSQL_BIN_LOG::process_commit_stage_queu If flush succeeded, attach to the session and commit it in the engines. */ +#ifndef DBUG_OFF + stage_manager.clear_preempt_status(head); +#endif if (flush_error != 0) head->commit_error= flush_error; else if (int error= excursion.attach_to(head)) @@ -6027,6 +6059,9 @@ MYSQL_BIN_LOG::process_commit_stage_queu bool all= head->transaction.flags.real_commit; if (head->transaction.flags.commit_low) { + /* head is parked to have exited append() */ + DBUG_ASSERT(head->transaction.flags.ready_preempt); + if (int error= ha_commit_low(head, all)) head->commit_error= error; else if (head->transaction.flags.xid_written) @@ -6265,6 +6300,17 @@ int MYSQL_BIN_LOG::ordered_commit(THD *t thd->transaction.flags.real_commit= all; thd->transaction.flags.xid_written= false; thd->transaction.flags.commit_low= !skip_commit; +#ifndef DBUG_OFF + /* + The group commit Leader may have to wait for follower whose transaction + is not ready to be preempted. Initially the status is pessimistic. + Preemption guarding logics is necessary only when DBUG_ON is set. + It won't be required for the dbug-off case as long as the follower won't + execute any thread-specific write access code in this method, which is + the case as of current. + */ + thd->transaction.flags.ready_preempt= 0; +#endif DBUG_PRINT("enter", ("flags.pending: %s, commit_error: %d, thread_id: %lu", YESNO(thd->transaction.flags.pending), === modified file 'sql/binlog.h' --- a/sql/binlog.h revid:sunny.bains@stripped +++ b/sql/binlog.h revid:andrei.elkin@stripped @@ -119,6 +119,10 @@ public: { mysql_mutex_init(key_LOCK_done, &m_lock_done, MY_MUTEX_INIT_FAST); mysql_cond_init(key_COND_done, &m_cond_done, NULL); +#ifndef DBUG_OFF + /* reuse key_COND_done 'cos a new PSI object would be wasteful in DBUG_ON */ + mysql_cond_init(key_COND_done, &m_cond_preempt, NULL); +#endif m_queue[FLUSH_STAGE].init( #ifdef HAVE_PSI_INTERFACE key_LOCK_flush_queue @@ -155,6 +159,7 @@ public: If wait_if_follower is true the thread is not the stage leader, the thread will be wait for the queue to be processed by the leader before it returns. + In DBUG-ON version the follower marks is preempt status as ready. @param stage Stage identifier for the queue to append to. @param first Queue to append. @@ -172,6 +177,17 @@ public: return m_queue[stage].pop_front(); } +#ifndef DBUG_OFF + /** + The method ensures the follower's execution path can be preempted + by the leader's thread. + Preempt status of @c head follower is checked to engange the leader + into waiting when set. + + @param head THD* of a follower thread + */ + void clear_preempt_status(THD *head); +#endif /** Fetch the entire queue and empty it. @@ -206,6 +222,13 @@ private: /** Mutex used for the condition variable above */ mysql_mutex_t m_lock_done; +#ifndef DBUG_OFF + /** Flag is set by Leader when it starts waiting for follower's all-clear */ + bool leader_await_preempt_status; + + /** Condition variable to indicate a follower started waiting for commit */ + mysql_cond_t m_cond_preempt; +#endif }; === modified file 'sql/sql_class.h' --- a/sql/sql_class.h revid:sunny.bains@stripped +++ b/sql/sql_class.h revid:andrei.elkin@stripped @@ -2325,6 +2325,9 @@ public: bool xid_written:1; // The session wrote an XID bool real_commit:1; // Is this a "real" commit? bool commit_low:1; // see MYSQL_BIN_LOG::ordered_commit +#ifndef DBUG_OFF + bool ready_preempt:1; // internal in MYSQL_BIN_LOG::ordered_commit +#endif } flags; void cleanup() No bundle (reason: useless for push emails).