sapling/eden/fs/utils/Synchronized.h
Chad Austin d0b1ad675d remove last ulock from eden
Summary:
I'd misunderstood the point of SharedMutex's upgrade locks -
unless they're used in rare paths, they don't allow for increased
concurrency. This diff and D7885245 remove all of Eden's ulocks,
replacing them with a helper which checks once with an rlock held, and
if the check fails, switches to a wlock (and checks again).

Reviewed By: yfeldblum

Differential Revision: D7886046

fbshipit-source-id: 545bb0dbb4898cbb71412efc6222ef12e4ee374e
2018-05-18 15:21:16 -07:00

53 lines
1.5 KiB
C++

/*
* Copyright (c) 2018-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#pragma once
#include <folly/Synchronized.h>
namespace facebook {
namespace eden {
/**
* Helper function that optimizes for the case where a read-only check on a
* contended data structure is likely to succeed. It first acquires the
* synchronized object with an rlock. If check returns a true-ish value, then
* the result of dereferencing it is returned. Otherwise, a wlock is acquired
* and update is called.
*
* check should have type (const State&) -> folly::Optional<T>
* update should have type (State&) -> T
*/
template <typename Return, typename State, typename CheckFn, typename UpdateFn>
Return tryRlockCheckBeforeUpdate(
folly::Synchronized<State>& state,
CheckFn&& check,
UpdateFn&& update) {
// First, acquire the rlock. If the check succeeds, acquiring a wlock is
// unnecessary.
{
auto rlock = state.rlock();
auto result = check(*rlock);
if (LIKELY(bool(result))) {
return *result;
}
}
auto wlock = state.wlock();
// Check again - something may have raced between the locks.
auto result = check(*wlock);
if (UNLIKELY(bool(result))) {
return *result;
}
return update(*wlock);
}
} // namespace eden
} // namespace facebook