Cachemere
Modular Caching Library for C++
eviction_segmented_lru.hpp
1 namespace cachemere::policy {
2 
3 template<class Key, class KeyHash, class Value>
4 EvictionSegmentedLRU<Key, KeyHash, Value>::VictimIterator::VictimIterator(const KeyRefReverseIt& probation_iterator,
5  const KeyRefReverseIt& probation_end_iterator,
6  const KeyRefReverseIt& protected_iterator)
7  : m_probation_iterator{probation_iterator},
8  m_probation_end_iterator{probation_end_iterator},
9  m_protected_iterator{protected_iterator},
10  m_done_with_probation{probation_iterator == probation_end_iterator}
11 {
12 }
13 
14 template<class Key, class KeyHash, class Value> const Key& EvictionSegmentedLRU<Key, KeyHash, Value>::VictimIterator::operator*() const
15 {
16  const auto it = m_done_with_probation ? m_protected_iterator : m_probation_iterator;
17  return *it;
18 }
19 
20 template<class Key, class KeyHash, class Value> auto EvictionSegmentedLRU<Key, KeyHash, Value>::VictimIterator::operator++() -> VictimIterator&
21 {
22  if (m_done_with_probation) {
23  ++m_protected_iterator;
24  } else {
25  ++m_probation_iterator;
26  m_done_with_probation |= m_probation_iterator == m_probation_end_iterator;
27  }
28  return *this;
29 }
30 
31 template<class Key, class KeyHash, class Value> auto EvictionSegmentedLRU<Key, KeyHash, Value>::VictimIterator::operator++(int) -> VictimIterator
32 {
33  auto tmp = *this;
34  ++*this;
35  return tmp;
36 }
37 
38 template<class Key, class KeyHash, class Value> bool EvictionSegmentedLRU<Key, KeyHash, Value>::VictimIterator::operator==(const VictimIterator& other) const
39 {
40  return m_protected_iterator == other.m_protected_iterator && m_probation_iterator == other.m_probation_iterator &&
41  m_done_with_probation == other.m_done_with_probation;
42 }
43 
44 template<class Key, class KeyHash, class Value> bool EvictionSegmentedLRU<Key, KeyHash, Value>::VictimIterator::operator!=(const VictimIterator& other) const
45 {
46  return !(*this == other);
47 }
48 
49 template<class Key, class KeyHash, class Value> void EvictionSegmentedLRU<Key, KeyHash, Value>::clear()
50 {
51  m_probation_list.clear();
52  m_probation_nodes.clear();
53 
54  m_protected_list.clear();
55  m_protected_nodes.clear();
56 }
57 
58 template<class Key, class KeyHash, class Value> void EvictionSegmentedLRU<Key, KeyHash, Value>::set_protected_segment_size(size_t size)
59 {
60  m_protected_segment_size = size;
61 }
62 
63 template<class Key, class KeyHash, class Value> void EvictionSegmentedLRU<Key, KeyHash, Value>::on_insert(const Key& key, const CacheItem& /* item */)
64 {
65  assert(m_probation_nodes.find(key) == m_probation_nodes.end());
66 
67  m_probation_list.emplace_front(std::ref(key));
68  m_probation_nodes.emplace(std::ref(key), m_probation_list.begin());
69 }
70 
71 template<class Key, class KeyHash, class Value>
72 void EvictionSegmentedLRU<Key, KeyHash, Value>::on_update(const Key& key, const CacheItem& /* old_item */, const CacheItem& new_item)
73 {
74  on_cache_hit(key, new_item);
75 }
76 
77 template<class Key, class KeyHash, class Value> void EvictionSegmentedLRU<Key, KeyHash, Value>::on_cache_hit(const Key& key, const CacheItem& /* item */)
78 {
79  assert(m_probation_nodes.size() == m_probation_list.size());
80  assert(m_protected_nodes.size() == m_protected_list.size());
81 
82  auto protected_node_it = m_protected_nodes.find(key);
83  if (protected_node_it != m_protected_nodes.end()) {
84  if (protected_node_it->second != m_protected_list.begin()) {
85  // If the node is in the protected segment, move it to the front of the protected segment.
86  m_protected_list.splice(m_protected_list.begin(), m_protected_list, protected_node_it->second);
87  }
88  } else {
89  // If the node is in probation, move it to the protected segment.
90  [[maybe_unused]] const bool promotion_ok = move_to_protected(key);
91  assert(promotion_ok);
92  }
93 
94  while (m_protected_list.size() > m_protected_segment_size) {
95  [[maybe_unused]] const bool demotion_ok = pop_to_probation();
96  assert(demotion_ok);
97  assert(m_protected_list.size() == m_protected_segment_size);
98  }
99 
100  assert(m_probation_nodes.size() == m_probation_list.size());
101  assert(m_protected_nodes.size() == m_protected_list.size());
102 }
103 
104 template<class Key, class KeyHash, class Value> void EvictionSegmentedLRU<Key, KeyHash, Value>::on_evict(const Key& key, const CacheItem& /* item */)
105 {
106  assert((!m_protected_list.empty()) || !m_probation_list.empty());
107 
108  auto key_and_it = m_probation_nodes.find(key);
109  if (key_and_it != m_probation_nodes.end()) {
110  m_probation_list.erase(key_and_it->second);
111  m_probation_nodes.erase(key_and_it);
112  } else {
113  key_and_it = m_protected_nodes.find(key);
114  assert(key_and_it != m_protected_nodes.end());
115  m_protected_list.erase(key_and_it->second);
116  m_protected_nodes.erase(key_and_it);
117  }
118 }
119 
120 template<class Key, class KeyHash, class Value> auto EvictionSegmentedLRU<Key, KeyHash, Value>::victim_begin() const -> VictimIterator
121 {
122  return VictimIterator{m_probation_list.rbegin(), m_probation_list.rend(), m_protected_list.rbegin()};
123 }
124 
125 template<class Key, class KeyHash, class Value> auto EvictionSegmentedLRU<Key, KeyHash, Value>::victim_end() const -> VictimIterator
126 {
127  return VictimIterator{m_probation_list.rend(), m_probation_list.rend(), m_protected_list.rend()};
128 }
129 
130 template<class Key, class KeyHash, class Value> bool EvictionSegmentedLRU<Key, KeyHash, Value>::move_to_protected(const Key& key)
131 {
132  auto probation_node_it = m_probation_nodes.find(key);
133  if (probation_node_it == m_probation_nodes.end()) {
134  return false;
135  }
136 
137  m_protected_list.splice(m_protected_list.begin(), m_probation_list, probation_node_it->second);
138  m_probation_nodes.erase(key);
139  m_protected_nodes.emplace(key, m_protected_list.begin());
140  return true;
141 }
142 
143 template<class Key, class KeyHash, class Value> bool EvictionSegmentedLRU<Key, KeyHash, Value>::pop_to_probation()
144 {
145  if (m_protected_list.empty()) {
146  return false;
147  }
148 
149  m_probation_list.splice(m_probation_list.begin(), m_protected_list, --m_protected_list.end());
150  m_protected_nodes.erase(*m_probation_list.begin());
151  m_probation_nodes.emplace(*m_probation_list.begin(), m_probation_list.begin());
152  return true;
153 }
154 
155 } // namespace cachemere::policy
cachemere::policy::EvictionSegmentedLRU::on_insert
void on_insert(const Key &key, const CacheItem &item)
Insertion event handler.
Definition: eviction_segmented_lru.hpp:63
cachemere::Item
A wrapper for items stored in the cache.
Definition: item.h:10
cachemere::policy::EvictionSegmentedLRU::on_update
void on_update(const Key &key, const CacheItem &old_item, const CacheItem &new_item)
Update event handler.
Definition: eviction_segmented_lru.hpp:72
cachemere::policy::EvictionSegmentedLRU::clear
void clear()
Clears the policy.
Definition: eviction_segmented_lru.hpp:49
cachemere::policy::EvictionSegmentedLRU::set_protected_segment_size
void set_protected_segment_size(size_t size)
Set the maximum number of items in the protected LRU segment.
Definition: eviction_segmented_lru.hpp:58
cachemere::policy::EvictionSegmentedLRU::on_cache_hit
void on_cache_hit(const Key &key, const CacheItem &item)
Cache hit event handler.
Definition: eviction_segmented_lru.hpp:77
cachemere::policy::EvictionSegmentedLRU::victim_end
VictimIterator victim_end() const
Get an end iterator.
Definition: eviction_segmented_lru.hpp:125
cachemere::policy::EvictionSegmentedLRU::VictimIterator
Iterator for iterating over cache items in the order they should be.
Definition: eviction_segmented_lru.h:34
cachemere::policy::EvictionSegmentedLRU::victim_begin
VictimIterator victim_begin() const
Get an iterator to the first item that should be evicted.
Definition: eviction_segmented_lru.hpp:120
cachemere::policy::EvictionSegmentedLRU
Segmented Least Recently Used (S-LRU) Eviction Policy.
Definition: eviction_segmented_lru.h:22
cachemere::policy::EvictionSegmentedLRU::on_evict
void on_evict(const Key &key, const CacheItem &item)
Eviction event handler.
Definition: eviction_segmented_lru.hpp:104