2
* DEBUG: section 54 Interprocess Communication
6
#include "ipc/MemMap.h"
7
#include "store_key_md5.h"
10
Ipc::MemMap::MemMap(const char *const aPath) :
13
shared(shm_old(Shared)(aPath))
15
assert(shared->limit > 0); // we should not be created otherwise
16
debugs(54, 5, "attached map [" << path << "] created: " <<
21
Ipc::MemMap::Init(const char *const path, const int limit, const size_t extrasSize)
23
assert(limit > 0); // we should not be created otherwise
24
Owner *const owner = shm_new(Shared)(path, limit, extrasSize);
25
debugs(54, 5, "new map [" << path << "] created: " << limit);
30
Ipc::MemMap::Init(const char *const path, const int limit)
32
return Init(path, limit, 0);
36
Ipc::MemMap::openForWriting(const cache_key *const key, sfileno &fileno)
38
debugs(54, 5, "trying to open slot for key " << storeKeyText(key)
39
<< " for writing in map [" << path << ']');
40
const int idx = slotIndexByKey(key);
42
if (Slot *slot = openForWritingAt(idx)) {
51
Ipc::MemMap::openForWritingAt(const sfileno fileno, bool overwriteExisting)
53
Slot &s = shared->slots[fileno];
54
ReadWriteLock &lock = s.lock;
56
if (lock.lockExclusive()) {
57
assert(s.writing() && !s.reading());
59
// bail if we cannot empty this position
60
if (!s.waitingToBeFreed && !s.empty() && !overwriteExisting) {
61
lock.unlockExclusive();
62
debugs(54, 5, "cannot open existing entry " << fileno <<
63
" for writing " << path);
67
// free if the entry was used, keeping the entry locked
68
if (s.waitingToBeFreed || !s.empty())
74
debugs(54, 5, "opened slot at " << fileno <<
75
" for writing in map [" << path << ']');
76
return &s; // and keep the entry locked
79
debugs(54, 5, "failed to open slot at " << fileno <<
80
" for writing in map [" << path << ']');
85
Ipc::MemMap::closeForWriting(const sfileno fileno, bool lockForReading)
87
debugs(54, 5, "closing slot at " << fileno << " for writing and "
88
"openning for reading in map [" << path << ']');
89
assert(valid(fileno));
90
Slot &s = shared->slots[fileno];
93
s.lock.switchExclusiveToShared();
95
s.lock.unlockExclusive();
98
/// terminate writing the entry, freeing its slot for others to use
100
Ipc::MemMap::abortWriting(const sfileno fileno)
102
debugs(54, 5, "abort writing slot at " << fileno <<
103
" in map [" << path << ']');
104
assert(valid(fileno));
105
Slot &s = shared->slots[fileno];
107
freeLocked(s, false);
110
const Ipc::MemMap::Slot *
111
Ipc::MemMap::peekAtReader(const sfileno fileno) const
113
assert(valid(fileno));
114
const Slot &s = shared->slots[fileno];
116
return &s; // immediate access by lock holder so no locking
118
return NULL; // cannot read the slot when it is being written
119
assert(false); // must be locked for reading or writing
124
Ipc::MemMap::free(const sfileno fileno)
126
debugs(54, 5, "marking slot at " << fileno << " to be freed in"
127
" map [" << path << ']');
129
assert(valid(fileno));
130
Slot &s = shared->slots[fileno];
132
if (s.lock.lockExclusive())
133
freeLocked(s, false);
135
s.waitingToBeFreed = true; // mark to free it later
138
const Ipc::MemMap::Slot *
139
Ipc::MemMap::openForReading(const cache_key *const key, sfileno &fileno)
141
debugs(54, 5, "trying to open slot for key " << storeKeyText(key)
142
<< " for reading in map [" << path << ']');
143
const int idx = slotIndexByKey(key);
144
if (const Slot *slot = openForReadingAt(idx)) {
145
if (slot->sameKey(key)) {
147
debugs(54, 5, "opened slot at " << fileno << " for key "
148
<< storeKeyText(key) << " for reading in map [" << path <<
150
return slot; // locked for reading
152
slot->lock.unlockShared();
154
debugs(54, 5, "failed to open slot for key " << storeKeyText(key)
155
<< " for reading in map [" << path << ']');
159
const Ipc::MemMap::Slot *
160
Ipc::MemMap::openForReadingAt(const sfileno fileno)
162
debugs(54, 5, "trying to open slot at " << fileno << " for "
163
"reading in map [" << path << ']');
164
assert(valid(fileno));
165
Slot &s = shared->slots[fileno];
167
if (!s.lock.lockShared()) {
168
debugs(54, 5, "failed to lock slot at " << fileno << " for "
169
"reading in map [" << path << ']');
174
s.lock.unlockShared();
175
debugs(54, 7, "empty slot at " << fileno << " for "
176
"reading in map [" << path << ']');
180
if (s.waitingToBeFreed) {
181
s.lock.unlockShared();
182
debugs(54, 7, "dirty slot at " << fileno << " for "
183
"reading in map [" << path << ']');
187
debugs(54, 5, "opened slot at " << fileno << " for reading in"
188
" map [" << path << ']');
193
Ipc::MemMap::closeForReading(const sfileno fileno)
195
debugs(54, 5, "closing slot at " << fileno << " for reading in "
196
"map [" << path << ']');
197
assert(valid(fileno));
198
Slot &s = shared->slots[fileno];
200
s.lock.unlockShared();
204
Ipc::MemMap::entryLimit() const
206
return shared->limit;
210
Ipc::MemMap::entryCount() const
212
return shared->count;
216
Ipc::MemMap::full() const
218
return entryCount() >= entryLimit();
222
Ipc::MemMap::updateStats(ReadWriteLockStats &stats) const
224
for (int i = 0; i < shared->limit; ++i)
225
shared->slots[i].lock.updateStats(stats);
229
Ipc::MemMap::valid(const int pos) const
231
return 0 <= pos && pos < entryLimit();
236
hash_key(const unsigned char *data, unsigned int len, unsigned int hashSize)
240
for(j = 0, n = 0; j < len; j++ ) {
244
return (n ^ (j * 271)) % hashSize;
248
Ipc::MemMap::slotIndexByKey(const cache_key *const key) const
250
const unsigned char *k = reinterpret_cast<const unsigned char *>(key);
251
return hash_key(k, MEMMAP_SLOT_KEY_SIZE, shared->limit);
255
Ipc::MemMap::slotByKey(const cache_key *const key)
257
return shared->slots[slotIndexByKey(key)];
260
/// unconditionally frees the already exclusively locked slot and releases lock
262
Ipc::MemMap::freeLocked(Slot &s, bool keepLocked)
264
if (!s.empty() && cleaner)
265
cleaner->noteFreeMapSlot(&s - shared->slots.raw());
267
s.waitingToBeFreed = false;
268
memset(s.key, 0, sizeof(s.key));
270
s.lock.unlockExclusive();
272
debugs(54, 5, "freed slot at " << (&s - shared->slots.raw()) <<
273
" in map [" << path << ']');
276
/* Ipc::MemMapSlot */
277
Ipc::MemMapSlot::MemMapSlot() :
281
memset(key, 0, sizeof(key));
282
memset(p, 0, sizeof(p));
286
Ipc::MemMapSlot::set(const unsigned char *aKey, const void *block, size_t blockSize, time_t expireAt)
288
memcpy(key, aKey, sizeof(key));
290
memcpy(p, block, blockSize);
296
Ipc::MemMapSlot::sameKey(const cache_key *const aKey) const
298
return (memcmp(key, aKey, sizeof(key)) == 0);
302
Ipc::MemMapSlot::empty() const
304
for (unsigned char const*u = key; u < key + sizeof(key); ++u) {
311
/* Ipc::MemMap::Shared */
313
Ipc::MemMap::Shared::Shared(const int aLimit, const size_t anExtrasSize):
314
limit(aLimit), extrasSize(anExtrasSize), count(0), slots(aLimit)
318
Ipc::MemMap::Shared::~Shared()
323
Ipc::MemMap::Shared::sharedMemorySize() const
325
return SharedMemorySize(limit, extrasSize);
329
Ipc::MemMap::Shared::SharedMemorySize(const int limit, const size_t extrasSize)
331
return sizeof(Shared) + limit * (sizeof(Slot) + extrasSize);