]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc/StoreMap.h
Documented some of the Packable API problems.
[thirdparty/squid.git] / src / ipc / StoreMap.h
CommitLineData
bbc27441 1/*
ef57eb7b 2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
bbc27441
AJ
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
44c95fcf
AR
9#ifndef SQUID_IPC_STORE_MAP_H
10#define SQUID_IPC_STORE_MAP_H
11
3a8c5551 12#include "ipc/mem/FlexibleArray.h"
68353d5a 13#include "ipc/mem/Pointer.h"
602d9612 14#include "ipc/ReadWriteLock.h"
65e41a45 15#include "sbuf/SBuf.h"
2745fea5 16#include "store/forward.h"
e1ba42a4 17#include "store_key_md5.h"
44c95fcf 18
9199139f
AR
19namespace Ipc
20{
44c95fcf 21
f13833e9 22typedef int32_t StoreMapSliceId;
bc8b6522
AR
23
24/// a piece of Store entry, linked to other pieces, forming a chain
ce49546e 25/// slices may be appended by writers while readers read the entry
bc8b6522
AR
26class StoreMapSlice
27{
28public:
ce49546e 29 typedef uint32_t Size;
bc8b6522 30
ce49546e 31 StoreMapSlice(): size(0), next(-1) {}
d2b13bab
AJ
32 StoreMapSlice(const StoreMapSlice &o) {
33 size.exchange(o.size);
34 next.exchange(o.next);
35 }
36
37 StoreMapSlice &operator =(const StoreMapSlice &o) {
38 size.store(o.size);
39 next.store(o.next);
40 return *this;
41 }
42
43 std::atomic<Size> size; ///< slice contents size
44 std::atomic<StoreMapSliceId> next; ///< ID of the next entry slice
bc8b6522
AR
45};
46
50dc81ec
AR
47/// Maintains shareable information about a StoreEntry as a whole.
48/// An anchor points to one or more StoreEntry slices. This is the
49/// only lockable part of shared StoreEntry information, providing
50/// protection for all StoreEntry slices.
51class StoreMapAnchor
9199139f 52{
44c95fcf 53public:
50dc81ec 54 StoreMapAnchor();
44c95fcf 55
50dc81ec 56 /// store StoreEntry key and basics for an inode slot
44c95fcf
AR
57 void set(const StoreEntry &anEntry);
58
59 void setKey(const cache_key *const aKey);
60 bool sameKey(const cache_key *const aKey) const;
61
50dc81ec
AR
62 /// undo the effects of set(), setKey(), etc., but keep locks and state
63 void rewind();
64
ce49546e
AR
65 /* entry state may change immediately after calling these methods unless
66 * the caller holds an appropriate lock */
67 bool empty() const { return !key[0] && !key[1]; }
68 bool reading() const { return lock.readers; }
a3023c03 69 bool writing() const { return lock.writing; }
ce49546e
AR
70 bool complete() const { return !empty() && !writing(); }
71
44c95fcf
AR
72public:
73 mutable ReadWriteLock lock; ///< protects slot data below
d2b13bab 74 std::atomic<uint8_t> waitingToBeFreed; ///< may be accessed w/o a lock
44c95fcf 75
ce49546e
AR
76 // fields marked with [app] can be modified when appending-while-reading
77
44c95fcf
AR
78 uint64_t key[2]; ///< StoreEntry key
79
80 // STORE_META_STD TLV field from StoreEntry
81 struct Basics {
82 time_t timestamp;
83 time_t lastref;
84 time_t expires;
85 time_t lastmod;
d2b13bab 86 std::atomic<uint64_t> swap_file_sz; // [app]
89924985
AR
87 uint16_t refcount;
88 uint16_t flags;
9199139f 89 } basics;
44c95fcf 90
e6d2c263 91 /// where the chain of StoreEntry slices begins [app]
d2b13bab 92 std::atomic<StoreMapSliceId> start;
1860fbac
AR
93};
94
95/// an array of shareable Items
96/// must be the last data member or, if used as a parent class, the last parent
97template <class C>
98class StoreMapItems
99{
100public:
101 typedef C Item;
102 typedef Ipc::Mem::Owner< StoreMapItems<Item> > Owner;
103
104 explicit StoreMapItems(const int aCapacity): capacity(aCapacity), items(aCapacity) {}
50dc81ec 105
1860fbac
AR
106 size_t sharedMemorySize() const { return SharedMemorySize(capacity); }
107 static size_t SharedMemorySize(const int aCapacity) { return sizeof(StoreMapItems<Item>) + aCapacity*sizeof(Item); }
108
109 const int capacity; ///< total number of items
110 Ipc::Mem::FlexibleArray<Item> items; ///< storage
44c95fcf
AR
111};
112
1860fbac
AR
113/// StoreMapSlices indexed by their slice ID.
114typedef StoreMapItems<StoreMapSlice> StoreMapSlices;
115
116/// StoreMapAnchors indexed by entry fileno plus
117/// sharing-safe basic housekeeping info about Store entries
118class StoreMapAnchors
9d4e9cfb 119{
50dc81ec 120public:
1860fbac
AR
121 typedef Ipc::Mem::Owner< StoreMapAnchors > Owner;
122
123 explicit StoreMapAnchors(const int aCapacity);
124
125 size_t sharedMemorySize() const;
126 static size_t SharedMemorySize(const int anAnchorLimit);
127
d2b13bab
AJ
128 std::atomic<int32_t> count; ///< current number of entries
129 std::atomic<uint32_t> victim; ///< starting point for purge search
1860fbac
AR
130 const int capacity; ///< total number of anchors
131 Ipc::Mem::FlexibleArray<StoreMapAnchor> items; ///< anchors storage
50dc81ec 132};
1860fbac 133// TODO: Find an elegant way to use StoreMapItems in StoreMapAnchors
50dc81ec 134
7f6748c8
AR
135class StoreMapCleaner;
136
1860fbac
AR
137/// Manages shared Store index (e.g., locking/unlocking/freeing entries) using
138/// StoreMapAnchors indexed by their keys and
139/// StoreMapSlices indexed by their slide ID.
44c95fcf
AR
140class StoreMap
141{
142public:
50dc81ec 143 typedef StoreMapAnchor Anchor;
1860fbac 144 typedef StoreMapAnchors Anchors;
50dc81ec
AR
145 typedef sfileno AnchorId;
146 typedef StoreMapSlice Slice;
1860fbac 147 typedef StoreMapSlices Slices;
50dc81ec 148 typedef StoreMapSliceId SliceId;
44c95fcf 149
1860fbac
AR
150public:
151 /// aggregates anchor and slice owners for Init() caller convenience
2da4bfe6
A
152 class Owner
153 {
f8f98441 154 public:
1860fbac
AR
155 Owner();
156 ~Owner();
157 Anchors::Owner *anchors;
158 Slices::Owner *slices;
159 private:
160 Owner(const Owner &); // not implemented
161 Owner &operator =(const Owner &); // not implemented
68353d5a
DK
162 };
163
68353d5a 164 /// initialize shared memory
1860fbac 165 static Owner *Init(const SBuf &path, const int slotLimit);
68353d5a 166
1860fbac 167 StoreMap(const SBuf &aPath);
44c95fcf 168
50dc81ec
AR
169 /// computes map entry position for a given entry key
170 sfileno anchorIndexByKey(const cache_key *const key) const;
171
172 /// Like strcmp(mapped, new), but for store entry versions/timestamps.
173 /// Returns +2 if the mapped entry does not exist; -1/0/+1 otherwise.
174 /// Comparison may be inaccurate unless the caller is a lock holder.
175 int compareVersions(const sfileno oldFileno, time_t newVersion) const;
176
177 /// finds, locks, and returns an anchor for an empty key position,
178 /// erasing the old entry (if any)
179 Anchor *openForWriting(const cache_key *const key, sfileno &fileno);
180 /// locks and returns an anchor for the empty fileno position; if
181 /// overwriteExisting is false and the position is not empty, returns nil
182 Anchor *openForWritingAt(sfileno fileno, bool overwriteExisting = true);
ce49546e
AR
183 /// restrict opened for writing entry to appending operations; allow reads
184 void startAppending(const sfileno fileno);
50dc81ec 185 /// successfully finish creating or updating the entry at fileno pos
44c95fcf 186 void closeForWriting(const sfileno fileno, bool lockForReading = false);
50dc81ec
AR
187 /// unlock and "forget" openForWriting entry, making it Empty again
188 /// this call does not free entry slices so the caller has to do that
189 void forgetWritingEntry(const sfileno fileno);
190
191 /// only works on locked entries; returns nil unless the slice is readable
192 const Anchor *peekAtReader(const sfileno fileno) const;
193
d366a7fa
AR
194 /// only works on locked entries; returns the corresponding Anchor
195 const Anchor &peekAtEntry(const sfileno fileno) const;
196
ce49546e 197 /// free the entry if possible or mark it as waiting to be freed if not
50dc81ec 198 void freeEntry(const sfileno fileno);
ce49546e
AR
199 /// free the entry if possible or mark it as waiting to be freed if not
200 /// does nothing if we cannot check that the key matches the cached entry
201 void freeEntryByKey(const cache_key *const key);
50dc81ec
AR
202
203 /// opens entry (identified by key) for reading, increments read level
204 const Anchor *openForReading(const cache_key *const key, sfileno &fileno);
205 /// opens entry (identified by sfileno) for reading, increments read level
206 const Anchor *openForReadingAt(const sfileno fileno);
207 /// closes open entry after reading, decrements read level
208 void closeForReading(const sfileno fileno);
44c95fcf 209
50dc81ec
AR
210 /// writeable slice within an entry chain created by openForWriting()
211 Slice &writeableSlice(const AnchorId anchorId, const SliceId sliceId);
212 /// readable slice within an entry chain opened by openForReading()
213 const Slice &readableSlice(const AnchorId anchorId, const SliceId sliceId) const;
214 /// writeable anchor for the entry created by openForWriting()
215 Anchor &writeableEntry(const AnchorId anchorId);
ce49546e
AR
216 /// readable anchor for the entry created by openForReading()
217 const Anchor &readableEntry(const AnchorId anchorId) const;
44c95fcf 218
a3023c03
AR
219 /// stop writing the entry, freeing its slot for others to use if possible
220 void abortWriting(const sfileno fileno);
44c95fcf 221
5bba33c9 222 /// either finds and frees an entry with at least 1 slice or returns false
50dc81ec 223 bool purgeOne();
44c95fcf 224
50dc81ec
AR
225 /// copies slice to its designated position
226 void importSlice(const SliceId sliceId, const Slice &slice);
44c95fcf 227
36c84e19
AR
228 /* SwapFilenMax limits the number of entries, but not slices or slots */
229 bool validEntry(const int n) const; ///< whether n is a valid slice coordinate
230 bool validSlice(const int n) const; ///< whether n is a valid slice coordinate
50dc81ec
AR
231 int entryCount() const; ///< number of writeable and readable entries
232 int entryLimit() const; ///< maximum entryCount() possible
36c84e19 233 int sliceLimit() const; ///< maximum number of slices possible
44c95fcf
AR
234
235 /// adds approximate current stats to the supplied ones
236 void updateStats(ReadWriteLockStats &stats) const;
237
7f6748c8
AR
238 StoreMapCleaner *cleaner; ///< notified before a readable entry is freed
239
44c95fcf 240protected:
1860fbac
AR
241 const SBuf path; ///< cache_dir path or similar cache name; for logging
242 Mem::Pointer<StoreMapAnchors> anchors; ///< entry inodes (starting blocks)
243 Mem::Pointer<StoreMapSlices> slices; ///< chained entry pieces positions
44c95fcf
AR
244
245private:
1860fbac
AR
246 Anchor &anchorAt(const sfileno fileno);
247 const Anchor &anchorAt(const sfileno fileno) const;
50dc81ec 248 Anchor &anchorByKey(const cache_key *const key);
44c95fcf 249
1860fbac
AR
250 Slice &sliceAt(const SliceId sliceId);
251 const Slice &sliceAt(const SliceId sliceId) const;
50dc81ec 252 Anchor *openForReading(Slice &s);
50dc81ec
AR
253
254 void freeChain(const sfileno fileno, Anchor &inode, const bool keepLock);
68353d5a 255};
44c95fcf 256
50dc81ec 257/// API for adjusting external state when dirty map slice is being freed
7f6748c8
AR
258class StoreMapCleaner
259{
260public:
261 virtual ~StoreMapCleaner() {}
262
50dc81ec 263 /// adjust slice-linked state before a locked Readable slice is erased
36c84e19 264 virtual void noteFreeMapSlice(const StoreMapSliceId sliceId) = 0;
7f6748c8
AR
265};
266
44c95fcf
AR
267} // namespace Ipc
268
75f8f9a2 269// We do not reuse FileMap because we cannot control its size,
44c95fcf
AR
270// resulting in sfilenos that are pointing beyond the database.
271
272#endif /* SQUID_IPC_STORE_MAP_H */
f53969cc 273