I think that queries and threads become ordered such way to trigger the crash easily with threadpool enabled. I think issue is not threadpool-specific, but is much easier to reproduce with threadpool. So far I had no luck reproducing the crash without threadpool. DEBUG_SYNC is also not much of use because group commit messing with THD and PSI of current thread.
As a workaround we can disable PSI instrumentation of follower thread until leader not done with commit. Just set PSI_thread to NULL in following method:
Stage_manager::enroll_for(StageID stage, THD *thd, mysql_mutex_t *stage_mutex)
{
// If the queue was empty: we're the leader for this batch
DBUG_PRINT("debug", ("Enqueue 0x%llx to queue for stage %d", (ulonglong) thd, stage));
bool leader= m_queue[stage].append(thd);
/*
The stage mutex can be NULL if we are enrolling for the first
stage.
*/
if (stage_mutex)
mysql_mutex_unlock(stage_mutex);
/*
If the queue was not empty, we're a follower and wait for the
leader to process the queue. If we were holding a mutex, we have
to release it before going to sleep.
*/
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);
}
return leader;
}
I think that queries and threads become ordered such way to trigger the crash easily with threadpool enabled. I think issue is not threadpool- specific, but is much easier to reproduce with threadpool. So far I had no luck reproducing the crash without threadpool. DEBUG_SYNC is also not much of use because group commit messing with THD and PSI of current thread.
As a workaround we can disable PSI instrumentation of follower thread until leader not done with commit. Just set PSI_thread to NULL in following method:
Stage_manager: :enroll_ for(StageID stage, THD *thd, mysql_mutex_t *stage_mutex) PRINT(" debug", ("Enqueue 0x%llx to queue for stage %d",
(ulonglong) thd, stage)); stage]. append( thd);
{
// If the queue was empty: we're the leader for this batch
DBUG_
bool leader= m_queue[
/* mutex_unlock( stage_mutex) ;
The stage mutex can be NULL if we are enrolling for the first
stage.
*/
if (stage_mutex)
mysql_
/* mutex_lock( &m_lock_ done); >transaction. flags.ready_ preempt= 1; await_preempt_ status) cond_signal( &m_cond_ preempt) ; on.flags. pending) { cond_wait( &m_cond_ done, &m_lock_done); mutex_unlock( &m_lock_ done);
If the queue was not empty, we're a follower and wait for the
leader to process the queue. If we were holding a mutex, we have
to release it before going to sleep.
*/
if (!leader)
{
mysql_
#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-
if (leader_
mysql_
#endif
while (thd->transacti
mysql_
}
mysql_
}
return leader;
}