]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/StoreMap.cc
2 * DEBUG: section 54 Interprocess Communication
6 #include "ipc/StoreMap.h"
7 #include "store_key_md5.h"
11 Ipc::StoreMap::Owner
*
12 Ipc::StoreMap::Init(const char *const path
, const int limit
, const size_t extrasSize
)
14 assert(limit
> 0); // we should not be created otherwise
15 Owner
*const owner
= shm_new(Shared
)(path
, limit
, extrasSize
);
16 debugs(54, 5, HERE
<< "new map [" << path
<< "] created: " << limit
);
20 Ipc::StoreMap::Owner
*
21 Ipc::StoreMap::Init(const char *const path
, const int limit
)
23 return Init(path
, limit
, 0);
26 Ipc::StoreMap::StoreMap(const char *const aPath
): cleaner(NULL
), path(aPath
),
27 shared(shm_old(Shared
)(aPath
))
29 assert(shared
->limit
> 0); // we should not be created otherwise
30 debugs(54, 5, HERE
<< "attached map [" << path
<< "] created: " <<
35 Ipc::StoreMap::openForWriting(const cache_key
*const key
, sfileno
&fileno
)
37 debugs(54, 5, HERE
<< " trying to open slot for key " << storeKeyText(key
)
38 << " for writing in map [" << path
<< ']');
39 const int idx
= slotIndexByKey(key
);
41 Slot
&s
= shared
->slots
[idx
];
42 ReadWriteLock
&lock
= s
.lock
;
44 if (lock
.lockExclusive()) {
45 assert(s
.state
!= Slot::Writeable
); // until we start breaking locks
47 // free if the entry was used, keeping the entry locked
48 if (s
.waitingToBeFreed
|| s
.state
== Slot::Readable
)
51 assert(s
.state
== Slot::Empty
);
53 s
.state
= Slot::Writeable
;
55 //s.setKey(key); // XXX: the caller should do that
56 debugs(54, 5, HERE
<< " opened slot at " << idx
<<
57 " for writing in map [" << path
<< ']');
58 return &s
; // and keep the entry locked
61 debugs(54, 5, HERE
<< " failed to open slot at " << idx
<<
62 " for writing in map [" << path
<< ']');
67 Ipc::StoreMap::closeForWriting(const sfileno fileno
, bool lockForReading
)
69 debugs(54, 5, HERE
<< " closing slot at " << fileno
<< " for writing and "
70 "openning for reading in map [" << path
<< ']');
71 assert(valid(fileno
));
72 Slot
&s
= shared
->slots
[fileno
];
73 assert(s
.state
== Slot::Writeable
);
74 s
.state
= Slot::Readable
;
76 s
.lock
.switchExclusiveToShared();
78 s
.lock
.unlockExclusive();
81 /// terminate writing the entry, freeing its slot for others to use
83 Ipc::StoreMap::abortWriting(const sfileno fileno
)
85 debugs(54, 5, HERE
<< " abort writing slot at " << fileno
<<
86 " in map [" << path
<< ']');
87 assert(valid(fileno
));
88 Slot
&s
= shared
->slots
[fileno
];
89 assert(s
.state
== Slot::Writeable
);
94 Ipc::StoreMap::abortIo(const sfileno fileno
)
96 debugs(54, 5, HERE
<< " abort I/O for slot at " << fileno
<<
97 " in map [" << path
<< ']');
98 assert(valid(fileno
));
99 Slot
&s
= shared
->slots
[fileno
];
101 // The caller is a lock holder. Thus, if we are Writeable, then the
102 // caller must be the writer; otherwise the caller must be the reader.
103 if (s
.state
== Slot::Writeable
)
104 abortWriting(fileno
);
106 closeForReading(fileno
);
109 const Ipc::StoreMap::Slot
*
110 Ipc::StoreMap::peekAtReader(const sfileno fileno
) const
112 assert(valid(fileno
));
113 const Slot
&s
= shared
->slots
[fileno
];
116 return &s
; // immediate access by lock holder so no locking
117 case Slot::Writeable
:
118 return NULL
; // cannot read the slot when it is being written
120 assert(false); // must be locked for reading or writing
122 assert(false); // not reachable
127 Ipc::StoreMap::free(const sfileno fileno
)
129 debugs(54, 5, HERE
<< " marking slot at " << fileno
<< " to be freed in"
130 " map [" << path
<< ']');
132 assert(valid(fileno
));
133 Slot
&s
= shared
->slots
[fileno
];
135 if (s
.lock
.lockExclusive())
136 freeLocked(s
, false);
138 s
.waitingToBeFreed
= true; // mark to free it later
141 const Ipc::StoreMap::Slot
*
142 Ipc::StoreMap::openForReading(const cache_key
*const key
, sfileno
&fileno
)
144 debugs(54, 5, HERE
<< " trying to open slot for key " << storeKeyText(key
)
145 << " for reading in map [" << path
<< ']');
146 const int idx
= slotIndexByKey(key
);
147 if (const Slot
*slot
= openForReadingAt(idx
)) {
148 if (slot
->sameKey(key
)) {
150 debugs(54, 5, HERE
<< " opened slot at " << fileno
<< " for key "
151 << storeKeyText(key
) << " for reading in map [" << path
<<
153 return slot
; // locked for reading
155 slot
->lock
.unlockShared();
157 debugs(54, 5, HERE
<< " failed to open slot for key " << storeKeyText(key
)
158 << " for reading in map [" << path
<< ']');
162 const Ipc::StoreMap::Slot
*
163 Ipc::StoreMap::openForReadingAt(const sfileno fileno
)
165 debugs(54, 5, HERE
<< " trying to open slot at " << fileno
<< " for "
166 "reading in map [" << path
<< ']');
167 assert(valid(fileno
));
168 Slot
&s
= shared
->slots
[fileno
];
170 if (!s
.lock
.lockShared()) {
171 debugs(54, 5, HERE
<< " failed to lock slot at " << fileno
<< " for "
172 "reading in map [" << path
<< ']');
176 if (s
.state
== Slot::Empty
) {
177 s
.lock
.unlockShared();
178 debugs(54, 7, HERE
<< " empty slot at " << fileno
<< " for "
179 "reading in map [" << path
<< ']');
183 if (s
.waitingToBeFreed
) {
184 s
.lock
.unlockShared();
185 debugs(54, 7, HERE
<< " dirty slot at " << fileno
<< " for "
186 "reading in map [" << path
<< ']');
190 // cannot be Writing here if we got shared lock and checked Empty above
191 assert(s
.state
== Slot::Readable
);
192 debugs(54, 5, HERE
<< " opened slot at " << fileno
<< " for reading in"
193 " map [" << path
<< ']');
198 Ipc::StoreMap::closeForReading(const sfileno fileno
)
200 debugs(54, 5, HERE
<< " closing slot at " << fileno
<< " for reading in "
201 "map [" << path
<< ']');
202 assert(valid(fileno
));
203 Slot
&s
= shared
->slots
[fileno
];
204 assert(s
.state
== Slot::Readable
);
205 s
.lock
.unlockShared();
209 Ipc::StoreMap::entryLimit() const
211 return shared
->limit
;
215 Ipc::StoreMap::entryCount() const
217 return shared
->count
;
221 Ipc::StoreMap::full() const
223 return entryCount() >= entryLimit();
227 Ipc::StoreMap::updateStats(ReadWriteLockStats
&stats
) const
229 for (int i
= 0; i
< shared
->limit
; ++i
)
230 shared
->slots
[i
].lock
.updateStats(stats
);
234 Ipc::StoreMap::valid(const int pos
) const
236 return 0 <= pos
&& pos
< entryLimit();
240 Ipc::StoreMap::slotIndexByKey(const cache_key
*const key
) const
242 const uint64_t *const k
= reinterpret_cast<const uint64_t *>(key
);
243 // TODO: use a better hash function
244 return (k
[0] + k
[1]) % shared
->limit
;
247 Ipc::StoreMap::Slot
&
248 Ipc::StoreMap::slotByKey(const cache_key
*const key
)
250 return shared
->slots
[slotIndexByKey(key
)];
253 /// unconditionally frees the already exclusively locked slot and releases lock
255 Ipc::StoreMap::freeLocked(Slot
&s
, bool keepLocked
)
257 if (s
.state
== Slot::Readable
&& cleaner
)
258 cleaner
->cleanReadable(&s
- shared
->slots
);
260 s
.waitingToBeFreed
= false;
261 s
.state
= Slot::Empty
;
263 s
.lock
.unlockExclusive();
265 debugs(54, 5, HERE
<< " freed slot at " << (&s
- shared
->slots
) <<
266 " in map [" << path
<< ']');
269 /* Ipc::StoreMapSlot */
271 Ipc::StoreMapSlot::StoreMapSlot(): state(Empty
)
273 xmemset(&key
, 0, sizeof(key
));
274 xmemset(&basics
, 0, sizeof(basics
));
278 Ipc::StoreMapSlot::setKey(const cache_key
*const aKey
)
280 memcpy(key
, aKey
, sizeof(key
));
284 Ipc::StoreMapSlot::sameKey(const cache_key
*const aKey
) const
286 const uint64_t *const k
= reinterpret_cast<const uint64_t *>(aKey
);
287 return k
[0] == key
[0] && k
[1] == key
[1];
291 Ipc::StoreMapSlot::set(const StoreEntry
&from
)
293 memcpy(key
, from
.key
, sizeof(key
));
294 // XXX: header = aHeader;
295 basics
.timestamp
= from
.timestamp
;
296 basics
.lastref
= from
.lastref
;
297 basics
.expires
= from
.expires
;
298 basics
.lastmod
= from
.lastmod
;
299 basics
.swap_file_sz
= from
.swap_file_sz
;
300 basics
.refcount
= from
.refcount
;
301 basics
.flags
= from
.flags
;
304 /* Ipc::StoreMap::Shared */
306 Ipc::StoreMap::Shared::Shared(const int aLimit
, const size_t anExtrasSize
):
307 limit(aLimit
), extrasSize(anExtrasSize
), count(0)
309 slots
=new Slot
[limit
];
312 Ipc::StoreMap::Shared::~Shared()
318 Ipc::StoreMap::Shared::sharedMemorySize() const
320 return SharedMemorySize(limit
, extrasSize
);
324 Ipc::StoreMap::Shared::SharedMemorySize(const int limit
, const size_t extrasSize
)
326 return sizeof(Shared
) + limit
* (sizeof(Slot
) + extrasSize
);