~yadi/squid/connection-manager

« back to all changes in this revision

Viewing changes to src/ipc/MemMap.cc

  • Committer: Amos Jeffries
  • Date: 2014-01-19 05:45:51 UTC
  • mfrom: (13045.1.209 trunk)
  • Revision ID: squid3@treenet.co.nz-20140119054551-3u1so2dy5vda7kfw
MergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DEBUG: section 54    Interprocess Communication
 
3
 */
 
4
 
 
5
#include "squid.h"
 
6
#include "ipc/MemMap.h"
 
7
#include "store_key_md5.h"
 
8
#include "tools.h"
 
9
 
 
10
Ipc::MemMap::MemMap(const char *const aPath) :
 
11
        cleaner(NULL),
 
12
        path(aPath),
 
13
        shared(shm_old(Shared)(aPath))
 
14
{
 
15
    assert(shared->limit > 0); // we should not be created otherwise
 
16
    debugs(54, 5, "attached map [" << path << "] created: " <<
 
17
           shared->limit);
 
18
}
 
19
 
 
20
Ipc::MemMap::Owner *
 
21
Ipc::MemMap::Init(const char *const path, const int limit, const size_t extrasSize)
 
22
{
 
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);
 
26
    return owner;
 
27
}
 
28
 
 
29
Ipc::MemMap::Owner *
 
30
Ipc::MemMap::Init(const char *const path, const int limit)
 
31
{
 
32
    return Init(path, limit, 0);
 
33
}
 
34
 
 
35
Ipc::MemMap::Slot *
 
36
Ipc::MemMap::openForWriting(const cache_key *const key, sfileno &fileno)
 
37
{
 
38
    debugs(54, 5, "trying to open slot for key " << storeKeyText(key)
 
39
           << " for writing in map [" << path << ']');
 
40
    const int idx = slotIndexByKey(key);
 
41
 
 
42
    if (Slot *slot = openForWritingAt(idx)) {
 
43
        fileno = idx;
 
44
        return slot;
 
45
    }
 
46
 
 
47
    return NULL;
 
48
}
 
49
 
 
50
Ipc::MemMap::Slot *
 
51
Ipc::MemMap::openForWritingAt(const sfileno fileno, bool overwriteExisting)
 
52
{
 
53
    Slot &s = shared->slots[fileno];
 
54
    ReadWriteLock &lock = s.lock;
 
55
 
 
56
    if (lock.lockExclusive()) {
 
57
        assert(s.writing() && !s.reading());
 
58
 
 
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);
 
64
            return NULL;
 
65
        }
 
66
 
 
67
        // free if the entry was used, keeping the entry locked
 
68
        if (s.waitingToBeFreed || !s.empty())
 
69
            freeLocked(s, true);
 
70
 
 
71
        assert(s.empty());
 
72
        ++shared->count;
 
73
 
 
74
        debugs(54, 5, "opened slot at " << fileno <<
 
75
               " for writing in map [" << path << ']');
 
76
        return &s; // and keep the entry locked
 
77
    }
 
78
 
 
79
    debugs(54, 5, "failed to open slot at " << fileno <<
 
80
           " for writing in map [" << path << ']');
 
81
    return NULL;
 
82
}
 
83
 
 
84
void
 
85
Ipc::MemMap::closeForWriting(const sfileno fileno, bool lockForReading)
 
86
{
 
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];
 
91
    assert(s.writing());
 
92
    if (lockForReading)
 
93
        s.lock.switchExclusiveToShared();
 
94
    else
 
95
        s.lock.unlockExclusive();
 
96
}
 
97
 
 
98
/// terminate writing the entry, freeing its slot for others to use
 
99
void
 
100
Ipc::MemMap::abortWriting(const sfileno fileno)
 
101
{
 
102
    debugs(54, 5, "abort writing slot at " << fileno <<
 
103
           " in map [" << path << ']');
 
104
    assert(valid(fileno));
 
105
    Slot &s = shared->slots[fileno];
 
106
    assert(s.writing());
 
107
    freeLocked(s, false);
 
108
}
 
109
 
 
110
const Ipc::MemMap::Slot *
 
111
Ipc::MemMap::peekAtReader(const sfileno fileno) const
 
112
{
 
113
    assert(valid(fileno));
 
114
    const Slot &s = shared->slots[fileno];
 
115
    if (s.reading())
 
116
        return &s; // immediate access by lock holder so no locking
 
117
    if (s.writing())
 
118
        return NULL; // cannot read the slot when it is being written
 
119
    assert(false); // must be locked for reading or writing
 
120
    return NULL;
 
121
}
 
122
 
 
123
void
 
124
Ipc::MemMap::free(const sfileno fileno)
 
125
{
 
126
    debugs(54, 5, "marking slot at " << fileno << " to be freed in"
 
127
           " map [" << path << ']');
 
128
 
 
129
    assert(valid(fileno));
 
130
    Slot &s = shared->slots[fileno];
 
131
 
 
132
    if (s.lock.lockExclusive())
 
133
        freeLocked(s, false);
 
134
    else
 
135
        s.waitingToBeFreed = true; // mark to free it later
 
136
}
 
137
 
 
138
const Ipc::MemMap::Slot *
 
139
Ipc::MemMap::openForReading(const cache_key *const key, sfileno &fileno)
 
140
{
 
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)) {
 
146
            fileno = idx;
 
147
            debugs(54, 5, "opened slot at " << fileno << " for key "
 
148
                   << storeKeyText(key) << " for reading in map [" << path <<
 
149
                   ']');
 
150
            return slot; // locked for reading
 
151
        }
 
152
        slot->lock.unlockShared();
 
153
    }
 
154
    debugs(54, 5, "failed to open slot for key " << storeKeyText(key)
 
155
           << " for reading in map [" << path << ']');
 
156
    return NULL;
 
157
}
 
158
 
 
159
const Ipc::MemMap::Slot *
 
160
Ipc::MemMap::openForReadingAt(const sfileno fileno)
 
161
{
 
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];
 
166
 
 
167
    if (!s.lock.lockShared()) {
 
168
        debugs(54, 5, "failed to lock slot at " << fileno << " for "
 
169
               "reading in map [" << path << ']');
 
170
        return NULL;
 
171
    }
 
172
 
 
173
    if (s.empty()) {
 
174
        s.lock.unlockShared();
 
175
        debugs(54, 7, "empty slot at " << fileno << " for "
 
176
               "reading in map [" << path << ']');
 
177
        return NULL;
 
178
    }
 
179
 
 
180
    if (s.waitingToBeFreed) {
 
181
        s.lock.unlockShared();
 
182
        debugs(54, 7, "dirty slot at " << fileno << " for "
 
183
               "reading in map [" << path << ']');
 
184
        return NULL;
 
185
    }
 
186
 
 
187
    debugs(54, 5, "opened slot at " << fileno << " for reading in"
 
188
           " map [" << path << ']');
 
189
    return &s;
 
190
}
 
191
 
 
192
void
 
193
Ipc::MemMap::closeForReading(const sfileno fileno)
 
194
{
 
195
    debugs(54, 5, "closing slot at " << fileno << " for reading in "
 
196
           "map [" << path << ']');
 
197
    assert(valid(fileno));
 
198
    Slot &s = shared->slots[fileno];
 
199
    assert(s.reading());
 
200
    s.lock.unlockShared();
 
201
}
 
202
 
 
203
int
 
204
Ipc::MemMap::entryLimit() const
 
205
{
 
206
    return shared->limit;
 
207
}
 
208
 
 
209
int
 
210
Ipc::MemMap::entryCount() const
 
211
{
 
212
    return shared->count;
 
213
}
 
214
 
 
215
bool
 
216
Ipc::MemMap::full() const
 
217
{
 
218
    return entryCount() >= entryLimit();
 
219
}
 
220
 
 
221
void
 
222
Ipc::MemMap::updateStats(ReadWriteLockStats &stats) const
 
223
{
 
224
    for (int i = 0; i < shared->limit; ++i)
 
225
        shared->slots[i].lock.updateStats(stats);
 
226
}
 
227
 
 
228
bool
 
229
Ipc::MemMap::valid(const int pos) const
 
230
{
 
231
    return 0 <= pos && pos < entryLimit();
 
232
}
 
233
 
 
234
static
 
235
unsigned int
 
236
hash_key(const unsigned char *data, unsigned int len, unsigned int hashSize)
 
237
{
 
238
    unsigned int n;
 
239
    unsigned int j;
 
240
    for(j = 0, n = 0; j < len; j++ ) {
 
241
        n ^= 271 * *data;
 
242
        ++data;
 
243
    }
 
244
    return (n ^ (j * 271)) % hashSize;
 
245
}
 
246
 
 
247
int
 
248
Ipc::MemMap::slotIndexByKey(const cache_key *const key) const
 
249
{
 
250
    const unsigned char *k = reinterpret_cast<const unsigned char *>(key);
 
251
    return hash_key(k, MEMMAP_SLOT_KEY_SIZE, shared->limit);
 
252
}
 
253
 
 
254
Ipc::MemMap::Slot &
 
255
Ipc::MemMap::slotByKey(const cache_key *const key)
 
256
{
 
257
    return shared->slots[slotIndexByKey(key)];
 
258
}
 
259
 
 
260
/// unconditionally frees the already exclusively locked slot and releases lock
 
261
void
 
262
Ipc::MemMap::freeLocked(Slot &s, bool keepLocked)
 
263
{
 
264
    if (!s.empty() && cleaner)
 
265
        cleaner->noteFreeMapSlot(&s - shared->slots.raw());
 
266
 
 
267
    s.waitingToBeFreed = false;
 
268
    memset(s.key, 0, sizeof(s.key));
 
269
    if (!keepLocked)
 
270
        s.lock.unlockExclusive();
 
271
    --shared->count;
 
272
    debugs(54, 5, "freed slot at " << (&s - shared->slots.raw()) <<
 
273
           " in map [" << path << ']');
 
274
}
 
275
 
 
276
/* Ipc::MemMapSlot */
 
277
Ipc::MemMapSlot::MemMapSlot() :
 
278
        pSize(0),
 
279
        expire(0)
 
280
{
 
281
    memset(key, 0, sizeof(key));
 
282
    memset(p, 0, sizeof(p));
 
283
}
 
284
 
 
285
void
 
286
Ipc::MemMapSlot::set(const unsigned char *aKey, const void *block, size_t blockSize, time_t expireAt)
 
287
{
 
288
    memcpy(key, aKey, sizeof(key));
 
289
    if (block)
 
290
        memcpy(p, block, blockSize);
 
291
    pSize = blockSize;
 
292
    expire = expireAt;
 
293
}
 
294
 
 
295
bool
 
296
Ipc::MemMapSlot::sameKey(const cache_key *const aKey) const
 
297
{
 
298
    return (memcmp(key, aKey, sizeof(key)) == 0);
 
299
}
 
300
 
 
301
bool
 
302
Ipc::MemMapSlot::empty() const
 
303
{
 
304
    for (unsigned char const*u = key; u < key + sizeof(key); ++u) {
 
305
        if (*u)
 
306
            return false;
 
307
    }
 
308
    return true;
 
309
}
 
310
 
 
311
/* Ipc::MemMap::Shared */
 
312
 
 
313
Ipc::MemMap::Shared::Shared(const int aLimit, const size_t anExtrasSize):
 
314
    limit(aLimit), extrasSize(anExtrasSize), count(0), slots(aLimit)
 
315
{
 
316
}
 
317
 
 
318
Ipc::MemMap::Shared::~Shared()
 
319
{
 
320
}
 
321
 
 
322
size_t
 
323
Ipc::MemMap::Shared::sharedMemorySize() const
 
324
{
 
325
    return SharedMemorySize(limit, extrasSize);
 
326
}
 
327
 
 
328
size_t
 
329
Ipc::MemMap::Shared::SharedMemorySize(const int limit, const size_t extrasSize)
 
330
{
 
331
    return sizeof(Shared) + limit * (sizeof(Slot) + extrasSize);
 
332
}