]> git.ipfire.org Git - thirdparty/squid.git/blame - src/MemStore.cc
Added RunnersRegistry, an API to register and, later, run a group of actions.
[thirdparty/squid.git] / src / MemStore.cc
CommitLineData
9487bae9
AR
1/*
2 * $Id$
3 *
4 * DEBUG: section 20 Memory Cache
5 *
6 */
7
8#include "config.h"
9#include "ipc/mem/Page.h"
10#include "ipc/mem/Pages.h"
11#include "MemObject.h"
12#include "MemStore.h"
13#include "HttpReply.h"
14
15
16// XXX: support storage using more than one page per entry
17
18
19MemStore::MemStore(): map(NULL)
20{
21}
22
23MemStore::~MemStore()
24{
25 delete map;
26}
27
28void
29MemStore::init()
30{
31 if (!map && Config.memMaxSize && (!UsingSmp() || IamWorkerProcess())) {
32 // TODO: warn if we cannot support the configured maximum entry size
33 const int64_t entrySize = Ipc::Mem::PageSize(); // for now
34 const int64_t entryCount = Config.memMaxSize / entrySize;
35 // TODO: warn if we cannot cache at least one item (misconfiguration)
7f6748c8 36 if (entryCount > 0) {
9487bae9 37 map = new MemStoreMap("cache_mem", entryCount);
7f6748c8
AR
38 map->cleaner = this;
39 }
9487bae9
AR
40 }
41}
42
43void
c4e688b7 44MemStore::stat(StoreEntry &e) const
9487bae9 45{
c4e688b7
AR
46 storeAppendPrintf(&e, "\n\nShared Memory Cache\n");
47
48 storeAppendPrintf(&e, "Maximum Size: %.0f KB\n", Config.memMaxSize/1024.0);
49
50 if (map) {
51 const int limit = map->entryLimit();
52 storeAppendPrintf(&e, "Maximum entries: %9d\n", limit);
53 if (limit > 0) {
54 const int entryCount = map->entryCount();
55 storeAppendPrintf(&e, "Current entries: %9d %.2f%%\n",
56 entryCount, (100.0 * entryCount / limit));
57
58 if (limit < 100) { // XXX: otherwise too expensive to count
59 Ipc::ReadWriteLockStats stats;
60 map->updateStats(stats);
61 stats.dump(e);
62 }
63 }
64 }
9487bae9
AR
65}
66
67void
68MemStore::maintain()
69{
70}
71
72uint64_t
73MemStore::minSize() const
74{
75 return 0; // XXX: irrelevant, but Store parent forces us to implement this
76}
77
78uint64_t
79MemStore::maxSize() const
80{
81 return 0; // XXX: make configurable
82}
83
84void
85MemStore::updateSize(int64_t eSize, int sign)
86{
87 // XXX: irrelevant, but Store parent forces us to implement this
88 fatal("MemStore::updateSize should not be called");
89}
90
91void
92MemStore::reference(StoreEntry &)
93{
94}
95
96void
97MemStore::dereference(StoreEntry &)
98{
99}
100
101int
102MemStore::callback()
103{
104 return 0;
105}
106
107StoreSearch *
108MemStore::search(String const, HttpRequest *)
109{
110 fatal("not implemented");
111 return NULL;
112}
113
114StoreEntry *
115MemStore::get(const cache_key *key)
116{
117 if (!map)
118 return NULL;
119
120 // XXX: replace sfileno with a bigger word (sfileno is only for cache_dirs)
121 sfileno index;
122 const Ipc::StoreMapSlot *const slot = map->openForReading(key, index);
123 if (!slot)
124 return NULL;
125
126 const Ipc::StoreMapSlot::Basics &basics = slot->basics;
127 const MemStoreMap::Extras &extras = map->extras(index);
128
129 // create a brand new store entry and initialize it with stored info
130 StoreEntry *e = new StoreEntry();
131 e->lock_count = 0;
132
133 e->swap_file_sz = basics.swap_file_sz;
134 e->lastref = basics.lastref;
135 e->timestamp = basics.timestamp;
136 e->expires = basics.expires;
137 e->lastmod = basics.lastmod;
138 e->refcount = basics.refcount;
139 e->flags = basics.flags;
140
141 e->store_status = STORE_OK;
142 e->mem_status = IN_MEMORY; // setMemStatus(IN_MEMORY) requires mem_obj
143 //e->swap_status = set in StoreEntry constructor to SWAPOUT_NONE;
144 e->ping_status = PING_NONE;
145
146 EBIT_SET(e->flags, ENTRY_CACHABLE);
147 EBIT_CLR(e->flags, RELEASE_REQUEST);
148 EBIT_CLR(e->flags, KEY_PRIVATE);
149 EBIT_SET(e->flags, ENTRY_VALIDATED);
150
151 const bool copied = copyFromShm(*e, extras);
152
153 // we copied everything we could to local memory; no more need to lock
154 map->closeForReading(index);
155
156 if (copied) {
157 e->hashInsert(key);
158 return e;
159 }
160
161 debugs(20, 3, HERE << "mem-loading failed; freeing " << index);
162 map->free(index); // do not let others into the same trap
163 return NULL;
164}
165
166void
167MemStore::get(String const key, STOREGETCLIENT aCallback, void *aCallbackData)
168{
169 // XXX: not needed but Store parent forces us to implement this
170 fatal("MemStore::get(key,callback,data) should not be called");
171}
172
173bool
174MemStore::copyFromShm(StoreEntry &e, const MemStoreMap::Extras &extras)
175{
176 const Ipc::Mem::PageId &page = extras.page;
177
178 StoreIOBuffer sourceBuf(extras.storedSize, 0,
179 static_cast<char*>(PagePointer(page)));
180
181 // XXX: We do not know the URLs yet, only the key, but we need to parse and
182 // store the response for the Root().get() callers to be happy because they
183 // expect IN_MEMORY entries to already have the response headers and body.
184 // At least one caller calls createMemObject() if there is not one, so
185 // we hide the true object until that happens (to avoid leaking TBD URLs).
186 e.createMemObject("TBD", "TBD");
187
188 // emulate the usual Store code but w/o inapplicable checks and callbacks:
189
190 // from store_client::readBody():
191 HttpReply *rep = (HttpReply *)e.getReply();
192 const ssize_t end = headersEnd(sourceBuf.data, sourceBuf.length);
193 if (!rep->parseCharBuf(sourceBuf.data, end)) {
194 debugs(20, DBG_IMPORTANT, "Could not parse mem-cached headers: " << e);
195 return false;
196 }
197 // local memory stores both headers and body
198 e.mem_obj->object_sz = sourceBuf.length; // from StoreEntry::complete()
199
200 storeGetMemSpace(sourceBuf.length); // from StoreEntry::write()
201
202 assert(e.mem_obj->data_hdr.write(sourceBuf)); // from MemObject::write()
203 const int64_t written = e.mem_obj->endOffset();
30204d23
AR
204 // we should write all because StoreEntry::write() never fails
205 assert(written >= 0 &&
206 static_cast<size_t>(written) == sourceBuf.length);
9487bae9
AR
207 // would be nice to call validLength() here, but it needs e.key
208
209 debugs(20, 7, HERE << "mem-loaded all " << written << " bytes of " << e <<
210 " from " << page);
211
212 e.hideMemObject();
213
214 return true;
215}
216
217void
218MemStore::considerKeeping(StoreEntry &e)
219{
220 if (!e.memoryCachable()) {
221 debugs(20, 7, HERE << "Not memory cachable: " << e);
222 return; // cannot keep due to entry state or properties
223 }
224
225 assert(e.mem_obj);
226 if (!willFit(e.mem_obj->endOffset())) {
227 debugs(20, 5, HERE << "No mem-cache space for " << e);
228 return; // failed to free enough space
229 }
230
231 keep(e); // may still fail
232}
233
234bool
235MemStore::willFit(int64_t need)
236{
237 // TODO: obey configured maximum entry size (with page-based rounding)
30204d23 238 return need <= static_cast<int64_t>(Ipc::Mem::PageSize());
9487bae9
AR
239}
240
241/// allocates map slot and calls copyToShm to store the entry in shared memory
242void
243MemStore::keep(StoreEntry &e)
244{
245 if (!map) {
246 debugs(20, 5, HERE << "No map to mem-cache " << e);
247 return;
248 }
249
250 sfileno index = 0;
251 Ipc::StoreMapSlot *slot = map->openForWriting(reinterpret_cast<const cache_key *>(e.key), index);
252 if (!slot) {
253 debugs(20, 5, HERE << "No room in mem-cache map to index " << e);
254 return;
255 }
256
257 MemStoreMap::Extras &extras = map->extras(index);
258 if (copyToShm(e, extras)) {
259 slot->set(e);
260 map->closeForWriting(index, false);
261 } else {
262 map->abortIo(index);
263 }
264}
265
266/// uses mem_hdr::copy() to copy local data to shared memory
267bool
268MemStore::copyToShm(StoreEntry &e, MemStoreMap::Extras &extras)
269{
270 Ipc::Mem::PageId page;
271 if (!Ipc::Mem::GetPage(page)) {
272 debugs(20, 5, HERE << "No mem-cache page for " << e);
273 return false; // GetPage is responsible for any cleanup on failures
274 }
275
276 const int64_t bufSize = Ipc::Mem::PageSize();
277 const int64_t eSize = e.mem_obj->endOffset();
278
279 StoreIOBuffer sharedSpace(bufSize, 0,
280 static_cast<char*>(PagePointer(page)));
281
282 // check that we kept everything or purge incomplete/sparse cached entry
283 const ssize_t copied = e.mem_obj->data_hdr.copy(sharedSpace);
284 if (eSize != copied) {
285 debugs(20, 2, HERE << "Failed to mem-cache " << e << ": " <<
286 eSize << "!=" << copied);
287 // cleanup
288 PutPage(page);
289 return false;
290 }
291
292 debugs(20, 7, HERE << "mem-cached all " << eSize << " bytes of " << e <<
293 " in " << page);
294
295 // remember storage location and size
296 extras.page = page;
297 extras.storedSize = copied;
298 return true;
299}
7f6748c8
AR
300
301void
302MemStore::cleanReadable(const sfileno fileno)
303{
304 Ipc::Mem::PutPage(map->extras(fileno).page);
305}
306