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