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 
16 Ipc::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 
27 Ipc::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 
36 Ipc::MemMap::Init(const char *const path, const int limit)
37 {
38  return Init(path, limit, 0);
39 }
40 
42 Ipc::MemMap::openForWriting(const cache_key *const key, sfileno &fileno)
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 
57 Ipc::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 
90 void
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 
101 void
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 
113 void
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 
124 const 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 
137 void
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 
152 const 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 
173 const 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 
206 void
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 
217 int
219 {
220  return shared->limit;
221 }
222 
223 int
225 {
226  return shared->count;
227 }
228 
229 bool
231 {
232  return entryCount() >= entryLimit();
233 }
234 
235 void
237 {
238  for (int i = 0; i < shared->limit; ++i)
239  shared->slots[i].lock.updateStats(stats);
240 }
241 
242 bool
243 Ipc::MemMap::valid(const int pos) const
244 {
245  return 0 <= pos && pos < entryLimit();
246 }
247 
248 static
249 unsigned int
250 hash_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 
261 int
262 Ipc::MemMap::slotIndexByKey(const cache_key *const key) const
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 
275 void
276 Ipc::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)
284  s.lock.unlockExclusive();
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 
299 void
300 Ipc::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 
309 bool
310 Ipc::MemMapSlot::sameKey(const cache_key *const aKey) const
311 {
312  return (memcmp(key, aKey, sizeof(key)) == 0);
313 }
314 
315 bool
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 
327 Ipc::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 
336 size_t
338 {
339  return SharedMemorySize(limit, extrasSize);
340 }
341 
342 size_t
343 Ipc::MemMap::Shared::SharedMemorySize(const int limit, const size_t extrasSize)
344 {
345  return sizeof(Shared) + limit * (sizeof(Slot) + extrasSize);
346 }
347 
ReadWriteLock lock
protects slot data below
Definition: MemMap.h:46
approximate stats of a set of ReadWriteLocks
Definition: ReadWriteLock.h:70
size_t sharedMemorySize() const
Definition: MemMap.cc:337
int entryCount() const
number of used slots
Definition: MemMap.cc:224
a MemMap basic element, holding basic shareable memory block info
Definition: MemMap.h:33
bool reading() const
Definition: MemMap.h:42
unsigned char cache_key
Store key.
Definition: forward.h:29
bool lockShared()
lock for reading or return false
const SBuf path
cache_dir path, used for logging
Definition: MemMap.h:128
const Slot * openForReading(const cache_key *const key, sfileno &fileno)
open slot for reading, increments read level
Definition: MemMap.cc:153
static unsigned int hash_key(const unsigned char *data, unsigned int len, unsigned int hashSize)
Definition: MemMap.cc:250
Slot * openForWritingAt(sfileno fileno, bool overwriteExisting=true)
Definition: MemMap.cc:57
bool lockExclusive()
lock for modification or return false
bool empty() const
Definition: MemMap.cc:316
void closeForWriting(const sfileno fileno)
successfully finish writing the entry
Definition: MemMap.cc:91
Mem::Pointer< Shared > shared
Definition: MemMap.h:129
void updateStats(ReadWriteLockStats &stats) const
adds approximate current stats to the supplied ones
Definition: MemMap.cc:236
void unlockShared()
undo successful sharedLock()
#define shm_new(Class)
Definition: Pointer.h:200
bool writing() const
Definition: MemMap.h:43
void abortWriting(const sfileno fileno)
terminate writing the entry, freeing its slot for others to use
Definition: MemMap.cc:114
void unlockExclusive()
undo successful exclusiveLock()
#define MEMMAP_SLOT_KEY_SIZE
Definition: MemMap.h:29
const Slot * peekAtReader(const sfileno fileno) const
only works on locked entries; returns nil unless the slot is readable
Definition: MemMap.cc:125
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
int entryLimit() const
maximum number of slots that can be used
Definition: MemMap.cc:218
void switchWritingToReading(const sfileno fileno)
stop writing the locked entry and start reading it
Definition: MemMap.cc:102
int slotIndexByKey(const cache_key *const key) const
Definition: MemMap.cc:262
static Owner * Init(const char *const path, const int limit)
initialize shared memory
Definition: MemMap.cc:36
#define shm_old(Class)
Definition: Pointer.h:201
#define assert(EX)
Definition: assert.h:17
const Slot * openForReadingAt(const sfileno fileno)
open slot for reading, increments read level
Definition: MemMap.cc:174
signed_int32_t sfileno
Definition: forward.h:22
unsigned char key[MEMMAP_SLOT_KEY_SIZE]
The entry key.
Definition: MemMap.h:47
data shared across maps in different processes
Definition: MemMap.h:62
unsigned char p[MEMMAP_SLOT_DATA_SIZE]
The memory block;.
Definition: MemMap.h:48
void set(const unsigned char *aKey, const void *block, size_t blockSize, time_t expire=0)
Definition: MemMap.cc:300
Slot * openForWriting(const cache_key *const key, sfileno &fileno)
Definition: MemMap.cc:42
void freeLocked(Slot &s, bool keepLocked)
unconditionally frees the already exclusively locked slot and releases lock
Definition: MemMap.cc:276
Slot & slotByKey(const cache_key *const key)
Definition: MemMap.cc:269
const char * storeKeyText(const cache_key *key)
void free(const sfileno fileno)
mark the slot as waiting to be freed and, if possible, free it
Definition: MemMap.cc:138
void switchExclusiveToShared()
static size_t SharedMemorySize(const int limit, const size_t anExtrasSize)
Definition: MemMap.cc:343
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void Init(void)
prepares to parse ACLs configuration
Definition: AclRegs.cc:189
bool sameKey(const cache_key *const aKey) const
Definition: MemMap.cc:310
Shared(const int aLimit, const size_t anExtrasSize)
Definition: MemMap.cc:327
void closeForReading(const sfileno fileno)
close slot after reading, decrements read level
Definition: MemMap.cc:207
std::atomic< uint8_t > waitingToBeFreed
may be accessed w/o a lock
Definition: MemMap.h:45
bool full() const
there are no empty slots left
Definition: MemMap.cc:230

 

Introduction

Documentation

Support

Miscellaneous