Page Speed Optimization Libraries  1.13.35.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
lru_cache_base.h
Go to the documentation of this file.
1 /*
2  * Copyright 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http:///www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #ifndef PAGESPEED_KERNEL_CACHE_LRU_CACHE_BASE_H_
20 #define PAGESPEED_KERNEL_CACHE_LRU_CACHE_BASE_H_
21 
22 #include <cstddef>
23 #include <list>
24 #include <utility>
25 
26 #include "base/logging.h"
27 #include "strings/stringpiece_utils.h"
33 
34 
35 namespace net_instaweb {
36 
60 template<class ValueType, class ValueHelper>
61 class LRUCacheBase {
62  typedef std::pair<GoogleString, ValueType> KeyValuePair;
63  typedef std::list<KeyValuePair*> EntryList;
65  typedef typename EntryList::iterator ListNode;
66 
67  typedef rde::hash_map<GoogleString, ListNode, CasePreserveStringHash> Map;
68 
69  public:
70  class Iterator {
71  public:
72  explicit Iterator(const typename EntryList::const_reverse_iterator& iter)
73  : iter_(iter) {
74  }
75 
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_; }
79 
80  const GoogleString& Key() const {
81  const KeyValuePair* key_value_pair = *iter_;
82  return key_value_pair->first;
83  }
84  const ValueType& Value() const {
85  const KeyValuePair* key_value_pair = *iter_;
86  return key_value_pair->second;
87  }
88 
89  private:
90  typename EntryList::const_reverse_iterator iter_;
91 
93  };
94 
95  LRUCacheBase(size_t max_size, ValueHelper* value_helper)
96  : max_bytes_in_cache_(max_size),
97  current_bytes_in_cache_(0),
98  value_helper_(value_helper) {
99  ClearStats();
100  }
101  ~LRUCacheBase() {
102  Clear();
103  }
104 
108  void set_max_bytes_in_cache(size_t max_size) {
109  max_bytes_in_cache_ = max_size;
110  }
111 
115  ValueType* GetFreshen(const GoogleString& key) {
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;
127  ++num_hits_;
128  } else {
129  ++num_misses_;
130  }
131  return value;
132  }
133 
134  ValueType* GetNoFreshen(const GoogleString& key) const {
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;
142  ++num_hits_;
143  } else {
144  ++num_misses_;
145  }
146  return value;
147  }
148 
151  void Put(const GoogleString& key, const ValueType& new_value) {
158  ListNode cell;
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;
164  if (found) {
165  cell = map_iter->second;
166  KeyValuePair* key_value = *cell;
167 
171  if (!value_helper_->ShouldReplace(key_value->second, new_value)) {
172  need_to_insert = false;
173  } else {
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_;
178  } else {
179  ++num_deletes_;
180  CHECK_GE(current_bytes_in_cache_, EntrySize(key_value));
181  current_bytes_in_cache_ -= EntrySize(key_value);
182  delete key_value;
183  lru_ordered_list_.erase(cell);
184  }
185  }
186  }
187 
188  if (need_to_insert) {
193 
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();
199  ++num_inserts_;
200  } else {
204  map_.erase(map_iter);
205  }
206  }
207  }
208 
209  void Delete(const GoogleString& key) {
210  typename Map::iterator p = map_.find(key);
211  if (p != map_.end()) {
212  DeleteAt(p);
213  } else {
215  }
216  }
217 
221  void DeleteWithPrefixForTesting(StringPiece prefix) {
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;
226  ++next;
227  DeleteAt(p);
228  p = next;
229  } else {
230  ++p;
231  }
232  }
233  }
234 
235  void MergeStats(const LRUCacheBase& src) {
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_;
243  }
244 
246  size_t size_bytes() const { return current_bytes_in_cache_; }
247 
249  size_t max_bytes_in_cache() const { return max_bytes_in_cache_; }
250 
252  size_t num_elements() const { return map_.size(); }
253 
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_; }
260 
262  void SanityCheck() {
263  CHECK_EQ(static_cast<size_t>(map_.size()), lru_ordered_list_.size());
264  size_t count = 0;
265  size_t bytes_used = 0;
266 
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);
277  }
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_);
281 
283  count = 0;
284  for (typename EntryList::reverse_iterator cell = lru_ordered_list_.rbegin(),
285  e = lru_ordered_list_.rend(); cell != e; ++cell, ++count) {
286  }
287  CHECK_EQ(count, static_cast<size_t>(map_.size()));
288  }
289 
292  void Clear() {
293  current_bytes_in_cache_ = 0;
294 
295  for (ListNode p = lru_ordered_list_.begin(), e = lru_ordered_list_.end();
296  p != e; ++p) {
297  KeyValuePair* key_value = *p;
298  delete key_value;
299  }
300  lru_ordered_list_.clear();
301  map_.clear();
302  }
303 
305  void ClearStats() {
306  num_evictions_ = 0;
307  num_hits_ = 0;
308  num_misses_ = 0;
309  num_inserts_ = 0;
310  num_identical_reinserts_ = 0;
311  num_deletes_ = 0;
312  }
313 
315  Iterator Begin() const { return Iterator(lru_ordered_list_.rbegin()); }
316  Iterator End() const { return Iterator(lru_ordered_list_.rend()); }
317 
318  private:
321  size_t EntrySize(KeyValuePair* kvp) const {
322  return kvp->first.size() + value_helper_->size(kvp->second);
323  }
324 
325  ListNode Freshen(ListNode cell) {
326  if (cell != lru_ordered_list_.begin()) {
327  lru_ordered_list_.splice(lru_ordered_list_.begin(),
328  lru_ordered_list_,
329  cell);
330  }
331 
332  return lru_ordered_list_.begin();
333  }
334 
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);
341  map_.erase(p);
342  delete key_value;
343  ++num_deletes_;
344  }
345 
346  bool EvictIfNecessary(size_t bytes_needed) {
347  bool ret = false;
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);
356  delete key_value;
357  ++num_evictions_;
358  }
359  current_bytes_in_cache_ += bytes_needed;
360  ret = true;
361  }
362  return ret;
363  }
364 
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_;
371  size_t num_inserts_;
372  size_t num_identical_reinserts_;
373  size_t num_deletes_;
374  EntryList lru_ordered_list_;
375  Map map_;
376  ValueHelper* value_helper_;
377 
378 
379 };
380 
381 }
382 
383 #endif
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