1
#pragma once
2

            
3
// Copyright 2016 Google Inc.
4
// Copyright Envoy Project Authors
5
// SPDX-License-Identifier: Apache-2.0
6

            
7
#pragma once
8

            
9
// A generic LRU cache that maps from type Key to Value*.
10
//
11
// . Memory usage is fairly high: on a 64-bit architecture, a cache with
12
//   8-byte keys can use 108 bytes per element, not counting the
13
//   size of the values. This overhead can be significant if many small
14
//   elements are stored in the cache.
15
//
16
// . lookup returns a "Value*". Client should call "release" when done.
17
//
18
// . Override "removeElement" if you want to be notified when an
19
//   element is being removed. The default implementation simply calls
20
//   "delete" on the pointer.
21
//
22
// . Call clear() before destruction.
23
//
24
// . No internal locking is done: if the same cache will be shared
25
//   by multiple threads, the caller should perform the required
26
//   synchronization before invoking any operations on the cache.
27
//   Note a reader lock is not sufficient as lookup() updates the pin count.
28
//
29
// . We provide support for setting a "max_idle_time". Entries
30
//   are discarded when they have not been used for a time
31
//   greater than the specified max idle time. If you do not
32
//   call setMaxIdleSeconds(), entries never expire (they can
33
//   only be removed to meet size constraints).
34
//
35
// . We also provide support for a strict age-based eviction policy
36
//   instead of LRU. See setAgeBasedEviction().
37

            
38
#pragma once
39

            
40
#include <stddef.h>
41

            
42
#include <cassert>
43
#include <chrono>
44
#include <cmath>
45
#include <limits>
46
#include <sstream>
47
#include <string>
48
#include <utility>
49

            
50
#include "source/common/jwt/simple_lru_cache.h"
51

            
52
#include "absl/container/flat_hash_map.h"
53

            
54
namespace Envoy {
55
namespace SimpleLruCache {
56

            
57
#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
58
#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName)                                                \
59
  TypeName(const TypeName&);                                                                       \
60
  void operator=(const TypeName&)
61

            
62
// Define number of microseconds for a second.
63
const int64_t kSecToUsec = 1000000;
64

            
65
// Define a simple cycle timer interface to encapsulate timer related code.
66
// The concept is from CPU cycle. The cycle clock code from
67
// https://github.com/google/benchmark/src/cycleclock.h can be used.
68
// But that code only works for some platforms. To make code works for all
69
// platforms, SimpleCycleTimer class uses a fake CPU cycle each taking a
70
// microsecond. If needed, this timer class can be easily replaced by a
71
// real cycle_clock.
72
class SimpleCycleTimer {
73
public:
74
  // Return the current cycle in microseconds.
75
6761
  static int64_t now() {
76
6761
    return std::chrono::duration_cast<std::chrono::microseconds>(
77
6761
               std::chrono::system_clock::now().time_since_epoch())
78
6761
        .count();
79
6761
  }
80
  // Return number of cycles in a second.
81
23
  static int64_t frequency() { return kSecToUsec; }
82

            
83
private:
84
  SimpleCycleTimer(); // no instances
85
};
86

            
87
// A constant iterator. a client of SimpleLRUCache should not create these
88
// objects directly, instead, create objects of type
89
// SimpleLRUCache::const_iterator. This is created inside of
90
// SimpleLRUCache::begin(),end(). Key and Value are the same as the template
91
// args to SimpleLRUCache Elem - the Value type for the internal hash_map that
92
// the SimpleLRUCache maintains H and EQ are the same as the template arguments
93
// for SimpleLRUCache
94
//
95
// NOTE: the iterator needs to keep a copy of end() for the Cache it is
96
// iterating over this is so SimpleLRUCacheConstIterator does not try to update
97
// its internal pair<Key, Value*> if its internal hash_map iterator is pointing
98
// to end see the implementation of operator++ for an example.
99
//
100
// NOTE: DO NOT SAVE POINTERS TO THE ITEM RETURNED BY THIS ITERATOR
101
// e.g. SimpleLRUCacheConstIterator it = something; do not say KeyToSave
102
// &something->first this will NOT work., as soon as you increment the iterator
103
// this will be gone. :(
104

            
105
template <class Key, class Value, class MapType>
106
class SimpleLRUCacheConstIterator
107
    : public std::iterator<std::input_iterator_tag, const std::pair<Key, Value*>> {
108
public:
109
  typedef typename MapType::const_iterator HashMapConstIterator;
110
  // Allow parent template's types to be referenced without qualification.
111
  typedef typename SimpleLRUCacheConstIterator::reference reference;
112
  typedef typename SimpleLRUCacheConstIterator::pointer pointer;
113

            
114
  // This default constructed Iterator can only be assigned to or destroyed.
115
  // All other operations give undefined behaviour.
116
1
  SimpleLRUCacheConstIterator() {}
117
  SimpleLRUCacheConstIterator(HashMapConstIterator it, HashMapConstIterator end);
118
  SimpleLRUCacheConstIterator& operator++();
119

            
120
100
  reference operator*() { return external_view_; }
121
49
  pointer operator->() { return &external_view_; }
122

            
123
  // For LRU mode, last_use_time() returns elements last use time.
124
  // See getLastUseTime() description for more information.
125
2
  int64_t last_use_time() const { return last_use_; }
126

            
127
  // For age-based mode, insertion_time() returns elements insertion time.
128
  // See getInsertionTime() description for more information.
129
2
  int64_t insertion_time() const { return last_use_; }
130

            
131
  friend bool operator==(const SimpleLRUCacheConstIterator& a,
132
124
                         const SimpleLRUCacheConstIterator& b) {
133
124
    return a.it_ == b.it_;
134
124
  }
135

            
136
  friend bool operator!=(const SimpleLRUCacheConstIterator& a,
137
124
                         const SimpleLRUCacheConstIterator& b) {
138
124
    return !(a == b);
139
124
  }
140

            
141
private:
142
  HashMapConstIterator it_;
143
  HashMapConstIterator end_;
144
  std::pair<Key, Value*> external_view_;
145
  int64_t last_use_;
146
};
147

            
148
// Each entry uses the following structure
149
template <typename Key, typename Value> struct SimpleLRUCacheElem {
150
  Key key;                            // The key
151
  Value* value;                       // The stored value
152
  int pin;                            // Number of outstanding releases
153
  size_t units;                       // Number of units for this value
154
  SimpleLRUCacheElem* next = nullptr; // Next entry in LRU chain
155
  SimpleLRUCacheElem* prev = nullptr; // Prev entry in LRU chain
156
  int64_t last_use_;                  // Timestamp of last use (in LRU mode)
157
  //     or creation (in age-based mode)
158

            
159
  SimpleLRUCacheElem(const Key& k, Value* v, int p, size_t u, int64_t last_use)
160
1898
      : key(k), value(v), pin(p), units(u), last_use_(last_use) {}
161

            
162
3621
  bool isLinked() const {
163
    // If we are in the LRU then next and prev should be non-NULL. Otherwise
164
    // both should be properly initialized to nullptr.
165
3621
    assert(static_cast<bool>(next == nullptr) == static_cast<bool>(prev == nullptr));
166
3621
    return next != nullptr;
167
3621
  }
168

            
169
3621
  void unlink() {
170
3621
    if (!isLinked())
171
157
      return;
172
3464
    prev->next = next;
173
3464
    next->prev = prev;
174
3464
    prev = nullptr;
175
3464
    next = nullptr;
176
3464
  }
177

            
178
3708
  void link(SimpleLRUCacheElem* head) {
179
3708
    next = head->next;
180
3708
    prev = head;
181
3708
    next->prev = this; // i.e. head->next->prev = this;
182
3708
    prev->next = this; // i.e. head->next = this;
183
3708
  }
184
  static const int64_t kNeverUsed = -1;
185
};
186

            
187
template <typename Key, typename Value> const int64_t SimpleLRUCacheElem<Key, Value>::kNeverUsed;
188

            
189
// A simple class passed into various cache methods to change the
190
// behavior for that single call.
191
class SimpleLRUCacheOptions {
192
public:
193
7039
  SimpleLRUCacheOptions() : update_eviction_order_(true) {}
194

            
195
  // If false neither the last modified time (for based age eviction) nor
196
  // the element ordering (for LRU eviction) will be updated.
197
  // This value must be the same for both lookup and release.
198
  // The default is true.
199
12188
  bool update_eviction_order() const { return update_eviction_order_; }
200
2
  void set_update_eviction_order(bool v) { update_eviction_order_ = v; }
201

            
202
private:
203
  bool update_eviction_order_;
204
};
205

            
206
// The MapType's value_type must be pair<const Key, Elem*>
207
template <class Key, class Value, class MapType, class EQ> class SimpleLRUCacheBase {
208
public:
209
  // class ScopedLookup
210
  // If you have some code that looks like this:
211
  // val = c->Lookup(key);
212
  // if (val) {
213
  //   if (something) {
214
  //     c->Release(key, val);
215
  //     return;
216
  //   }
217
  //   if (something else) {
218
  //     c->Release(key, val);
219
  //     return;
220
  //   }
221
  // Then ScopedLookup will make the code simpler. It automatically
222
  // releases the value when the instance goes out of scope.
223
  // Example:
224
  //   ScopedLookup lookup(c, key);
225
  //   if (lookup.Found()) {
226
  //     ...
227
  //
228
  // NOTE:  Be extremely careful when using ScopedLookup with Mutexes. This
229
  // code is safe since the lock will be released after the ScopedLookup is
230
  // destroyed.
231
  //   MutexLock l(&mu_);
232
  //   ScopedLookup lookup(....);
233
  //
234
  // This is NOT safe since the lock is released before the ScopedLookup is
235
  // destroyed, and consequently the value will be unpinned without the lock
236
  // being held.
237
  //   mu_.Lock();
238
  //   ScopedLookup lookup(....);
239
  //   ...
240
  //   mu_.Unlock();
241
  class ScopedLookup {
242
  public:
243
    ScopedLookup(SimpleLRUCacheBase* cache, const Key& key)
244
111
        : cache_(cache), key_(key), value_(cache_->lookupWithOptions(key_, options_)) {}
245

            
246
    ScopedLookup(SimpleLRUCacheBase* cache, const Key& key, const SimpleLRUCacheOptions& options)
247
9000
        : cache_(cache), key_(key), options_(options),
248
9000
          value_(cache_->lookupWithOptions(key_, options_)) {}
249

            
250
9111
    ~ScopedLookup() {
251
9111
      if (value_ != nullptr)
252
994
        cache_->releaseWithOptions(key_, value_, options_);
253
9111
    }
254
    const Key& key() const { return key_; }
255
9952
    Value* value() const { return value_; }
256
99
    bool found() const { return value_ != nullptr; }
257
    const SimpleLRUCacheOptions& options() const { return options_; }
258

            
259
  private:
260
    SimpleLRUCacheBase* const cache_;
261
    const Key key_;
262
    const SimpleLRUCacheOptions options_;
263
    Value* const value_;
264

            
265
    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ScopedLookup);
266
  };
267

            
268
  // Create a cache that will hold up to the specified number of units.
269
  // Usually the units will be byte sizes, but in some caches different
270
  // units may be used. For instance, we may want each open file to
271
  // be one unit in an open-file cache.
272
  //
273
  // By default, the max_idle_time is infinity; i.e. entries will
274
  // stick around in the cache regardless of how old they are.
275
  explicit SimpleLRUCacheBase(int64_t total_units);
276

            
277
  // Release all resources. Cache must have been "clear"ed. This
278
  // requirement is imposed because "clear()" will call
279
  // "removeElement" for each element in the cache. The destructor
280
  // cannot do that because it runs after any subclass destructor.
281
54
  virtual ~SimpleLRUCacheBase() {
282
54
    assert(table_.size() == 0);
283
54
    assert(defer_.size() == 0);
284
54
  }
285

            
286
  // Change the maximum size of the cache to the specified number of units.
287
  // If necessary, entries will be evicted to comply with the new size.
288
6
  void setMaxSize(int64_t total_units) {
289
6
    max_units_ = total_units;
290
6
    garbageCollect();
291
6
  }
292

            
293
  // Change the max idle time to the specified number of seconds.
294
  // If "seconds" is a negative number, it sets the max idle time
295
  // to infinity.
296
8
  void setMaxIdleSeconds(double seconds) { setTimeout(seconds, true /* lru */); }
297

            
298
  // Stop using the LRU eviction policy and instead expire anything
299
  // that has been in the cache for more than the specified number
300
  // of seconds.
301
  // If "seconds" is a negative number, entries don't expire but if
302
  // we need to make room the oldest entries will be removed first.
303
  // You can't set both a max idle time and age-based eviction.
304
9
  void setAgeBasedEviction(double seconds) { setTimeout(seconds, false /* lru */); }
305

            
306
  // If cache contains an entry for "k", return a pointer to it.
307
  // Else return nullptr.
308
  //
309
  // If a value is returned, the caller must call "release" when it no
310
  // longer needs that value. This functionality is useful to prevent
311
  // the value from being evicted from the cache until it is no longer
312
  // being used.
313
3205
  Value* lookup(const Key& k) { return lookupWithOptions(k, SimpleLRUCacheOptions()); }
314

            
315
  // Same as "lookup(Key)" but allows for additional options. See
316
  // the SimpleLRUCacheOptions object for more information.
317
  Value* lookupWithOptions(const Key& k, const SimpleLRUCacheOptions& options);
318

            
319
  // Removes the pinning done by an earlier "lookup". After this call,
320
  // the caller should no longer depend on the value sticking around.
321
  //
322
  // If there are no more pins on this entry, it may be deleted if
323
  // either it has been "remove"d, or the cache is overfull.
324
  // In this case "removeElement" will be called.
325
3721
  void release(const Key& k, Value* value) {
326
3721
    releaseWithOptions(k, value, SimpleLRUCacheOptions());
327
3721
  }
328

            
329
  // Same as "release(Key, Value)" but allows for additional options. See
330
  // the SimpleLRUCacheOptions object for more information. Take care
331
  // that the SimpleLRUCacheOptions object passed into this method is
332
  // compatible with SimpleLRUCacheOptions object passed into lookup.
333
  // If they are incompatible it can put the cache into some unexpected
334
  // states. Better yet, just use a ScopedLookup which takes care of this
335
  // for you.
336
  void releaseWithOptions(const Key& k, Value* value, const SimpleLRUCacheOptions& options);
337

            
338
  // Insert the specified "k,value" pair in the cache. Remembers that
339
  // the value occupies "units" units. For "InsertPinned", the newly
340
  // inserted value will be pinned in the cache: the caller should
341
  // call "release" when it wants to remove the pin.
342
  //
343
  // Any old entry for "k" is "remove"d.
344
  //
345
  // If the insertion causes the cache to become overfull, unpinned
346
  // entries will be deleted in an LRU order to make room.
347
  // "removeElement" will be called for each such entry.
348
1626
  void insert(const Key& k, Value* value, size_t units) {
349
1626
    insertPinned(k, value, units);
350
1626
    release(k, value);
351
1626
  }
352
  void insertPinned(const Key& k, Value* value, size_t units);
353

            
354
  // Change the reported size of an object.
355
  void updateSize(const Key& k, const Value* value, size_t units);
356

            
357
  // return true iff <k, value> pair is still in use
358
  // (i.e., either in the table or the deferred list)
359
  // Note, if (value == nullptr), only key is used for matching
360
197
  bool stillInUse(const Key& k) const { return stillInUse(k, nullptr); }
361
  bool stillInUse(const Key& k, const Value* value) const;
362

            
363
  // Remove any entry corresponding to "k" from the cache. Note that
364
  // if the entry is pinned because of an earlier lookup or
365
  // insertPinned operation, the entry will disappear from further
366
  // lookups, but will not actually be deleted until all of the pins
367
  // are released.
368
  //
369
  // "removeElement" will be called if an entry is actually removed.
370
  void remove(const Key& k);
371

            
372
  // Removes all entries from the cache. The pinned entries will
373
  // disappear from further Lookups, but will not actually be deleted
374
  // until all of the pins are released. This is different from clear()
375
  // because clear() cleans up everything and requires that all Values are
376
  // unpinned.
377
  //
378
  // "remove" will be called for each cache entry.
379
  void removeAll();
380

            
381
  // Remove all unpinned entries from the cache.
382
  // "removeElement" will be called for each such entry.
383
  void removeUnpinned();
384

            
385
  // Remove all entries from the cache. It is an error to call this
386
  // operation if any entry in the cache is currently pinned.
387
  //
388
  // "removeElement" will be called for all removed entries.
389
  void clear();
390

            
391
  // Remove all entries which have exceeded their max idle time or age
392
  // set using setMaxIdleSeconds() or setAgeBasedEviction() respectively.
393
21317
  void removeExpiredEntries() {
394
21317
    if (max_idle_ >= 0)
395
1511
      discardIdle(max_idle_);
396
21317
  }
397

            
398
  // Return current size of cache
399
28
  int64_t size() const { return units_; }
400

            
401
  // Return number of entries in the cache. This value may differ
402
  // from size() if some of the elements have a cost != 1.
403
211
  int64_t entries() const { return table_.size(); }
404

            
405
  // Return size of deferred deletions
406
  int64_t deferredSize() const;
407

            
408
  // Return number of deferred deletions
409
  int64_t deferredEntries() const;
410

            
411
  // Return size of entries that are pinned but not deferred
412
19
  int64_t pinnedSize() const { return pinned_units_; }
413

            
414
  // Return maximum size of cache
415
15
  int64_t maxSize() const { return max_units_; }
416

            
417
  // Return the age (in microseconds) of the least recently used element in
418
  // the cache. If the cache is empty, zero (0) is returned.
419
  int64_t ageOfLRUItemInMicroseconds() const;
420

            
421
  // In LRU mode, this is the time of last use in cycles. Last use is defined
422
  // as time of last release(), insert() or insertPinned() methods.
423
  //
424
  // The timer is not updated on lookup(), so getLastUseTime() will
425
  // still return time of previous access until release().
426
  //
427
  // Returns -1 if key was not found, CycleClock cycle count otherwise.
428
  // REQUIRES: LRU mode
429
  int64_t getLastUseTime(const Key& k) const;
430

            
431
  // For age-based mode, this is the time of element insertion in cycles,
432
  // set by insert() and insertPinned() methods.
433
  // Returns -1 if key was not found, CycleClock cycle count otherwise.
434
  // REQUIRES: age-based mode
435
  int64_t getInsertionTime(const Key& k) const;
436

            
437
  // Invokes 'debugIterator' on each element in the cache. The
438
  // 'pin_count' argument supplied will be the pending reference count
439
  // for the element. The 'is_deferred' argument will be true for
440
  // elements that have been removed but whose removal is deferred.
441
  // The supplied value for "output" will be passed to the debugIterator.
442
  void debugOutput(std::string* output) const;
443

            
444
  // Return a std::string that summarizes the contents of the cache.
445
  std::string summary() const {
446
    std::stringstream ss;
447
    ss << pinnedSize() << "/" << deferredSize() << "/" << size() << " p/d/a";
448
    return ss.str();
449
  }
450

            
451
  // STL style const_iterator support
452
  typedef SimpleLRUCacheConstIterator<Key, Value, MapType> const_iterator;
453
  friend class SimpleLRUCacheConstIterator<Key, Value, MapType>;
454
5
  const_iterator begin() const { return const_iterator(table_.begin(), table_.end()); }
455
24
  const_iterator end() const { return const_iterator(table_.end(), table_.end()); }
456

            
457
  // Invokes the 'resize' operation on the underlying map with the given
458
  // size hint. The exact meaning of this operation and its availability
459
  // depends on the supplied MapType.
460
  void resizeTable(typename MapType::size_type size_hint) { table_.resize(size_hint); }
461

            
462
protected:
463
  // Override this operation if you want to control how a value is
464
  // cleaned up. For example, if the value is a "File", you may want
465
  // to close it instead of deleting it.
466
  //
467
  // Not actually implemented here because often value's destructor is
468
  // protected, and the derived SimpleLRUCache is declared a friend,
469
  // so we implement it in the derived SimpleLRUCache.
470
  virtual void removeElement(Value* value) = 0;
471

            
472
  virtual void debugIterator(const Value* value, int pin_count, int64_t last_timestamp,
473
3
                             bool is_deferred, std::string* output) const {
474
3
    std::stringstream ss;
475
3
    ss << "ox" << std::hex << value << std::dec << ": pin: " << pin_count;
476
3
    ss << ", is_deferred: " << is_deferred;
477
3
    ss << ", last_use: " << last_timestamp << std::endl;
478
3
    *output += ss.str();
479
3
  }
480

            
481
  // Override this operation if you want to evict cache entries
482
  // based on parameters other than the total units stored.
483
  // For example, if the cache stores open file handles, where the cost
484
  // is the size in bytes of the open file, you may want to evict
485
  // entries from the cache not only before the max size in bytes
486
  // is reached but also before reaching the limit of open file
487
  // descriptors. Thus, you may want to override this function in a
488
  // subclass and return true if either size() is too large or
489
  // entries() is too large.
490
5944
  virtual bool isOverfull() const { return units_ > max_units_; }
491

            
492
private:
493
  typedef SimpleLRUCacheElem<Key, Value> Elem;
494
  typedef MapType Table;
495
  typedef typename Table::iterator TableIterator;
496
  typedef typename Table::const_iterator TableConstIterator;
497
  typedef MapType DeferredTable;
498
  typedef typename DeferredTable::iterator DeferredTableIterator;
499
  typedef typename DeferredTable::const_iterator DeferredTableConstIterator;
500

            
501
  Table table_; // Main table
502
  // Pinned entries awaiting to be released before they can be discarded.
503
  // This is a key -> list mapping (multiple deferred entries for the same key)
504
  // The machinery used to maintain main LRU list is reused here, though this
505
  // list is not necessarily LRU and we don't care about the order of elements.
506
  DeferredTable defer_;
507
  int64_t units_;        // Combined units of all elements
508
  int64_t max_units_;    // Max allowed units
509
  int64_t pinned_units_; // Combined units of all pinned elements
510
  Elem head_;            // Dummy head of LRU list (next is mru elem)
511
  int64_t max_idle_;     // Maximum number of idle cycles
512
  bool lru_;             // LRU or age-based eviction?
513

            
514
  // Representation invariants:
515
  // . LRU list is circular doubly-linked list
516
  // . Each live "Elem" is either in "table_" or "defer_"
517
  // . LRU list contains elements in "table_" that can be removed to free space
518
  // . Each "Elem" in "defer_" has a non-zero pin count
519

            
520
1844
  void discard(Elem* e) {
521
1844
    assert(e->pin == 0);
522
1844
    units_ -= e->units;
523
1844
    removeElement(e->value);
524
1844
    delete e;
525
1844
  }
526

            
527
  // Count the number and total size of the elements in the deferred table.
528
  void countDeferredEntries(int64_t* num_entries, int64_t* total_size) const;
529

            
530
  // Currently in deferred table?
531
  // Note, if (value == nullptr), only key is used for matching.
532
  bool inDeferredTable(const Key& k, const Value* value) const;
533

            
534
  void garbageCollect();              // Discard to meet space constraints
535
  void discardIdle(int64_t max_idle); // Discard to meet idle-time constraints
536

            
537
  void setTimeout(double seconds, bool lru);
538

            
539
7373
  bool isOverfullInternal() const { return ((units_ > max_units_) || isOverfull()); }
540
  void remove(Elem* e);
541

            
542
public:
543
  static const size_t kElemSize = sizeof(Elem);
544

            
545
private:
546
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleLRUCacheBase);
547
};
548

            
549
template <class Key, class Value, class MapType, class EQ>
550
SimpleLRUCacheBase<Key, Value, MapType, EQ>::SimpleLRUCacheBase(int64_t total_units)
551
54
    : head_(Key(), nullptr, 0, 0, Elem::kNeverUsed) {
552
54
  units_ = 0;
553
54
  pinned_units_ = 0;
554
54
  max_units_ = total_units;
555
54
  head_.next = &head_;
556
54
  head_.prev = &head_;
557
54
  max_idle_ = -1; // Stands for "no expiration"
558
54
  lru_ = true;    // default to LRU, not age-based
559
54
}
560

            
561
template <class Key, class Value, class MapType, class EQ>
562
17
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::setTimeout(double seconds, bool lru) {
563
17
  if (seconds < 0 || std::isinf(seconds)) {
564
    // Treat as no expiration based on idle time
565
3
    lru_ = lru;
566
3
    max_idle_ = -1;
567
14
  } else if (max_idle_ >= 0 && lru != lru_) {
568
    // LOG(DFATAL) << "Can't setMaxIdleSeconds() and setAgeBasedEviction()";
569
    // In production we'll just ignore the second call
570
    assert(0);
571
14
  } else {
572
14
    lru_ = lru;
573

            
574
    // Convert to cycles ourselves in order to perform all calculations in
575
    // floating point so that we avoid integer overflow.
576
    // NOTE: The largest representable int64_t cannot be represented exactly as
577
    // a
578
    // double, so the cast results in a slightly larger value which cannot be
579
    // converted back to an int64_t. The next smallest double is representable
580
    // as
581
    // an int64_t, however, so if we make sure that `timeout_cycles` is strictly
582
    // smaller than the result of the cast, we know that casting
583
    // `timeout_cycles` to int64_t will not overflow.
584
    // NOTE 2: If you modify the computation here, make sure to update the
585
    // getBoundaryTimeout() method in the test as well.
586
14
    const double timeout_cycles = seconds * SimpleCycleTimer::frequency();
587
14
    if (timeout_cycles >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
588
      // The value is outside the range of int64_t, so "round" down to something
589
      // that can be represented.
590
2
      max_idle_ = std::numeric_limits<int64_t>::max();
591
12
    } else {
592
12
      max_idle_ = static_cast<int64_t>(timeout_cycles);
593
12
    }
594
14
    discardIdle(max_idle_);
595
14
  }
596
17
}
597

            
598
template <class Key, class Value, class MapType, class EQ>
599
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::removeAll() {
600
  // For each element: call "Remove"
601
  for (TableIterator iter = table_.begin(); iter != table_.end(); ++iter) {
602
    remove(iter->second);
603
  }
604
  table_.clear();
605
}
606

            
607
template <class Key, class Value, class MapType, class EQ>
608
6
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::removeUnpinned() {
609
37
  for (Elem* e = head_.next; e != &head_;) {
610
31
    Elem* next = e->next;
611
31
    if (e->pin == 0)
612
30
      remove(e->key);
613
31
    e = next;
614
31
  }
615
6
}
616

            
617
template <class Key, class Value, class MapType, class EQ>
618
59
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::clear() {
619
  // For each element: call "removeElement" and delete it
620
363
  for (TableConstIterator iter = table_.begin(); iter != table_.end();) {
621
304
    Elem* e = iter->second;
622
    // Pre-increment the iterator to avoid possible
623
    // accesses to deleted memory in cases where the
624
    // key is a pointer to the memory that is freed by
625
    // Discard.
626
304
    ++iter;
627
304
    discard(e);
628
304
  }
629
  // Pinned entries cannot be Discarded and defer_ contains nothing but pinned
630
  // entries. Therefore, it must be already be empty at this point.
631
59
  assert(defer_.empty());
632
  // Get back into pristine state
633
59
  table_.clear();
634
59
  head_.next = &head_;
635
59
  head_.prev = &head_;
636
59
  units_ = 0;
637
59
  pinned_units_ = 0;
638
59
}
639

            
640
template <class Key, class Value, class MapType, class EQ>
641
Value* SimpleLRUCacheBase<Key, Value, MapType, EQ>::lookupWithOptions(
642
21317
    const Key& k, const SimpleLRUCacheOptions& options) {
643
21317
  removeExpiredEntries();
644

            
645
21317
  TableIterator iter = table_.find(k);
646
21317
  if (iter != table_.end()) {
647
    // We set last_use_ upon Release, not during lookup.
648
3772
    Elem* e = iter->second;
649
3772
    if (e->pin == 0) {
650
2857
      pinned_units_ += e->units;
651
      // We are pinning this entry, take it off the LRU list if we are in LRU
652
      // mode. In strict age-based mode entries stay on the list while pinned.
653
2857
      if (lru_ && options.update_eviction_order())
654
1922
        e->unlink();
655
2857
    }
656
3772
    e->pin++;
657
3772
    return e->value;
658
3772
  }
659
17545
  return nullptr;
660
21317
}
661

            
662
template <class Key, class Value, class MapType, class EQ>
663
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::releaseWithOptions(
664
5616
    const Key& k, Value* value, const SimpleLRUCacheOptions& options) {
665
5616
  { // First check to see if this is a deferred value
666
5616
    DeferredTableIterator iter = defer_.find(k);
667
5616
    if (iter != defer_.end()) {
668
160
      const Elem* const head = iter->second;
669
      // Go from oldest to newest, assuming that oldest entries get released
670
      // first. This may or may not be true and makes no semantic difference.
671
160
      Elem* e = head->prev;
672
5013
      while (e != head && e->value != value) {
673
4853
        e = e->prev;
674
4853
      }
675
160
      if (e->value == value) {
676
        // Found in deferred list: release it
677
159
        assert(e->pin > 0);
678
159
        e->pin--;
679
159
        if (e->pin == 0) {
680
159
          if (e == head) {
681
            // When changing the head, remove the head item and re-insert the
682
            // second item on the list (if there are any left). Do not re-use
683
            // the key from the first item.
684
            // Even though the two keys compare equal, the lifetimes may be
685
            // different (such as a key of Std::StringPiece).
686
159
            defer_.erase(iter);
687
159
            if (e->prev != e) {
688
99
              defer_[e->prev->key] = e->prev;
689
99
            }
690
159
          }
691
159
          e->unlink();
692
159
          discard(e);
693
159
        }
694
159
        return;
695
159
      }
696
160
    }
697
5616
  }
698
5457
  { // Not deferred; so look in hash table
699
5457
    TableIterator iter = table_.find(k);
700
5457
    assert(iter != table_.end());
701
5457
    Elem* e = iter->second;
702
5457
    assert(e->value == value);
703
5457
    assert(e->pin > 0);
704
5457
    if (lru_ && options.update_eviction_order()) {
705
3340
      e->last_use_ = SimpleCycleTimer::now();
706
3340
    }
707
5457
    e->pin--;
708

            
709
5457
    if (e->pin == 0) {
710
4542
      if (lru_ && options.update_eviction_order())
711
3325
        e->link(&head_);
712
4542
      pinned_units_ -= e->units;
713
4542
      if (isOverfullInternal()) {
714
        // This element is no longer needed, and we are full. So kick it out.
715
181
        remove(k);
716
181
      }
717
4542
    }
718
5457
  }
719
5457
}
720

            
721
template <class Key, class Value, class MapType, class EQ>
722
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::insertPinned(const Key& k, Value* value,
723
1844
                                                               size_t units) {
724
  // Get rid of older entry (if any) from table
725
1844
  remove(k);
726

            
727
  // Make new element
728
1844
  Elem* e = new Elem(k, value, 1, units, SimpleCycleTimer::now());
729

            
730
  // Adjust table, total units fields.
731
1844
  units_ += units;
732
1844
  pinned_units_ += units;
733
1844
  table_[k] = e;
734

            
735
  // If we are in the strict age-based eviction mode, the entry goes on the LRU
736
  // list now and is never removed. In the LRU mode, the list will only contain
737
  // unpinned entries.
738
1844
  if (!lru_)
739
284
    e->link(&head_);
740
1844
  garbageCollect();
741
1844
}
742

            
743
template <class Key, class Value, class MapType, class EQ>
744
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::updateSize(const Key& k, const Value* value,
745
4
                                                             size_t units) {
746
4
  TableIterator table_iter = table_.find(k);
747
4
  if ((table_iter != table_.end()) &&
748
4
      ((value == nullptr) || (value == table_iter->second->value))) {
749
3
    Elem* e = table_iter->second;
750
3
    units_ -= e->units;
751
3
    if (e->pin > 0) {
752
2
      pinned_units_ -= e->units;
753
2
    }
754
3
    e->units = units;
755
3
    units_ += e->units;
756
3
    if (e->pin > 0) {
757
2
      pinned_units_ += e->units;
758
2
    }
759
3
  } else {
760
1
    const DeferredTableIterator iter = defer_.find(k);
761
1
    if (iter != defer_.end()) {
762
1
      const Elem* const head = iter->second;
763
1
      Elem* e = iter->second;
764
1
      do {
765
1
        if (e->value == value || value == nullptr) {
766
1
          units_ -= e->units;
767
1
          e->units = units;
768
1
          units_ += e->units;
769
1
        }
770
1
        e = e->prev;
771
1
      } while (e != head);
772
1
    }
773
1
  }
774
4
  garbageCollect();
775
4
}
776

            
777
template <class Key, class Value, class MapType, class EQ>
778
bool SimpleLRUCacheBase<Key, Value, MapType, EQ>::stillInUse(const Key& k,
779
298
                                                             const Value* value) const {
780
298
  TableConstIterator iter = table_.find(k);
781
298
  if ((iter != table_.end()) && ((value == nullptr) || (value == iter->second->value))) {
782
3
    return true;
783
295
  } else {
784
295
    return inDeferredTable(k, value);
785
295
  }
786
298
}
787

            
788
template <class Key, class Value, class MapType, class EQ>
789
bool SimpleLRUCacheBase<Key, Value, MapType, EQ>::inDeferredTable(const Key& k,
790
295
                                                                  const Value* value) const {
791
295
  const DeferredTableConstIterator iter = defer_.find(k);
792
295
  if (iter != defer_.end()) {
793
197
    const Elem* const head = iter->second;
794
197
    const Elem* e = head;
795
5048
    do {
796
5048
      if (e->value == value || value == nullptr)
797
197
        return true;
798
4851
      e = e->prev;
799
4851
    } while (e != head);
800
197
  }
801
98
  return false;
802
295
}
803

            
804
template <class Key, class Value, class MapType, class EQ>
805
2255
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::remove(const Key& k) {
806
2255
  TableIterator iter = table_.find(k);
807
2255
  if (iter != table_.end()) {
808
563
    Elem* e = iter->second;
809
563
    table_.erase(iter);
810
563
    remove(e);
811
563
  }
812
2255
}
813

            
814
template <class Key, class Value, class MapType, class EQ>
815
563
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::remove(Elem* e) {
816
  // Unlink e whether it is in the LRU or the deferred list. It is safe to call
817
  // unlink() if it is not in either list.
818
563
  e->unlink();
819
563
  if (e->pin > 0) {
820
159
    pinned_units_ -= e->units;
821

            
822
    // Now add it to the deferred table.
823
159
    DeferredTableIterator iter = defer_.find(e->key);
824
159
    if (iter == defer_.end()) {
825
      // Inserting a new key, the element becomes the head of the list.
826
60
      e->prev = e->next = e;
827
60
      defer_[e->key] = e;
828
104
    } else {
829
      // There is already a deferred list for this key, attach the element to it
830
99
      Elem* head = iter->second;
831
99
      e->link(head);
832
99
    }
833
409
  } else {
834
404
    discard(e);
835
404
  }
836
563
}
837

            
838
template <class Key, class Value, class MapType, class EQ>
839
1854
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::garbageCollect() {
840
1854
  Elem* e = head_.prev;
841
2831
  while (isOverfullInternal() && (e != &head_)) {
842
977
    Elem* prev = e->prev;
843
977
    if (e->pin == 0) {
844
      // Erase from hash-table
845
977
      TableIterator iter = table_.find(e->key);
846
977
      assert(iter != table_.end());
847
977
      assert(iter->second == e);
848
977
      table_.erase(iter);
849
977
      e->unlink();
850
977
      discard(e);
851
977
    }
852
977
    e = prev;
853
977
  }
854
1854
}
855

            
856
// Not using cycle. Instead using second from time()
857
static const int kAcceptableClockSynchronizationDriftCycles = 1;
858

            
859
template <class Key, class Value, class MapType, class EQ>
860
1525
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::discardIdle(int64_t max_idle) {
861
1525
  if (max_idle < 0)
862
    return;
863

            
864
1525
  Elem* e = head_.prev;
865
1525
  const int64_t threshold = SimpleCycleTimer::now() - max_idle;
866
#ifndef NDEBUG
867
  int64_t last = 0;
868
#endif
869
1563
  while ((e != &head_) && (e->last_use_ < threshold)) {
870
    // Sanity check: LRU list should be sorted by last_use_. We could
871
    // check the entire list, but that gives quadratic behavior.
872
    //
873
    // TSCs on different cores of multi-core machines sometime get slightly out
874
    // of sync; compensate for this by allowing clock to go backwards by up to
875
    // kAcceptableClockSynchronizationDriftCycles CPU cycles.
876
    //
877
    // A kernel bug (http://b/issue?id=777807) sometimes causes TSCs to become
878
    // widely unsynchronized, in which case this CHECK will fail. As a
879
    // temporary work-around, running
880
    //
881
    //  $ sudo bash
882
    //  # echo performance>/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
883
    //  # /etc/init.d/cpufrequtils restart
884
    //
885
    // fixes the problem.
886
#ifndef NDEBUG
887
    assert(last <= e->last_use_ + kAcceptableClockSynchronizationDriftCycles);
888
    last = e->last_use_;
889
#endif
890

            
891
38
    Elem* prev = e->prev;
892
    // There are no pinned elements on the list in the LRU mode, and in the
893
    // age-based mode we push them out of the main table regardless of pinning.
894
38
    assert(e->pin == 0 || !lru_);
895
38
    remove(e->key);
896
38
    e = prev;
897
38
  }
898
1525
}
899

            
900
template <class Key, class Value, class MapType, class EQ>
901
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::countDeferredEntries(int64_t* num_entries,
902
13
                                                                       int64_t* total_size) const {
903
13
  *num_entries = *total_size = 0;
904
17
  for (DeferredTableConstIterator iter = defer_.begin(); iter != defer_.end(); ++iter) {
905
4
    const Elem* const head = iter->second;
906
4
    const Elem* e = head;
907
5
    do {
908
5
      (*num_entries)++;
909
5
      *total_size += e->units;
910
5
      e = e->prev;
911
5
    } while (e != head);
912
4
  }
913
13
}
914

            
915
template <class Key, class Value, class MapType, class EQ>
916
10
int64_t SimpleLRUCacheBase<Key, Value, MapType, EQ>::deferredSize() const {
917
10
  int64_t entries, size;
918
10
  countDeferredEntries(&entries, &size);
919
10
  return size;
920
10
}
921

            
922
template <class Key, class Value, class MapType, class EQ>
923
3
int64_t SimpleLRUCacheBase<Key, Value, MapType, EQ>::deferredEntries() const {
924
3
  int64_t entries, size;
925
3
  countDeferredEntries(&entries, &size);
926
3
  return entries;
927
3
}
928

            
929
template <class Key, class Value, class MapType, class EQ>
930
9
int64_t SimpleLRUCacheBase<Key, Value, MapType, EQ>::ageOfLRUItemInMicroseconds() const {
931
9
  if (head_.prev == &head_)
932
2
    return 0;
933
7
  return kSecToUsec * (SimpleCycleTimer::now() - head_.prev->last_use_) /
934
7
         SimpleCycleTimer::frequency();
935
9
}
936

            
937
template <class Key, class Value, class MapType, class EQ>
938
9072
int64_t SimpleLRUCacheBase<Key, Value, MapType, EQ>::getLastUseTime(const Key& k) const {
939
  // getLastUseTime works only in LRU mode
940
9072
  assert(lru_);
941
9072
  TableConstIterator iter = table_.find(k);
942
9072
  if (iter == table_.end())
943
8102
    return -1;
944
970
  const Elem* e = iter->second;
945
970
  return e->last_use_;
946
9072
}
947

            
948
template <class Key, class Value, class MapType, class EQ>
949
15
int64_t SimpleLRUCacheBase<Key, Value, MapType, EQ>::getInsertionTime(const Key& k) const {
950
  // getInsertionTime works only in age-based mode
951
15
  assert(!lru_);
952
15
  TableConstIterator iter = table_.find(k);
953
15
  if (iter == table_.end())
954
2
    return -1;
955
13
  const Elem* e = iter->second;
956
13
  return e->last_use_;
957
15
}
958

            
959
template <class Key, class Value, class MapType, class EQ>
960
1
void SimpleLRUCacheBase<Key, Value, MapType, EQ>::debugOutput(std::string* output) const {
961
1
  std::stringstream ss;
962
1
  ss << "SimpleLRUCache of " << table_.size();
963
1
  ss << " elements plus " << deferredEntries();
964
1
  ss << " deferred elements (" << size();
965
1
  ss << " units, " << maxSize() << " max units)";
966
1
  *output += ss.str();
967
2
  for (TableConstIterator iter = table_.begin(); iter != table_.end(); ++iter) {
968
1
    const Elem* e = iter->second;
969
1
    debugIterator(e->value, e->pin, e->last_use_, false, output);
970
1
  }
971
1
  *output += "Deferred elements\n";
972
2
  for (DeferredTableConstIterator iter = defer_.begin(); iter != defer_.end(); ++iter) {
973
1
    const Elem* const head = iter->second;
974
1
    const Elem* e = head;
975
2
    do {
976
2
      debugIterator(e->value, e->pin, e->last_use_, true, output);
977
2
      e = e->prev;
978
2
    } while (e != head);
979
1
  }
980
1
}
981

            
982
// construct an iterator be sure to save a copy of end() as well, so we don't
983
// update external_view_ in that case. this is b/c if it_ == end(), calling
984
// it_->first segfaults. we could do this by making sure a specific field in
985
// it_ is not nullptr but that relies on the internal implementation of it_, so
986
// we pass in end() instead
987
template <class MapType, class Key, class Value>
988
SimpleLRUCacheConstIterator<MapType, Key, Value>::SimpleLRUCacheConstIterator(
989
    HashMapConstIterator it, HashMapConstIterator end)
990
29
    : it_(it), end_(end) {
991
29
  if (it_ != end_) {
992
5
    external_view_.first = it_->first;
993
5
    external_view_.second = it_->second->value;
994
5
    last_use_ = it_->second->last_use_;
995
5
  }
996
29
}
997

            
998
template <class MapType, class Key, class Value>
999
auto SimpleLRUCacheConstIterator<MapType, Key, Value>::operator++()
119
    -> SimpleLRUCacheConstIterator& {
119
  it_++;
119
  if (it_ != end_) {
114
    external_view_.first = it_->first;
114
    external_view_.second = it_->second->value;
114
    last_use_ = it_->second->last_use_;
114
  }
119
  return *this;
119
}
template <class Key, class Value, class H, class EQ>
class SimpleLRUCache
    : public SimpleLRUCacheBase<
          Key, Value, absl::flat_hash_map<Key, SimpleLRUCacheElem<Key, Value>*, H, EQ>, EQ> {
public:
  explicit SimpleLRUCache(int64_t total_units)
54
      : SimpleLRUCacheBase<Key, Value,
54
                           absl::flat_hash_map<Key, SimpleLRUCacheElem<Key, Value>*, H, EQ>, EQ>(
54
            total_units) {}
protected:
12
  virtual void removeElement(Value* value) { delete value; }
private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleLRUCache);
};
template <class Key, class Value, class Deleter, class H, class EQ>
class SimpleLRUCacheWithDeleter
    : public SimpleLRUCacheBase<
          Key, Value, absl::flat_hash_map<Key, SimpleLRUCacheElem<Key, Value>*, H, EQ>, EQ> {
  typedef absl::flat_hash_map<Key, SimpleLRUCacheElem<Key, Value>*, H, EQ> HashMap;
  typedef SimpleLRUCacheBase<Key, Value, HashMap, EQ> Base;
public:
  explicit SimpleLRUCacheWithDeleter(int64_t total_units) : Base(total_units), deleter_() {}
  SimpleLRUCacheWithDeleter(int64_t total_units, Deleter deleter)
      : Base(total_units), deleter_(deleter) {}
protected:
  virtual void removeElement(Value* value) { deleter_(value); }
private:
  Deleter deleter_;
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleLRUCacheWithDeleter);
};
} // namespace SimpleLruCache
} // namespace Envoy