]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
2 | // This source code is licensed under both the GPLv2 (found in the |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
7c673cae FG |
5 | |
6 | #ifndef ROCKSDB_LITE | |
7 | ||
8 | #include "utilities/transactions/transaction_db_mutex_impl.h" | |
9 | ||
10 | #include <chrono> | |
11 | #include <condition_variable> | |
12 | #include <functional> | |
13 | #include <mutex> | |
14 | ||
15 | #include "rocksdb/utilities/transaction_db_mutex.h" | |
16 | ||
f67539c2 | 17 | namespace ROCKSDB_NAMESPACE { |
7c673cae FG |
18 | |
19 | class TransactionDBMutexImpl : public TransactionDBMutex { | |
20 | public: | |
21 | TransactionDBMutexImpl() {} | |
494da23a | 22 | ~TransactionDBMutexImpl() override {} |
7c673cae FG |
23 | |
24 | Status Lock() override; | |
25 | ||
26 | Status TryLockFor(int64_t timeout_time) override; | |
27 | ||
28 | void UnLock() override { mutex_.unlock(); } | |
29 | ||
30 | friend class TransactionDBCondVarImpl; | |
31 | ||
32 | private: | |
33 | std::mutex mutex_; | |
34 | }; | |
35 | ||
36 | class TransactionDBCondVarImpl : public TransactionDBCondVar { | |
37 | public: | |
38 | TransactionDBCondVarImpl() {} | |
494da23a | 39 | ~TransactionDBCondVarImpl() override {} |
7c673cae FG |
40 | |
41 | Status Wait(std::shared_ptr<TransactionDBMutex> mutex) override; | |
42 | ||
43 | Status WaitFor(std::shared_ptr<TransactionDBMutex> mutex, | |
44 | int64_t timeout_time) override; | |
45 | ||
46 | void Notify() override { cv_.notify_one(); } | |
47 | ||
48 | void NotifyAll() override { cv_.notify_all(); } | |
49 | ||
50 | private: | |
51 | std::condition_variable cv_; | |
52 | }; | |
53 | ||
54 | std::shared_ptr<TransactionDBMutex> | |
55 | TransactionDBMutexFactoryImpl::AllocateMutex() { | |
56 | return std::shared_ptr<TransactionDBMutex>(new TransactionDBMutexImpl()); | |
57 | } | |
58 | ||
59 | std::shared_ptr<TransactionDBCondVar> | |
60 | TransactionDBMutexFactoryImpl::AllocateCondVar() { | |
61 | return std::shared_ptr<TransactionDBCondVar>(new TransactionDBCondVarImpl()); | |
62 | } | |
63 | ||
64 | Status TransactionDBMutexImpl::Lock() { | |
65 | mutex_.lock(); | |
66 | return Status::OK(); | |
67 | } | |
68 | ||
69 | Status TransactionDBMutexImpl::TryLockFor(int64_t timeout_time) { | |
70 | bool locked = true; | |
71 | ||
72 | if (timeout_time == 0) { | |
73 | locked = mutex_.try_lock(); | |
74 | } else { | |
75 | // Previously, this code used a std::timed_mutex. However, this was changed | |
76 | // due to known bugs in gcc versions < 4.9. | |
77 | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54562 | |
78 | // | |
79 | // Since this mutex isn't held for long and only a single mutex is ever | |
80 | // held at a time, it is reasonable to ignore the lock timeout_time here | |
81 | // and only check it when waiting on the condition_variable. | |
82 | mutex_.lock(); | |
83 | } | |
84 | ||
85 | if (!locked) { | |
86 | // timeout acquiring mutex | |
87 | return Status::TimedOut(Status::SubCode::kMutexTimeout); | |
88 | } | |
89 | ||
90 | return Status::OK(); | |
91 | } | |
92 | ||
93 | Status TransactionDBCondVarImpl::Wait( | |
94 | std::shared_ptr<TransactionDBMutex> mutex) { | |
95 | auto mutex_impl = reinterpret_cast<TransactionDBMutexImpl*>(mutex.get()); | |
96 | ||
97 | std::unique_lock<std::mutex> lock(mutex_impl->mutex_, std::adopt_lock); | |
98 | cv_.wait(lock); | |
99 | ||
100 | // Make sure unique_lock doesn't unlock mutex when it destructs | |
101 | lock.release(); | |
102 | ||
103 | return Status::OK(); | |
104 | } | |
105 | ||
106 | Status TransactionDBCondVarImpl::WaitFor( | |
107 | std::shared_ptr<TransactionDBMutex> mutex, int64_t timeout_time) { | |
108 | Status s; | |
109 | ||
110 | auto mutex_impl = reinterpret_cast<TransactionDBMutexImpl*>(mutex.get()); | |
111 | std::unique_lock<std::mutex> lock(mutex_impl->mutex_, std::adopt_lock); | |
112 | ||
113 | if (timeout_time < 0) { | |
114 | // If timeout is negative, do not use a timeout | |
115 | cv_.wait(lock); | |
116 | } else { | |
117 | auto duration = std::chrono::microseconds(timeout_time); | |
118 | auto cv_status = cv_.wait_for(lock, duration); | |
119 | ||
120 | // Check if the wait stopped due to timing out. | |
121 | if (cv_status == std::cv_status::timeout) { | |
122 | s = Status::TimedOut(Status::SubCode::kMutexTimeout); | |
123 | } | |
124 | } | |
125 | ||
126 | // Make sure unique_lock doesn't unlock mutex when it destructs | |
127 | lock.release(); | |
128 | ||
129 | // CV was signaled, or we spuriously woke up (but didn't time out) | |
130 | return s; | |
131 | } | |
132 | ||
f67539c2 | 133 | } // namespace ROCKSDB_NAMESPACE |
7c673cae FG |
134 | |
135 | #endif // ROCKSDB_LITE |