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