19 #ifndef PAGESPEED_KERNEL_CACHE_LRU_CACHE_BASE_H_
20 #define PAGESPEED_KERNEL_CACHE_LRU_CACHE_BASE_H_
26 #include "base/logging.h"
27 #include "strings/stringpiece_utils.h"
35 namespace net_instaweb {
60 template<
class ValueType,
class ValueHelper>
62 typedef std::pair<GoogleString, ValueType> KeyValuePair;
63 typedef std::list<KeyValuePair*> EntryList;
65 typedef typename EntryList::iterator ListNode;
67 typedef rde::hash_map<GoogleString, ListNode, CasePreserveStringHash> Map;
72 explicit Iterator(
const typename EntryList::const_reverse_iterator& iter)
76 void operator++() { ++iter_; }
77 bool operator==(
const Iterator& src)
const {
return iter_ == src.iter_; }
78 bool operator!=(
const Iterator& src)
const {
return iter_ != src.iter_; }
81 const KeyValuePair* key_value_pair = *iter_;
82 return key_value_pair->first;
84 const ValueType& Value()
const {
85 const KeyValuePair* key_value_pair = *iter_;
86 return key_value_pair->second;
90 typename EntryList::const_reverse_iterator iter_;
96 : max_bytes_in_cache_(max_size),
97 current_bytes_in_cache_(0),
98 value_helper_(value_helper) {
109 max_bytes_in_cache_ = max_size;
116 ValueType* value = NULL;
117 typename Map::iterator p = map_.find(key);
118 if (p != map_.end()) {
119 ListNode cell = p->second;
120 KeyValuePair* key_value = *cell;
121 p->second = Freshen(cell);
126 value = &key_value->second;
135 ValueType* value = NULL;
136 typename Map::const_iterator p = map_.find(key);
137 if (p != map_.end()) {
138 ListNode cell = p->second;
139 KeyValuePair* key_value = *cell;
141 value = &key_value->second;
159 std::pair<typename Map::iterator, bool> iter_found =
160 map_.insert(
typename Map::value_type(key, cell));
161 bool found = !iter_found.second;
162 typename Map::iterator map_iter = iter_found.first;
163 bool need_to_insert =
true;
165 cell = map_iter->second;
166 KeyValuePair* key_value = *cell;
171 if (!value_helper_->ShouldReplace(key_value->second, new_value)) {
172 need_to_insert =
false;
174 if (value_helper_->Equal(new_value, key_value->second)) {
175 map_iter->second = Freshen(cell);
176 need_to_insert =
false;
177 ++num_identical_reinserts_;
180 CHECK_GE(current_bytes_in_cache_, EntrySize(key_value));
181 current_bytes_in_cache_ -= EntrySize(key_value);
183 lru_ordered_list_.erase(cell);
188 if (need_to_insert) {
194 if (EvictIfNecessary(key.size() + value_helper_->size(new_value))) {
196 KeyValuePair* kvp =
new KeyValuePair(map_iter->first, new_value);
197 lru_ordered_list_.push_front(kvp);
198 map_iter->second = lru_ordered_list_.begin();
204 map_.erase(map_iter);
210 typename Map::iterator p = map_.find(key);
211 if (p != map_.end()) {
222 typename Map::iterator p = map_.begin();
223 while (p != map_.end()) {
224 if (strings::StartsWith(p->first, prefix)) {
225 typename Map::iterator next = p;
236 current_bytes_in_cache_ += src.current_bytes_in_cache_;
237 num_evictions_ += src.num_evictions_;
238 num_hits_ += src.num_hits_;
239 num_misses_ += src.num_misses_;
240 num_inserts_ += src.num_inserts_;
241 num_identical_reinserts_ += src.num_identical_reinserts_;
242 num_deletes_ += src.num_deletes_;
246 size_t size_bytes()
const {
return current_bytes_in_cache_; }
254 size_t num_evictions()
const {
return num_evictions_; }
255 size_t num_hits()
const {
return num_hits_; }
256 size_t num_misses()
const {
return num_misses_; }
257 size_t num_inserts()
const {
return num_inserts_; }
258 size_t num_identical_reinserts()
const {
return num_identical_reinserts_; }
259 size_t num_deletes()
const {
return num_deletes_; }
263 CHECK_EQ(static_cast<size_t>(map_.size()), lru_ordered_list_.size());
265 size_t bytes_used = 0;
269 for (ListNode cell = lru_ordered_list_.begin(), e = lru_ordered_list_.end();
270 cell != e; ++cell, ++count) {
271 KeyValuePair* key_value = *cell;
272 typename Map::iterator map_iter = map_.find(key_value->first);
273 CHECK(map_iter != map_.end());
274 CHECK(map_iter->first == key_value->first);
275 CHECK(map_iter->second == cell);
276 bytes_used += EntrySize(key_value);
278 CHECK_EQ(count, static_cast<size_t>(map_.size()));
279 CHECK_EQ(current_bytes_in_cache_, bytes_used);
280 CHECK_LE(current_bytes_in_cache_, max_bytes_in_cache_);
284 for (
typename EntryList::reverse_iterator cell = lru_ordered_list_.rbegin(),
285 e = lru_ordered_list_.rend(); cell != e; ++cell, ++count) {
287 CHECK_EQ(count, static_cast<size_t>(map_.size()));
293 current_bytes_in_cache_ = 0;
295 for (ListNode p = lru_ordered_list_.begin(), e = lru_ordered_list_.end();
297 KeyValuePair* key_value = *p;
300 lru_ordered_list_.clear();
310 num_identical_reinserts_ = 0;
315 Iterator
Begin()
const {
return Iterator(lru_ordered_list_.rbegin()); }
316 Iterator End()
const {
return Iterator(lru_ordered_list_.rend()); }
321 size_t EntrySize(KeyValuePair* kvp)
const {
322 return kvp->first.size() + value_helper_->size(kvp->second);
325 ListNode Freshen(ListNode cell) {
326 if (cell != lru_ordered_list_.begin()) {
327 lru_ordered_list_.splice(lru_ordered_list_.begin(),
332 return lru_ordered_list_.begin();
335 void DeleteAt(
typename Map::iterator p) {
336 ListNode cell = p->second;
337 KeyValuePair* key_value = *cell;
338 lru_ordered_list_.erase(cell);
339 CHECK_GE(current_bytes_in_cache_, EntrySize(key_value));
340 current_bytes_in_cache_ -= EntrySize(key_value);
346 bool EvictIfNecessary(
size_t bytes_needed) {
348 if (bytes_needed < max_bytes_in_cache_) {
349 while (bytes_needed + current_bytes_in_cache_ > max_bytes_in_cache_) {
350 KeyValuePair* key_value = lru_ordered_list_.back();
351 lru_ordered_list_.pop_back();
352 CHECK_GE(current_bytes_in_cache_, EntrySize(key_value));
353 current_bytes_in_cache_ -= EntrySize(key_value);
354 value_helper_->EvictNotify(key_value->second);
355 map_.erase(key_value->first);
359 current_bytes_in_cache_ += bytes_needed;
366 size_t max_bytes_in_cache_;
367 size_t current_bytes_in_cache_;
368 size_t num_evictions_;
369 mutable size_t num_hits_;
370 mutable size_t num_misses_;
372 size_t num_identical_reinserts_;
374 EntryList lru_ordered_list_;
376 ValueHelper* value_helper_;
ValueType * GetFreshen(const GoogleString &key)
Definition: lru_cache_base.h:115
size_t size_bytes() const
Total size in bytes of keys and values stored.
Definition: lru_cache_base.h:246
void Delete(const GoogleString &key)
Definition: lru_cache_base.h:209
void Clear()
Definition: lru_cache_base.h:292
void Put(const GoogleString &key, const ValueType &new_value)
Definition: lru_cache_base.h:151
void SanityCheck()
Sanity check the cache data structures.
Definition: lru_cache_base.h:262
void set_max_bytes_in_cache(size_t max_size)
Definition: lru_cache_base.h:108
Definition: lru_cache_base.h:61
ValueType * GetNoFreshen(const GoogleString &key) const
Definition: lru_cache_base.h:134
Iterator Begin() const
Iterators for walking cache entries from oldest to youngest.
Definition: lru_cache_base.h:315
Definition: lru_cache_base.h:70
std::string GoogleString
PAGESPEED_KERNEL_BASE_STRING_H_.
Definition: string.h:24
size_t num_elements() const
Number of elements stored.
Definition: lru_cache_base.h:252
size_t max_bytes_in_cache() const
Maximum capacity.
Definition: lru_cache_base.h:249
void DeleteWithPrefixForTesting(StringPiece prefix)
Definition: lru_cache_base.h:221
void ClearStats()
Clear the stats – note that this will not clear the content.
Definition: lru_cache_base.h:305