Skip to content

Commit f9d81dc

Browse files
authored
Porting/issue 3238 context lock contention fix (#357)
* Fix parallel loading of data parts porting ClickHouse/ClickHouse#34310 on Feb 04, 2022 * Reset thread name in thread pool porting ClickHouse/ClickHouse#36115 on Apr 14, 2022 * ThreadPool fixes porting ClickHouse/ClickHouse#39160 on Jul 14, 2022 * Improve ThreadPool porting ClickHouse/ClickHouse#47657 on Mar 22, 2023 * Lower ThreadPool mutex contention and simplify porting ClickHouse/ClickHouse#48750 on Apr 14 * Fix ThreadPool::wait porting ClickHouse/ClickHouse#49572 on May 6 2023 * ProfileEvents added ContextLockWaitMicroseconds porting ClickHouse/ClickHouse#55029 (on Sep 26, 2023) * Fix race in Context::createCopy porting ClickHouse/ClickHouse#49663 * Use a separate mutex for query_factories_info in Context. porting ClickHouse/ClickHouse#37532 on May 26, 2022 * Avoid possible deadlock on server shutdown porting ClickHouse/ClickHouse#35081 on Mar 7, 2022 * Porting/issue 3238 context lock contention fix part 2 (#313)
1 parent e931bb5 commit f9d81dc

File tree

6 files changed

+653
-317
lines changed

6 files changed

+653
-317
lines changed

base/base/defines.h

+2
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
# define TSA_ACQUIRE_SHARED(...) __attribute__((acquire_shared_capability(__VA_ARGS__))) /// function acquires a shared capability, but does not release it
156156
# define TSA_TRY_ACQUIRE_SHARED(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__))) /// function tries to acquire a shared capability and returns a boolean value indicating success or failure
157157
# define TSA_RELEASE_SHARED(...) __attribute__((release_shared_capability(__VA_ARGS__))) /// function releases the given shared capability
158+
# define TSA_SCOPED_LOCKABLE __attribute__((scoped_lockable)) /// object of a class has scoped lockable capability
158159

159160
/// Macros for suppressing TSA warnings for specific reads/writes (instead of suppressing it for the whole function)
160161
/// They use a lambda function to apply function attribute to a single statement. This enable us to suppress warnings locally instead of
@@ -182,6 +183,7 @@
182183
# define TSA_ACQUIRE_SHARED(...)
183184
# define TSA_TRY_ACQUIRE_SHARED(...)
184185
# define TSA_RELEASE_SHARED(...)
186+
# define TSA_SCOPED_LOCKABLE
185187

186188
# define TSA_SUPPRESS_WARNING_FOR_READ(x) (x)
187189
# define TSA_SUPPRESS_WARNING_FOR_WRITE(x) (x)

src/Common/SharedLockGuard.h

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
3+
#include <base/defines.h>
4+
5+
namespace DB
6+
{
7+
8+
/** SharedLockGuard provide RAII-style locking mechanism for acquiring shared ownership of the implementation
9+
* of the SharedLockable concept (for example std::shared_mutex) supplied as the constructor argument.
10+
* On construction it acquires shared ownership using `lock_shared` method.
11+
* On desruction shared ownership is released using `unlock_shared` method.
12+
*/
13+
template <typename Mutex>
14+
class TSA_SCOPED_LOCKABLE SharedLockGuard
15+
{
16+
public:
17+
explicit SharedLockGuard(Mutex & mutex_) TSA_ACQUIRE_SHARED(mutex_) : mutex(mutex_) { mutex_.lock_shared(); }
18+
19+
~SharedLockGuard() TSA_RELEASE() { mutex.unlock_shared(); }
20+
21+
private:
22+
Mutex & mutex;
23+
};
24+
25+
}

src/Common/SharedMutexHelper.h

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#pragma once
2+
3+
#include <base/types.h>
4+
#include <base/defines.h>
5+
#include <Common/SharedMutex.h>
6+
7+
namespace DB
8+
{
9+
10+
/** SharedMutexHelper class allows to inject specific logic when underlying shared mutex is acquired
11+
* and released.
12+
*
13+
* Example:
14+
*
15+
* class ProfileSharedMutex : public SharedMutexHelper<ProfileSharedMutex>
16+
* {
17+
* public:
18+
* size_t getLockCount() const { return lock_count; }
19+
*
20+
* size_t getSharedLockCount() const { return shared_lock_count; }
21+
*
22+
* private:
23+
* using Base = SharedMutexHelper<ProfileSharedMutex, SharedMutex>;
24+
* friend class SharedMutexHelper<ProfileSharedMutex, SharedMutex>;
25+
*
26+
* void lockImpl()
27+
* {
28+
* ++lock_count;
29+
* Base::lockImpl();
30+
* }
31+
*
32+
* void lockSharedImpl()
33+
* {
34+
* ++shared_lock_count;
35+
* Base::lockSharedImpl();
36+
* }
37+
*
38+
* std::atomic<size_t> lock_count = 0;
39+
* std::atomic<size_t> shared_lock_count = 0;
40+
* };
41+
*/
42+
template <typename Derived, typename MutexType = SharedMutex>
43+
class TSA_CAPABILITY("SharedMutexHelper") SharedMutexHelper
44+
{
45+
public:
46+
// Exclusive ownership
47+
void lock() TSA_ACQUIRE() /// NOLINT
48+
{
49+
static_cast<Derived *>(this)->lockImpl();
50+
}
51+
52+
bool try_lock() TSA_TRY_ACQUIRE(true) /// NOLINT
53+
{
54+
static_cast<Derived *>(this)->tryLockImpl();
55+
}
56+
57+
void unlock() TSA_RELEASE() /// NOLINT
58+
{
59+
static_cast<Derived *>(this)->unlockImpl();
60+
}
61+
62+
// Shared ownership
63+
void lock_shared() TSA_ACQUIRE_SHARED() /// NOLINT
64+
{
65+
static_cast<Derived *>(this)->lockSharedImpl();
66+
}
67+
68+
bool try_lock_shared() TSA_TRY_ACQUIRE_SHARED(true) /// NOLINT
69+
{
70+
static_cast<Derived *>(this)->tryLockSharedImpl();
71+
}
72+
73+
void unlock_shared() TSA_RELEASE_SHARED() /// NOLINT
74+
{
75+
static_cast<Derived *>(this)->unlockSharedImpl();
76+
}
77+
78+
protected:
79+
void lockImpl() TSA_NO_THREAD_SAFETY_ANALYSIS
80+
{
81+
mutex.lock();
82+
}
83+
84+
void tryLockImpl() TSA_NO_THREAD_SAFETY_ANALYSIS
85+
{
86+
mutex.try_lock();
87+
}
88+
89+
void unlockImpl() TSA_NO_THREAD_SAFETY_ANALYSIS
90+
{
91+
mutex.unlock();
92+
}
93+
94+
void lockSharedImpl() TSA_NO_THREAD_SAFETY_ANALYSIS
95+
{
96+
mutex.lock_shared();
97+
}
98+
99+
void tryLockSharedImpl() TSA_NO_THREAD_SAFETY_ANALYSIS
100+
{
101+
mutex.try_lock_shared();
102+
}
103+
104+
void unlockSharedImpl() TSA_NO_THREAD_SAFETY_ANALYSIS
105+
{
106+
mutex.unlock_shared();
107+
}
108+
109+
MutexType mutex;
110+
};
111+
112+
}

src/Common/callOnce.h

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
3+
#include <mutex>
4+
5+
namespace DB
6+
{
7+
8+
using OnceFlag = std::once_flag;
9+
10+
template <typename Callable, typename ...Args>
11+
void callOnce(OnceFlag & flag, Callable && func, Args&&... args)
12+
{
13+
std::call_once(flag, std::forward<Callable>(func), std::forward<Args>(args)...);
14+
}
15+
16+
}

0 commit comments

Comments
 (0)