Skip to content

Commit d3ca31b

Browse files
Ravi Nagarjun AkellaRavi Nagarjun Akella
authored andcommitted
fix bugs in the do_evict logic
1 parent 5eb1077 commit d3ca31b

File tree

6 files changed

+55
-30
lines changed

6 files changed

+55
-30
lines changed

include/sisl/cache/evictor.hpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,13 @@ typedef ValueEntryBase CacheRecord;
2828

2929
class Evictor {
3030
public:
31-
typedef std::function< bool(const CacheRecord&) > can_evict_cb_t;
32-
typedef std::function< void(const CacheRecord&) > post_eviction_cb_t;
31+
typedef std::function< bool(const CacheRecord&) > eviction_cb_t;
32+
using can_evict_cb_t = eviction_cb_t;
33+
34+
struct RecordFamily {
35+
Evictor::eviction_cb_t can_evict_cb{nullptr};
36+
Evictor::eviction_cb_t post_eviction_cb{nullptr};
37+
};
3338

3439
Evictor(const int64_t max_size, const uint32_t num_partitions) :
3540
m_max_size{max_size}, m_num_partitions{num_partitions} {}
@@ -39,12 +44,12 @@ class Evictor {
3944
Evictor& operator=(Evictor&&) noexcept = delete;
4045
virtual ~Evictor() = default;
4146

42-
uint32_t register_record_family(can_evict_cb_t can_evict_cb = nullptr, post_eviction_cb_t post_eviction_cb = nullptr) {
47+
uint32_t register_record_family(RecordFamily record_family) {
4348
uint32_t id{0};
4449
std::unique_lock lk(m_reg_mtx);
4550
while (id < m_eviction_cbs.size()) {
46-
if (std::get<bool>(m_eviction_cbs[id]) == false) {
47-
m_eviction_cbs[id] = std::make_tuple(true, can_evict_cb, post_eviction_cb);
51+
if (m_eviction_cbs[id].first == false) {
52+
m_eviction_cbs[id] = std::make_pair(true, record_family);
4853
return id;
4954
}
5055
++id;
@@ -55,7 +60,7 @@ class Evictor {
5560

5661
void unregister_record_family(const uint32_t record_type_id) {
5762
std::unique_lock lk(m_reg_mtx);
58-
m_eviction_cbs[record_type_id] = std::make_tuple(false, nullptr, nullptr);
63+
m_eviction_cbs[record_type_id] = std::make_pair(false, RecordFamily{});
5964
}
6065

6166
virtual bool add_record(uint64_t hash_code, CacheRecord& record) = 0;
@@ -65,14 +70,14 @@ class Evictor {
6570

6671
int64_t max_size() const { return m_max_size; }
6772
uint32_t num_partitions() const { return m_num_partitions; }
68-
const can_evict_cb_t& can_evict_cb(const uint32_t record_id) const { return std::get<can_evict_cb_t>(m_eviction_cbs[record_id]); }
69-
const post_eviction_cb_t& post_eviction_cb(const uint32_t record_id) const { return std::get<post_eviction_cb_t>(m_eviction_cbs[record_id]); }
73+
const eviction_cb_t& can_evict_cb(const uint32_t record_id) const { return m_eviction_cbs[record_id].second.can_evict_cb; }
74+
const eviction_cb_t& post_eviction_cb(const uint32_t record_id) const { return m_eviction_cbs[record_id].second.post_eviction_cb; }
7075

7176
private:
7277
int64_t m_max_size;
7378
uint32_t m_num_partitions;
7479

7580
std::mutex m_reg_mtx;
76-
std::array< std::tuple< bool, can_evict_cb_t, post_eviction_cb_t >, CacheRecord::max_record_families() > m_eviction_cbs;
81+
std::array< std::pair< bool, RecordFamily >, CacheRecord::max_record_families() > m_eviction_cbs;
7782
};
7883
} // namespace sisl

include/sisl/cache/lru_evictor.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class LRUEvictor : public Evictor {
5050
void record_resized(uint64_t hash_code, const CacheRecord& record, uint32_t old_size) override;
5151

5252
// for testing purpose
53-
int64_t filled_size() const {
53+
int64_t filled_size() {
5454
int64_t filled_size{0};
5555
for (uint32_t i{0}; i < num_partitions(); ++i) {
5656
filled_size += m_partitions[i].filled_size();
@@ -92,12 +92,15 @@ class LRUEvictor : public Evictor {
9292
void record_resized(const CacheRecord& record, uint32_t old_size);
9393

9494
// for testing purpose
95-
int64_t filled_size() const { return m_filled_size; }
95+
int64_t filled_size() {
96+
std::unique_lock guard{m_list_guard};
97+
return m_filled_size;
98+
}
9699

97100
private:
98101
bool do_evict(const uint32_t record_fid, const uint32_t needed_size);
99102
bool will_fill(const uint32_t new_size) const { return ((m_filled_size + new_size) > m_max_size); }
100-
bool is_full() const { return will_fill(0); }
103+
bool is_full() const { return (m_filled_size >= m_max_size); }
101104
};
102105

103106
private:

include/sisl/cache/range_cache.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class RangeCache {
3939
m_map{RangeHashMap< K >(num_buckets, bind_this(RangeCache< K >::extract_value, 3),
4040
bind_this(RangeCache< K >::on_hash_operation, 4))},
4141
m_per_value_size{per_val_size} {
42-
m_evictor->register_record_family(std::move(evict_cb));
42+
m_evictor->register_record_family(Evictor::RecordFamily{.can_evict_cb = evict_cb});
4343
}
4444

4545
~RangeCache() { m_evictor->unregister_record_family(m_record_family_id); }

include/sisl/cache/simple_cache.hpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,33 @@ class SimpleCache {
3737

3838
public:
3939
SimpleCache(const std::shared_ptr< Evictor >& evictor, uint32_t num_buckets, uint32_t per_val_size,
40-
key_extractor_cb_t< K, V >&& extract_cb, Evictor::can_evict_cb_t evict_cb = nullptr) :
40+
key_extractor_cb_t< K, V >&& extract_cb, Evictor::eviction_cb_t evict_cb = nullptr) :
4141
m_evictor{evictor},
4242
m_key_extract_cb{std::move(extract_cb)},
4343
m_map{num_buckets, m_key_extract_cb, std::bind(&SimpleCache< K, V >::on_hash_operation, this, _1, _2, _3)},
4444
m_per_value_size{per_val_size} {
45-
m_record_family_id = m_evictor->register_record_family(std::move(evict_cb), [this](const CacheRecord& record) {
46-
V const value = reinterpret_cast<SingleEntryHashNode< V >*>(const_cast< CacheRecord* >(&record))->m_value;
47-
K key = m_key_extract_cb(value);
48-
return m_map.try_erase(key);
49-
});
45+
m_record_family_id = m_evictor->register_record_family(Evictor::RecordFamily{.can_evict_cb = evict_cb
46+
, .post_eviction_cb = [this](const CacheRecord& record) {
47+
V const value = reinterpret_cast<SingleEntryHashNode< V >*>(const_cast< CacheRecord* >(&record))->m_value;
48+
K key = m_key_extract_cb(value);
49+
return m_map.try_erase(key);
50+
}});
5051
}
5152

5253
~SimpleCache() { m_evictor->unregister_record_family(m_record_family_id); }
5354

5455
bool insert(const V& value) {
5556
K k = m_key_extract_cb(value);
5657
bool ret = m_map.insert(k, value);
58+
if (t_failed_keys.size()) {
59+
// There are some failures to add for some keys
60+
for (auto& key : t_failed_keys) {
61+
V dummy_v;
62+
m_map.erase(key, dummy_v);
63+
ret = false;
64+
}
65+
t_failed_keys.clear();
66+
}
5767
return ret;
5868
}
5969

src/cache/lru_evictor.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,24 @@ bool LRUEvictor::LRUPartition::do_evict(const uint32_t record_fid,
8989
auto it = std::begin(m_list);
9090
while (will_fill(needed_size) && (it != std::end(m_list))) {
9191
CacheRecord &rec = *it;
92-
92+
bool eviction_failed{true};
9393
/* return the next element */
9494
if (!rec.is_pinned() && (!m_evictor->can_evict_cb(record_fid) || m_evictor->can_evict_cb(record_fid)(rec))) {
95-
m_filled_size -= rec.size();
95+
auto const rec_size = rec.size();
9696
it = m_list.erase(it);
97-
if(m_evictor->post_eviction_cb(record_fid)) {
98-
m_evictor->post_eviction_cb(record_fid)(rec);
97+
if (m_evictor->post_eviction_cb(record_fid) && !m_evictor->post_eviction_cb(record_fid)(rec)) {
98+
// If the post eviction callback fails, we need to reinsert the record
99+
// back into the list.
100+
it = m_list.insert(it, rec);
101+
} else {
102+
eviction_failed = false;
103+
m_filled_size -= rec_size;
99104
}
100-
} else {
101-
++count;
102-
it = std::next(it);
105+
}
106+
107+
if (eviction_failed) {
108+
++count;
109+
it = std::next(it);
103110
}
104111
}
105112

src/cache/tests/test_simple_cache.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,15 +213,15 @@ TEST(SimpleCacheSize, TriggerEvict) {
213213
std::shared_ptr< Evictor > evictor = std::make_unique< LRUEvictor >(cache_size, num_partitions);
214214
auto simple_cache = std::make_unique< SimpleCache< uint32_t, std::shared_ptr< Entry > > >(
215215
evictor, // Evictor to evict used entries
216-
cache_size / 4096, // Total number of buckets
216+
10000, // Total number of buckets
217217
g_val_size, // Value size
218218
[](const std::shared_ptr< Entry >& e) -> uint32_t { return e->m_id; }, // Method to extract key
219219
nullptr // Method to prevent eviction
220220
);
221221
auto* evictor_ptr = dynamic_cast<LRUEvictor*>(evictor.get());
222222
uint32_t num_iters = num_partitions * max_nodes_per_partition * 1000;
223223
for(uint32_t i = 0; i < num_iters; i++) {
224-
simple_cache->insert(std::make_shared< Entry >(i, fmt::format("test{}", i)));
224+
ASSERT_TRUE(simple_cache->insert(std::make_shared< Entry >(i, fmt::format("test{}", i))));
225225
ASSERT_LE(evictor_ptr->filled_size(), cache_size);
226226
}
227227
uint32_t cache_hits{0};
@@ -239,8 +239,8 @@ TEST(SimpleCacheSize, MultithreadedEviction) {
239239
uint32_t cache_size = g_val_size * num_partitions * max_nodes_per_partition;
240240
std::shared_ptr< Evictor > evictor = std::make_unique< LRUEvictor >(cache_size, num_partitions);
241241
auto simple_cache = std::make_unique< SimpleCache< uint32_t, std::shared_ptr< Entry > > >(
242-
evictor, // Evictor to evict used entries
243-
cache_size / 4096, // Total number of buckets
242+
evictor, // Evictor to evict used entries
243+
10000, // Total number of buckets
244244
g_val_size, // Value size
245245
[](const std::shared_ptr< Entry >& e) -> uint32_t { return e->m_id; }, // Method to extract key
246246
nullptr // Method to prevent eviction

0 commit comments

Comments
 (0)