Pyrogenesis  trunk
cache_adt.h
Go to the documentation of this file.
1 /* Copyright (C) 2021 Wildfire Games.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * Customizable cache data structure.
25  */
26 
27 #ifndef INCLUDED_CACHE_ADT
28 #define INCLUDED_CACHE_ADT
29 
30 #include <cfloat>
31 #include <list>
32 #include <queue> // std::priority_queue
33 #include <unordered_map>
34 
35 /*
36 Cache for items of variable size and value/"cost".
37 underlying displacement algorithm is pluggable; default is "Landlord".
38 
39 template reference:
40 Entry provides size, cost, credit and credit_density().
41  rationale:
42  - made a template instead of exposing Cache::Entry because
43  that would drag a lot of stuff out of Cache.
44  - calculates its own density since that entails a Divider functor,
45  which requires storage inside Entry.
46 Entries is a collection with iterator and begin()/end() and
47  "static Entry& entry_from_it(iterator)".
48  rationale:
49  - STL map has pair<key, item> as its value_type, so this
50  function would return it->second. however, we want to support
51  other container types (where we'd just return *it).
52 Manager is a template parameterized on typename Key and class Entry.
53  its interface is as follows:
54 
55  // is the cache empty?
56  bool empty() const;
57 
58  // add (key, entry) to cache.
59  void add(const Key& key, const Entry& entry);
60 
61  // if the entry identified by <key> is not in cache, return false;
62  // otherwise return true and pass back a pointer to it.
63  bool find(const Key& key, const Entry** pentry) const;
64 
65  // remove an entry from cache, which is assumed to exist!
66  // this makes sense because callers will typically first use find() to
67  // return info about the entry; this also checks if present.
68  void remove(const Key& key);
69 
70  // mark <entry> as just accessed for purpose of cache management.
71  // it will tend to be kept in cache longer.
72  void on_access(Entry& entry);
73 
74  // caller's intent is to remove the least valuable entry.
75  // in implementing this, you have the latitude to "shake loose"
76  // several entries (e.g. because their 'value' is equal).
77  // they must all be push_back-ed into the list; Cache will dole
78  // them out one at a time in FIFO order to callers.
79  //
80  // rationale:
81  // - it is necessary for callers to receive a copy of the
82  // Entry being evicted - e.g. file_cache owns its items and
83  // they must be passed back to allocator when evicted.
84  // - e.g. Landlord can potentially see several entries become
85  // evictable in one call to remove_least_valuable. there are
86  // several ways to deal with this:
87  // 1) generator interface: we return one of { empty, nevermind,
88  // removed, remove-and-call-again }. this greatly complicates
89  // the call site.
90  // 2) return immediately after finding an item to evict.
91  // this changes cache behavior - entries stored at the
92  // beginning would be charged more often (unfair).
93  // resuming charging at the next entry doesn't work - this
94  // would have to be flushed when adding, at which time there
95  // is no provision for returning any items that may be evicted.
96  // 3) return list of all entries "shaken loose". this incurs
97  // frequent mem allocs, which can be alleviated via suballocator.
98  // note: an intrusive linked-list doesn't make sense because
99  // entries to be returned need to be copied anyway (they are
100  // removed from the manager's storage).
101  void remove_least_valuable(std::list<Entry>& entry_list)
102 */
103 
104 
105 //
106 // functors to calculate minimum credit density (MCD)
107 //
108 
109 // MCD is required for the Landlord algorithm's evict logic.
110 // [Young02] calls it '\delta'.
111 
112 // scan over all entries and return MCD.
113 template<class Entries> float ll_calc_min_credit_density(const Entries& entries)
114 {
115  float min_credit_density = FLT_MAX;
116  for(typename Entries::const_iterator it = entries.begin(); it != entries.end(); ++it)
117  {
118  const float credit_density = Entries::entry_from_it(it).credit_density();
119  min_credit_density = std::min(min_credit_density, credit_density);
120  }
121  return min_credit_density;
122 }
123 
124 // note: no warning is given that the MCD entry is being removed!
125 // (reduces overhead in remove_least_valuable)
126 // these functors must account for that themselves (e.g. by resetting
127 // their state directly after returning MCD).
128 
129 // determine MCD by scanning over all entries.
130 // tradeoff: O(N) time complexity, but all notify* calls are no-ops.
131 template<class Entry, class Entries>
133 {
134 public:
135  void notify_added(const Entry&) const {}
136  void notify_decreased(const Entry&) const {}
138  void notify_increased_or_removed(const Entry&) const {}
139  float operator()(const Entries& entries) const
140  {
141  const float mcd = ll_calc_min_credit_density(entries);
142  return mcd;
143  }
144 };
145 
146 // cache previous MCD and update it incrementally (when possible).
147 // tradeoff: amortized O(1) time complexity, but notify* calls must
148 // perform work whenever something in the cache changes.
149 template<class Entry, class Entries>
151 {
152 public:
153  McdCalc_Cached() : min_credit_density(FLT_MAX), min_valid(false) {}
154 
155  void notify_added(const Entry& entry)
156  {
157  // when adding a new item, the minimum credit density can only
158  // decrease or remain the same; acting as if entry's credit had
159  // been decreased covers both cases.
160  notify_decreased(entry);
161  }
162 
163  void notify_decreased(const Entry& entry)
164  {
165  min_credit_density = std::min(min_credit_density, entry.credit_density());
166  }
167 
169  {
170  // remember if this entry had the smallest density
171  is_min_entry = feq(min_credit_density, entry.credit_density());
172  }
173 
175  {
176  // .. it did and was increased or removed. we must invalidate
177  // MCD and recalculate it next time.
178  if(is_min_entry)
179  {
180  min_valid = false;
181  min_credit_density = -1.0f;
182  }
183  }
184 
185  float operator()(const Entries& entries)
186  {
187  if(min_valid)
188  {
189  // the entry that has MCD will be removed anyway by caller;
190  // we need to invalidate here because they don't call
191  // notify_increased_or_removed.
192  min_valid = false;
193  return min_credit_density;
194  }
195 
196  // this is somewhat counterintuitive. since we're calculating
197  // MCD directly, why not mark our cached version of it valid
198  // afterwards? reason is that our caller will remove the entry with
199  // MCD, so it'll be invalidated anyway.
200  // instead, our intent is to calculate MCD for the *next time*.
201  const float ret = ll_calc_min_credit_density(entries);
202  min_valid = true;
203  min_credit_density = FLT_MAX;
204  return ret;
205  }
206 
207 private:
209  bool min_valid;
210 
211  // temporary flag set by notify_impending_increase_or_remove
213 };
214 
215 
216 //
217 // Landlord cache management policy: see [Young02].
218 //
219 
220 // in short, each entry has credit initially set to cost. when wanting to
221 // remove an item, all are charged according to MCD and their size;
222 // entries are evicted if their credit is exhausted. accessing an entry
223 // restores "some" of its credit.
224 template<typename Key, typename Entry, template<class Entry_, class Entries> class McdCalc = McdCalc_Cached>
225 class Landlord
226 {
227 public:
228  bool empty() const
229  {
230  return map.empty();
231  }
232 
233  void add(const Key& key, const Entry& entry)
234  {
235  // adapter for add_ (which returns an iterator)
236  (void)add_(key, entry);
237  }
238 
239  bool find(const Key& key, const Entry** pentry) const
240  {
241  MapCIt it = map.find(key);
242  if(it == map.end())
243  return false;
244  *pentry = &it->second;
245  return true;
246  }
247 
248  void remove(const Key& key)
249  {
250  MapIt it = map.find(key);
251  // note: don't complain if not in the cache: this happens after
252  // writing a file and invalidating its cache entry, which may
253  // or may not exist.
254  if(it != map.end())
255  remove_(it);
256  }
257 
258  void on_access(Entry& entry)
259  {
260  mcd_calc.notify_impending_increase_or_remove(entry);
261 
262  // Landlord algorithm calls for credit to be reset to anything
263  // between its current value and the cost.
264  const float gain = 0.75f; // restore most credit
265  entry.credit = gain*entry.cost + (1.0f-gain)*entry.credit;
266 
267  mcd_calc.notify_increased_or_removed(entry);
268  }
269 
270  void remove_least_valuable(std::list<Entry>& entry_list)
271  {
272  // we are required to evict at least one entry. one iteration
273  // ought to suffice, due to definition of min_credit_density and
274  // tolerance; however, we provide for repeating if necessary.
275 again:
276 
277  // messing with this (e.g. raising if tiny) would result in
278  // different evictions than Landlord_Lazy, which is unacceptable.
279  // nor is doing so necessary: if mcd is tiny, so is credit.
280  const float min_credit_density = mcd_calc(map);
281  ENSURE(min_credit_density > 0.0f);
282 
283  for(MapIt it = map.begin(); it != map.end();) // no ++it
284  {
285  Entry& entry = it->second;
286 
287  charge(entry, min_credit_density);
288  if(should_evict(entry))
289  {
290  entry_list.push_back(entry);
291 
292  // annoying: we have to increment <it> before erasing
293  MapIt it_to_remove = it++;
294  map.erase(it_to_remove);
295  }
296  else
297  {
298  mcd_calc.notify_decreased(entry);
299  ++it;
300  }
301  }
302 
303  if(entry_list.empty())
304  goto again;
305  }
306 
307 protected:
308  class Map : public std::unordered_map<Key, Entry>
309  {
310  public:
311  static Entry& entry_from_it(typename Map::iterator it) { return it->second; }
312  static const Entry& entry_from_it(typename Map::const_iterator it) { return it->second; }
313  };
314  typedef typename Map::iterator MapIt;
315  typedef typename Map::const_iterator MapCIt;
316  Map map;
317 
318  // add entry and return iterator pointing to it.
319  MapIt add_(const Key& key, const Entry& entry)
320  {
321  typedef std::pair<MapIt, bool> PairIB;
322  typename Map::value_type val = std::make_pair(key, entry);
323  PairIB ret = map.insert(val);
324  ENSURE(ret.second); // must not already be in map
325 
326  mcd_calc.notify_added(entry);
327 
328  return ret.first;
329  }
330 
331  // remove entry (given by iterator) directly.
332  void remove_(MapIt it)
333  {
334  const Entry& entry = it->second;
335  mcd_calc.notify_impending_increase_or_remove(entry);
336  mcd_calc.notify_increased_or_removed(entry);
337  map.erase(it);
338  }
339 
340  void charge(Entry& entry, float delta)
341  {
342  entry.credit -= delta * entry.size;
343 
344  // don't worry about entry.size being 0 - if so, cost
345  // should also be 0, so credit will already be 0 anyway.
346  }
347 
348  // for each entry, 'charge' it (i.e. reduce credit by) delta * its size.
349  // delta is typically MCD (see above); however, several such updates
350  // may be lumped together to save time. Landlord_Lazy does this.
351  void charge_all(float delta)
352  {
353  for(MapIt it = map.begin(); it != map.end(); ++it)
354  {
355  Entry& entry = it->second;
356  entry.credit -= delta * entry.size;
357  if(!should_evict(entry))
358  mcd_calc.notify_decreased(entry);
359  }
360  }
361 
362  // is entry's credit exhausted? if so, it should be evicted.
363  bool should_evict(const Entry& entry)
364  {
365  // we need a bit of leeway because density calculations may not
366  // be exact. choose value carefully: must not be high enough to
367  // trigger false positives.
368  return entry.credit < 0.0001f;
369  }
370 
371 private:
372  McdCalc<Entry, Map> mcd_calc;
373 };
374 
375 // Cache manger policies. (these are partial specializations of Landlord,
376 // adapting it to the template params required by Cache)
377 template<class Key, class Entry> class Landlord_Naive : public Landlord<Key, Entry, McdCalc_Naive> {};
378 template<class Key, class Entry> class Landlord_Cached: public Landlord<Key, Entry, McdCalc_Cached> {};
379 
380 // variant of Landlord that adds a priority queue to directly determine
381 // which entry to evict. this allows lumping several charge operations
382 // together and thus reduces iteration over all entries.
383 // tradeoff: O(logN) removal (instead of N), but additional O(N) storage.
384 template<typename Key, class Entry>
385 class Landlord_Lazy : public Landlord_Naive<Key, Entry>
386 {
390 
391 public:
392  Landlord_Lazy() { pending_delta = 0.0f; }
393 
394  void add(const Key& key, const Entry& entry)
395  {
396  // we must apply pending_delta now - otherwise, the existing delta
397  // would later be applied to this newly added item (incorrect).
398  commit_pending_delta();
399 
400  MapIt it = Parent::add_(key, entry);
401  pri_q.push(it);
402  }
403 
404  void remove(const Key& key)
405  {
406  Parent::remove(key);
407 
408  // reconstruct pri_q from current map. this is slow (N*logN) and
409  // could definitely be done better, but we don't bother since
410  // remove is a very rare operation (e.g. invalidating entries).
411  while(!pri_q.empty())
412  pri_q.pop();
413  for(MapCIt it = this->map.begin(); it != this->map.end(); ++it)
414  pri_q.push(it);
415  }
416 
417  void on_access(Entry& entry)
418  {
419  Parent::on_access(entry);
420 
421  // entry's credit was changed. we now need to reshuffle the
422  // pri queue to reflect this.
423  pri_q.ensure_heap_order();
424  }
425 
426  void remove_least_valuable(std::list<Entry>& entry_list)
427  {
428  MapIt least_valuable_it = pri_q.top(); pri_q.pop();
429  Entry& entry = Map::entry_from_it(least_valuable_it);
430 
431  entry_list.push_back(entry);
432 
433  // add to pending_delta the MCD that would have resulted
434  // if removing least_valuable_it normally.
435  // first, calculate actual credit (i.e. apply pending_delta to
436  // this entry); then add the resulting density to pending_delta.
437  entry.credit -= pending_delta*entry.size;
438  const float credit_density = entry.credit_density();
439  ENSURE(credit_density > 0.0f);
440  pending_delta += credit_density;
441 
442  Parent::remove_(least_valuable_it);
443  }
444 
445 private:
447 
448  // sort iterators by credit_density of the Entry they reference.
449  struct CD_greater
450  {
451  bool operator()(MapIt it1, MapIt it2) const
452  {
453  return Map::entry_from_it(it1).credit_density() >
454  Map::entry_from_it(it2).credit_density();
455  }
456  };
457  // wrapper on top of priority_queue that allows 'heap re-sift'
458  // (see on_access).
459  // notes:
460  // - greater comparator makes pri_q.top() the one with
461  // LEAST credit_density, which is what we want.
462  // - deriving from an STL container is a bit dirty, but we need this
463  // to get at the underlying data (priority_queue interface is not
464  // very capable).
465  class PriQ: public std::priority_queue<MapIt, std::vector<MapIt>, CD_greater>
466  {
467  public:
469  {
470  // TODO: this is actually N*logN - ouch! that explains high
471  // CPU cost in profile. this is called after only 1 item has
472  // changed, so a logN "sift" operation ought to suffice.
473  // that's not supported by the STL heap functions, so we'd
474  // need a better implementation. pending..
475  std::make_heap(this->c.begin(), this->c.end(), this->comp);
476  }
477  };
479 
480  // delta values that have accumulated over several
481  // remove_least_valuable() calls. applied during add().
483 
485  {
486  if(pending_delta > 0.0f)
487  {
488  this->charge_all(pending_delta);
489  pending_delta = 0.0f;
490 
491  // we've changed entry credit, so the heap order *may* have been
492  // violated; reorder the pri queue. (I don't think so,
493  // due to definition of delta, but we'll play it safe)
494  pri_q.ensure_heap_order();
495  }
496  }
497 };
498 
499 
500 //
501 // functor that implements division of first arg by second
502 //
503 
504 // this is used to calculate credit_density(); performance matters
505 // because this is called for each entry during each remove operation.
506 
507 // floating-point division (fairly slow)
509 {
510 public:
511  Divider_Naive() {} // needed for default CacheEntry ctor
512  Divider_Naive(float UNUSED(x)) {}
513  float operator()(float val, float divisor) const
514  {
515  return val / divisor;
516  }
517 };
518 
519 // caches reciprocal of divisor and multiplies by that.
520 // tradeoff: only 4 clocks (instead of 20), but 4 bytes extra per entry.
522 {
523  float recip;
524 public:
525  Divider_Recip() {} // needed for default CacheEntry ctor
526  Divider_Recip(float x) { recip = 1.0f / x; }
527  float operator()(float val, float UNUSED(divisor)) const
528  {
529  return val * recip;
530  }
531 };
532 
533 
534 // initial implementation for testing purposes; quite inefficient.
535 template<typename Key, typename Entry>
536 class LRU
537 {
538 public:
539  bool empty() const
540  {
541  return lru.empty();
542  }
543 
544  void add(const Key& key, const Entry& entry)
545  {
546  lru.push_back(KeyAndEntry(key, entry));
547  }
548 
549  bool find(const Key& key, const Entry** pentry) const
550  {
551  CIt it = std::find(lru.begin(), lru.end(), KeyAndEntry(key));
552  if(it == lru.end())
553  return false;
554  *pentry = &it->entry;
555  return true;
556  }
557 
558  void remove(const Key& key)
559  {
560  lru.remove(KeyAndEntry(key));
561  }
562 
563  void on_access(Entry& entry)
564  {
565  for(It it = lru.begin(); it != lru.end(); ++it)
566  {
567  if(&entry == &it->entry)
568  {
569  add(it->key, it->entry);
570  lru.erase(it);
571  return;
572  }
573  }
574  DEBUG_WARN_ERR(ERR::LOGIC); // entry not found in list
575  }
576 
577  void remove_least_valuable(std::list<Entry>& entry_list)
578  {
579  entry_list.push_back(lru.front().entry);
580  lru.pop_front();
581  }
582 
583 private:
584  struct KeyAndEntry
585  {
586  KeyAndEntry(const Key& key): key(key) {}
587  KeyAndEntry(const Key& key, const Entry& entry): key(key), entry(entry) {}
588 
589  bool operator==(const KeyAndEntry& rhs) const { return key == rhs.key; }
590  bool operator!=(const KeyAndEntry& rhs) const { return !operator==(rhs); }
591 
592  Key key;
594  };
595 
596  typedef std::list<KeyAndEntry> List;
597  typedef typename List::iterator It;
598  typedef typename List::const_iterator CIt;
599  List lru;
600 };
601 
602 
603 // this is applicable to all cache management policies and stores all
604 // required information. a Divider functor is used to implement
605 // division for credit_density.
606 template<class Item, class Divider> struct CacheEntry
607 {
608  Item item;
609  size_t size;
610  size_t cost;
611  float credit;
612 
613  Divider divider;
614 
615  // needed for mgr.remove_least_valuable's entry_copy
617  {
618  }
619 
620  CacheEntry(const Item& item_, size_t size_, size_t cost_)
621  : item(item_), divider((float)size_)
622  {
623  size = size_;
624  cost = cost_;
625  credit = (float)cost;
626 
627  // else divider will fail
628  ENSURE(size != 0);
629  }
630 
631  float credit_density() const
632  {
633  return divider(credit, (float)size);
634  }
635 };
636 
637 
638 //
639 // Cache
640 //
641 
642 template
643 <
644 typename Key, typename Item,
645 // see documentation above for Manager's interface.
646 template<typename Key_, class Entry> class Manager = Landlord_Cached,
647 class Divider = Divider_Naive
648 >
649 class Cache
650 {
651 public:
652  Cache() : mgr() {}
653 
654  void add(const Key& key, const Item& item, size_t size, size_t cost)
655  {
656  return mgr.add(key, Entry(item, size, cost));
657  }
658 
659  // remove the entry identified by <key>. expected usage is to check
660  // if present and determine size via retrieve(), so no need for
661  // error checking.
662  // useful for invalidating single cache entries.
663  void remove(const Key& key)
664  {
665  mgr.remove(key);
666  }
667 
668  // if there is no entry for <key> in the cache, return false.
669  // otherwise, return true and pass back item and (optionally) size.
670  //
671  // if refill_credit (default), the cache manager 'rewards' this entry,
672  // tending to keep it in cache longer. this parameter is not used in
673  // normal operation - it's only for special cases where we need to
674  // make an end run around the cache accounting (e.g. for cache simulator).
675  bool retrieve(const Key& key, Item& item, size_t* psize = 0, bool refill_credit = true)
676  {
677  const Entry* entry;
678  if(!mgr.find(key, &entry))
679  return false;
680 
681  item = entry->item;
682  if(psize)
683  *psize = entry->size;
684 
685  if(refill_credit)
686  mgr.on_access((Entry&)*entry);
687 
688  return true;
689  }
690 
691  bool peek(const Key& key, Item& item, size_t* psize = 0)
692  {
693  return retrieve(key, item, psize, false);
694  }
695 
696  // toss out the least valuable entry. return false if cache is empty,
697  // otherwise true and (optionally) pass back its item and size.
698  bool remove_least_valuable(Item* pItem = 0, size_t* pSize = 0)
699  {
700  // as an artefact of the cache eviction policy, several entries
701  // may be "shaken loose" by one call to remove_least_valuable.
702  // we cache them in a list to disburden callers (they always get
703  // exactly one).
704  if(entries_awaiting_eviction.empty())
705  {
706  if(empty())
707  return false;
708 
709  mgr.remove_least_valuable(entries_awaiting_eviction);
710  ENSURE(!entries_awaiting_eviction.empty());
711  }
712 
713  const Entry& entry = entries_awaiting_eviction.front();
714  if(pItem)
715  *pItem = entry.item;
716  if(pSize)
717  *pSize = entry.size;
718  entries_awaiting_eviction.pop_front();
719 
720  return true;
721  }
722 
723  bool empty() const
724  {
725  return mgr.empty();
726  }
727 
728 private:
730 
731  // see note in remove_least_valuable().
732  std::list<Entry> entries_awaiting_eviction;
733 
734  Manager<Key, Entry> mgr;
735 };
736 
737 #endif // #ifndef INCLUDED_CACHE_ADT
void notify_impending_increase_or_remove(const Entry &entry)
Definition: cache_adt.h:168
void commit_pending_delta()
Definition: cache_adt.h:484
const Status LOGIC
Definition: status.h:407
bool retrieve(const Key &key, Item &item, size_t *psize=0, bool refill_credit=true)
Definition: cache_adt.h:675
Definition: cache_adt.h:308
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
Definition: code_annotation.h:38
void remove_(MapIt it)
Definition: cache_adt.h:332
Definition: cache_adt.h:606
float min_credit_density
Definition: cache_adt.h:208
McdCalc< Entry, Map > mcd_calc
Definition: cache_adt.h:372
bool operator()(MapIt it1, MapIt it2) const
Definition: cache_adt.h:451
CacheEntry()
Definition: cache_adt.h:616
Definition: cache_adt.h:377
void add(const Key &key, const Entry &entry)
Definition: cache_adt.h:233
float operator()(float val, float divisor) const
Definition: cache_adt.h:527
void notify_increased_or_removed(const Entry &entry)
Definition: cache_adt.h:174
Divider divider
Definition: cache_adt.h:613
Landlord_Naive< Key, Entry >::Map Map
Definition: cache_adt.h:387
Item item
Definition: cache_adt.h:608
bool operator==(const FCDJointWeightPair &a, const FCDJointWeightPair &b)
Definition: GeomReindex.cpp:59
bool remove_least_valuable(Item *pItem=0, size_t *pSize=0)
Definition: cache_adt.h:698
Divider_Naive()
Definition: cache_adt.h:511
float credit
Definition: cache_adt.h:611
void charge(Entry &entry, float delta)
Definition: cache_adt.h:340
bool should_evict(const Entry &entry)
Definition: cache_adt.h:363
bool find(const Key &key, const Entry **pentry) const
Definition: cache_adt.h:549
bool find(const Key &key, const Entry **pentry) const
Definition: cache_adt.h:239
void on_access(Entry &entry)
Definition: cache_adt.h:258
float credit_density() const
Definition: cache_adt.h:631
void add(const Key &key, const Item &item, size_t size, size_t cost)
Definition: cache_adt.h:654
void notify_decreased(const Entry &) const
Definition: cache_adt.h:136
Definition: cache_adt.h:150
bool operator==(const KeyAndEntry &rhs) const
Definition: cache_adt.h:589
static const Entry & entry_from_it(typename Map::const_iterator it)
Definition: cache_adt.h:312
Definition: cache_adt.h:584
KeyAndEntry(const Key &key, const Entry &entry)
Definition: cache_adt.h:587
void charge_all(float delta)
Definition: cache_adt.h:351
CacheEntry(const Item &item_, size_t size_, size_t cost_)
Definition: cache_adt.h:620
Definition: cache_adt.h:465
void add(const Key &key, const Entry &entry)
Definition: cache_adt.h:544
Entry entry
Definition: cache_adt.h:593
Manager< Key, Entry > mgr
Definition: cache_adt.h:734
Definition: cache_adt.h:649
Landlord_Naive< Key, Entry > Parent
Definition: cache_adt.h:446
float pending_delta
Definition: cache_adt.h:482
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Definition: debug.h:290
PriQ pri_q
Definition: cache_adt.h:478
size_t cost
Definition: cache_adt.h:610
Definition: cache_adt.h:536
bool peek(const Key &key, Item &item, size_t *psize=0)
Definition: cache_adt.h:691
List::const_iterator CIt
Definition: cache_adt.h:598
Map::const_iterator MapCIt
Definition: cache_adt.h:315
Map map
Definition: cache_adt.h:316
bool empty() const
Definition: cache_adt.h:723
void ensure_heap_order()
Definition: cache_adt.h:468
void remove_least_valuable(std::list< Entry > &entry_list)
Definition: cache_adt.h:426
Definition: cache_adt.h:449
void remove_least_valuable(std::list< Entry > &entry_list)
Definition: cache_adt.h:577
pthread_key_t key
Definition: wpthread.cpp:140
Definition: cache_adt.h:225
void on_access(Entry &entry)
Definition: cache_adt.h:417
List lru
Definition: cache_adt.h:599
size_t size
Definition: cache_adt.h:609
bool empty() const
Definition: cache_adt.h:539
uint32_t Entry
Definition: SilhouetteRenderer.cpp:138
Landlord_Naive< Key, Entry >::MapIt MapIt
Definition: cache_adt.h:388
bool operator!=(const KeyAndEntry &rhs) const
Definition: cache_adt.h:590
static Entry & entry_from_it(typename Map::iterator it)
Definition: cache_adt.h:311
Definition: cache_adt.h:508
void on_access(Entry &entry)
Definition: cache_adt.h:563
Key key
Definition: cache_adt.h:592
CacheEntry< Item, Divider > Entry
Definition: cache_adt.h:729
Cache()
Definition: cache_adt.h:652
Landlord_Lazy()
Definition: cache_adt.h:392
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
Definition: debug.h:339
McdCalc_Cached()
Definition: cache_adt.h:153
Divider_Recip()
Definition: cache_adt.h:525
Definition: cache_adt.h:385
Landlord_Naive< Key, Entry >::MapCIt MapCIt
Definition: cache_adt.h:389
void remove_least_valuable(std::list< Entry > &entry_list)
Definition: cache_adt.h:270
std::list< KeyAndEntry > List
Definition: cache_adt.h:596
bool empty() const
Definition: cache_adt.h:228
void notify_increased_or_removed(const Entry &) const
Definition: cache_adt.h:138
float recip
Definition: cache_adt.h:523
void add(const Key &key, const Entry &entry)
Definition: cache_adt.h:394
void notify_added(const Entry &) const
Definition: cache_adt.h:135
bool min_valid
Definition: cache_adt.h:209
Definition: cache_adt.h:132
bool feq(double d1, double d2, double epsilon=0.00001)
are the given floats nearly "equal"?
Definition: lib.h:88
float operator()(const Entries &entries) const
Definition: cache_adt.h:139
bool is_min_entry
Definition: cache_adt.h:212
std::list< Entry > entries_awaiting_eviction
Definition: cache_adt.h:732
Definition: cache_adt.h:378
float operator()(float val, float divisor) const
Definition: cache_adt.h:513
Map::iterator MapIt
Definition: cache_adt.h:314
List::iterator It
Definition: cache_adt.h:597
Divider_Naive(float x)
Definition: cache_adt.h:512
Divider_Recip(float x)
Definition: cache_adt.h:526
Definition: cache_adt.h:521
KeyAndEntry(const Key &key)
Definition: cache_adt.h:586
void notify_decreased(const Entry &entry)
Definition: cache_adt.h:163
void notify_impending_increase_or_remove(const Entry &) const
Definition: cache_adt.h:137
void notify_added(const Entry &entry)
Definition: cache_adt.h:155
MapIt add_(const Key &key, const Entry &entry)
Definition: cache_adt.h:319
float ll_calc_min_credit_density(const Entries &entries)
Definition: cache_adt.h:113
float operator()(const Entries &entries)
Definition: cache_adt.h:185