]>
Commit | Line | Data |
---|---|---|
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 |
9 | namespace 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. | |
16 | class StoreMapAnchor | |
9199139f | 17 | { |
44c95fcf | 18 | public: |
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 |
30 | public: |
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 |
59 | class StoreMapSlot { | |
60 | public: | |
61 | StoreMapAnchor anchor; | |
62 | StoreMapSlice slice; | |
63 | }; | |
64 | ||
7f6748c8 AR |
65 | class 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 |
69 | class StoreMap | |
70 | { | |
71 | public: | |
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 | ||
92 | public: | |
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 | 160 | protected: |
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 | |
166 | private: | |
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 | |
178 | template <class ExtrasT> | |
179 | class StoreMapWithExtras: public StoreMap | |
180 | { | |
181 | public: | |
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 | ||
194 | protected: | |
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 |
200 | class StoreMapCleaner |
201 | { | |
202 | public: | |
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 | ||
211 | template <class ExtrasT> | |
212 | StoreMap::Owner * | |
213 | StoreMapWithExtras<ExtrasT>::Init(const char *const path, const int limit) | |
214 | { | |
215 | return StoreMap::Init(path, limit, sizeof(Extras)); | |
216 | } | |
217 | ||
218 | template <class ExtrasT> | |
219 | StoreMapWithExtras<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 | ||
227 | template <class ExtrasT> | |
228 | ExtrasT & | |
229 | StoreMapWithExtras<ExtrasT>::extras(const sfileno fileno) | |
230 | { | |
231 | return const_cast<ExtrasT &>(const_cast<const StoreMapWithExtras *>(this)->extras(fileno)); | |
232 | } | |
233 | ||
234 | template <class ExtrasT> | |
235 | const ExtrasT & | |
236 | StoreMapWithExtras<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 */ |