MemMap.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 54 Interprocess Communication */
10
11#include "squid.h"
12#include "ipc/MemMap.h"
13#include "store_key_md5.h"
14#include "tools.h"
15
16Ipc::MemMap::MemMap(const char *const aPath) :
17 cleaner(nullptr),
18 path(aPath),
19 shared(shm_old(Shared)(aPath))
20{
21 assert(shared->limit > 0); // we should not be created otherwise
22 debugs(54, 5, "attached map [" << path << "] created: " <<
23 shared->limit);
24}
25
27Ipc::MemMap::Init(const char *const path, const int limit, const size_t extrasSize)
28{
29 assert(limit > 0); // we should not be created otherwise
30 Owner *const owner = shm_new(Shared)(path, limit, extrasSize);
31 debugs(54, 5, "new map [" << path << "] created: " << limit);
32 return owner;
33}
34
36Ipc::MemMap::Init(const char *const path, const int limit)
37{
38 return Init(path, limit, 0);
39}
40
43{
44 debugs(54, 5, "trying to open slot for key " << storeKeyText(key)
45 << " for writing in map [" << path << ']');
46 const int idx = slotIndexByKey(key);
47
48 if (Slot *slot = openForWritingAt(idx)) {
49 fileno = idx;
50 return slot;
51 }
52
53 return nullptr;
54}
55
57Ipc::MemMap::openForWritingAt(const sfileno fileno, bool overwriteExisting)
58{
59 Slot &s = shared->slots[fileno];
60 ReadWriteLock &lock = s.lock;
61
62 if (lock.lockExclusive()) {
63 assert(s.writing() && !s.reading());
64
65 // bail if we cannot empty this position
66 if (!s.waitingToBeFreed && !s.empty() && !overwriteExisting) {
67 lock.unlockExclusive();
68 debugs(54, 5, "cannot open existing entry " << fileno <<
69 " for writing " << path);
70 return nullptr;
71 }
72
73 // free if the entry was used, keeping the entry locked
74 if (s.waitingToBeFreed || !s.empty())
75 freeLocked(s, true);
76
77 assert(s.empty());
78 ++shared->count;
79
80 debugs(54, 5, "opened slot at " << fileno <<
81 " for writing in map [" << path << ']');
82 return &s; // and keep the entry locked
83 }
84
85 debugs(54, 5, "failed to open slot at " << fileno <<
86 " for writing in map [" << path << ']');
87 return nullptr;
88}
89
90void
92{
93 debugs(54, 5, "stop writing slot at " << fileno <<
94 " in map [" << path << ']');
95 assert(valid(fileno));
96 Slot &s = shared->slots[fileno];
97 assert(s.writing());
99}
100
101void
103{
104 debugs(54, 5, "switching writing slot at " << fileno <<
105 " to reading in map [" << path << ']');
106 assert(valid(fileno));
107 Slot &s = shared->slots[fileno];
108 assert(s.writing());
110}
111
113void
115{
116 debugs(54, 5, "abort writing slot at " << fileno <<
117 " in map [" << path << ']');
118 assert(valid(fileno));
119 Slot &s = shared->slots[fileno];
120 assert(s.writing());
121 freeLocked(s, false);
122}
123
124const Ipc::MemMap::Slot *
126{
127 assert(valid(fileno));
128 const Slot &s = shared->slots[fileno];
129 if (s.reading())
130 return &s; // immediate access by lock holder so no locking
131 if (s.writing())
132 return nullptr; // cannot read the slot when it is being written
133 assert(false); // must be locked for reading or writing
134 return nullptr;
135}
136
137void
139{
140 debugs(54, 5, "marking slot at " << fileno << " to be freed in"
141 " map [" << path << ']');
142
143 assert(valid(fileno));
144 Slot &s = shared->slots[fileno];
145
146 if (s.lock.lockExclusive())
147 freeLocked(s, false);
148 else
149 s.waitingToBeFreed = true; // mark to free it later
150}
151
152const Ipc::MemMap::Slot *
154{
155 debugs(54, 5, "trying to open slot for key " << storeKeyText(key)
156 << " for reading in map [" << path << ']');
157 const int idx = slotIndexByKey(key);
158 if (const Slot *slot = openForReadingAt(idx)) {
159 if (slot->sameKey(key)) {
160 fileno = idx;
161 debugs(54, 5, "opened slot at " << fileno << " for key "
162 << storeKeyText(key) << " for reading in map [" << path <<
163 ']');
164 return slot; // locked for reading
165 }
166 slot->lock.unlockShared();
167 }
168 debugs(54, 5, "failed to open slot for key " << storeKeyText(key)
169 << " for reading in map [" << path << ']');
170 return nullptr;
171}
172
173const Ipc::MemMap::Slot *
175{
176 debugs(54, 5, "trying to open slot at " << fileno << " for "
177 "reading in map [" << path << ']');
178 assert(valid(fileno));
179 Slot &s = shared->slots[fileno];
180
181 if (!s.lock.lockShared()) {
182 debugs(54, 5, "failed to lock slot at " << fileno << " for "
183 "reading in map [" << path << ']');
184 return nullptr;
185 }
186
187 if (s.empty()) {
188 s.lock.unlockShared();
189 debugs(54, 7, "empty slot at " << fileno << " for "
190 "reading in map [" << path << ']');
191 return nullptr;
192 }
193
194 if (s.waitingToBeFreed) {
195 s.lock.unlockShared();
196 debugs(54, 7, "dirty slot at " << fileno << " for "
197 "reading in map [" << path << ']');
198 return nullptr;
199 }
200
201 debugs(54, 5, "opened slot at " << fileno << " for reading in"
202 " map [" << path << ']');
203 return &s;
204}
205
206void
208{
209 debugs(54, 5, "closing slot at " << fileno << " for reading in "
210 "map [" << path << ']');
211 assert(valid(fileno));
212 Slot &s = shared->slots[fileno];
213 assert(s.reading());
214 s.lock.unlockShared();
215}
216
217int
219{
220 return shared->limit;
221}
222
223int
225{
226 return shared->count;
227}
228
229bool
231{
232 return entryCount() >= entryLimit();
233}
234
235void
237{
238 for (int i = 0; i < shared->limit; ++i)
239 shared->slots[i].lock.updateStats(stats);
240}
241
242bool
243Ipc::MemMap::valid(const int pos) const
244{
245 return 0 <= pos && pos < entryLimit();
246}
247
248static
249unsigned int
250hash_key(const unsigned char *data, unsigned int len, unsigned int hashSize)
251{
252 unsigned int n;
253 unsigned int j;
254 for (j = 0, n = 0; j < len; j++ ) {
255 n ^= 271 * *data;
256 ++data;
257 }
258 return (n ^ (j * 271)) % hashSize;
259}
260
261int
263{
264 const unsigned char *k = reinterpret_cast<const unsigned char *>(key);
265 return hash_key(k, MEMMAP_SLOT_KEY_SIZE, shared->limit);
266}
267
270{
271 return shared->slots[slotIndexByKey(key)];
272}
273
275void
276Ipc::MemMap::freeLocked(Slot &s, bool keepLocked)
277{
278 if (!s.empty() && cleaner)
279 cleaner->noteFreeMapSlot(&s - shared->slots.raw());
280
281 s.waitingToBeFreed = false;
282 memset(s.key, 0, sizeof(s.key));
283 if (!keepLocked)
285 --shared->count;
286 debugs(54, 5, "freed slot at " << (&s - shared->slots.raw()) <<
287 " in map [" << path << ']');
288}
289
290/* Ipc::MemMapSlot */
292 pSize(0),
293 expire(0)
294{
295 memset(key, 0, sizeof(key));
296 memset(p, 0, sizeof(p));
297}
298
299void
300Ipc::MemMapSlot::set(const unsigned char *aKey, const void *block, size_t blockSize, time_t expireAt)
301{
302 memcpy(key, aKey, sizeof(key));
303 if (block)
304 memcpy(p, block, blockSize);
305 pSize = blockSize;
306 expire = expireAt;
307}
308
309bool
310Ipc::MemMapSlot::sameKey(const cache_key *const aKey) const
311{
312 return (memcmp(key, aKey, sizeof(key)) == 0);
313}
314
315bool
317{
318 for (unsigned char const*u = key; u < key + sizeof(key); ++u) {
319 if (*u)
320 return false;
321 }
322 return true;
323}
324
325/* Ipc::MemMap::Shared */
326
327Ipc::MemMap::Shared::Shared(const int aLimit, const size_t anExtrasSize):
328 limit(aLimit), extrasSize(anExtrasSize), count(0), slots(aLimit)
329{
330}
331
333{
334}
335
336size_t
338{
339 return SharedMemorySize(limit, extrasSize);
340}
341
342size_t
343Ipc::MemMap::Shared::SharedMemorySize(const int limit, const size_t extrasSize)
344{
345 return sizeof(Shared) + limit * (sizeof(Slot) + extrasSize);
346}
347
static unsigned int hash_key(const unsigned char *data, unsigned int len, unsigned int hashSize)
Definition: MemMap.cc:250
#define MEMMAP_SLOT_KEY_SIZE
Definition: MemMap.h:29
#define shm_new(Class)
Definition: Pointer.h:200
#define shm_old(Class)
Definition: Pointer.h:201
#define assert(EX)
Definition: assert.h:17
a MemMap basic element, holding basic shareable memory block info
Definition: MemMap.h:34
bool sameKey(const cache_key *const aKey) const
Definition: MemMap.cc:310
void set(const unsigned char *aKey, const void *block, size_t blockSize, time_t expire=0)
Definition: MemMap.cc:300
std::atomic< uint8_t > waitingToBeFreed
may be accessed w/o a lock
Definition: MemMap.h:45
bool reading() const
Definition: MemMap.h:42
bool writing() const
Definition: MemMap.h:43
bool empty() const
Definition: MemMap.cc:316
ReadWriteLock lock
protects slot data below
Definition: MemMap.h:46
unsigned char key[MEMMAP_SLOT_KEY_SIZE]
The entry key.
Definition: MemMap.h:47
unsigned char p[MEMMAP_SLOT_DATA_SIZE]
The memory block;.
Definition: MemMap.h:48
data shared across maps in different processes
Definition: MemMap.h:63
static size_t SharedMemorySize(const int limit, const size_t anExtrasSize)
Definition: MemMap.cc:343
size_t sharedMemorySize() const
Definition: MemMap.cc:337
Shared(const int aLimit, const size_t anExtrasSize)
Definition: MemMap.cc:327
void free(const sfileno fileno)
mark the slot as waiting to be freed and, if possible, free it
Definition: MemMap.cc:138
const SBuf path
cache_dir path, used for logging
Definition: MemMap.h:128
void updateStats(ReadWriteLockStats &stats) const
adds approximate current stats to the supplied ones
Definition: MemMap.cc:236
MemMap(const char *const aPath)
Definition: MemMap.cc:16
bool valid(const int n) const
whether n is a valid slot coordinate
Definition: MemMap.cc:243
Mem::Pointer< Shared > shared
Definition: MemMap.h:129
void abortWriting(const sfileno fileno)
terminate writing the entry, freeing its slot for others to use
Definition: MemMap.cc:114
bool full() const
there are no empty slots left
Definition: MemMap.cc:230
int slotIndexByKey(const cache_key *const key) const
Definition: MemMap.cc:262
int entryLimit() const
maximum number of slots that can be used
Definition: MemMap.cc:218
void freeLocked(Slot &s, bool keepLocked)
unconditionally frees the already exclusively locked slot and releases lock
Definition: MemMap.cc:276
void closeForReading(const sfileno fileno)
close slot after reading, decrements read level
Definition: MemMap.cc:207
const Slot * openForReading(const cache_key *const key, sfileno &fileno)
open slot for reading, increments read level
Definition: MemMap.cc:153
void switchWritingToReading(const sfileno fileno)
stop writing the locked entry and start reading it
Definition: MemMap.cc:102
const Slot * openForReadingAt(const sfileno fileno)
open slot for reading, increments read level
Definition: MemMap.cc:174
Slot * openForWriting(const cache_key *const key, sfileno &fileno)
Definition: MemMap.cc:42
Slot & slotByKey(const cache_key *const key)
Definition: MemMap.cc:269
static Owner * Init(const char *const path, const int limit)
initialize shared memory
Definition: MemMap.cc:36
int entryCount() const
number of used slots
Definition: MemMap.cc:224
void closeForWriting(const sfileno fileno)
successfully finish writing the entry
Definition: MemMap.cc:91
const Slot * peekAtReader(const sfileno fileno) const
only works on locked entries; returns nil unless the slot is readable
Definition: MemMap.cc:125
Slot * openForWritingAt(sfileno fileno, bool overwriteExisting=true)
Definition: MemMap.cc:57
approximate stats of a set of ReadWriteLocks
Definition: ReadWriteLock.h:71
void switchExclusiveToShared()
void unlockExclusive()
undo successful exclusiveLock()
bool lockExclusive()
lock for modification or return false
void unlockShared()
undo successful sharedLock()
bool lockShared()
lock for reading or return false
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
void Init(void)
prepares to parse ACLs configuration
Definition: AclRegs.cc:191
class Ping::pingStats_ stats
unsigned char cache_key
Store key.
Definition: forward.h:29
signed_int32_t sfileno
Definition: forward.h:22
const char * storeKeyText(const cache_key *key)

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors