]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc/StoreMap.h
Report IpcIo file name with errors and warnings
[thirdparty/squid.git] / src / ipc / StoreMap.h
CommitLineData
44c95fcf
AR
1#ifndef SQUID_IPC_STORE_MAP_H
2#define SQUID_IPC_STORE_MAP_H
3
3a8c5551 4#include "ipc/mem/FlexibleArray.h"
68353d5a 5#include "ipc/mem/Pointer.h"
602d9612 6#include "ipc/ReadWriteLock.h"
6d68a230 7#include "typedefs.h"
44c95fcf 8
9199139f
AR
9namespace Ipc
10{
44c95fcf 11
f13833e9 12typedef int32_t StoreMapSliceId;
bc8b6522
AR
13
14/// a piece of Store entry, linked to other pieces, forming a chain
ce49546e 15/// slices may be appended by writers while readers read the entry
bc8b6522
AR
16class StoreMapSlice
17{
18public:
ce49546e 19 typedef uint32_t Size;
bc8b6522 20
ce49546e
AR
21 StoreMapSlice(): size(0), next(-1) {}
22
23 Atomic::WordT<Size> size; ///< slice contents size
24 Atomic::WordT<StoreMapSliceId> next; ///< ID of the next entry slice
bc8b6522
AR
25};
26
50dc81ec
AR
27/// Maintains shareable information about a StoreEntry as a whole.
28/// An anchor points to one or more StoreEntry slices. This is the
29/// only lockable part of shared StoreEntry information, providing
30/// protection for all StoreEntry slices.
31class StoreMapAnchor
9199139f 32{
44c95fcf 33public:
50dc81ec 34 StoreMapAnchor();
44c95fcf 35
50dc81ec 36 /// store StoreEntry key and basics for an inode slot
44c95fcf
AR
37 void set(const StoreEntry &anEntry);
38
39 void setKey(const cache_key *const aKey);
40 bool sameKey(const cache_key *const aKey) const;
41
50dc81ec
AR
42 /// undo the effects of set(), setKey(), etc., but keep locks and state
43 void rewind();
44
ce49546e
AR
45 /* entry state may change immediately after calling these methods unless
46 * the caller holds an appropriate lock */
47 bool empty() const { return !key[0] && !key[1]; }
48 bool reading() const { return lock.readers; }
a3023c03 49 bool writing() const { return lock.writing; }
ce49546e
AR
50 bool complete() const { return !empty() && !writing(); }
51
44c95fcf
AR
52public:
53 mutable ReadWriteLock lock; ///< protects slot data below
794d4c0c 54 Atomic::WordT<uint8_t> waitingToBeFreed; ///< may be accessed w/o a lock
44c95fcf 55
ce49546e
AR
56 // fields marked with [app] can be modified when appending-while-reading
57
44c95fcf
AR
58 uint64_t key[2]; ///< StoreEntry key
59
60 // STORE_META_STD TLV field from StoreEntry
61 struct Basics {
62 time_t timestamp;
63 time_t lastref;
64 time_t expires;
65 time_t lastmod;
e6d2c263 66 Atomic::WordT<uint64_t> swap_file_sz; // [app]
89924985
AR
67 uint16_t refcount;
68 uint16_t flags;
9199139f 69 } basics;
44c95fcf 70
e6d2c263 71 /// where the chain of StoreEntry slices begins [app]
9d4e9cfb 72 Atomic::WordT<StoreMapSliceId> start;
50dc81ec 73
ce49546e 74#if 0
44c95fcf
AR
75 /// possible persistent states
76 typedef enum {
77 Empty, ///< ready for writing, with nothing of value
78 Writeable, ///< transitions from Empty to Readable
79 Readable, ///< ready for reading
9199139f 80 } State;
44c95fcf 81 State state; ///< current state
ce49546e 82#endif
44c95fcf
AR
83};
84
6d68a230
AR
85/// A hack to allocate one shared array for both anchors and slices.
86/// Anchors are indexed by store entry ID and are independent from each other.
87/// Slices are indexed by slice IDs and form entry chains using slice.next.
9d4e9cfb
AR
88class StoreMapSlot
89{
50dc81ec 90public:
6d68a230
AR
91 StoreMapAnchor anchor; ///< information about store entry as a whole
92 StoreMapSlice slice; ///< information about one stored entry piece
50dc81ec
AR
93};
94
7f6748c8
AR
95class StoreMapCleaner;
96
50dc81ec 97/// map of StoreMapSlots indexed by their keys, with read/write slice locking
44c95fcf
AR
98/// kids extend to store custom data
99class StoreMap
100{
101public:
50dc81ec
AR
102 typedef StoreMapAnchor Anchor;
103 typedef sfileno AnchorId;
104 typedef StoreMapSlice Slice;
105 typedef StoreMapSliceId SliceId;
44c95fcf 106
f8f98441 107 /// data shared across maps in different processes
fc3921ec
A
108 class Shared
109 {
f8f98441 110 public:
68353d5a
DK
111 Shared(const int aLimit, const size_t anExtrasSize);
112 size_t sharedMemorySize() const;
113 static size_t SharedMemorySize(const int limit, const size_t anExtrasSize);
114
50dc81ec
AR
115 const int limit; ///< maximum number of store entries
116 const size_t extrasSize; ///< size of slice extra data
117 Atomic::Word count; ///< current number of entries
02458e9b 118 Atomic::WordT<uint32_t> victim; ///< starting point for purge search
50dc81ec 119 Ipc::Mem::FlexibleArray<StoreMapSlot> slots; ///< storage
68353d5a
DK
120 };
121
122public:
123 typedef Mem::Owner<Shared> Owner;
124
125 /// initialize shared memory
126 static Owner *Init(const char *const path, const int limit);
127
128 StoreMap(const char *const aPath);
44c95fcf 129
50dc81ec
AR
130 /// computes map entry position for a given entry key
131 sfileno anchorIndexByKey(const cache_key *const key) const;
132
133 /// Like strcmp(mapped, new), but for store entry versions/timestamps.
134 /// Returns +2 if the mapped entry does not exist; -1/0/+1 otherwise.
135 /// Comparison may be inaccurate unless the caller is a lock holder.
136 int compareVersions(const sfileno oldFileno, time_t newVersion) const;
137
138 /// finds, locks, and returns an anchor for an empty key position,
139 /// erasing the old entry (if any)
140 Anchor *openForWriting(const cache_key *const key, sfileno &fileno);
141 /// locks and returns an anchor for the empty fileno position; if
142 /// overwriteExisting is false and the position is not empty, returns nil
143 Anchor *openForWritingAt(sfileno fileno, bool overwriteExisting = true);
ce49546e
AR
144 /// restrict opened for writing entry to appending operations; allow reads
145 void startAppending(const sfileno fileno);
50dc81ec 146 /// successfully finish creating or updating the entry at fileno pos
44c95fcf 147 void closeForWriting(const sfileno fileno, bool lockForReading = false);
50dc81ec
AR
148 /// unlock and "forget" openForWriting entry, making it Empty again
149 /// this call does not free entry slices so the caller has to do that
150 void forgetWritingEntry(const sfileno fileno);
151
152 /// only works on locked entries; returns nil unless the slice is readable
153 const Anchor *peekAtReader(const sfileno fileno) const;
154
d366a7fa
AR
155 /// only works on locked entries; returns the corresponding Anchor
156 const Anchor &peekAtEntry(const sfileno fileno) const;
157
ce49546e 158 /// free the entry if possible or mark it as waiting to be freed if not
50dc81ec 159 void freeEntry(const sfileno fileno);
ce49546e
AR
160 /// free the entry if possible or mark it as waiting to be freed if not
161 /// does nothing if we cannot check that the key matches the cached entry
162 void freeEntryByKey(const cache_key *const key);
50dc81ec
AR
163
164 /// opens entry (identified by key) for reading, increments read level
165 const Anchor *openForReading(const cache_key *const key, sfileno &fileno);
166 /// opens entry (identified by sfileno) for reading, increments read level
167 const Anchor *openForReadingAt(const sfileno fileno);
168 /// closes open entry after reading, decrements read level
169 void closeForReading(const sfileno fileno);
44c95fcf 170
50dc81ec
AR
171 /// writeable slice within an entry chain created by openForWriting()
172 Slice &writeableSlice(const AnchorId anchorId, const SliceId sliceId);
173 /// readable slice within an entry chain opened by openForReading()
174 const Slice &readableSlice(const AnchorId anchorId, const SliceId sliceId) const;
175 /// writeable anchor for the entry created by openForWriting()
176 Anchor &writeableEntry(const AnchorId anchorId);
ce49546e
AR
177 /// readable anchor for the entry created by openForReading()
178 const Anchor &readableEntry(const AnchorId anchorId) const;
44c95fcf 179
a3023c03
AR
180 /// stop writing the entry, freeing its slot for others to use if possible
181 void abortWriting(const sfileno fileno);
44c95fcf 182
5bba33c9 183 /// either finds and frees an entry with at least 1 slice or returns false
50dc81ec 184 bool purgeOne();
44c95fcf 185
50dc81ec
AR
186 /// copies slice to its designated position
187 void importSlice(const SliceId sliceId, const Slice &slice);
44c95fcf 188
50dc81ec
AR
189 bool valid(const int n) const; ///< whether n is a valid slice coordinate
190 int entryCount() const; ///< number of writeable and readable entries
191 int entryLimit() const; ///< maximum entryCount() possible
44c95fcf
AR
192
193 /// adds approximate current stats to the supplied ones
194 void updateStats(ReadWriteLockStats &stats) const;
195
7f6748c8
AR
196 StoreMapCleaner *cleaner; ///< notified before a readable entry is freed
197
44c95fcf 198protected:
68353d5a 199 static Owner *Init(const char *const path, const int limit, const size_t extrasSize);
44c95fcf 200
920378ba 201 const String path; ///< cache_dir path or similar cache name; for logging
68353d5a 202 Mem::Pointer<Shared> shared;
44c95fcf
AR
203
204private:
50dc81ec 205 Anchor &anchorByKey(const cache_key *const key);
44c95fcf 206
50dc81ec 207 Anchor *openForReading(Slice &s);
50dc81ec
AR
208
209 void freeChain(const sfileno fileno, Anchor &inode, const bool keepLock);
68353d5a 210};
44c95fcf 211
50dc81ec 212/// StoreMap with extra slice data
68353d5a
DK
213/// Note: ExtrasT must be POD, it is initialized with zeroes, no
214/// constructors or destructors are called
215template <class ExtrasT>
216class StoreMapWithExtras: public StoreMap
217{
218public:
219 typedef ExtrasT Extras;
220
221 /// initialize shared memory
222 static Owner *Init(const char *const path, const int limit);
223
224 StoreMapWithExtras(const char *const path);
225
226 /// write access to the extras; call openForWriting() first!
227 ExtrasT &extras(const sfileno fileno);
228 /// read-only access to the extras; call openForReading() first!
229 const ExtrasT &extras(const sfileno fileno) const;
230
231protected:
232
233 ExtrasT *sharedExtras; ///< pointer to extras in shared memory
44c95fcf
AR
234};
235
50dc81ec 236/// API for adjusting external state when dirty map slice is being freed
7f6748c8
AR
237class StoreMapCleaner
238{
239public:
240 virtual ~StoreMapCleaner() {}
241
50dc81ec
AR
242 /// adjust slice-linked state before a locked Readable slice is erased
243 virtual void noteFreeMapSlice(const sfileno sliceId) = 0;
7f6748c8
AR
244};
245
68353d5a
DK
246// StoreMapWithExtras implementation
247
248template <class ExtrasT>
249StoreMap::Owner *
250StoreMapWithExtras<ExtrasT>::Init(const char *const path, const int limit)
251{
252 return StoreMap::Init(path, limit, sizeof(Extras));
253}
254
255template <class ExtrasT>
5f621cd0
AJ
256StoreMapWithExtras<ExtrasT>::StoreMapWithExtras(const char *const aPath):
257 StoreMap(aPath)
68353d5a
DK
258{
259 const size_t sharedSizeWithoutExtras =
260 Shared::SharedMemorySize(entryLimit(), 0);
261 sharedExtras = reinterpret_cast<Extras *>(reinterpret_cast<char *>(shared.getRaw()) + sharedSizeWithoutExtras);
262}
263
264template <class ExtrasT>
265ExtrasT &
266StoreMapWithExtras<ExtrasT>::extras(const sfileno fileno)
267{
268 return const_cast<ExtrasT &>(const_cast<const StoreMapWithExtras *>(this)->extras(fileno));
269}
270
271template <class ExtrasT>
272const ExtrasT &
273StoreMapWithExtras<ExtrasT>::extras(const sfileno fileno) const
274{
275 assert(sharedExtras);
276 assert(valid(fileno));
277 return sharedExtras[fileno];
278}
279
44c95fcf
AR
280} // namespace Ipc
281
75f8f9a2 282// We do not reuse FileMap because we cannot control its size,
44c95fcf
AR
283// resulting in sfilenos that are pointing beyond the database.
284
285#endif /* SQUID_IPC_STORE_MAP_H */