5 #ifndef _FABCOIN_CUCKOOCACHE_H_ 6 #define _FABCOIN_CUCKOOCACHE_H_ 44 std::unique_ptr<std::atomic<uint8_t>[]>
mem;
64 size = (size + 7) / 8;
65 mem.reset(
new std::atomic<uint8_t>[size]);
66 for (uint32_t i = 0; i <
size; ++i)
94 mem[s >> 3].fetch_or(1 << (s & 7), std::memory_order_relaxed);
105 mem[s >> 3].fetch_and(~(1 << (s & 7)), std::memory_order_relaxed);
115 return (1 << (s & 7)) & mem[s >> 3].load(std::memory_order_relaxed);
159 template <
typename Element,
typename Hash>
245 return {{(uint32_t)((hash_function.template
operator()<0>(e) * (uint64_t)size) >> 32),
246 (uint32_t)((hash_function.template operator()<1>(
e) * (uint64_t)
size) >> 32),
247 (uint32_t)((hash_function.template
operator()<2>(
e) * (uint64_t)
size) >> 32),
248 (uint32_t)((hash_function.template
operator()<3>(
e) * (uint64_t)
size) >> 32),
249 (uint32_t)((hash_function.template
operator()<4>(
e) * (uint64_t)
size) >> 32),
250 (uint32_t)((hash_function.template
operator()<5>(
e) * (uint64_t)
size) >> 32),
251 (uint32_t)((hash_function.template
operator()<6>(
e) * (uint64_t)
size) >> 32),
252 (uint32_t)((hash_function.template
operator()<7>(
e) * (uint64_t)
size) >> 32)}};
291 if (epoch_heuristic_counter != 0) {
292 --epoch_heuristic_counter;
297 uint32_t epoch_unused_count = 0;
298 for (uint32_t i = 0; i <
size; ++i)
299 epoch_unused_count += epoch_flags[i] &&
305 if (epoch_unused_count >= epoch_size) {
306 for (uint32_t i = 0; i <
size; ++i)
308 epoch_flags[i] =
false;
311 epoch_heuristic_counter = epoch_size;
320 epoch_size - epoch_unused_count));
327 cache() : table(), size(), collection_flags(0), epoch_flags(),
328 epoch_heuristic_counter(), epoch_size(), depth_limit(0), hash_function()
343 depth_limit =
static_cast<uint8_t
>(std::log2(static_cast<float>(
std::max((uint32_t)2, new_size))));
344 size = std::max<uint32_t>(2, new_size);
346 collection_flags.
setup(size);
347 epoch_flags.resize(size);
349 epoch_size =
std::max((uint32_t)1, (45 * size) / 100);
351 epoch_heuristic_counter = epoch_size;
369 return setup(bytes/
sizeof(Element));
395 uint32_t last_loc = invalid();
396 bool last_epoch =
true;
397 std::array<uint32_t, 8> locs = compute_hashes(e);
400 for (uint32_t loc : locs)
401 if (table[loc] == e) {
403 epoch_flags[loc] = last_epoch;
406 for (uint8_t depth = 0; depth < depth_limit; ++depth) {
408 for (uint32_t loc : locs) {
411 table[loc] = std::move(e);
413 epoch_flags[loc] = last_epoch;
430 last_loc = locs[(1 + (std::find(locs.begin(), locs.end(), last_loc) - locs.begin())) & 7];
433 bool epoch = last_epoch;
434 last_epoch = epoch_flags[last_loc];
435 epoch_flags[last_loc] = epoch;
438 locs = compute_hashes(e);
467 inline bool contains(
const Element&
e,
const bool erase)
const 469 std::array<uint32_t, 8> locs = compute_hashes(e);
470 for (uint32_t loc : locs)
471 if (table[loc] == e) {
void please_keep(uint32_t n) const
please_keep marks the element at index n as an entry that should be kept.
void swap(dev::eth::Watch &_a, dev::eth::Watch &_b)
void allow_erase(uint32_t n) const
allow_erase marks the element at index n as discardable.
std::unique_ptr< std::atomic< uint8_t >[]> mem
bit_packed_atomic_flags(uint32_t size)
bit_packed_atomic_flags constructor creates memory to sufficiently keep track of garbage collection i...
cache implements a cache with properties similar to a cuckoo-set
void bit_set(uint32_t s)
bit_set sets an entry as discardable.
uint32_t epoch_size
epoch_size is set to be the number of elements supposed to be in a epoch.
bool bit_is_set(uint32_t s) const
bit_is_set queries the table for discardability at s
std::vector< bool > epoch_flags
epoch_flags tracks how recently an element was inserted into the cache.
const Hash hash_function
hash_function is a const instance of the hash function.
bit_packed_atomic_flags implements a container for garbage collection flags that is only thread unsaf...
cache()
You must always construct a cache with some elements via a subsequent call to setup or setup_bytes...
uint32_t size
size stores the total available slots in the hash table
uint8_t depth_limit
depth_limit determines how many elements insert should try to replace.
std::vector< byte > bytes
constexpr uint32_t invalid() const
bool contains(const Element &e, const bool erase) const
uint32_t epoch_heuristic_counter
epoch_heuristic_counter is used to determine when an epoch might be aged & an expensive scan should b...
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
void insert(Element e)
insert loops at most depth_limit times trying to insert a hash at various locations in the table via ...
uint32_t setup_bytes(size_t bytes)
setup_bytes is a convenience function which accounts for internal memory usage when deciding how many...
std::vector< Element > table
table stores all the elements
namespace CuckooCache provides high performance cache primitives
std::array< uint32_t, 8 > compute_hashes(const Element &e) const
compute_hashes is convenience for not having to write out this expression everywhere we use the hash ...
uint8_t const size_t const size
void epoch_check()
epoch_check handles the changing of epochs for elements stored in the cache.
bit_packed_atomic_flags collection_flags
The bit_packed_atomic_flags array is marked mutable because we want garbage collection to be allowed ...
uint32_t setup(uint32_t new_size)
setup initializes the container to store no more than new_size elements.
void bit_unset(uint32_t s)
bit_unset marks an entry as something that should not be overwritten
dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
void setup(uint32_t b)
setup marks all entries and ensures that bit_packed_atomic_flags can store at least size entries ...
bit_packed_atomic_flags()=delete
No default constructor as there must be some size.