]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/StoreMap.cc
4 * DEBUG: section 54 Interprocess Communication
10 #include "ipc/StoreMap.h"
12 Ipc::StoreMap::Owner
*
13 Ipc::StoreMap::Init(const char *const path
, const int limit
, const size_t extrasSize
)
15 assert(limit
> 0); // we should not be created otherwise
16 assert(extrasSize
>= 0);
17 Owner
*const owner
= shm_new(Shared
)(path
, limit
, extrasSize
);
18 debugs(54, 5, HERE
<< "new map [" << path
<< "] created: " << limit
);
22 Ipc::StoreMap::Owner
*
23 Ipc::StoreMap::Init(const char *const path
, const int limit
)
25 return Init(path
, limit
, 0);
28 Ipc::StoreMap::StoreMap(const char *const aPath
): cleaner(NULL
), path(aPath
),
29 shared(shm_old(Shared
)(aPath
))
31 assert(shared
->limit
> 0); // we should not be created otherwise
32 debugs(54, 5, HERE
<< "attached map [" << path
<< "] created: " <<
37 Ipc::StoreMap::openForWriting(const cache_key
*const key
, sfileno
&fileno
)
39 debugs(54, 5, HERE
<< " trying to open slot for key " << storeKeyText(key
)
40 << " for writing in map [" << path
<< ']');
41 const int idx
= slotIndexByKey(key
);
43 Slot
&s
= shared
->slots
[idx
];
44 ReadWriteLock
&lock
= s
.lock
;
46 if (lock
.lockExclusive()) {
47 assert(s
.state
!= Slot::Writeable
); // until we start breaking locks
49 // free if the entry was used, keeping the entry locked
50 if (s
.waitingToBeFreed
== true || s
.state
== Slot::Readable
)
53 assert(s
.state
== Slot::Empty
);
55 s
.state
= Slot::Writeable
;
57 //s.setKey(key); // XXX: the caller should do that
58 debugs(54, 5, HERE
<< " opened slot at " << idx
<<
59 " for writing in map [" << path
<< ']');
60 return &s
; // and keep the entry locked
63 debugs(54, 5, HERE
<< " failed to open slot at " << idx
<<
64 " for writing in map [" << path
<< ']');
69 Ipc::StoreMap::closeForWriting(const sfileno fileno
, bool lockForReading
)
71 debugs(54, 5, HERE
<< " closing slot at " << fileno
<< " for writing and "
72 "openning for reading in map [" << path
<< ']');
73 assert(valid(fileno
));
74 Slot
&s
= shared
->slots
[fileno
];
75 assert(s
.state
== Slot::Writeable
);
76 s
.state
= Slot::Readable
;
78 s
.lock
.switchExclusiveToShared();
80 s
.lock
.unlockExclusive();
83 /// terminate writing the entry, freeing its slot for others to use
85 Ipc::StoreMap::abortWriting(const sfileno fileno
)
87 debugs(54, 5, HERE
<< " abort writing slot at " << fileno
<<
88 " in map [" << path
<< ']');
89 assert(valid(fileno
));
90 Slot
&s
= shared
->slots
[fileno
];
91 assert(s
.state
== Slot::Writeable
);
96 Ipc::StoreMap::abortIo(const sfileno fileno
)
98 debugs(54, 5, HERE
<< " abort I/O for slot at " << fileno
<<
99 " in map [" << path
<< ']');
100 assert(valid(fileno
));
101 Slot
&s
= shared
->slots
[fileno
];
103 // The caller is a lock holder. Thus, if we are Writeable, then the
104 // caller must be the writer; otherwise the caller must be the reader.
105 if (s
.state
== Slot::Writeable
)
106 abortWriting(fileno
);
108 closeForReading(fileno
);
111 const Ipc::StoreMap::Slot
*
112 Ipc::StoreMap::peekAtReader(const sfileno fileno
) const
114 assert(valid(fileno
));
115 const Slot
&s
= shared
->slots
[fileno
];
118 return &s
; // immediate access by lock holder so no locking
119 case Slot::Writeable
:
120 return NULL
; // cannot read the slot when it is being written
122 assert(false); // must be locked for reading or writing
124 assert(false); // not reachable
129 Ipc::StoreMap::free(const sfileno fileno
)
131 debugs(54, 5, HERE
<< " marking slot at " << fileno
<< " to be freed in"
132 " map [" << path
<< ']');
134 assert(valid(fileno
));
135 Slot
&s
= shared
->slots
[fileno
];
137 if (s
.lock
.lockExclusive())
138 freeLocked(s
, false);
140 s
.waitingToBeFreed
= true; // mark to free it later
143 const Ipc::StoreMap::Slot
*
144 Ipc::StoreMap::openForReading(const cache_key
*const key
, sfileno
&fileno
)
146 debugs(54, 5, HERE
<< " trying to open slot for key " << storeKeyText(key
)
147 << " for reading in map [" << path
<< ']');
148 const int idx
= slotIndexByKey(key
);
149 if (const Slot
*slot
= openForReadingAt(idx
)) {
150 if (slot
->sameKey(key
)) {
152 debugs(54, 5, HERE
<< " opened slot at " << fileno
<< " for key "
153 << storeKeyText(key
) << " for reading in map [" << path
<<
155 return slot
; // locked for reading
157 slot
->lock
.unlockShared();
159 debugs(54, 5, HERE
<< " failed to open slot for key " << storeKeyText(key
)
160 << " for reading in map [" << path
<< ']');
164 const Ipc::StoreMap::Slot
*
165 Ipc::StoreMap::openForReadingAt(const sfileno fileno
)
167 debugs(54, 5, HERE
<< " trying to open slot at " << fileno
<< " for "
168 "reading in map [" << path
<< ']');
169 assert(valid(fileno
));
170 Slot
&s
= shared
->slots
[fileno
];
172 if (!s
.lock
.lockShared()) {
173 debugs(54, 5, HERE
<< " failed to lock slot at " << fileno
<< " for "
174 "reading in map [" << path
<< ']');
178 if (s
.state
== Slot::Empty
) {
179 s
.lock
.unlockShared();
180 debugs(54, 7, HERE
<< " empty slot at " << fileno
<< " for "
181 "reading in map [" << path
<< ']');
185 if (s
.waitingToBeFreed
) {
186 s
.lock
.unlockShared();
187 debugs(54, 7, HERE
<< " dirty slot at " << fileno
<< " for "
188 "reading in map [" << path
<< ']');
192 // cannot be Writing here if we got shared lock and checked Empty above
193 assert(s
.state
== Slot::Readable
);
194 debugs(54, 5, HERE
<< " opened slot at " << fileno
<< " for reading in"
195 " map [" << path
<< ']');
200 Ipc::StoreMap::closeForReading(const sfileno fileno
)
202 debugs(54, 5, HERE
<< " closing slot at " << fileno
<< " for reading in "
203 "map [" << path
<< ']');
204 assert(valid(fileno
));
205 Slot
&s
= shared
->slots
[fileno
];
206 assert(s
.state
== Slot::Readable
);
207 s
.lock
.unlockShared();
211 Ipc::StoreMap::entryLimit() const
213 return shared
->limit
;
217 Ipc::StoreMap::entryCount() const
219 return shared
->count
;
223 Ipc::StoreMap::full() const
225 return entryCount() >= entryLimit();
229 Ipc::StoreMap::updateStats(ReadWriteLockStats
&stats
) const
231 for (int i
= 0; i
< shared
->limit
; ++i
)
232 shared
->slots
[i
].lock
.updateStats(stats
);
236 Ipc::StoreMap::valid(const int pos
) const
238 return 0 <= pos
&& pos
< entryLimit();
242 Ipc::StoreMap::slotIndexByKey(const cache_key
*const key
) const
244 const uint64_t *const k
= reinterpret_cast<const uint64_t *>(key
);
245 // TODO: use a better hash function
246 return (k
[0] + k
[1]) % shared
->limit
;
249 Ipc::StoreMap::Slot
&
250 Ipc::StoreMap::slotByKey(const cache_key
*const key
)
252 return shared
->slots
[slotIndexByKey(key
)];
255 /// unconditionally frees the already exclusively locked slot and releases lock
257 Ipc::StoreMap::freeLocked(Slot
&s
, bool keepLocked
)
259 if (s
.state
== Slot::Readable
&& cleaner
)
260 cleaner
->cleanReadable(&s
- shared
->slots
);
262 s
.waitingToBeFreed
= false;
263 s
.state
= Slot::Empty
;
265 s
.lock
.unlockExclusive();
267 debugs(54, 5, HERE
<< " freed slot at " << (&s
- shared
->slots
) <<
268 " in map [" << path
<< ']');
272 /* Ipc::StoreMapSlot */
274 Ipc::StoreMapSlot::StoreMapSlot(): state(Empty
)
276 xmemset(&key
, 0, sizeof(key
));
277 xmemset(&basics
, 0, sizeof(basics
));
281 Ipc::StoreMapSlot::setKey(const cache_key
*const aKey
)
283 memcpy(key
, aKey
, sizeof(key
));
287 Ipc::StoreMapSlot::sameKey(const cache_key
*const aKey
) const
289 const uint64_t *const k
= reinterpret_cast<const uint64_t *>(aKey
);
290 return k
[0] == key
[0] && k
[1] == key
[1];
294 Ipc::StoreMapSlot::set(const StoreEntry
&from
)
296 memcpy(key
, from
.key
, sizeof(key
));
297 // XXX: header = aHeader;
298 basics
.timestamp
= from
.timestamp
;
299 basics
.lastref
= from
.lastref
;
300 basics
.expires
= from
.expires
;
301 basics
.lastmod
= from
.lastmod
;
302 basics
.swap_file_sz
= from
.swap_file_sz
;
303 basics
.refcount
= from
.refcount
;
304 basics
.flags
= from
.flags
;
307 /* Ipc::StoreMap::Shared */
309 Ipc::StoreMap::Shared::Shared(const int aLimit
, const size_t anExtrasSize
):
310 limit(aLimit
), extrasSize(anExtrasSize
), count(0)
315 Ipc::StoreMap::Shared::sharedMemorySize() const
317 return SharedMemorySize(limit
, extrasSize
);
321 Ipc::StoreMap::Shared::SharedMemorySize(const int limit
, const size_t extrasSize
)
323 return sizeof(Shared
) + limit
* (sizeof(Slot
) + extrasSize
);