Skip to content

Commit ebafc73

Browse files
Anton Likhtarovfacebook-github-bot
authored andcommitted
Reduce lock contention in InFlightPuts
Summary: invalidateToken() is called on the hot miss path in NvmCache::find(). We can avoid the exclusive lock by changing the valid state to an atomic, as the only transition is true -> false. Use TimedRWMutexWritePriority to avoid readers starving writers: if we have a request waiting to fill from NVM, always allow it to succeed first before queueing up additional readers. Reviewed By: AlnisM Differential Revision: D81963166 fbshipit-source-id: e1c3d33bfc5b0a5f008e68d1b694997329921608
1 parent 1997207 commit ebafc73

File tree

1 file changed

+13
-12
lines changed

1 file changed

+13
-12
lines changed

cachelib/allocator/nvmcache/InFlightPuts.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ using folly::fibers::TimedMutex;
3535
// user guarantees that the lifetime of the token is within the lifetime of the
3636
// string piece with which they obtain the token.
3737
class alignas(folly::hardware_destructive_interference_size) InFlightPuts {
38-
using LockGuard = std::lock_guard<TimedMutex>;
39-
using UniqueLock = std::unique_lock<TimedMutex>;
40-
4138
public:
4239
class PutToken;
4340

@@ -50,12 +47,12 @@ class alignas(folly::hardware_destructive_interference_size) InFlightPuts {
5047
template <typename F>
5148
folly::Expected<PutToken, PutTokenError> tryAcquireToken(
5249
folly::StringPiece key, F&& fn) {
53-
UniqueLock l(mutex_, std::try_to_lock);
50+
std::unique_lock l{rwMutex_, std::try_to_lock};
5451
if (!l.owns_lock()) {
5552
return folly::makeUnexpected(PutTokenError::TRY_LOCK_FAIL);
5653
}
5754

58-
auto ret = keys_.emplace(key, true);
55+
auto ret = keys_.emplace(key, std::make_unique<std::atomic<bool>>(true));
5956
// record for same key being inflight written to nvmcache should be rare.
6057
// In that case, fail the latter one.
6158
if (!ret.second) {
@@ -77,10 +74,10 @@ class alignas(folly::hardware_destructive_interference_size) InFlightPuts {
7774
// function on this token and simply remove the token when the token gets
7875
// destroyed.
7976
void invalidateToken(folly::StringPiece key) {
80-
LockGuard l(mutex_);
77+
std::shared_lock l{rwMutex_};
8178
auto it = keys_.find(key);
8279
if (it != keys_.end()) {
83-
it->second = false;
80+
it->second->store(false);
8481
}
8582
}
8683

@@ -157,9 +154,9 @@ class alignas(folly::hardware_destructive_interference_size) InFlightPuts {
157154
// @throw if fn throws, token is preserved.
158155
template <typename F>
159156
bool executeIfValid(folly::StringPiece key, F&& fn) {
160-
LockGuard l(mutex_);
157+
std::unique_lock l{rwMutex_};
161158
auto it = keys_.find(key);
162-
const bool valid = it != keys_.end() && it->second;
159+
const bool valid = it != keys_.end() && it->second->load();
163160
if (valid) {
164161
fn();
165162
keys_.erase(it);
@@ -170,16 +167,20 @@ class alignas(folly::hardware_destructive_interference_size) InFlightPuts {
170167

171168
// erases the record from inflight map.
172169
void removeToken(folly::StringPiece key) {
173-
LockGuard l(mutex_);
170+
std::unique_lock l{rwMutex_};
174171
auto res = keys_.erase(key);
175172
XDCHECK_EQ(res, 1u);
176173
}
177174

178175
// map storing the presence of a token and its validity
179-
folly::F14FastMap<folly::StringPiece, bool, folly::Hash> keys_;
176+
folly::F14FastMap<folly::StringPiece,
177+
std::unique_ptr<std::atomic<bool>>,
178+
folly::Hash>
179+
keys_;
180180

181181
// mutex protecting the map.
182-
TimedMutex mutex_;
182+
folly::fibers::TimedRWMutexWritePriority<folly::fibers::GenericBaton>
183+
rwMutex_;
183184
};
184185

185186
} // namespace cachelib

0 commit comments

Comments
 (0)