]>
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 Owner
*const owner
= shm_new(Shared
)(path
, limit
, extrasSize
);
17 debugs(54, 5, HERE
<< "new map [" << path
<< "] created: " << limit
);
21 Ipc::StoreMap::Owner
*
22 Ipc::StoreMap::Init(const char *const path
, const int limit
)
24 return Init(path
, limit
, 0);
27 Ipc::StoreMap::StoreMap(const char *const aPath
): cleaner(NULL
), path(aPath
),
28 shared(shm_old(Shared
)(aPath
))
30 assert(shared
->limit
> 0); // we should not be created otherwise
31 debugs(54, 5, HERE
<< "attached map [" << path
<< "] created: " <<
36 Ipc::StoreMap::openForWriting(const cache_key
*const key
, sfileno
&fileno
)
38 debugs(54, 5, HERE
<< " trying to open slot for key " << storeKeyText(key
)
39 << " for writing in map [" << path
<< ']');
40 const int idx
= slotIndexByKey(key
);
42 Slot
&s
= shared
->slots
[idx
];
43 ReadWriteLock
&lock
= s
.lock
;
45 if (lock
.lockExclusive()) {
46 assert(s
.state
!= Slot::Writeable
); // until we start breaking locks
48 // free if the entry was used, keeping the entry locked
49 if (s
.waitingToBeFreed
|| s
.state
== Slot::Readable
)
52 assert(s
.state
== Slot::Empty
);
54 s
.state
= Slot::Writeable
;
56 //s.setKey(key); // XXX: the caller should do that
57 debugs(54, 5, HERE
<< " opened slot at " << idx
<<
58 " for writing in map [" << path
<< ']');
59 return &s
; // and keep the entry locked
62 debugs(54, 5, HERE
<< " failed to open slot at " << idx
<<
63 " for writing in map [" << path
<< ']');
68 Ipc::StoreMap::closeForWriting(const sfileno fileno
, bool lockForReading
)
70 debugs(54, 5, HERE
<< " closing slot at " << fileno
<< " for writing and "
71 "openning for reading in map [" << path
<< ']');
72 assert(valid(fileno
));
73 Slot
&s
= shared
->slots
[fileno
];
74 assert(s
.state
== Slot::Writeable
);
75 s
.state
= Slot::Readable
;
77 s
.lock
.switchExclusiveToShared();
79 s
.lock
.unlockExclusive();
82 /// terminate writing the entry, freeing its slot for others to use
84 Ipc::StoreMap::abortWriting(const sfileno fileno
)
86 debugs(54, 5, HERE
<< " abort writing slot at " << fileno
<<
87 " in map [" << path
<< ']');
88 assert(valid(fileno
));
89 Slot
&s
= shared
->slots
[fileno
];
90 assert(s
.state
== Slot::Writeable
);
95 Ipc::StoreMap::abortIo(const sfileno fileno
)
97 debugs(54, 5, HERE
<< " abort I/O for slot at " << fileno
<<
98 " in map [" << path
<< ']');
99 assert(valid(fileno
));
100 Slot
&s
= shared
->slots
[fileno
];
102 // The caller is a lock holder. Thus, if we are Writeable, then the
103 // caller must be the writer; otherwise the caller must be the reader.
104 if (s
.state
== Slot::Writeable
)
105 abortWriting(fileno
);
107 closeForReading(fileno
);
110 const Ipc::StoreMap::Slot
*
111 Ipc::StoreMap::peekAtReader(const sfileno fileno
) const
113 assert(valid(fileno
));
114 const Slot
&s
= shared
->slots
[fileno
];
117 return &s
; // immediate access by lock holder so no locking
118 case Slot::Writeable
:
119 return NULL
; // cannot read the slot when it is being written
121 assert(false); // must be locked for reading or writing
123 assert(false); // not reachable
128 Ipc::StoreMap::free(const sfileno fileno
)
130 debugs(54, 5, HERE
<< " marking slot at " << fileno
<< " to be freed in"
131 " map [" << path
<< ']');
133 assert(valid(fileno
));
134 Slot
&s
= shared
->slots
[fileno
];
136 if (s
.lock
.lockExclusive())
137 freeLocked(s
, false);
139 s
.waitingToBeFreed
= true; // mark to free it later
142 const Ipc::StoreMap::Slot
*
143 Ipc::StoreMap::openForReading(const cache_key
*const key
, sfileno
&fileno
)
145 debugs(54, 5, HERE
<< " trying to open slot for key " << storeKeyText(key
)
146 << " for reading in map [" << path
<< ']');
147 const int idx
= slotIndexByKey(key
);
148 if (const Slot
*slot
= openForReadingAt(idx
)) {
149 if (slot
->sameKey(key
)) {
151 debugs(54, 5, HERE
<< " opened slot at " << fileno
<< " for key "
152 << storeKeyText(key
) << " for reading in map [" << path
<<
154 return slot
; // locked for reading
156 slot
->lock
.unlockShared();
158 debugs(54, 5, HERE
<< " failed to open slot for key " << storeKeyText(key
)
159 << " for reading in map [" << path
<< ']');
163 const Ipc::StoreMap::Slot
*
164 Ipc::StoreMap::openForReadingAt(const sfileno fileno
)
166 debugs(54, 5, HERE
<< " trying to open slot at " << fileno
<< " for "
167 "reading in map [" << path
<< ']');
168 assert(valid(fileno
));
169 Slot
&s
= shared
->slots
[fileno
];
171 if (!s
.lock
.lockShared()) {
172 debugs(54, 5, HERE
<< " failed to lock slot at " << fileno
<< " for "
173 "reading in map [" << path
<< ']');
177 if (s
.state
== Slot::Empty
) {
178 s
.lock
.unlockShared();
179 debugs(54, 7, HERE
<< " empty slot at " << fileno
<< " for "
180 "reading in map [" << path
<< ']');
184 if (s
.waitingToBeFreed
) {
185 s
.lock
.unlockShared();
186 debugs(54, 7, HERE
<< " dirty slot at " << fileno
<< " for "
187 "reading in map [" << path
<< ']');
191 // cannot be Writing here if we got shared lock and checked Empty above
192 assert(s
.state
== Slot::Readable
);
193 debugs(54, 5, HERE
<< " opened slot at " << fileno
<< " for reading in"
194 " map [" << path
<< ']');
199 Ipc::StoreMap::closeForReading(const sfileno fileno
)
201 debugs(54, 5, HERE
<< " closing slot at " << fileno
<< " for reading in "
202 "map [" << path
<< ']');
203 assert(valid(fileno
));
204 Slot
&s
= shared
->slots
[fileno
];
205 assert(s
.state
== Slot::Readable
);
206 s
.lock
.unlockShared();
210 Ipc::StoreMap::entryLimit() const
212 return shared
->limit
;
216 Ipc::StoreMap::entryCount() const
218 return shared
->count
;
222 Ipc::StoreMap::full() const
224 return entryCount() >= entryLimit();
228 Ipc::StoreMap::updateStats(ReadWriteLockStats
&stats
) const
230 for (int i
= 0; i
< shared
->limit
; ++i
)
231 shared
->slots
[i
].lock
.updateStats(stats
);
235 Ipc::StoreMap::valid(const int pos
) const
237 return 0 <= pos
&& pos
< entryLimit();
241 Ipc::StoreMap::slotIndexByKey(const cache_key
*const key
) const
243 const uint64_t *const k
= reinterpret_cast<const uint64_t *>(key
);
244 // TODO: use a better hash function
245 return (k
[0] + k
[1]) % shared
->limit
;
248 Ipc::StoreMap::Slot
&
249 Ipc::StoreMap::slotByKey(const cache_key
*const key
)
251 return shared
->slots
[slotIndexByKey(key
)];
254 /// unconditionally frees the already exclusively locked slot and releases lock
256 Ipc::StoreMap::freeLocked(Slot
&s
, bool keepLocked
)
258 if (s
.state
== Slot::Readable
&& cleaner
)
259 cleaner
->cleanReadable(&s
- shared
->slots
);
261 s
.waitingToBeFreed
= false;
262 s
.state
= Slot::Empty
;
264 s
.lock
.unlockExclusive();
266 debugs(54, 5, HERE
<< " freed slot at " << (&s
- shared
->slots
) <<
267 " in map [" << path
<< ']');
271 /* Ipc::StoreMapSlot */
273 Ipc::StoreMapSlot::StoreMapSlot(): state(Empty
)
275 xmemset(&key
, 0, sizeof(key
));
276 xmemset(&basics
, 0, sizeof(basics
));
280 Ipc::StoreMapSlot::setKey(const cache_key
*const aKey
)
282 memcpy(key
, aKey
, sizeof(key
));
286 Ipc::StoreMapSlot::sameKey(const cache_key
*const aKey
) const
288 const uint64_t *const k
= reinterpret_cast<const uint64_t *>(aKey
);
289 return k
[0] == key
[0] && k
[1] == key
[1];
293 Ipc::StoreMapSlot::set(const StoreEntry
&from
)
295 memcpy(key
, from
.key
, sizeof(key
));
296 // XXX: header = aHeader;
297 basics
.timestamp
= from
.timestamp
;
298 basics
.lastref
= from
.lastref
;
299 basics
.expires
= from
.expires
;
300 basics
.lastmod
= from
.lastmod
;
301 basics
.swap_file_sz
= from
.swap_file_sz
;
302 basics
.refcount
= from
.refcount
;
303 basics
.flags
= from
.flags
;
306 /* Ipc::StoreMap::Shared */
308 Ipc::StoreMap::Shared::Shared(const int aLimit
, const size_t anExtrasSize
):
309 limit(aLimit
), extrasSize(anExtrasSize
), count(0)
314 Ipc::StoreMap::Shared::sharedMemorySize() const
316 return SharedMemorySize(limit
, extrasSize
);
320 Ipc::StoreMap::Shared::SharedMemorySize(const int limit
, const size_t extrasSize
)
322 return sizeof(Shared
) + limit
* (sizeof(Slot
) + extrasSize
);