Skip to content

Commit 9aafa9b

Browse files
Ravi Nagarjun AkellaRavi Nagarjun Akella
authored andcommitted
use try_lock to delete the evicted entry from hashmap on a best effort basis
1 parent bc40a3b commit 9aafa9b

File tree

3 files changed

+47
-33
lines changed

3 files changed

+47
-33
lines changed

include/sisl/cache/simple_cache.hpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ class SimpleCache {
3434
uint32_t m_per_value_size;
3535

3636
static thread_local std::set< K > t_failed_keys;
37-
static thread_local std::set< K > t_evicted_keys;
3837

3938
public:
4039
SimpleCache(const std::shared_ptr< Evictor >& evictor, uint32_t num_buckets, uint32_t per_val_size,
@@ -46,7 +45,7 @@ class SimpleCache {
4645
m_record_family_id = m_evictor->register_record_family(std::move(evict_cb), [this](const CacheRecord& record) {
4746
V const value = reinterpret_cast<SingleEntryHashNode< V >*>(const_cast< CacheRecord* >(&record))->m_value;
4847
K key = m_key_extract_cb(value);
49-
t_evicted_keys.insert(key);
48+
return m_map.try_erase(key);
5049
});
5150
}
5251

@@ -55,14 +54,6 @@ class SimpleCache {
5554
bool insert(const V& value) {
5655
K k = m_key_extract_cb(value);
5756
bool ret = m_map.insert(k, value);
58-
// erase evicted keys
59-
if (t_evicted_keys.size() > 0) {
60-
for (const auto& key : t_evicted_keys) {
61-
V out_val;
62-
m_map.erase(key, out_val);
63-
}
64-
t_evicted_keys.clear();
65-
}
6657
return ret;
6758
}
6859

@@ -116,6 +107,4 @@ class SimpleCache {
116107
template < typename K, typename V >
117108
thread_local std::set< K > SimpleCache< K, V >::t_failed_keys;
118109

119-
template < typename K, typename V >
120-
thread_local std::set< K > SimpleCache< K, V >::t_evicted_keys;
121110
} // namespace sisl

include/sisl/cache/simple_hashmap.hpp

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class SimpleHashMap {
7373
bool upsert(const K& key, const V& value);
7474
bool get(const K& input_key, V& out_val);
7575
bool erase(const K& key, V& out_val);
76+
bool try_erase(const K& key);
7677
bool update(const K& key, auto&& update_cb);
7778
bool upsert_or_delete(const K& key, auto&& update_or_delete_cb);
7879

@@ -102,6 +103,7 @@ class SimpleHashMap {
102103
template < typename V >
103104
struct SingleEntryHashNode : public ValueEntryBase, public boost::intrusive::slist_base_hook<> {
104105
V m_value;
106+
bool evicted{false};
105107
SingleEntryHashNode(const V& value) : m_value{value} {}
106108
};
107109

@@ -184,27 +186,21 @@ class SimpleHashBucket {
184186
#ifndef GLOBAL_HASHSET_LOCK
185187
folly::SharedMutexWritePriority::WriteHolder holder(m_lock);
186188
#endif
187-
SingleEntryHashNode< V >* n = nullptr;
188-
189-
auto it = m_list.begin();
190-
for (auto itend{m_list.end()}; it != itend; ++it) {
191-
const K k = SimpleHashMap< K, V >::extractor_cb()(it->m_value);
192-
if (input_key > k) {
193-
break;
194-
} else if (input_key == k) {
195-
n = &*it;
196-
break;
197-
}
198-
}
189+
return erase_unsafe(input_key, out_val, true /* call_access_cb */);
190+
}
199191

200-
if (n) {
201-
access_cb(*n, input_key, hash_op_t::DELETE);
202-
out_val = n->m_value;
203-
m_list.erase(it);
204-
delete n;
205-
return true;
192+
bool try_erase(const K& input_key) {
193+
V dummy_val;
194+
#ifndef GLOBAL_HASHSET_LOCK
195+
if(m_lock.try_lock()) {
196+
bool ret = erase_unsafe(input_key, dummy_val, false /* call_access_cb */);
197+
m_lock.unlock();
198+
return ret;
199+
} else {
200+
return false;
206201
}
207-
return false;
202+
#endif
203+
return erase_unsafe(input_key, dummy_val, false);
208204
}
209205

210206
bool upsert_or_delete(const K& input_key, auto&& update_or_delete_cb) {
@@ -266,9 +262,33 @@ class SimpleHashBucket {
266262
static void access_cb(const SingleEntryHashNode< V >& node, const K& key, hash_op_t op) {
267263
SimpleHashMap< K, V >::call_access_cb((const ValueEntryBase&)node, key, op);
268264
}
265+
266+
bool erase_unsafe(const K& input_key, V& out_val, bool call_access_cb) {
267+
SingleEntryHashNode< V >* n = nullptr;
268+
269+
auto it = m_list.begin();
270+
for (auto itend{m_list.end()}; it != itend; ++it) {
271+
const K k = SimpleHashMap< K, V >::extractor_cb()(it->m_value);
272+
if (input_key > k) {
273+
break;
274+
} else if (input_key == k) {
275+
n = &*it;
276+
break;
277+
}
278+
}
279+
280+
if (n) {
281+
if (call_access_cb) { access_cb(*n, input_key, hash_op_t::DELETE); }
282+
out_val = n->m_value;
283+
m_list.erase(it);
284+
delete n;
285+
return true;
286+
}
287+
return false;
288+
}
269289
};
270290

271-
///////////////////////////////////////////// RangeHashMap Definitions ///////////////////////////////////
291+
///////////////////////////////////////////// SimpleHashMap Definitions ///////////////////////////////////
272292
template < typename K, typename V >
273293
SimpleHashMap< K, V >::SimpleHashMap(uint32_t nBuckets, const key_extractor_cb_t< K, V >& extract_cb,
274294
key_access_cb_t< K > access_cb) :
@@ -317,6 +337,12 @@ bool SimpleHashMap< K, V >::erase(const K& key, V& out_val) {
317337
return get_bucket(key).erase(key, out_val);
318338
}
319339

340+
template < typename K, typename V >
341+
bool SimpleHashMap< K, V >::try_erase(const K& key) {
342+
set_current_instance(this);
343+
return get_bucket(key).try_erase(key);
344+
}
345+
320346
/// This is a special atomic operation where user can insert_or_update_or_erase based on condition atomically. It
321347
/// performs differently based on certain conditions.
322348
///

src/cache/tests/test_simple_cache.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,6 @@ TEST(SimpleCacheSize, TriggerEvict) {
231231
++cache_hits;
232232
}
233233
}
234-
ASSERT_EQ(cache_hits, num_partitions * max_nodes_per_partition);
235234
}
236235

237236
TEST(SimpleCacheSize, MultithreadedEviction) {

0 commit comments

Comments
 (0)