This repository has been archived by the owner on Apr 30, 2020. It is now read-only.
forked from gigablast/open-source-search-engine
-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathGbCache.h
163 lines (129 loc) · 3.23 KB
/
GbCache.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#ifndef GB_GBCACHE_H
#define GB_GBCACHE_H
#include "GbMutex.h"
#include "ScopedLock.h"
#include "Log.h"
#include "fctypes.h"
#include <inttypes.h>
#include <unordered_map>
#include <deque>
#include <algorithm>
#include <sstream>
template <typename TKey, typename TData>
class GbCache {
public:
GbCache()
: m_mtx()
, m_queue()
, m_map()
, m_max_age(300000) // 5 minutes
, m_max_item(10000)
, m_log_trace(false)
, m_log_cache_name("cache") {
}
~GbCache() {
clear();
}
void configure(int64_t max_age, size_t max_item, bool log_trace, const char *log_cache_name) {
ScopedLock sl(m_mtx);
m_max_age = max_age;
m_max_item = max_item;
m_log_trace = log_trace;
m_log_cache_name = log_cache_name;
if (disabled()) {
clear_unlocked();
}
}
void clear() {
ScopedLock sl(m_mtx);
clear_unlocked();
}
void insert(const TKey &key, const TData &data) {
ScopedLock sl(m_mtx);
// cache disabled
if (disabled()) {
return;
}
purge_step();
if (m_log_trace) {
logTrace(m_log_trace, "inserting key='%s' to %s", getKeyStr(key).c_str(), m_log_cache_name);
}
CacheItem item(data);
auto map_it = m_map.find(key);
if (map_it == m_map.end()) {
m_map.insert(std::make_pair(key, item));
} else {
map_it->second = item;
auto queue_it = std::find(m_queue.begin(), m_queue.end(), key);
if (queue_it != m_queue.end()) {
m_queue.erase(queue_it);
}
}
m_queue.push_back(key);
if (m_queue.size() > m_max_item) {
purge_step(true);
}
}
bool lookup(const TKey &key, TData *data) {
ScopedLock sl(m_mtx);
// cache disabled
if (disabled()) {
return false;
}
purge_step();
auto map_it = m_map.find(key);
if (map_it != m_map.end() && !expired(map_it->second)) {
logTrace(m_log_trace, "found key='%s' in %s", getKeyStr(key).c_str(), m_log_cache_name);
*data = map_it->second.m_data;
return true;
} else {
logTrace(m_log_trace, "unable to find key='%s' in %s", getKeyStr(key).c_str(), m_log_cache_name);
return false;
}
}
private:
GbCache(const GbCache&);
GbCache& operator=(const GbCache&);
struct CacheItem {
CacheItem(const TData &data)
: m_timestamp(gettimeofdayInMilliseconds())
, m_data(data) {
}
int64_t m_timestamp;
TData m_data;
};
bool expired(const CacheItem &item) const {
return (item.m_timestamp + m_max_age < gettimeofdayInMilliseconds());
}
bool disabled() const {
return (m_max_age == 0 || m_max_item == 0);
}
void clear_unlocked() {
m_map.clear();
m_queue.clear();
}
static std::string getKeyStr(const TKey &key) {
std::stringstream os;
os << key;
return os.str();
}
void purge_step(bool forced=false) {
if (m_queue.empty()) {
return;
}
auto iter = m_map.find(m_queue.front());
assert(iter != m_map.end());
if (forced || expired(iter->second)) {
m_map.erase(iter);
m_queue.pop_front();
}
}
GbMutex m_mtx;
std::deque<TKey> m_queue; //queue of items to expire, ordered by epiration time
std::unordered_map<TKey,CacheItem> m_map; //cached items
int64_t m_max_age; //max item age (expiry) in msecs
size_t m_max_item; //maximum number of items
bool m_log_trace;
const char *m_log_cache_name;
};
#endif //GB_GBCACHE_H