TARAXA
cache.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <functional>
4 #include <map>
5 #include <mutex>
6 #include <shared_mutex>
7 #include <unordered_map>
8 #include <vector>
9 
10 namespace taraxa {
11 
12 // TODO: could it be somehow prettier?
13 // partial specialization is not allowed for functions, so make it with structs
14 namespace {
15 template <class T>
16 struct is_empty {
17  is_empty(const T &v) : v_(v) {}
18  operator bool() const { return !v_; }
19  const T &v_;
20 };
21 template <class T>
22 struct is_empty<std::vector<T>> {
23  is_empty(const std::vector<T> &v) : v_(v) {}
24  operator bool() const { return v_.empty(); }
25  const std::vector<T> &v_;
26 };
27 } // namespace
28 
29 template <class Key, class Value>
31  public:
32  using GetterFn = std::function<Value(uint64_t, const Key &)>;
33  using ValueMap = std::unordered_map<Key, Value>;
34  using DataMap = std::map<uint64_t, ValueMap>;
35 
36  MapByBlockCache(const MapByBlockCache &) = delete;
40 
41  MapByBlockCache(uint64_t blocks_to_save, GetterFn &&getter_fn)
42  : kBlocksToKeep(blocks_to_save), getter_fn_(std::move(getter_fn)) {}
43 
44  void append(uint64_t block_num, const Key &key, const Value &value) const {
45  std::unique_lock lock(mutex_);
46 
47  auto blk_entry = data_by_block_.find(block_num);
48  if (blk_entry == data_by_block_.end()) {
49  blk_entry = data_by_block_.emplace(block_num, ValueMap()).first;
50  }
51  blk_entry->second.emplace(key, value);
52 
53  // Remove older element after we added one more
54  if (data_by_block_.size() > kBlocksToKeep) {
55  data_by_block_.erase(data_by_block_.begin());
56  }
57  }
58 
59  Value get(uint64_t blk_num, const Key &key) const {
60  {
61  std::shared_lock lock(mutex_);
62  auto blk_entry = data_by_block_.find(blk_num);
63  if (blk_entry != data_by_block_.end()) {
64  auto e = blk_entry->second.find(key);
65  if (e != blk_entry->second.end()) {
66  return e->second;
67  }
68  }
69  }
70 
71  auto value = getter_fn_(blk_num, key);
72  if (is_empty(value)) {
73  return {};
74  }
75  // Not save old values in cache
76  auto last_num = lastBlockNum();
77  if (last_num < kBlocksToKeep || blk_num >= last_num - kBlocksToKeep) {
78  append(blk_num, key, value);
79  }
80  return value;
81  }
82 
83  uint64_t lastBlockNum() const {
84  std::shared_lock lock(mutex_);
85  if (data_by_block_.empty()) {
86  return 0;
87  }
88  return data_by_block_.rbegin()->first;
89  }
90 
91  protected:
92  const uint64_t kBlocksToKeep;
94 
95  // cache is used from const methods in other class, so should be mutable
96  mutable std::shared_mutex mutex_;
98 };
99 
100 template <class Value>
102  public:
103  using GetterFn = std::function<Value(uint64_t)>;
104  using DataMap = std::map<uint64_t, Value>;
105 
110 
111  ValueByBlockCache(uint64_t blocks_to_save, GetterFn &&getter_fn)
112  : kBlocksToKeep(blocks_to_save), getter_fn_(std::move(getter_fn)) {}
113 
114  void append(uint64_t block_num, Value value) const {
115  std::unique_lock lock(mutex_);
116  data_by_block_.emplace(block_num, value);
117 
118  // Remove older element after we added one more
119  if (data_by_block_.size() > kBlocksToKeep) {
120  data_by_block_.erase(data_by_block_.begin());
121  }
122  }
123 
124  Value get(uint64_t block_num) const {
125  {
126  std::shared_lock lock(mutex_);
127  auto blk_entry = data_by_block_.find(block_num);
128  if (blk_entry != data_by_block_.end()) {
129  return blk_entry->second;
130  }
131  }
132 
133  auto value = getter_fn_(block_num);
134  if (is_empty(value)) {
135  return {};
136  }
137  // Not save old values in cache
138  auto last_num = lastBlockNum();
139  if (last_num < kBlocksToKeep || block_num >= last_num - kBlocksToKeep) {
140  append(block_num, value);
141  }
142  return value;
143  }
144 
145  Value last() const {
146  std::shared_lock lock(mutex_);
147  if (data_by_block_.empty()) {
148  return {};
149  }
150  return data_by_block_.rbegin()->second;
151  }
152 
153  uint64_t lastBlockNum() const {
154  std::shared_lock lock(mutex_);
155  if (data_by_block_.empty()) {
156  return 0;
157  }
158  return data_by_block_.rbegin()->first;
159  }
160 
161  protected:
162  const uint64_t kBlocksToKeep;
164 
165  // cache is used from const methods in other class, so should be mutable
166  mutable std::shared_mutex mutex_;
168 };
169 
170 } // namespace taraxa
Definition: cache.hpp:30
Value get(uint64_t blk_num, const Key &key) const
Definition: cache.hpp:59
const uint64_t kBlocksToKeep
Definition: cache.hpp:92
std::map< uint64_t, ValueMap > DataMap
Definition: cache.hpp:34
DataMap data_by_block_
Definition: cache.hpp:97
MapByBlockCache(uint64_t blocks_to_save, GetterFn &&getter_fn)
Definition: cache.hpp:41
std::unordered_map< Key, Value > ValueMap
Definition: cache.hpp:33
std::shared_mutex mutex_
Definition: cache.hpp:96
std::function< Value(uint64_t, const Key &)> GetterFn
Definition: cache.hpp:32
void append(uint64_t block_num, const Key &key, const Value &value) const
Definition: cache.hpp:44
MapByBlockCache(MapByBlockCache &&)=delete
MapByBlockCache & operator=(MapByBlockCache &&)=delete
uint64_t lastBlockNum() const
Definition: cache.hpp:83
GetterFn getter_fn_
Definition: cache.hpp:93
MapByBlockCache & operator=(const MapByBlockCache &)=delete
MapByBlockCache(const MapByBlockCache &)=delete
Definition: cache.hpp:101
Value get(uint64_t block_num) const
Definition: cache.hpp:124
ValueByBlockCache & operator=(const ValueByBlockCache &)=delete
std::shared_mutex mutex_
Definition: cache.hpp:166
ValueByBlockCache(uint64_t blocks_to_save, GetterFn &&getter_fn)
Definition: cache.hpp:111
const uint64_t kBlocksToKeep
Definition: cache.hpp:162
std::map< uint64_t, Value > DataMap
Definition: cache.hpp:104
ValueByBlockCache(const ValueByBlockCache &)=delete
uint64_t lastBlockNum() const
Definition: cache.hpp:153
void append(uint64_t block_num, Value value) const
Definition: cache.hpp:114
Value last() const
Definition: cache.hpp:145
std::function< Value(uint64_t)> GetterFn
Definition: cache.hpp:103
ValueByBlockCache(ValueByBlockCache &&)=delete
ValueByBlockCache & operator=(ValueByBlockCache &&)=delete
GetterFn getter_fn_
Definition: cache.hpp:163
DataMap data_by_block_
Definition: cache.hpp:167
std::hash for asio::adress
Definition: FixedHash.h:483
Definition: config.hpp:8