]>
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::StoreMap(const char *const aPath
, const int limit
,
13 size_t sharedSizeExtra
):
14 path(aPath
), shm(aPath
), shared(NULL
)
16 const size_t mySharedSize
= Shared::MemSize(limit
);
17 shm
.create(mySharedSize
+ sharedSizeExtra
);
18 shared
= new (shm
.reserve(mySharedSize
)) Shared(limit
);
19 debugs(54, 5, HERE
<< "new map [" << path
<< "] created");
22 Ipc::StoreMap::StoreMap(const char *const aPath
):
23 path(aPath
), shm(aPath
), shared(NULL
)
27 shared
= reinterpret_cast<Shared
*>(shm
.mem());
28 // check that nobody used our segment chunk and that shared->limit is sane
29 assert(shared
== reinterpret_cast<Shared
*>(shm
.reserve(Shared::MemSize(shared
->limit
))));
30 debugs(54, 5, HERE
<< "attached map [" << path
<< "] created");
34 Ipc::StoreMap::openForWriting(const cache_key
*const key
, sfileno
&fileno
)
36 debugs(54, 5, HERE
<< " trying to open slot for key " << storeKeyText(key
)
37 << " for writing in map [" << path
<< ']');
38 const int idx
= slotIndexByKey(key
);
40 Slot
&s
= shared
->slots
[idx
];
41 ReadWriteLock
&lock
= s
.lock
;
43 if (lock
.lockExclusive()) {
44 assert(s
.state
!= Slot::Writeable
); // until we start breaking locks
46 // free if the entry was dirty, keeping the entry locked
47 if (s
.waitingToBeFreed
== true)
50 if (s
.state
== Slot::Empty
) // we may also overwrite a Readable slot
52 s
.state
= Slot::Writeable
;
54 //s.setKey(key); // XXX: the caller should do that
55 debugs(54, 5, HERE
<< " opened slot at " << idx
<<
56 " for writing in map [" << path
<< ']');
57 return &s
; // and keep the entry locked
60 debugs(54, 5, HERE
<< " failed to open slot at " << idx
<<
61 " for writing in map [" << path
<< ']');
66 Ipc::StoreMap::closeForWriting(const sfileno fileno
, bool lockForReading
)
68 debugs(54, 5, HERE
<< " closing slot at " << fileno
<< " for writing and "
69 "openning for reading in map [" << path
<< ']');
70 assert(valid(fileno
));
71 Slot
&s
= shared
->slots
[fileno
];
72 assert(s
.state
== Slot::Writeable
);
73 s
.state
= Slot::Readable
;
75 s
.lock
.switchExclusiveToShared();
77 s
.lock
.unlockExclusive();
80 /// terminate writing the entry, freeing its slot for others to use
82 Ipc::StoreMap::abortWriting(const sfileno fileno
)
84 debugs(54, 5, HERE
<< " abort writing slot at " << fileno
<<
85 " in map [" << path
<< ']');
86 assert(valid(fileno
));
87 Slot
&s
= shared
->slots
[fileno
];
88 assert(s
.state
== Slot::Writeable
);
93 Ipc::StoreMap::abortIo(const sfileno fileno
)
95 debugs(54, 5, HERE
<< " abort I/O for slot at " << fileno
<<
96 " in map [" << path
<< ']');
97 assert(valid(fileno
));
98 Slot
&s
= shared
->slots
[fileno
];
100 // The caller is a lock holder. Thus, if we are Writeable, then the
101 // caller must be the writer; otherwise the caller must be the reader.
102 if (s
.state
== Slot::Writeable
)
103 abortWriting(fileno
);
105 closeForReading(fileno
);
108 const Ipc::StoreMap::Slot
*
109 Ipc::StoreMap::peekAtReader(const sfileno fileno
) const
111 assert(valid(fileno
));
112 const Slot
&s
= shared
->slots
[fileno
];
115 return &s
; // immediate access by lock holder so no locking
116 case Slot::Writeable
:
117 return NULL
; // cannot read the slot when it is being written
119 assert(false); // must be locked for reading or writing
121 assert(false); // not reachable
126 Ipc::StoreMap::free(const sfileno fileno
)
128 debugs(54, 5, HERE
<< " marking slot at " << fileno
<< " to be freed in"
129 " map [" << path
<< ']');
131 assert(valid(fileno
));
132 Slot
&s
= shared
->slots
[fileno
];
134 if (s
.lock
.lockExclusive())
135 freeLocked(s
, false);
137 s
.waitingToBeFreed
= true; // mark to free it later
140 const Ipc::StoreMap::Slot
*
141 Ipc::StoreMap::openForReading(const cache_key
*const key
, sfileno
&fileno
)
143 debugs(54, 5, HERE
<< " trying to open slot for key " << storeKeyText(key
)
144 << " for reading in map [" << path
<< ']');
145 const int idx
= slotIndexByKey(key
);
146 if (const Slot
*slot
= openForReadingAt(idx
)) {
147 if (slot
->sameKey(key
)) {
149 debugs(54, 5, HERE
<< " opened slot at " << fileno
<< " for key "
150 << storeKeyText(key
) << " for reading in map [" << path
<<
152 return slot
; // locked for reading
154 slot
->lock
.unlockShared();
156 debugs(54, 5, HERE
<< " failed to open slot for key " << storeKeyText(key
)
157 << " for reading in map [" << path
<< ']');
161 const Ipc::StoreMap::Slot
*
162 Ipc::StoreMap::openForReadingAt(const sfileno fileno
)
164 debugs(54, 5, HERE
<< " trying to open slot at " << fileno
<< " for "
165 "reading in map [" << path
<< ']');
166 assert(valid(fileno
));
167 Slot
&s
= shared
->slots
[fileno
];
169 if (!s
.lock
.lockShared()) {
170 debugs(54, 5, HERE
<< " failed to lock slot at " << fileno
<< " for "
171 "reading in map [" << path
<< ']');
175 if (s
.state
== Slot::Empty
) {
176 s
.lock
.unlockShared();
177 debugs(54, 7, HERE
<< " empty slot at " << fileno
<< " for "
178 "reading in map [" << path
<< ']');
182 if (s
.waitingToBeFreed
) {
183 s
.lock
.unlockShared();
184 debugs(54, 7, HERE
<< " dirty slot at " << fileno
<< " for "
185 "reading in map [" << path
<< ']');
189 // cannot be Writing here if we got shared lock and checked Empty above
190 assert(s
.state
== Slot::Readable
);
191 debugs(54, 5, HERE
<< " opened slot at " << fileno
<< " for reading in"
192 " map [" << path
<< ']');
197 Ipc::StoreMap::closeForReading(const sfileno fileno
)
199 debugs(54, 5, HERE
<< " closing slot at " << fileno
<< " for reading in "
200 "map [" << path
<< ']');
201 assert(valid(fileno
));
202 Slot
&s
= shared
->slots
[fileno
];
203 assert(s
.state
== Slot::Readable
);
204 s
.lock
.unlockShared();
208 Ipc::StoreMap::entryLimit() const
210 return shared
->limit
;
214 Ipc::StoreMap::entryCount() const
216 return shared
->count
;
220 Ipc::StoreMap::full() const
222 return entryCount() >= entryLimit();
226 Ipc::StoreMap::updateStats(ReadWriteLockStats
&stats
) const
228 for (int i
= 0; i
< shared
->limit
; ++i
)
229 shared
->slots
[i
].lock
.updateStats(stats
);
233 Ipc::StoreMap::valid(const int pos
) const
235 return 0 <= pos
&& pos
< entryLimit();
239 Ipc::StoreMap::slotIndexByKey(const cache_key
*const key
) const
241 const uint64_t *const k
= reinterpret_cast<const uint64_t *>(key
);
242 // TODO: use a better hash function
243 return (k
[0] + k
[1]) % shared
->limit
;
246 Ipc::StoreMap::Slot
&
247 Ipc::StoreMap::slotByKey(const cache_key
*const key
)
249 return shared
->slots
[slotIndexByKey(key
)];
252 /// unconditionally frees the already exclusively locked slot and releases lock
254 Ipc::StoreMap::freeLocked(Slot
&s
, bool keepLocked
)
256 s
.waitingToBeFreed
= false;
257 s
.state
= Slot::Empty
;
259 s
.lock
.unlockExclusive();
261 debugs(54, 5, HERE
<< " freed slot at " << (&s
- shared
->slots
) <<
262 " in map [" << path
<< ']');
266 /* Ipc::StoreMapSlot */
268 Ipc::StoreMapSlot::StoreMapSlot(): state(Empty
)
270 xmemset(&key
, 0, sizeof(key
));
271 xmemset(&basics
, 0, sizeof(basics
));
275 Ipc::StoreMapSlot::setKey(const cache_key
*const aKey
)
277 memcpy(key
, aKey
, sizeof(key
));
281 Ipc::StoreMapSlot::sameKey(const cache_key
*const aKey
) const
283 const uint64_t *const k
= reinterpret_cast<const uint64_t *>(aKey
);
284 return k
[0] == key
[0] && k
[1] == key
[1];
288 Ipc::StoreMapSlot::set(const StoreEntry
&from
)
290 memcpy(key
, from
.key
, sizeof(key
));
291 // XXX: header = aHeader;
292 basics
.timestamp
= from
.timestamp
;
293 basics
.lastref
= from
.lastref
;
294 basics
.expires
= from
.expires
;
295 basics
.lastmod
= from
.lastmod
;
296 basics
.swap_file_sz
= from
.swap_file_sz
;
297 basics
.refcount
= from
.refcount
;
298 basics
.flags
= from
.flags
;
301 /* Ipc::StoreMap::Shared */
303 Ipc::StoreMap::Shared::Shared(const int aLimit
): limit(aLimit
), count(0)
308 Ipc::StoreMap::Shared::MemSize(int limit
)
310 return sizeof(Shared
) + limit
* sizeof(Slot
);