mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-26 09:32:01 +00:00
Use executors snapshot
This commit is contained in:
parent
849fac672a
commit
aa776d00fe
@ -397,23 +397,26 @@ CancellationCode QueryStatus::cancelQuery(bool)
|
||||
|
||||
is_killed.store(true);
|
||||
|
||||
std::unique_lock lock(executors_mutex);
|
||||
for (const auto & e : executors)
|
||||
std::vector<ExecutorHolderPtr> executors_snapshot;
|
||||
|
||||
{
|
||||
/// We should call cancel() with unlocked executors_mutex, because
|
||||
/// cancel() can try to lock some internal mutex that is already locked by query executing
|
||||
/// thread, and query executing thread can call removePipelineExecutor and lock executors_mutex,
|
||||
/// which will lead to deadlock.
|
||||
/// Note that the size and the content of executors cannot be changed while
|
||||
/// executors_mutex is unlocked, because:
|
||||
/// 1) We don't allow adding new executors while cancelling query in addPipelineExecutor
|
||||
/// 2) We don't actually remove executor holder from executors in removePipelineExecutor,
|
||||
/// just mark that executor is invalid.
|
||||
/// So, it's safe to continue iteration over executors after subsequent mutex locking.
|
||||
lock.unlock();
|
||||
e->cancel();
|
||||
lock.lock();
|
||||
/// Create a snapshot of executors under a mutex.
|
||||
std::lock_guard lock(executors_mutex);
|
||||
executors_snapshot = executors;
|
||||
}
|
||||
|
||||
/// We should call cancel() for each executor with unlocked executors_mutex, because
|
||||
/// cancel() can try to lock some internal mutex that is already locked by query executing
|
||||
/// thread, and query executing thread can call removePipelineExecutor and lock executors_mutex,
|
||||
/// which will lead to deadlock.
|
||||
/// Note that the size and the content of executors cannot be changed while
|
||||
/// executors_mutex is unlocked, because:
|
||||
/// 1) We don't allow adding new executors while cancelling query in addPipelineExecutor
|
||||
/// 2) We don't actually remove executor holder from executors in removePipelineExecutor,
|
||||
/// just mark that executor is invalid.
|
||||
/// So, it's ok to use a snapshot created above under a mutex, it won't be any differ from actual executors.
|
||||
for (const auto & e : executors_shapshot)
|
||||
e->cancel();
|
||||
|
||||
return CancellationCode::CancelSent;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user