Skip to content

Commit 7ccce42

Browse files
deletions in concurrent hash
1 parent 10d9603 commit 7ccce42

File tree

4 files changed

+60
-124
lines changed

4 files changed

+60
-124
lines changed

cachelib/allocator/MMS3FIFO.h

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
#include "cachelib/allocator/memory/serialize/gen-cpp2/objects_types.h"
3434
#include "cachelib/common/CompilerUtils.h"
3535
#include "cachelib/common/FIFOHashSet.h"
36-
#include "cachelib/common/FIFOAtomicHashSet.h"
3736
#include "cachelib/common/FIFOConcurrentHashSet.h"
3837

3938
namespace facebook::cachelib {
@@ -386,10 +385,15 @@ class MMS3FIFO {
386385
void maybeResizeGhostLocked() noexcept;
387386

388387
// Returns the hash of node's key
389-
static size_t hashNode(const T& node) noexcept {
388+
static size_t hashNode64(const T& node) noexcept {
390389
return folly::hasher<folly::StringPiece>()(node.getKey());
391390
}
392391

392+
static uint32_t hashNode(const T& node) noexcept {
393+
return static_cast<uint32_t>(
394+
folly::hasher<folly::StringPiece>()(node.getKey()));
395+
}
396+
393397
void removeLocked(T& node) noexcept;
394398

395399
static bool isTiny(const T& node) noexcept {
@@ -429,9 +433,8 @@ class MMS3FIFO {
429433
// the lru
430434
LruList lru_;
431435

432-
facebook::cachelib::util::detail::FIFOConcurrentHashSet ghostQueue_;
433-
// facebook::cachelib::util::detail::FIFOAtomicHashSet ghostQueue_;
434-
// facebook::cachelib::util::FIFOHashSet ghostQueue_;
436+
facebook::cachelib::util::FIFOConcurrentHashSet32 ghostQueue_;
437+
// facebook::cachelib::util::FIFOHashSet32 ghostQueue_;
435438

436439
// Config for this lru.
437440
// Write access to the MMS3FIFO Config is serialized.
@@ -482,7 +485,7 @@ bool MMS3FIFO::Container<T, HookPtr>::recordAccess(T& node,
482485
}
483486
const auto currTime = static_cast<Time>(util::getCurrentTimeSec());
484487

485-
// Remove lock from record access wince we only set bits
488+
// Remove lock from record access since we only set bits
486489
if (node.isInMMContainer()) {
487490
if (!isAccessed(node)) {
488491
markAccessed(node);
@@ -643,13 +646,12 @@ void MMS3FIFO::Container<T, HookPtr>::withContainerLock(F&& fun) {
643646
lruMutex_->lock_combine([&fun]() { fun(); });
644647
}
645648

649+
// Ghost queue insertion done on callee, outside lock
646650
template <typename T, MMS3FIFO::Hook<T> T::* HookPtr>
647651
void MMS3FIFO::Container<T, HookPtr>::removeLocked(T& node) noexcept {
648652
if (isTiny(node)) {
649653
lru_.getList(LruType::Tiny).remove(node);
650654
unmarkTiny(node);
651-
// Insert into ghost queue upon eviction from tiny queue
652-
ghostQueue_.insert(hashNode(node));
653655
} else {
654656
lru_.getList(LruType::Main).remove(node);
655657
}
@@ -661,13 +663,19 @@ void MMS3FIFO::Container<T, HookPtr>::removeLocked(T& node) noexcept {
661663

662664
template <typename T, MMS3FIFO::Hook<T> T::* HookPtr>
663665
bool MMS3FIFO::Container<T, HookPtr>::remove(T& node) noexcept {
664-
return lruMutex_->lock_combine([this, &node]() {
666+
bool isTiny_ = isTiny(node);
667+
auto result = lruMutex_->lock_combine([this, &node]() {
665668
if (!node.isInMMContainer()) {
666669
return false;
667670
}
668671
removeLocked(node);
669672
return true;
670673
});
674+
if (result && isTiny_) {
675+
// Insert to ghost queue
676+
ghostQueue_.insert(hashNode(node));
677+
}
678+
return result;
671679
}
672680

673681
template <typename T, MMS3FIFO::Hook<T> T::* HookPtr>

cachelib/common/FIFOAtomicHashSet.h

Lines changed: 0 additions & 55 deletions
This file was deleted.

cachelib/common/FIFOConcurrentHashSet.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
namespace facebook::cachelib::util {
1010
namespace detail {
1111

12-
class FIFOConcurrentHashSet {
12+
template <typename KeyT = uint32_t>
13+
class FIFOConcurrentHashSetBase {
1314
public:
14-
using Key = uint64_t; // hashed object id
15+
using Key = KeyT; // hashed object id
1516
using TS = uint64_t; // logical time / FIFO order
1617

17-
explicit FIFOConcurrentHashSet(size_t capacity)
18+
explicit FIFOConcurrentHashSetBase(size_t capacity)
1819
: ghost_(capacity), seq_(0), queueSize_(0) {}
1920

20-
FIFOConcurrentHashSet() : seq_(0), queueSize_(0) {}
21+
FIFOConcurrentHashSetBase() : seq_(0), queueSize_(0) {}
2122

2223
struct PendingEntry {
2324
Key k;
@@ -27,16 +28,26 @@ class FIFOConcurrentHashSet {
2728
inline void insert(Key k) {
2829
TS ts = seq_.fetch_add(1, std::memory_order_relaxed);
2930
ghost_.insert_or_assign(k, ts);
31+
// If it overflows and wraps around, we reset the entire structure.
32+
if (UNLIKELY(ts == std::numeric_limits<TS>::max())) {
33+
ghost_.clear();
34+
}
3035
}
3136

32-
inline bool contains(Key k) const {
37+
inline bool contains(Key k) {
3338
auto it = ghost_.find(k);
3439
if (it == ghost_.end())
3540
return false;
3641
// Seq - current must be larger
3742
auto currDiff = seq_.load(std::memory_order_relaxed) - it->second;
38-
return currDiff <=
39-
queueSize_.load(std::memory_order_relaxed); // stale == not present
43+
auto isValid = currDiff <= queueSize_.load(std::memory_order_relaxed);
44+
45+
if (!isValid) {
46+
// remove stale entry
47+
ghost_.erase(k);
48+
}
49+
50+
return isValid;
4051
}
4152

4253
inline void resize(TS limitTS) {
@@ -53,4 +64,7 @@ class FIFOConcurrentHashSet {
5364
};
5465

5566
} // namespace detail
67+
using FIFOConcurrentHashSet32 = detail::FIFOConcurrentHashSetBase<uint32_t>;
68+
using FIFOConcurrentHashSet64 = detail::FIFOConcurrentHashSetBase<uint64_t>;
69+
5670
} // namespace facebook::cachelib::util

cachelib/common/FIFOHashSet.h

Lines changed: 22 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
#include <folly/Format.h>
44
#include <folly/Math.h>
55
#include <folly/container/F14Set.h>
6+
#include <folly/synchronization/DistributedMutex.h>
67

78
#include <cstdint>
89
#include <deque>
910
#include <stdexcept>
10-
#include <unordered_set>
1111

1212
namespace facebook::cachelib::util {
1313
namespace detail {
@@ -26,94 +26,63 @@ class FIFOHashSetBase {
2626
FIFOHashSetBase(const FIFOHashSetBase&) = delete;
2727
FIFOHashSetBase& operator=(const FIFOHashSetBase&) = delete;
2828

29-
FIFOHashSetBase(FIFOHashSetBase&& other) noexcept {
30-
maxSize_ = other.maxSize_;
31-
fifo_ = std::move(other.fifo_);
32-
set_ = std::move(other.set_);
33-
other.maxSize_ = 0;
34-
}
35-
36-
FIFOHashSetBase& operator=(FIFOHashSetBase&& other) noexcept {
37-
if (this != &other) {
38-
maxSize_ = other.maxSize_;
39-
fifo_ = std::move(other.fifo_);
40-
set_ = std::move(other.set_);
41-
other.maxSize_ = 0;
42-
}
43-
return *this;
44-
}
4529

4630
bool contains(KeyT key) {
47-
return set_.contains(key);
48-
}
49-
50-
// Enforce size variant of contains
51-
bool containsEnforce(KeyT key) {
52-
enforceCapacityLocked();
53-
return set_.contains(key);
31+
return mutex_.lock_combine([&]() { return set_.contains(key); });
5432
}
5533

5634
size_t size() {
57-
return set_.size();
35+
return mutex_.lock_combine([&]() { return set_.size(); });
5836
}
5937

6038
size_t capacity() {
61-
return maxSize_;
39+
return mutex_.lock_combine([&]() { return maxSize_; });
6240
}
6341

6442
void reserve(size_t newCap) {
65-
set_.reserve(newCap);
43+
mutex_.lock_combine([&]() { set_.reserve(newCap); });
6644
}
6745

6846
void insert(KeyT key) {
69-
auto [it, inserted] = set_.insert(key);
70-
if (inserted) {
71-
fifo_.push_back(key);
72-
}
73-
enforceCapacityLocked();
74-
}
75-
76-
// No enforce variant of insert
77-
void insertNoEnforce(KeyT key) {
78-
auto [it, inserted] = set_.insert(key);
79-
if (inserted) {
80-
fifo_.push_back(key);
81-
}
47+
mutex_.lock_combine([&]() {
48+
auto [it, inserted] = set_.insert(key);
49+
if (inserted) {
50+
fifo_.push_back(key);
51+
}
52+
enforceCapacityLocked();
53+
});
8254
}
8355

8456
void resize(size_t newSize) {
85-
maxSize_ = newSize;
86-
enforceCapacityLocked();
87-
}
88-
89-
// No enforce variant of resize
90-
void resizeNoEnforce(size_t newSize) {
91-
maxSize_ = newSize;
57+
mutex_.lock_combine([&]() {
58+
maxSize_ = newSize;
59+
});
9260
}
9361

9462
private:
95-
// To prevent tail latency, limits max elements removed per call.
63+
// Enforce max removal to control tail latency
9664
void enforceCapacityLocked() {
97-
constexpr int max_rem = 5;
65+
constexpr int max_rem = 2;
9866
int removed = 0;
9967

10068
while (fifo_.size() > maxSize_ && removed < max_rem) {
10169
KeyT k = fifo_.front();
10270
fifo_.pop_front();
10371
set_.erase(k);
104-
removed++;
72+
++removed;
10573
}
10674
}
10775

10876
private:
109-
// mutable folly::SpinLock lock_;
77+
folly::DistributedMutex mutex_;
78+
11079
size_t maxSize_{0};
11180
std::deque<KeyT> fifo_;
11281
folly::F14FastSet<KeyT> set_;
11382
};
11483

11584
} // namespace detail
11685

117-
using FIFOHashSet = detail::FIFOHashSetBase<uint64_t>;
86+
using FIFOHashSet32 = detail::FIFOHashSetBase<uint32_t>;
11887

119-
} // namespace facebook::cachelib::util
88+
} // namespace facebook::cachelib::util

0 commit comments

Comments
 (0)