]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | #pragma once |
2 | ||
3 | #include <atomic> | |
4 | #include <chrono> | |
5 | #include <functional> | |
6 | #include <map> | |
7 | #include <memory> | |
8 | #include <string> | |
9 | #include <vector> | |
10 | ||
11 | #include "PyUtil.h" | |
12 | ||
20effc67 TL |
13 | template <class Key, class Value> class Cache { |
14 | private: | |
15 | std::atomic<uint64_t> hits, misses; | |
16 | ||
17 | protected: | |
18 | unsigned int capacity; | |
19 | Cache(unsigned int size = UINT16_MAX) : hits{0}, misses{0}, capacity{size} {}; | |
20 | std::map<Key, Value> content; | |
1e59de90 | 21 | std::vector<std::string> allowed_keys = {"osd_map", "pg_dump", "pg_stats"}; |
20effc67 TL |
22 | |
23 | void mark_miss() { | |
24 | misses++; | |
25 | } | |
26 | ||
27 | void mark_hit() { | |
28 | hits++; | |
29 | } | |
30 | ||
31 | unsigned int get_misses() { return misses; } | |
32 | unsigned int get_hits() { return hits; } | |
33 | void throw_key_not_found(Key key) { | |
34 | std::stringstream ss; | |
35 | ss << "Key " << key << " couldn't be found\n"; | |
36 | throw std::out_of_range(ss.str()); | |
37 | } | |
38 | ||
39 | public: | |
40 | void insert(Key key, Value value) { | |
41 | mark_miss(); | |
42 | if (content.size() < capacity) { | |
43 | content.insert({key, value}); | |
44 | } | |
45 | } | |
46 | Value get(Key key, bool count_hit = true) { | |
47 | if (count_hit) { | |
48 | mark_hit(); | |
49 | } | |
50 | return content[key]; | |
51 | } | |
52 | void erase(Key key) { content.erase(content.find(key)); } | |
53 | void clear() { content.clear(); } | |
54 | bool exists(Key key) { return content.find(key) != content.end(); } | |
55 | std::pair<uint64_t, uint64_t> get_hit_miss_ratio() { | |
56 | return std::make_pair(hits.load(), misses.load()); | |
57 | } | |
58 | bool is_cacheable(Key key) { | |
59 | for (auto k : allowed_keys) { | |
60 | if (key == k) return true; | |
61 | } | |
62 | return false; | |
63 | } | |
64 | int size() { return content.size(); } | |
65 | ||
66 | ~Cache(){}; | |
67 | }; | |
68 | ||
69 | using ttl_time_point = std::chrono::time_point<std::chrono::steady_clock>; | |
70 | template <class Key, class Value> | |
71 | class TTLCacheBase : public Cache<Key, std::pair<Value, ttl_time_point>> { | |
72 | private: | |
73 | uint16_t ttl; | |
74 | float ttl_spread_ratio; | |
75 | using value_type = std::pair<Value, ttl_time_point>; | |
76 | using cache = Cache<Key, value_type>; | |
77 | ||
78 | protected: | |
79 | Value get_value(Key key, bool count_hit = true); | |
80 | ttl_time_point get_value_time_point(Key key); | |
81 | bool exists(Key key); | |
82 | bool expired(Key key); | |
83 | void finish_get(Key key); | |
84 | void finish_erase(Key key); | |
85 | void throw_key_not_found(Key key); | |
86 | ||
87 | public: | |
88 | TTLCacheBase(uint16_t ttl_ = 0, uint16_t size = UINT16_MAX, | |
89 | float spread = 0.25) | |
90 | : Cache<Key, value_type>(size), ttl{ttl_}, ttl_spread_ratio{spread} {} | |
91 | ~TTLCacheBase(){}; | |
92 | void insert(Key key, Value value); | |
93 | Value get(Key key); | |
94 | void erase(Key key); | |
95 | void clear(); | |
96 | uint16_t get_ttl() { return ttl; }; | |
97 | void set_ttl(uint16_t ttl); | |
98 | }; | |
99 | ||
100 | template <class Key, class Value> | |
101 | class TTLCache : public TTLCacheBase<Key, Value> { | |
102 | public: | |
103 | TTLCache(uint16_t ttl_ = 0, uint16_t size = UINT16_MAX, float spread = 0.25) | |
104 | : TTLCacheBase<Key, Value>(ttl_, size, spread) {} | |
105 | ~TTLCache(){}; | |
106 | }; | |
107 | ||
108 | template <class Key> | |
109 | class TTLCache<Key, PyObject*> : public TTLCacheBase<Key, PyObject*> { | |
110 | public: | |
111 | TTLCache(uint16_t ttl_ = 0, uint16_t size = UINT16_MAX, float spread = 0.25) | |
112 | : TTLCacheBase<Key, PyObject*>(ttl_, size, spread) {} | |
113 | ~TTLCache(){}; | |
114 | PyObject* get(Key key); | |
115 | void erase(Key key); | |
116 | ||
117 | private: | |
118 | using ttl_base = TTLCacheBase<Key, PyObject*>; | |
119 | }; | |
120 | ||
121 | #include "TTLCache.cc" | |
122 |