ClpMap.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#ifndef SQUID__SRC_BASE_CLPMAP_H
10#define SQUID__SRC_BASE_CLPMAP_H
11
13#include "SquidMath.h"
14#include "time/gadgets.h"
15
16#include <functional>
17#include <limits>
18#include <list>
19#include <optional>
20#include <unordered_map>
21
22template<class Value>
23uint64_t
24DefaultMemoryUsage(const Value &e)
25{
26 return sizeof(e);
27}
28
39template <class Key, class Value, uint64_t MemoryUsedBy(const Value &) = DefaultMemoryUsage>
40class ClpMap
41{
42public:
43 using key_type = Key;
44 using mapped_type = Value;
45
47 using Ttl = int;
48
50 class Entry
51 {
52 public:
53 Entry(const Key &, const Value &, const Ttl);
54
56 bool expired() const { return expires < squid_curtime; }
57
58 public:
59 Key key;
60 Value value;
61 time_t expires = 0;
62 uint64_t memCounted = 0;
63 };
64
66 using Entries = std::list<Entry, PoolingAllocator<Entry> >;
67 using EntriesIterator = typename Entries::iterator;
68 using ConstEntriesIterator = typename Entries::const_iterator;
69
70 explicit ClpMap(const uint64_t capacity) { setMemLimit(capacity); }
71 ClpMap(uint64_t capacity, Ttl defaultTtl);
72 ~ClpMap() = default;
73
74 // copying disabled because it may be expensive for large maps
75 // moving (implicitly) disabled for simplicity sake
76 ClpMap(const ClpMap &) = delete;
77 ClpMap &operator =(const ClpMap &) = delete;
78
83 const Value *get(const Key &);
84
88 bool add(const Key &, const Value &, Ttl);
89
91 bool add(const Key &key, const Value &v) { return add(key, v, defaultTtl_); }
92
94 void del(const Key &);
95
97 void setMemLimit(uint64_t newLimit);
98
100 uint64_t memLimit() const { return memLimit_; }
101
103 uint64_t freeMem() const { return memLimit() - memoryUsed(); }
104
106 uint64_t memoryUsed() const { return memUsed_; }
107
109 size_t entries() const { return entries_.size(); }
110
114 ConstEntriesIterator cbegin() const { return entries_.cbegin(); }
115 ConstEntriesIterator cend() const { return entries_.cend(); }
117 ConstEntriesIterator begin() const { return cbegin(); }
118 ConstEntriesIterator end() const { return cend(); }
119
120private:
121 using IndexItem = std::pair<const Key, EntriesIterator>;
123 using Index = std::unordered_map<Key, EntriesIterator, std::hash<Key>, std::equal_to<Key>, PoolingAllocator<IndexItem> >;
124 using IndexIterator = typename Index::iterator;
125
126 static std::optional<uint64_t> MemoryCountedFor(const Key &, const Value &);
127
128 void trim(uint64_t wantSpace);
129 void erase(const IndexIterator &);
130 IndexIterator find(const Key &);
131
134
137
140
142 uint64_t memLimit_ = 0;
143
145 uint64_t memUsed_ = 0;
146};
147
148template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
149ClpMap<Key, Value, MemoryUsedBy>::ClpMap(const uint64_t capacity, const Ttl defaultTtl):
150 defaultTtl_(defaultTtl)
151{
152 assert(defaultTtl >= 0);
153 setMemLimit(capacity);
154}
155
156template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
157void
159{
160 if (memUsed_ > newLimit)
161 trim(memLimit_ - newLimit);
162 memLimit_ = newLimit;
163}
164
166template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
169{
170 const auto i = index_.find(key);
171 if (i == index_.end())
172 return i;
173
174 const auto entryPosition = i->second;
175 if (!entryPosition->expired()) {
176 if (entryPosition != entries_.begin())
177 entries_.splice(entries_.begin(), entries_, entryPosition);
178 return i;
179 }
180 // else fall through to cleanup
181
182 erase(i);
183 return index_.end();
184}
185
186template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
187const Value *
189{
190 const auto i = find(key);
191 if (i != index_.end()) {
192 const auto &entry = *(i->second);
193 return &entry.value;
194 }
195 return nullptr;
196}
197
198template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
199std::optional<uint64_t>
201{
202 // Both storage and index store keys, but we count keySz once, assuming that
203 // copying a Key does not consume more memory. This assumption holds for
204 // Key=SBuf, but, ideally, we should be outsourcing this decision to another
205 // configurable function, storing each key once, or hard-coding Key=SBuf.
206 const auto keySz = k.length();
207
208 // approximate calculation (e.g., containers store wrappers not value_types)
209 return NaturalSum<uint64_t>(
210 keySz,
211 // storage
212 sizeof(typename Entries::value_type),
213 MemoryUsedBy(v),
214 // index
215 sizeof(typename Index::value_type));
216}
217
218template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
219bool
220ClpMap<Key, Value, MemoryUsedBy>::add(const Key &key, const Value &v, const Ttl ttl)
221{
222 // optimization: avoid del() search, MemoryCountedFor() in always-empty maps
223 if (memLimit() == 0)
224 return false;
225
226 del(key);
227
228 if (ttl < 0)
229 return false; // already expired; will never be returned by get()
230
231 const auto memoryRequirements = MemoryCountedFor(key, v);
232 if (!memoryRequirements)
233 return false; // cannot even compute memory requirements
234
235 const auto wantSpace = memoryRequirements.value();
236 if (wantSpace > memLimit() || wantSpace == 0) // 0 is 64-bit integer overflow
237 return false; // will never fit
238 trim(wantSpace);
239
240 auto &addedEntry = entries_.emplace_front(key, v, ttl);
241 index_.emplace(key, entries_.begin());
242
243 addedEntry.memCounted = wantSpace;
244 memUsed_ += wantSpace;
245 assert(memUsed_ >= wantSpace); // no overflows
246 return true;
247}
248
250template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
251void
253{
254 assert(i != index_.end());
255 const auto entryPosition = i->second;
256
257 assert(entryPosition != entries_.end());
258 const auto sz = entryPosition->memCounted;
259 assert(memUsed_ >= sz);
260 memUsed_ -= sz;
261
262 index_.erase(i); // destroys a "pointer" to our Entry
263 entries_.erase(entryPosition); // destroys our Entry
264}
265
266template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
267void
269{
270 const auto i = find(key);
271 if (i != index_.end())
272 erase(i);
273}
274
276template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
277void
279{
280 assert(wantSpace <= memLimit()); // no infinite loops and in-vain trimming
281 while (freeMem() < wantSpace) {
282 assert(!entries_.empty());
283 // TODO: Purge expired entries first. They are useless, but their
284 // presence may lead to purging potentially useful fresh entries here.
285 del(entries_.rbegin()->key);
286 }
287}
288
289template <class Key, class Value, uint64_t MemoryUsedBy(const Value &)>
290ClpMap<Key, Value, MemoryUsedBy>::Entry::Entry(const Key &aKey, const Value &v, const Ttl ttl) :
291 key(aKey),
292 value(v),
293 expires(0) // reset below
294{
296}
297
298#endif /* SQUID__SRC_BASE_CLPMAP_H */
299
uint64_t DefaultMemoryUsage(const Value &e)
Definition: ClpMap.h:24
static char const * trim(char const *s)
Definition: Expression.cc:674
time_t squid_curtime
Definition: stub_libtime.cc:20
S SetToNaturalSumOrMax(S &var, const Args... args)
Definition: SquidMath.h:176
#define assert(EX)
Definition: assert.h:17
the keeper of cache entry Key, Value, and caching-related entry metadata
Definition: ClpMap.h:51
bool expired() const
whether the entry is stale
Definition: ClpMap.h:56
Value value
cached value provided by the map user
Definition: ClpMap.h:60
time_t expires
get() stops returning the entry after this time
Definition: ClpMap.h:61
uint64_t memCounted
memory accounted for this entry in our ClpMap
Definition: ClpMap.h:62
Key key
the entry search key; see ClpMap::get()
Definition: ClpMap.h:59
Entry(const Key &, const Value &, const Ttl)
Definition: ClpMap.h:290
Definition: ClpMap.h:41
ConstEntriesIterator cbegin() const
Definition: ClpMap.h:114
const Value * get(const Key &)
Definition: ClpMap.h:188
std::pair< const Key, EntriesIterator > IndexItem
Definition: ClpMap.h:121
ClpMap(const ClpMap &)=delete
ConstEntriesIterator end() const
Definition: ClpMap.h:118
ClpMap(const uint64_t capacity)
Definition: ClpMap.h:70
void del(const Key &)
Remove the corresponding entry (if any)
Definition: ClpMap.h:268
void trim(uint64_t wantSpace)
purges entries to make free memory large enough to fit wantSpace bytes
Definition: ClpMap.h:278
typename Entries::iterator EntriesIterator
Definition: ClpMap.h:67
uint64_t memLimit() const
The memory capacity for the map.
Definition: ClpMap.h:100
uint64_t freeMem() const
The free space of the map.
Definition: ClpMap.h:103
ClpMap & operator=(const ClpMap &)=delete
Ttl defaultTtl_
entry TTL to use if none provided to add()
Definition: ClpMap.h:139
typename Index::iterator IndexIterator
Definition: ClpMap.h:124
uint64_t memUsed_
the total amount of memory we currently use for all cached entries
Definition: ClpMap.h:145
void erase(const IndexIterator &)
removes the cached entry (identified by its index) from the map
Definition: ClpMap.h:252
Index index_
entries_ positions indexed by the entry key
Definition: ClpMap.h:136
static std::optional< uint64_t > MemoryCountedFor(const Key &, const Value &)
Definition: ClpMap.h:200
uint64_t memLimit_
the maximum memory we are allowed to use for all cached entries
Definition: ClpMap.h:142
IndexIterator find(const Key &)
Definition: ClpMap.h:168
std::unordered_map< Key, EntriesIterator, std::hash< Key >, std::equal_to< Key >, PoolingAllocator< IndexItem > > Index
key:entry_position mapping for fast entry lookups by key
Definition: ClpMap.h:123
Key key_type
Definition: ClpMap.h:43
int Ttl
maximum desired entry caching duration (a.k.a. TTL), in seconds
Definition: ClpMap.h:47
typename Entries::const_iterator ConstEntriesIterator
Definition: ClpMap.h:68
ConstEntriesIterator begin() const
range-based for loop support;
Definition: ClpMap.h:117
void setMemLimit(uint64_t newLimit)
Reset the memory capacity for this map, purging if needed.
Definition: ClpMap.h:158
size_t entries() const
The number of currently stored entries, including expired ones.
Definition: ClpMap.h:109
~ClpMap()=default
bool add(const Key &, const Value &, Ttl)
Definition: ClpMap.h:220
Value mapped_type
Definition: ClpMap.h:44
ConstEntriesIterator cend() const
Definition: ClpMap.h:115
uint64_t memoryUsed() const
The current (approximate) memory usage of the map.
Definition: ClpMap.h:106
Entries entries_
cached entries, including expired ones, in LRU order
Definition: ClpMap.h:133
std::list< Entry, PoolingAllocator< Entry > > Entries
Entries in LRU order.
Definition: ClpMap.h:66
bool add(const Key &key, const Value &v)
Copy the given value into the map (with the given key and default TTL)
Definition: ClpMap.h:91
STL Allocator that uses Squid memory pools for memory management.
A const & max(A const &lhs, A const &rhs)
int unsigned int
Definition: stub_fd.cc:19
static StoreEntry * addedEntry(Store::Disk *aStore, String name, String, String)

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors