rippled
KeyCache.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_BASICS_KEYCACHE_H_INCLUDED
21 #define RIPPLE_BASICS_KEYCACHE_H_INCLUDED
22 
23 #include <ripple/basics/UnorderedContainers.h>
24 #include <ripple/basics/hardened_hash.h>
25 #include <ripple/beast/clock/abstract_clock.h>
26 #include <ripple/beast/insight/Insight.h>
27 #include <mutex>
28 
29 namespace ripple {
30 
37 template <
38  class Key,
39  class Hash = hardened_hash<>,
40  class KeyEqual = std::equal_to<Key>,
41  // class Allocator = std::allocator <std::pair <Key const, Entry>>,
42  class Mutex = std::mutex>
43 class KeyCache
44 {
45 public:
46  using key_type = Key;
48 
49 private:
50  struct Stats
51  {
52  template <class Handler>
54  std::string const& prefix,
55  Handler const& handler,
56  beast::insight::Collector::ptr const& collector)
57  : hook(collector->make_hook(handler))
58  , size(collector->make_gauge(prefix, "size"))
59  , hit_rate(collector->make_gauge(prefix, "hit_rate"))
60  , hits(0)
61  , misses(0)
62  {
63  }
64 
68 
71  };
72 
73  struct Entry
74  {
75  explicit Entry(clock_type::time_point const& last_access_)
76  : last_access(last_access_)
77  {
78  }
79 
81  };
82 
84  using iterator = typename map_type::iterator;
85 
86 public:
87  using size_type = typename map_type::size_type;
88 
89 private:
90  Mutex mutable m_mutex;
92  Stats mutable m_stats;
97 
98 public:
105  std::string const& name,
106  clock_type& clock,
107  beast::insight::Collector::ptr const& collector,
108  size_type target_size = 0,
110  : m_stats(name, std::bind(&KeyCache::collect_metrics, this), collector)
111  , m_clock(clock)
112  , m_name(name)
113  , m_target_size(target_size)
114  , m_target_age(expiration)
115  {
116  }
117 
118  // VFALCO TODO Use a forwarding constructor call here
120  std::string const& name,
121  clock_type& clock,
122  size_type target_size = 0,
124  : m_stats(
125  name,
128  , m_clock(clock)
129  , m_name(name)
130  , m_target_size(target_size)
131  , m_target_age(expiration)
132  {
133  }
134 
135  //--------------------------------------------------------------------------
136 
138  std::string const&
139  name() const
140  {
141  return m_name;
142  }
143 
145  clock_type&
147  {
148  return m_clock;
149  }
150 
152  size_type
153  size() const
154  {
155  std::lock_guard lock(m_mutex);
156  return m_map.size();
157  }
158 
160  void
162  {
163  std::lock_guard lock(m_mutex);
164  m_map.clear();
165  }
166 
167  void
169  {
170  std::lock_guard lock(m_mutex);
171  m_map.clear();
172  m_stats.hits = 0;
173  m_stats.misses = 0;
174  }
175 
176  void
178  {
179  std::lock_guard lock(m_mutex);
180  m_target_size = s;
181  }
182 
183  void
185  {
186  std::lock_guard lock(m_mutex);
187  m_target_age = s;
188  }
189 
193  template <class KeyComparable>
194  bool
195  exists(KeyComparable const& key) const
196  {
197  std::lock_guard lock(m_mutex);
198  typename map_type::const_iterator const iter(m_map.find(key));
199  if (iter != m_map.end())
200  {
201  ++m_stats.hits;
202  return true;
203  }
204  ++m_stats.misses;
205  return false;
206  }
207 
212  bool
213  insert(Key const& key)
214  {
215  std::lock_guard lock(m_mutex);
216  clock_type::time_point const now(m_clock.now());
217  auto [it, inserted] = m_map.emplace(
218  std::piecewise_construct,
220  std::forward_as_tuple(now));
221  if (!inserted)
222  {
223  it->second.last_access = now;
224  return false;
225  }
226  return true;
227  }
228 
232  template <class KeyComparable>
233  bool
234  touch_if_exists(KeyComparable const& key)
235  {
236  std::lock_guard lock(m_mutex);
237  iterator const iter(m_map.find(key));
238  if (iter == m_map.end())
239  {
240  ++m_stats.misses;
241  return false;
242  }
243  iter->second.last_access = m_clock.now();
244  ++m_stats.hits;
245  return true;
246  }
247 
252  bool
253  erase(key_type const& key)
254  {
255  std::lock_guard lock(m_mutex);
256  if (m_map.erase(key) > 0)
257  {
258  ++m_stats.hits;
259  return true;
260  }
261  ++m_stats.misses;
262  return false;
263  }
264 
266  void
268  {
269  clock_type::time_point const now(m_clock.now());
270  clock_type::time_point when_expire;
271 
272  std::lock_guard lock(m_mutex);
273 
274  if (m_target_size == 0 || (m_map.size() <= m_target_size))
275  {
276  when_expire = now - m_target_age;
277  }
278  else
279  {
280  when_expire = now - m_target_age * m_target_size / m_map.size();
281 
282  clock_type::duration const minimumAge(std::chrono::seconds(1));
283  if (when_expire > (now - minimumAge))
284  when_expire = now - minimumAge;
285  }
286 
287  iterator it = m_map.begin();
288 
289  while (it != m_map.end())
290  {
291  if (it->second.last_access > now)
292  {
293  it->second.last_access = now;
294  ++it;
295  }
296  else if (it->second.last_access <= when_expire)
297  {
298  it = m_map.erase(it);
299  }
300  else
301  {
302  ++it;
303  }
304  }
305  }
306 
307 private:
308  void
310  {
311  m_stats.size.set(size());
312 
313  {
315  {
316  std::lock_guard lock(m_mutex);
317  auto const total(m_stats.hits + m_stats.misses);
318  if (total != 0)
319  hit_rate = (m_stats.hits * 100) / total;
320  }
321  m_stats.hit_rate.set(hit_rate);
322  }
323  }
324 };
325 
326 } // namespace ripple
327 
328 #endif
ripple::KeyCache::m_mutex
Mutex m_mutex
Definition: KeyCache.h:90
ripple::KeyCache::m_stats
Stats m_stats
Definition: KeyCache.h:92
ripple::KeyCache< ripple::base_uint >::iterator
typename map_type::iterator iterator
Definition: KeyCache.h:84
ripple::KeyCache::size
size_type size() const
Returns the number of items in the container.
Definition: KeyCache.h:153
std::bind
T bind(T... args)
std::string
STL class.
std::shared_ptr< Collector >
ripple::KeyCache::erase
bool erase(key_type const &key)
Remove the specified cache entry.
Definition: KeyCache.h:253
ripple::KeyCache::m_map
map_type m_map
Definition: KeyCache.h:91
ripple::KeyCache::Stats::Stats
Stats(std::string const &prefix, Handler const &handler, beast::insight::Collector::ptr const &collector)
Definition: KeyCache.h:53
ripple::KeyCache::m_name
const std::string m_name
Definition: KeyCache.h:94
std::unordered_map::find
T find(T... args)
std::unordered_map::size
T size(T... args)
ripple::KeyCache::Stats::size
beast::insight::Gauge size
Definition: KeyCache.h:66
std::chrono::seconds
ripple::KeyCache::collect_metrics
void collect_metrics()
Definition: KeyCache.h:309
ripple::KeyCache::Stats::hits
std::size_t hits
Definition: KeyCache.h:69
std::unordered_map::emplace
T emplace(T... args)
std::lock_guard
STL class.
ripple::KeyCache::reset
void reset()
Definition: KeyCache.h:168
std::unordered_map::clear
T clear(T... args)
beast::abstract_clock::now
virtual time_point now() const =0
Returns the current time.
ripple::KeyCache::touch_if_exists
bool touch_if_exists(KeyComparable const &key)
Refresh the last access time on a key if present.
Definition: KeyCache.h:234
ripple::KeyCache::m_clock
clock_type & m_clock
Definition: KeyCache.h:93
ripple::KeyCache::m_target_size
size_type m_target_size
Definition: KeyCache.h:95
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:73
ripple::KeyCache::KeyCache
KeyCache(std::string const &name, clock_type &clock, beast::insight::Collector::ptr const &collector, size_type target_size=0, std::chrono::seconds expiration=std::chrono::minutes{2})
Construct with the specified name.
Definition: KeyCache.h:104
ripple::KeyCache::insert
bool insert(Key const &key)
Insert the specified key.
Definition: KeyCache.h:213
ripple::KeyCache::clock_type
beast::abstract_clock< std::chrono::steady_clock > clock_type
Definition: KeyCache.h:47
ripple::KeyCache::Stats::hit_rate
beast::insight::Gauge hit_rate
Definition: KeyCache.h:67
std::unordered_map::erase
T erase(T... args)
ripple::KeyCache::exists
bool exists(KeyComparable const &key) const
Returns true if the key was found.
Definition: KeyCache.h:195
ripple::KeyCache::m_target_age
clock_type::duration m_target_age
Definition: KeyCache.h:96
std::uint64_t
std::forward_as_tuple
T forward_as_tuple(T... args)
ripple::KeyCache::sweep
void sweep()
Remove stale entries from the cache.
Definition: KeyCache.h:267
beast::abstract_clock< std::chrono::steady_clock >
ripple::KeyCache::Entry::Entry
Entry(clock_type::time_point const &last_access_)
Definition: KeyCache.h:75
beast::insight::Gauge
A metric for measuring an integral value.
Definition: Gauge.h:39
ripple::KeyCache::KeyCache
KeyCache(std::string const &name, clock_type &clock, size_type target_size=0, std::chrono::seconds expiration=std::chrono::minutes{2})
Definition: KeyCache.h:119
std::equal_to
ripple::KeyCache::clear
void clear()
Empty the cache.
Definition: KeyCache.h:161
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::KeyCache::Entry::last_access
clock_type::time_point last_access
Definition: KeyCache.h:80
ripple::KeyCache::setTargetSize
void setTargetSize(size_type s)
Definition: KeyCache.h:177
std::unordered_map::begin
T begin(T... args)
ripple::KeyCache< ripple::base_uint >::size_type
typename map_type::size_type size_type
Definition: KeyCache.h:87
ripple::KeyCache::Entry
Definition: KeyCache.h:73
ripple::KeyCache::setTargetAge
void setTargetAge(std::chrono::seconds s)
Definition: KeyCache.h:184
ripple::KeyCache::name
std::string const & name() const
Retrieve the name of this object.
Definition: KeyCache.h:139
ripple::KeyCache::Stats
Definition: KeyCache.h:50
ripple::KeyCache::Stats::misses
std::size_t misses
Definition: KeyCache.h:70
mutex
std::size_t
std::unordered_map::end
T end(T... args)
ripple::KeyCache::clock
clock_type & clock()
Return the clock associated with the cache.
Definition: KeyCache.h:146
ripple::KeyCache
Maintains a cache of keys with no associated data.
Definition: KeyCache.h:43
std::unordered_map
STL class.
beast::abstract_clock< std::chrono::steady_clock >::time_point
typename std::chrono::steady_clock ::time_point time_point
Definition: abstract_clock.h:63
beast::insight::Hook
A reference to a handler for performing polled collection.
Definition: Hook.h:31
beast::insight::NullCollector::New
static std::shared_ptr< Collector > New()
Definition: NullCollector.cpp:152
beast::abstract_clock< std::chrono::steady_clock >::duration
typename std::chrono::steady_clock ::duration duration
Definition: abstract_clock.h:62
ripple::KeyCache::Stats::hook
beast::insight::Hook hook
Definition: KeyCache.h:65
beast::insight::Gauge::set
void set(value_type value) const
Set the value on the gauge.
Definition: Gauge.h:68