1
#include "source/common/stats/recent_lookups.h"
2

            
3
#include "source/common/common/assert.h"
4

            
5
namespace Envoy {
6
namespace Stats {
7

            
8
56569622
void RecentLookups::lookup(absl::string_view str) {
9
56569622
  ++total_;
10
56569623
  if (capacity_ == 0) {
11
56569579
    return;
12
56569579
  }
13
44
  auto map_iter = map_.find(str);
14
44
  if (map_iter != map_.end()) {
15
    // The item is already in the list. Bump its reference-count and move it to
16
    // the front of the list.
17
14
    auto list_iter = map_iter->second;
18
14
    ++list_iter->count_;
19
14
    if (list_iter != list_.begin()) {
20
3
      list_.splice(list_.begin(), list_, list_iter);
21
3
    }
22
30
  } else {
23
30
    ASSERT(list_.size() <= capacity_);
24
    // Evict oldest item if needed.
25
30
    if (list_.size() >= capacity_) {
26
4
      evictOne();
27
4
    }
28

            
29
    // The string storage is in the list entry.
30
30
    list_.push_front(ItemCount{std::string(str), 1});
31
30
    auto list_iter = list_.begin();
32
30
    map_[list_iter->item_] = list_iter;
33
30
  }
34
44
  ASSERT(list_.size() == map_.size());
35
44
}
36

            
37
22391
void RecentLookups::forEach(const IterFn& fn) const {
38
22404
  for (const ItemCount& item_count : list_) {
39
26
    fn(item_count.item_, item_count.count_);
40
26
  }
41
22391
}
42

            
43
15
void RecentLookups::setCapacity(uint64_t capacity) {
44
15
  capacity_ = capacity;
45
16
  while (capacity_ < list_.size()) {
46
1
    evictOne();
47
1
  }
48
15
}
49

            
50
5
void RecentLookups::evictOne() {
51
5
  ASSERT(!list_.empty());
52
5
  ASSERT(!map_.empty());
53
5
  const ItemCount& item_count = list_.back();
54
5
  int erased = map_.erase(item_count.item_);
55
5
  ASSERT(erased == 1);
56
5
  list_.pop_back();
57
5
}
58

            
59
} // namespace Stats
60
} // namespace Envoy