From ca11f9f2001c029c7d2bbfb95ddcf0e9926d226b Mon Sep 17 00:00:00 2001 From: achirkin Date: Tue, 23 Jan 2024 15:27:22 +0100 Subject: [PATCH] Use plain the vector instead of the unordered_map for the cache and custom resources under assumption they are never big enough for the map --- .../raft/core/resource/custom_resource.hpp | 15 ++-- cpp/include/raft/util/cache.hpp | 68 ++++++++++++------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/cpp/include/raft/core/resource/custom_resource.hpp b/cpp/include/raft/core/resource/custom_resource.hpp index dcb97ff2a1..ee34d736a2 100644 --- a/cpp/include/raft/core/resource/custom_resource.hpp +++ b/cpp/include/raft/core/resource/custom_resource.hpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -34,17 +35,21 @@ class custom_resource : public resource { { std::lock_guard _(lock_); auto key = std::type_index{typeid(ResourceT)}; - auto pos = map_.find(key); - if (pos != map_.end()) { return reinterpret_cast(pos->second.get()); } + auto pos = std::lower_bound(store_.begin(), store_.end(), kv{key, {nullptr}}); + if ((pos != store_.end()) && std::get<0>(*pos) == key) { + return reinterpret_cast(std::get<1>(*pos).get()); + } auto store_ptr = new ResourceT{}; - map_[key] = - std::shared_ptr(store_ptr, [](void* ptr) { delete reinterpret_cast(ptr); }); + store_.insert(pos, kv{key, std::shared_ptr(store_ptr, [](void* ptr) { + delete reinterpret_cast(ptr); + })}); return store_ptr; } private: - std::unordered_map> map_{}; + using kv = std::tuple>; std::mutex lock_{}; + std::vector store_{}; }; /** Factory that knows how to construct a specific raft::resource to populate the res_t. */ diff --git a/cpp/include/raft/util/cache.hpp b/cpp/include/raft/util/cache.hpp index 8b214ecfbc..e298e7d23d 100644 --- a/cpp/include/raft/util/cache.hpp +++ b/cpp/include/raft/util/cache.hpp @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include namespace raft::cache { @@ -37,49 +37,67 @@ class lru { /** Default cache size. */ static constexpr size_t kDefaultSize = 100; - explicit lru(size_t size = kDefaultSize) : size_(size) + explicit lru(size_t size = kDefaultSize) : size_(size), data_(size), order_(size) { + for (size_t i = 0; i < size_; i++) { + order_[i] = i + 1; + data_[i] = std::nullopt; + } RAFT_EXPECTS(size >= 1, "The cache must fit at least one record."); } void set(const K& key, const Values&... values) { std::lock_guard guard(lock_); - auto pos = map_.find(key); - if (pos == map_.end()) { - if (map_.size() >= size_) { - map_.erase(queue_.back()); - queue_.pop_back(); - } - } else { - queue_.erase(std::get<0>(pos->second)); + auto pos = root_; + auto prev = root_; + while (true) { + auto next = order_[pos]; + if (next >= size_ || !data_[pos].has_value()) { break; } + prev = pos; + pos = next; } - queue_.push_front(key); - map_[key] = std::make_tuple(queue_.begin(), values...); + update_lru(prev, pos); + data_[pos].emplace(key, values...); } auto get(const K& key, Values*... values) -> bool { std::lock_guard guard(lock_); - auto pos = map_.find(key); - if (pos == map_.end()) { return false; } - auto& map_val = pos->second; - queue_.erase(std::get<0>(map_val)); - queue_.push_front(key); - std::get<0>(map_val) = queue_.begin(); - set_values(map_val, values..., std::index_sequence_for()); - return true; + auto pos = root_; + auto prev = root_; + while (pos < size_ && data_[pos].has_value()) { + auto& val = data_[pos].value(); + if (std::get<0>(val) == key) { + update_lru(prev, pos); + set_values(val, values..., std::index_sequence_for()); + return true; + } + prev = pos; + pos = order_[pos]; + } + return false; } private: - using queue_iterator = typename std::list::iterator; - std::list queue_{}; - std::unordered_map, HashK, EqK> map_{}; + std::size_t size_; + std::vector>> data_; + std::vector order_; std::mutex lock_{}; - size_t size_; + std::size_t root_{0}; + + // Place `pos` at the root of the queue. + inline void update_lru(std::size_t prev, std::size_t pos) + { + if (pos != root_) { + order_[prev] = order_[pos]; + order_[pos] = root_; + root_ = pos; + } + } template - static void set_values(const std::tuple& tup, + static void set_values(const std::tuple& tup, Values*... vals, std::index_sequence) {