1#pragma once
2
3#include <Core/Types.h>
4
5#include <list>
6#include <vector>
7#include <mutex>
8#include <condition_variable>
9#include <map>
10#include <string>
11#include <unordered_map>
12
13
14namespace DB
15{
16
17class RWLockImpl;
18using RWLock = std::shared_ptr<RWLockImpl>;
19
20
21/// Implements shared lock with FIFO service
22/// Can be acquired recursively (several calls for the same query) in Read mode
23///
24/// NOTE: it is important to allow acquiring the same lock in Read mode without waiting if it is already
25/// acquired by another thread of the same query. Otherwise the following deadlock is possible:
26/// - SELECT thread 1 locks in the Read mode
27/// - ALTER tries to lock in the Write mode (waits for SELECT thread 1)
28/// - SELECT thread 2 tries to lock in the Read mode (waits for ALTER)
29class RWLockImpl : public std::enable_shared_from_this<RWLockImpl>
30{
31public:
32 enum Type
33 {
34 Read,
35 Write,
36 };
37
38 static RWLock create() { return RWLock(new RWLockImpl); }
39
40 /// Just use LockHolder::reset() to release the lock
41 class LockHolderImpl;
42 friend class LockHolderImpl;
43 using LockHolder = std::shared_ptr<LockHolderImpl>;
44
45 /// Waits in the queue and returns appropriate lock
46 /// Empty query_id means the lock is acquired out of the query context (e.g. in a background thread).
47 LockHolder getLock(Type type, const String & query_id);
48
49 /// Use as query_id to acquire a lock outside the query context.
50 inline static const String NO_QUERY = String();
51
52private:
53 RWLockImpl() = default;
54
55 struct Group;
56 using GroupsContainer = std::list<Group>;
57 using OwnerQueryIds = std::unordered_map<String, size_t>;
58
59 /// Group of locking requests that should be granted concurrently
60 /// i.e. a group can contain several readers, but only one writer
61 struct Group
62 {
63 const Type type;
64 size_t refererrs;
65
66 std::condition_variable cv; /// all locking requests of the group wait on this condvar
67
68 explicit Group(Type type_) : type{type_}, refererrs{0} {}
69 };
70
71 GroupsContainer queue;
72 OwnerQueryIds owner_queries;
73
74 mutable std::mutex mutex;
75};
76
77
78}
79