]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/StoreMap.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / ipc / StoreMap.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section 54 Interprocess Communication
5 */
6
7 #include "squid-old.h"
8
9 #include "Store.h"
10 #include "ipc/StoreMap.h"
11
12 Ipc::StoreMap::Owner *
13 Ipc::StoreMap::Init(const char *const path, const int limit, const size_t extrasSize)
14 {
15 assert(limit > 0); // we should not be created otherwise
16 Owner *const owner = shm_new(Shared)(path, limit, extrasSize);
17 debugs(54, 5, HERE << "new map [" << path << "] created: " << limit);
18 return owner;
19 }
20
21 Ipc::StoreMap::Owner *
22 Ipc::StoreMap::Init(const char *const path, const int limit)
23 {
24 return Init(path, limit, 0);
25 }
26
27 Ipc::StoreMap::StoreMap(const char *const aPath): cleaner(NULL), path(aPath),
28 shared(shm_old(Shared)(aPath))
29 {
30 assert(shared->limit > 0); // we should not be created otherwise
31 debugs(54, 5, HERE << "attached map [" << path << "] created: " <<
32 shared->limit);
33 }
34
35 Ipc::StoreMap::Slot *
36 Ipc::StoreMap::openForWriting(const cache_key *const key, sfileno &fileno)
37 {
38 debugs(54, 5, HERE << " trying to open slot for key " << storeKeyText(key)
39 << " for writing in map [" << path << ']');
40 const int idx = slotIndexByKey(key);
41
42 Slot &s = shared->slots[idx];
43 ReadWriteLock &lock = s.lock;
44
45 if (lock.lockExclusive()) {
46 assert(s.state != Slot::Writeable); // until we start breaking locks
47
48 // free if the entry was used, keeping the entry locked
49 if (s.waitingToBeFreed || s.state == Slot::Readable)
50 freeLocked(s, true);
51
52 assert(s.state == Slot::Empty);
53 ++shared->count;
54 s.state = Slot::Writeable;
55 fileno = idx;
56 //s.setKey(key); // XXX: the caller should do that
57 debugs(54, 5, HERE << " opened slot at " << idx <<
58 " for writing in map [" << path << ']');
59 return &s; // and keep the entry locked
60 }
61
62 debugs(54, 5, HERE << " failed to open slot at " << idx <<
63 " for writing in map [" << path << ']');
64 return NULL;
65 }
66
67 void
68 Ipc::StoreMap::closeForWriting(const sfileno fileno, bool lockForReading)
69 {
70 debugs(54, 5, HERE << " closing slot at " << fileno << " for writing and "
71 "openning for reading in map [" << path << ']');
72 assert(valid(fileno));
73 Slot &s = shared->slots[fileno];
74 assert(s.state == Slot::Writeable);
75 s.state = Slot::Readable;
76 if (lockForReading)
77 s.lock.switchExclusiveToShared();
78 else
79 s.lock.unlockExclusive();
80 }
81
82 /// terminate writing the entry, freeing its slot for others to use
83 void
84 Ipc::StoreMap::abortWriting(const sfileno fileno)
85 {
86 debugs(54, 5, HERE << " abort writing slot at " << fileno <<
87 " in map [" << path << ']');
88 assert(valid(fileno));
89 Slot &s = shared->slots[fileno];
90 assert(s.state == Slot::Writeable);
91 freeLocked(s, false);
92 }
93
94 void
95 Ipc::StoreMap::abortIo(const sfileno fileno)
96 {
97 debugs(54, 5, HERE << " abort I/O for slot at " << fileno <<
98 " in map [" << path << ']');
99 assert(valid(fileno));
100 Slot &s = shared->slots[fileno];
101
102 // The caller is a lock holder. Thus, if we are Writeable, then the
103 // caller must be the writer; otherwise the caller must be the reader.
104 if (s.state == Slot::Writeable)
105 abortWriting(fileno);
106 else
107 closeForReading(fileno);
108 }
109
110 const Ipc::StoreMap::Slot *
111 Ipc::StoreMap::peekAtReader(const sfileno fileno) const
112 {
113 assert(valid(fileno));
114 const Slot &s = shared->slots[fileno];
115 switch (s.state) {
116 case Slot::Readable:
117 return &s; // immediate access by lock holder so no locking
118 case Slot::Writeable:
119 return NULL; // cannot read the slot when it is being written
120 case Slot::Empty:
121 assert(false); // must be locked for reading or writing
122 }
123 assert(false); // not reachable
124 return NULL;
125 }
126
127 void
128 Ipc::StoreMap::free(const sfileno fileno)
129 {
130 debugs(54, 5, HERE << " marking slot at " << fileno << " to be freed in"
131 " map [" << path << ']');
132
133 assert(valid(fileno));
134 Slot &s = shared->slots[fileno];
135
136 if (s.lock.lockExclusive())
137 freeLocked(s, false);
138 else
139 s.waitingToBeFreed = true; // mark to free it later
140 }
141
142 const Ipc::StoreMap::Slot *
143 Ipc::StoreMap::openForReading(const cache_key *const key, sfileno &fileno)
144 {
145 debugs(54, 5, HERE << " trying to open slot for key " << storeKeyText(key)
146 << " for reading in map [" << path << ']');
147 const int idx = slotIndexByKey(key);
148 if (const Slot *slot = openForReadingAt(idx)) {
149 if (slot->sameKey(key)) {
150 fileno = idx;
151 debugs(54, 5, HERE << " opened slot at " << fileno << " for key "
152 << storeKeyText(key) << " for reading in map [" << path <<
153 ']');
154 return slot; // locked for reading
155 }
156 slot->lock.unlockShared();
157 }
158 debugs(54, 5, HERE << " failed to open slot for key " << storeKeyText(key)
159 << " for reading in map [" << path << ']');
160 return NULL;
161 }
162
163 const Ipc::StoreMap::Slot *
164 Ipc::StoreMap::openForReadingAt(const sfileno fileno)
165 {
166 debugs(54, 5, HERE << " trying to open slot at " << fileno << " for "
167 "reading in map [" << path << ']');
168 assert(valid(fileno));
169 Slot &s = shared->slots[fileno];
170
171 if (!s.lock.lockShared()) {
172 debugs(54, 5, HERE << " failed to lock slot at " << fileno << " for "
173 "reading in map [" << path << ']');
174 return NULL;
175 }
176
177 if (s.state == Slot::Empty) {
178 s.lock.unlockShared();
179 debugs(54, 7, HERE << " empty slot at " << fileno << " for "
180 "reading in map [" << path << ']');
181 return NULL;
182 }
183
184 if (s.waitingToBeFreed) {
185 s.lock.unlockShared();
186 debugs(54, 7, HERE << " dirty slot at " << fileno << " for "
187 "reading in map [" << path << ']');
188 return NULL;
189 }
190
191 // cannot be Writing here if we got shared lock and checked Empty above
192 assert(s.state == Slot::Readable);
193 debugs(54, 5, HERE << " opened slot at " << fileno << " for reading in"
194 " map [" << path << ']');
195 return &s;
196 }
197
198 void
199 Ipc::StoreMap::closeForReading(const sfileno fileno)
200 {
201 debugs(54, 5, HERE << " closing slot at " << fileno << " for reading in "
202 "map [" << path << ']');
203 assert(valid(fileno));
204 Slot &s = shared->slots[fileno];
205 assert(s.state == Slot::Readable);
206 s.lock.unlockShared();
207 }
208
209 int
210 Ipc::StoreMap::entryLimit() const
211 {
212 return shared->limit;
213 }
214
215 int
216 Ipc::StoreMap::entryCount() const
217 {
218 return shared->count;
219 }
220
221 bool
222 Ipc::StoreMap::full() const
223 {
224 return entryCount() >= entryLimit();
225 }
226
227 void
228 Ipc::StoreMap::updateStats(ReadWriteLockStats &stats) const
229 {
230 for (int i = 0; i < shared->limit; ++i)
231 shared->slots[i].lock.updateStats(stats);
232 }
233
234 bool
235 Ipc::StoreMap::valid(const int pos) const
236 {
237 return 0 <= pos && pos < entryLimit();
238 }
239
240 int
241 Ipc::StoreMap::slotIndexByKey(const cache_key *const key) const
242 {
243 const uint64_t *const k = reinterpret_cast<const uint64_t *>(key);
244 // TODO: use a better hash function
245 return (k[0] + k[1]) % shared->limit;
246 }
247
248 Ipc::StoreMap::Slot &
249 Ipc::StoreMap::slotByKey(const cache_key *const key)
250 {
251 return shared->slots[slotIndexByKey(key)];
252 }
253
254 /// unconditionally frees the already exclusively locked slot and releases lock
255 void
256 Ipc::StoreMap::freeLocked(Slot &s, bool keepLocked)
257 {
258 if (s.state == Slot::Readable && cleaner)
259 cleaner->cleanReadable(&s - shared->slots);
260
261 s.waitingToBeFreed = false;
262 s.state = Slot::Empty;
263 if (!keepLocked)
264 s.lock.unlockExclusive();
265 --shared->count;
266 debugs(54, 5, HERE << " freed slot at " << (&s - shared->slots) <<
267 " in map [" << path << ']');
268 }
269
270
271 /* Ipc::StoreMapSlot */
272
273 Ipc::StoreMapSlot::StoreMapSlot(): state(Empty)
274 {
275 xmemset(&key, 0, sizeof(key));
276 xmemset(&basics, 0, sizeof(basics));
277 }
278
279 void
280 Ipc::StoreMapSlot::setKey(const cache_key *const aKey)
281 {
282 memcpy(key, aKey, sizeof(key));
283 }
284
285 bool
286 Ipc::StoreMapSlot::sameKey(const cache_key *const aKey) const
287 {
288 const uint64_t *const k = reinterpret_cast<const uint64_t *>(aKey);
289 return k[0] == key[0] && k[1] == key[1];
290 }
291
292 void
293 Ipc::StoreMapSlot::set(const StoreEntry &from)
294 {
295 memcpy(key, from.key, sizeof(key));
296 // XXX: header = aHeader;
297 basics.timestamp = from.timestamp;
298 basics.lastref = from.lastref;
299 basics.expires = from.expires;
300 basics.lastmod = from.lastmod;
301 basics.swap_file_sz = from.swap_file_sz;
302 basics.refcount = from.refcount;
303 basics.flags = from.flags;
304 }
305
306 /* Ipc::StoreMap::Shared */
307
308 Ipc::StoreMap::Shared::Shared(const int aLimit, const size_t anExtrasSize):
309 limit(aLimit), extrasSize(anExtrasSize), count(0)
310 {
311 }
312
313 size_t
314 Ipc::StoreMap::Shared::sharedMemorySize() const
315 {
316 return SharedMemorySize(limit, extrasSize);
317 }
318
319 size_t
320 Ipc::StoreMap::Shared::SharedMemorySize(const int limit, const size_t extrasSize)
321 {
322 return sizeof(Shared) + limit * (sizeof(Slot) + extrasSize);
323 }
324