Skip to content

Commit 96bb73a

Browse files
authored
Merge pull request ceph#56844 from cyx1231st/wip-crimson-fix-tri-mutex
crimson/common/tri_mutex: make locking/promotion atomic if possible Reviewed-by: Samuel Just <[email protected]> Reviewed-by: Kefu Chai <[email protected]>
2 parents be964d8 + 676947e commit 96bb73a

File tree

3 files changed

+41
-49
lines changed

3 files changed

+41
-49
lines changed

src/crimson/common/tri_mutex.cc

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include "tri_mutex.h"
55

6+
#include <seastar/util/later.hh>
7+
68
seastar::future<> read_lock::lock()
79
{
810
return static_cast<tri_mutex*>(this)->lock_for_read();
@@ -15,7 +17,7 @@ void read_lock::unlock()
1517

1618
seastar::future<> write_lock::lock()
1719
{
18-
return static_cast<tri_mutex*>(this)->lock_for_write(false);
20+
return static_cast<tri_mutex*>(this)->lock_for_write();
1921
}
2022

2123
void write_lock::unlock()
@@ -33,37 +35,26 @@ void excl_lock::unlock()
3335
static_cast<tri_mutex*>(this)->unlock_for_excl();
3436
}
3537

36-
seastar::future<> excl_lock_from_read::lock()
38+
void excl_lock_from_read::lock()
3739
{
3840
static_cast<tri_mutex*>(this)->promote_from_read();
39-
return seastar::make_ready_future<>();
4041
}
4142

4243
void excl_lock_from_read::unlock()
4344
{
4445
static_cast<tri_mutex*>(this)->demote_to_read();
4546
}
4647

47-
seastar::future<> excl_lock_from_write::lock()
48+
void excl_lock_from_write::lock()
4849
{
4950
static_cast<tri_mutex*>(this)->promote_from_write();
50-
return seastar::make_ready_future<>();
5151
}
5252

5353
void excl_lock_from_write::unlock()
5454
{
5555
static_cast<tri_mutex*>(this)->demote_to_write();
5656
}
5757

58-
seastar::future<> excl_lock_from_excl::lock()
59-
{
60-
return seastar::make_ready_future<>();
61-
}
62-
63-
void excl_lock_from_excl::unlock()
64-
{
65-
}
66-
6758
tri_mutex::~tri_mutex()
6859
{
6960
assert(!is_acquired());
@@ -72,7 +63,7 @@ tri_mutex::~tri_mutex()
7263
seastar::future<> tri_mutex::lock_for_read()
7364
{
7465
if (try_lock_for_read()) {
75-
return seastar::make_ready_future<>();
66+
return seastar::now();
7667
}
7768
waiters.emplace_back(seastar::promise<>(), type_t::read);
7869
return waiters.back().pr.get_future();
@@ -110,19 +101,19 @@ void tri_mutex::demote_to_read()
110101
++readers;
111102
}
112103

113-
seastar::future<> tri_mutex::lock_for_write(bool greedy)
104+
seastar::future<> tri_mutex::lock_for_write()
114105
{
115-
if (try_lock_for_write(greedy)) {
116-
return seastar::make_ready_future<>();
106+
if (try_lock_for_write()) {
107+
return seastar::now();
117108
}
118109
waiters.emplace_back(seastar::promise<>(), type_t::write);
119110
return waiters.back().pr.get_future();
120111
}
121112

122-
bool tri_mutex::try_lock_for_write(bool greedy) noexcept
113+
bool tri_mutex::try_lock_for_write() noexcept
123114
{
124115
if (!readers && !exclusively_used) {
125-
if (greedy || waiters.empty()) {
116+
if (waiters.empty()) {
126117
++writers;
127118
return true;
128119
}
@@ -156,7 +147,7 @@ void tri_mutex::demote_to_write()
156147
seastar::future<> tri_mutex::lock_for_excl()
157148
{
158149
if (try_lock_for_excl()) {
159-
return seastar::make_ready_future<>();
150+
return seastar::now();
160151
}
161152
waiters.emplace_back(seastar::promise<>(), type_t::exclusive);
162153
return waiters.back().pr.get_future();

src/crimson/common/tri_mutex.h

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,38 @@ class excl_lock {
2727
// promote from read to excl
2828
class excl_lock_from_read {
2929
public:
30-
seastar::future<> lock();
30+
void lock();
3131
void unlock();
3232
};
3333

3434
// promote from write to excl
3535
class excl_lock_from_write {
3636
public:
37-
seastar::future<> lock();
38-
void unlock();
39-
};
40-
41-
// promote from excl to excl
42-
class excl_lock_from_excl {
43-
public:
44-
seastar::future<> lock();
37+
void lock();
4538
void unlock();
4639
};
4740

4841
/// shared/exclusive mutual exclusion
4942
///
50-
/// this lock design uses reader and writer is entirely and completely
51-
/// independent of the conventional reader/writer lock usage. Here, what we
52-
/// mean is that we can pipeline reads, and we can pipeline writes, but we
53-
/// cannot allow a read while writes are in progress or a write while reads are
54-
/// in progress. Any rmw operation is therefore exclusive.
43+
/// Unlike reader/write lock, tri_mutex does not enforce the exclusive access
44+
/// of write operations, on the contrary, multiple write operations are allowed
45+
/// to hold the same tri_mutex at the same time. Here, what we mean is that we
46+
/// can pipeline reads, and we can pipeline writes, but we cannot allow a read
47+
/// while writes are in progress or a write while reads are in progress.
5548
///
5649
/// tri_mutex is based on seastar::shared_mutex, but instead of two kinds of
5750
/// waiters, tri_mutex keeps track of three kinds of lock users:
5851
/// - readers
5952
/// - writers
6053
/// - exclusive users
54+
///
55+
/// For lock promotion, a read or a write lock is only allowed to be promoted
56+
/// atomically upon the first locking.
6157
class tri_mutex : private read_lock,
6258
write_lock,
6359
excl_lock,
6460
excl_lock_from_read,
65-
excl_lock_from_write,
66-
excl_lock_from_excl
61+
excl_lock_from_write
6762
{
6863
public:
6964
tri_mutex() = default;
@@ -84,9 +79,6 @@ class tri_mutex : private read_lock,
8479
excl_lock_from_write& excl_from_write() {
8580
return *this;
8681
}
87-
excl_lock_from_excl& excl_from_excl() {
88-
return *this;
89-
}
9082

9183
// for shared readers
9284
seastar::future<> lock_for_read();
@@ -99,8 +91,8 @@ class tri_mutex : private read_lock,
9991
}
10092

10193
// for shared writers
102-
seastar::future<> lock_for_write(bool greedy);
103-
bool try_lock_for_write(bool greedy) noexcept;
94+
seastar::future<> lock_for_write();
95+
bool try_lock_for_write() noexcept;
10496
void unlock_for_write();
10597
void promote_from_write();
10698
void demote_to_write();

src/crimson/osd/object_context.h

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class ObjectContext : public ceph::common::intrusive_lru_base<
121121
bool recovery_read_marker = false;
122122

123123
template <typename Lock, typename Func>
124-
auto _with_lock(Lock&& lock, Func&& func) {
124+
auto _with_lock(Lock& lock, Func&& func) {
125125
Ref obc = this;
126126
return lock.lock().then([&lock, func = std::forward<Func>(func), obc]() mutable {
127127
return seastar::futurize_invoke(func).finally([&lock, obc] {
@@ -130,6 +130,15 @@ class ObjectContext : public ceph::common::intrusive_lru_base<
130130
});
131131
}
132132

133+
template <typename Lock, typename Func>
134+
auto _with_promoted_lock(Lock& lock, Func&& func) {
135+
Ref obc = this;
136+
lock.lock();
137+
return seastar::futurize_invoke(func).finally([&lock, obc] {
138+
lock.unlock();
139+
});
140+
}
141+
133142
boost::intrusive::list_member_hook<> obc_accessing_hook;
134143
uint64_t list_link_cnt = 0;
135144
bool fully_loaded = false;
@@ -196,11 +205,11 @@ class ObjectContext : public ceph::common::intrusive_lru_base<
196205
auto wrapper = ::crimson::interruptible::interruptor<InterruptCond>::wrap_function(std::forward<Func>(func));
197206
switch (Type) {
198207
case RWState::RWWRITE:
199-
return _with_lock(lock.excl_from_write(), std::move(wrapper));
208+
return _with_promoted_lock(lock.excl_from_write(), std::move(wrapper));
200209
case RWState::RWREAD:
201-
return _with_lock(lock.excl_from_read(), std::move(wrapper));
210+
return _with_promoted_lock(lock.excl_from_read(), std::move(wrapper));
202211
case RWState::RWEXCL:
203-
return _with_lock(lock.excl_from_excl(), std::move(wrapper));
212+
return seastar::futurize_invoke(std::move(wrapper));
204213
case RWState::RWNONE:
205214
return _with_lock(lock.for_excl(), std::move(wrapper));
206215
default:
@@ -209,11 +218,11 @@ class ObjectContext : public ceph::common::intrusive_lru_base<
209218
} else {
210219
switch (Type) {
211220
case RWState::RWWRITE:
212-
return _with_lock(lock.excl_from_write(), std::forward<Func>(func));
221+
return _with_promoted_lock(lock.excl_from_write(), std::forward<Func>(func));
213222
case RWState::RWREAD:
214-
return _with_lock(lock.excl_from_read(), std::forward<Func>(func));
223+
return _with_promoted_lock(lock.excl_from_read(), std::forward<Func>(func));
215224
case RWState::RWEXCL:
216-
return _with_lock(lock.excl_from_excl(), std::forward<Func>(func));
225+
return seastar::futurize_invoke(std::forward<Func>(func));
217226
case RWState::RWNONE:
218227
return _with_lock(lock.for_excl(), std::forward<Func>(func));
219228
default:

0 commit comments

Comments
 (0)