]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/StoreMap.h
2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
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.
9 #ifndef SQUID_IPC_STORE_MAP_H
10 #define SQUID_IPC_STORE_MAP_H
12 #include "ipc/mem/FlexibleArray.h"
13 #include "ipc/mem/Pointer.h"
14 #include "ipc/ReadWriteLock.h"
15 #include "sbuf/SBuf.h"
16 #include "store/forward.h"
17 #include "store_key_md5.h"
22 typedef int32_t StoreMapSliceId
;
24 /// a piece of Store entry, linked to other pieces, forming a chain
25 /// slices may be appended by writers while readers read the entry
29 typedef uint32_t Size
;
31 StoreMapSlice(): size(0), next(-1) {}
32 StoreMapSlice(const StoreMapSlice
&o
) {
33 size
.exchange(o
.size
);
34 next
.exchange(o
.next
);
37 StoreMapSlice
&operator =(const StoreMapSlice
&o
) {
43 std::atomic
<Size
> size
; ///< slice contents size
44 std::atomic
<StoreMapSliceId
> next
; ///< ID of the next entry slice
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.
56 /// store StoreEntry key and basics for an inode slot
57 void set(const StoreEntry
&anEntry
);
59 void setKey(const cache_key
*const aKey
);
60 bool sameKey(const cache_key
*const aKey
) const;
62 /// undo the effects of set(), setKey(), etc., but keep locks and state
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
; }
69 bool writing() const { return lock
.writing
; }
70 bool complete() const { return !empty() && !writing(); }
73 mutable ReadWriteLock lock
; ///< protects slot data below
74 std::atomic
<uint8_t> waitingToBeFreed
; ///< may be accessed w/o a lock
76 // fields marked with [app] can be modified when appending-while-reading
78 uint64_t key
[2]; ///< StoreEntry key
80 // STORE_META_STD TLV field from StoreEntry
86 std::atomic
<uint64_t> swap_file_sz
; // [app]
91 /// where the chain of StoreEntry slices begins [app]
92 std::atomic
<StoreMapSliceId
> start
;
95 /// an array of shareable Items
96 /// must be the last data member or, if used as a parent class, the last parent
102 typedef Ipc::Mem::Owner
< StoreMapItems
<Item
> > Owner
;
104 explicit StoreMapItems(const int aCapacity
): capacity(aCapacity
), items(aCapacity
) {}
106 size_t sharedMemorySize() const { return SharedMemorySize(capacity
); }
107 static size_t SharedMemorySize(const int aCapacity
) { return sizeof(StoreMapItems
<Item
>) + aCapacity
*sizeof(Item
); }
109 const int capacity
; ///< total number of items
110 Ipc::Mem::FlexibleArray
<Item
> items
; ///< storage
113 /// StoreMapSlices indexed by their slice ID.
114 typedef StoreMapItems
<StoreMapSlice
> StoreMapSlices
;
116 /// StoreMapAnchors indexed by entry fileno plus
117 /// sharing-safe basic housekeeping info about Store entries
118 class StoreMapAnchors
121 typedef Ipc::Mem::Owner
< StoreMapAnchors
> Owner
;
123 explicit StoreMapAnchors(const int aCapacity
);
125 size_t sharedMemorySize() const;
126 static size_t SharedMemorySize(const int anAnchorLimit
);
128 std::atomic
<int32_t> count
; ///< current number of entries
129 std::atomic
<uint32_t> victim
; ///< starting point for purge search
130 const int capacity
; ///< total number of anchors
131 Ipc::Mem::FlexibleArray
<StoreMapAnchor
> items
; ///< anchors storage
133 // TODO: Find an elegant way to use StoreMapItems in StoreMapAnchors
135 class StoreMapCleaner
;
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.
143 typedef StoreMapAnchor Anchor
;
144 typedef StoreMapAnchors Anchors
;
145 typedef sfileno AnchorId
;
146 typedef StoreMapSlice Slice
;
147 typedef StoreMapSlices Slices
;
148 typedef StoreMapSliceId SliceId
;
151 /// aggregates anchor and slice owners for Init() caller convenience
157 Anchors::Owner
*anchors
;
158 Slices::Owner
*slices
;
160 Owner(const Owner
&); // not implemented
161 Owner
&operator =(const Owner
&); // not implemented
164 /// initialize shared memory
165 static Owner
*Init(const SBuf
&path
, const int slotLimit
);
167 StoreMap(const SBuf
&aPath
);
169 /// computes map entry position for a given entry key
170 sfileno
anchorIndexByKey(const cache_key
*const key
) const;
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;
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);
183 /// restrict opened for writing entry to appending operations; allow reads
184 void startAppending(const sfileno fileno
);
185 /// successfully finish creating or updating the entry at fileno pos
186 void closeForWriting(const sfileno fileno
, bool lockForReading
= false);
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
);
191 /// only works on locked entries; returns nil unless the slice is readable
192 const Anchor
*peekAtReader(const sfileno fileno
) const;
194 /// only works on locked entries; returns the corresponding Anchor
195 const Anchor
&peekAtEntry(const sfileno fileno
) const;
197 /// free the entry if possible or mark it as waiting to be freed if not
198 void freeEntry(const sfileno fileno
);
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
);
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
);
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
);
216 /// readable anchor for the entry created by openForReading()
217 const Anchor
&readableEntry(const AnchorId anchorId
) const;
219 /// stop writing the entry, freeing its slot for others to use if possible
220 void abortWriting(const sfileno fileno
);
222 /// either finds and frees an entry with at least 1 slice or returns false
225 /// copies slice to its designated position
226 void importSlice(const SliceId sliceId
, const Slice
&slice
);
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
231 int entryCount() const; ///< number of writeable and readable entries
232 int entryLimit() const; ///< maximum entryCount() possible
233 int sliceLimit() const; ///< maximum number of slices possible
235 /// adds approximate current stats to the supplied ones
236 void updateStats(ReadWriteLockStats
&stats
) const;
238 StoreMapCleaner
*cleaner
; ///< notified before a readable entry is freed
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
246 Anchor
&anchorAt(const sfileno fileno
);
247 const Anchor
&anchorAt(const sfileno fileno
) const;
248 Anchor
&anchorByKey(const cache_key
*const key
);
250 Slice
&sliceAt(const SliceId sliceId
);
251 const Slice
&sliceAt(const SliceId sliceId
) const;
252 Anchor
*openForReading(Slice
&s
);
254 void freeChain(const sfileno fileno
, Anchor
&inode
, const bool keepLock
);
257 /// API for adjusting external state when dirty map slice is being freed
258 class StoreMapCleaner
261 virtual ~StoreMapCleaner() {}
263 /// adjust slice-linked state before a locked Readable slice is erased
264 virtual void noteFreeMapSlice(const StoreMapSliceId sliceId
) = 0;
269 // We do not reuse FileMap because we cannot control its size,
270 // resulting in sfilenos that are pointing beyond the database.
272 #endif /* SQUID_IPC_STORE_MAP_H */