]> git.ipfire.org Git - thirdparty/squid.git/blame - src/MemObject.cc
Removed squid-old.h
[thirdparty/squid.git] / src / MemObject.cc
CommitLineData
528b2c61 1
2/*
262a0e14 3 * $Id$
528b2c61 4 *
5 * DEBUG: section 19 Store Memory Primitives
6 * AUTHOR: Robert Collins
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
26ac0430 24 *
528b2c61 25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
26ac0430 29 *
528b2c61 30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
582c2af2 36#include "squid.h"
3e4bebf8 37#include "comm/Connection.h"
582c2af2 38#include "Generic.h"
528b2c61 39#include "HttpReply.h"
582c2af2
FC
40#include "HttpRequest.h"
41#include "MemBuf.h"
42#include "MemObject.h"
43#include "profiler/Profiler.h"
528b2c61 44#include "Store.h"
45#include "StoreClient.h"
582c2af2
FC
46#include "protos.h"
47
9a0a18de 48#if USE_DELAY_POOLS
b67e2c8c 49#include "DelayPools.h"
50#endif
528b2c61 51
52/* TODO: make this global or private */
53#if URL_CHECKSUM_DEBUG
54static unsigned int url_checksum(const char *url);
55unsigned int
56url_checksum(const char *url)
57{
58 unsigned int ck;
c3031d67 59 SquidMD5_CTX M;
528b2c61 60 static unsigned char digest[16];
c3031d67 61 SquidMD5Init(&M);
62 SquidMD5Update(&M, (unsigned char *) url, strlen(url));
63 SquidMD5Final(digest, &M);
41d00cd3 64 memcpy(&ck, digest, sizeof(ck));
528b2c61 65 return ck;
66}
62e76326 67
528b2c61 68#endif
69
aa839030 70RemovalPolicy * mem_policy = NULL;
71
528b2c61 72size_t
73MemObject::inUseCount()
74{
9f9e06f3 75 return Pool().inUseCount();
528b2c61 76}
77
9487bae9
AR
78void
79MemObject::resetUrls(char const *aUrl, char const *aLog_url)
80{
81 safe_free(url);
82 safe_free(log_url); /* XXX account log_url */
83 log_url = xstrdup(aLog_url);
84 url = xstrdup(aUrl);
85}
86
06a5ae20 87MemObject::MemObject(char const *aUrl, char const *aLog_url)
528b2c61 88{
e85137f1 89 debugs(20, 3, HERE << "new MemObject " << this);
4a56ee8d 90 HttpReply *rep = new HttpReply;
91
6dd9f4bd 92 _reply = HTTPMSGLOCK(rep);
528b2c61 93 url = xstrdup(aUrl);
4a56ee8d 94
528b2c61 95#if URL_CHECKSUM_DEBUG
62e76326 96
528b2c61 97 chksum = url_checksum(url);
4a56ee8d 98
528b2c61 99#endif
62e76326 100
528b2c61 101 log_url = xstrdup(aLog_url);
4a56ee8d 102
528b2c61 103 object_sz = -1;
4a56ee8d 104
528b2c61 105 /* XXX account log_url */
ddc9b32c
AR
106
107 swapout.decision = SwapOut::swNeedsCheck;
528b2c61 108}
109
110MemObject::~MemObject()
111{
e85137f1 112 debugs(20, 3, HERE << "del MemObject " << this);
528b2c61 113 const Ctx ctx = ctx_enter(url);
528b2c61 114#if URL_CHECKSUM_DEBUG
62e76326 115
528b2c61 116 assert(chksum == url_checksum(url));
117#endif
62e76326 118
528b2c61 119 if (!shutting_down)
120 assert(swapout.sio == NULL);
62e76326 121
528b2c61 122 data_hdr.freeContent();
62e76326 123
9cdee68d 124#if 0
528b2c61 125 /*
126 * There is no way to abort FD-less clients, so they might
9cdee68d 127 * still have mem->clients set.
528b2c61 128 */
9cdee68d 129 assert(clients.head == NULL);
130
131#endif
62e76326 132
6dd9f4bd 133 HTTPMSGUNLOCK(_reply);
62e76326 134
6dd9f4bd 135 HTTPMSGUNLOCK(request);
62e76326 136
528b2c61 137 ctx_exit(ctx); /* must exit before we free mem->url */
62e76326 138
528b2c61 139 safe_free(url);
62e76326 140
528b2c61 141 safe_free(log_url); /* XXX account log_url */
62e76326 142
528b2c61 143 safe_free(vary_headers);
144}
145
146void
147MemObject::unlinkRequest()
148{
6dd9f4bd 149 HTTPMSGUNLOCK(request);
528b2c61 150}
151
152void
153MemObject::write ( StoreIOBuffer writeBuffer, STMCB *callback, void *callbackData)
154{
1d5161bd 155 PROF_start(MemObject_write);
4a7a3d56 156 debugs(19, 6, "memWrite: offset " << writeBuffer.offset << " len " << writeBuffer.length);
528b2c61 157
158 /* the offset is into the content, not the headers */
159 writeBuffer.offset += (_reply ? _reply->hdr_sz : 0);
160
161 /* We don't separate out mime headers yet, so ensure that the first
26ac0430 162 * write is at offset 0 - where they start
528b2c61 163 */
164 assert (data_hdr.endOffset() || writeBuffer.offset == 0);
165
166 assert (data_hdr.write (writeBuffer));
167 callback (callbackData, writeBuffer);
1d5161bd 168 PROF_stop(MemObject_write);
528b2c61 169}
170
171void
172MemObject::dump() const
173{
42a503bd 174 data_hdr.dump();
528b2c61 175#if 0
176 /* do we want this one? */
e0236918 177 debugs(20, DBG_IMPORTANT, "MemObject->data.origin_offset: " << (data_hdr.head ? data_hdr.head->nodeBuffer.offset : 0));
528b2c61 178#endif
62e76326 179
e0236918
FC
180 debugs(20, DBG_IMPORTANT, "MemObject->start_ping: " << start_ping.tv_sec << "."<< std::setfill('0') << std::setw(6) << start_ping.tv_usec);
181 debugs(20, DBG_IMPORTANT, "MemObject->inmem_hi: " << data_hdr.endOffset());
182 debugs(20, DBG_IMPORTANT, "MemObject->inmem_lo: " << inmem_lo);
183 debugs(20, DBG_IMPORTANT, "MemObject->nclients: " << nclients);
184 debugs(20, DBG_IMPORTANT, "MemObject->reply: " << _reply);
185 debugs(20, DBG_IMPORTANT, "MemObject->request: " << request);
186 debugs(20, DBG_IMPORTANT, "MemObject->log_url: " << log_url << " " << checkNullString(log_url));
528b2c61 187}
188
189HttpReply const *
190MemObject::getReply() const
191{
192 return _reply;
193}
194
4a56ee8d 195void
196MemObject::replaceHttpReply(HttpReply *newrep)
197{
6dd9f4bd 198 HTTPMSGUNLOCK(_reply);
199 _reply = HTTPMSGLOCK(newrep);
4a56ee8d 200}
201
26ac0430
AJ
202struct LowestMemReader : public unary_function<store_client, void> {
203 LowestMemReader(int64_t seed):current(seed) {}
62e76326 204
26ac0430 205 void operator() (store_client const &x) {
62e76326 206 if (x.memReaderHasLowerOffset(current))
207 current = x.copyInto.offset;
208 }
209
47f6e231 210 int64_t current;
528b2c61 211};
212
26ac0430
AJ
213struct StoreClientStats : public unary_function<store_client, void> {
214 StoreClientStats(MemBuf *anEntry):where(anEntry),index(0) {}
62e76326 215
26ac0430 216 void operator()(store_client const &x) {
aec55359
FC
217 x.dumpStats(where, index);
218 ++index;
528b2c61 219 }
62e76326 220
fcc35180 221 MemBuf *where;
528b2c61 222 size_t index;
223};
224
225void
83af6fa2 226MemObject::stat(MemBuf * mb) const
528b2c61 227{
2fe7eff9 228 mb->Printf("\t%s %s\n",
60745f24 229 RequestMethodStr(method), log_url);
83af6fa2
AJ
230 if (vary_headers)
231 mb->Printf("\tvary_headers: %s\n", vary_headers);
c91ca3ce
DK
232 mb->Printf("\tinmem_lo: %" PRId64 "\n", inmem_lo);
233 mb->Printf("\tinmem_hi: %" PRId64 "\n", data_hdr.endOffset());
234 mb->Printf("\tswapout: %" PRId64 " bytes queued\n",
47f6e231 235 swapout.queue_offset);
62e76326 236
528b2c61 237 if (swapout.sio.getRaw())
c91ca3ce 238 mb->Printf("\tswapout: %" PRId64 " bytes written\n",
47f6e231 239 (int64_t) swapout.sio->offset());
62e76326 240
fcc35180 241 StoreClientStats statsVisitor(mb);
62e76326 242
4cbb7fa8 243 for_each<StoreClientStats>(clients, statsVisitor);
528b2c61 244}
245
47f6e231 246int64_t
528b2c61 247MemObject::endOffset () const
248{
249 return data_hdr.endOffset();
250}
251
3756e5c0
AR
252void
253MemObject::markEndOfReplyHeaders()
254{
255 const int hdr_sz = endOffset();
256 assert(hdr_sz >= 0);
257 assert(_reply);
258 _reply->hdr_sz = hdr_sz;
259}
260
47f6e231 261int64_t
528b2c61 262MemObject::size() const
263{
62e76326 264 if (object_sz < 0)
265 return endOffset();
266
528b2c61 267 return object_sz;
268}
269
aa1a691e 270int64_t
9199139f
AR
271MemObject::expectedReplySize() const
272{
aa1a691e
AR
273 debugs(20, 7, HERE << "object_sz: " << object_sz);
274 if (object_sz >= 0) // complete() has been called; we know the exact answer
275 return object_sz;
276
277 if (_reply) {
278 const int64_t clen = _reply->bodySize(method);
279 debugs(20, 7, HERE << "clen: " << clen);
280 if (clen >= 0 && _reply->hdr_sz > 0) // yuck: HttpMsg sets hdr_sz to 0
281 return clen + _reply->hdr_sz;
282 }
283
284 return -1; // not enough information to predict
285}
286
528b2c61 287void
288MemObject::reset()
289{
290 assert(swapout.sio == NULL);
291 data_hdr.freeContent();
292 inmem_lo = 0;
293 /* Should we check for clients? */
294}
295
296
47f6e231 297int64_t
528b2c61 298MemObject::lowestMemReaderOffset() const
299{
300 LowestMemReader lowest (endOffset() + 1);
301
4cbb7fa8 302 for_each <LowestMemReader>(clients, lowest);
62e76326 303
528b2c61 304 return lowest.current;
305}
306
307/* XXX: This is wrong. It breaks *badly* on range combining */
308bool
309MemObject::readAheadPolicyCanRead() const
310{
47f6e231 311 return endOffset() - getReply()->hdr_sz < lowestMemReaderOffset() + Config.readAheadGap;
528b2c61 312}
313
314void
315MemObject::addClient(store_client *aClient)
316{
317 ++nclients;
318 dlinkAdd(aClient, &aClient->node, &clients);
319}
320
321#if URL_CHECKSUM_DEBUG
322void
323MemObject::checkUrlChecksum () const
324{
325 assert(chksum == url_checksum(url));
326}
62e76326 327
528b2c61 328#endif
329
330/*
331 * How much of the object data is on the disk?
332 */
47f6e231 333int64_t
528b2c61 334MemObject::objectBytesOnDisk() const
335{
336 /*
337 * NOTE: storeOffset() represents the disk file size,
338 * not the amount of object data on disk.
26ac0430 339 *
528b2c61 340 * If we don't have at least 'swap_hdr_sz' bytes
341 * then none of the object data is on disk.
342 *
343 * This should still be safe if swap_hdr_sz == 0,
344 * meaning we haven't even opened the swapout file
345 * yet.
346 */
62e76326 347
528b2c61 348 if (swapout.sio.getRaw() == NULL)
62e76326 349 return 0;
350
47f6e231 351 int64_t nwritten = swapout.sio->offset();
62e76326 352
ed013b6c 353 if (nwritten <= (int64_t)swap_hdr_sz)
62e76326 354 return 0;
355
47f6e231 356 return (nwritten - swap_hdr_sz);
528b2c61 357}
358
47f6e231 359int64_t
10aeba1d 360MemObject::policyLowestOffsetToKeep(bool swap) const
528b2c61 361{
362 /*
363 * Careful. lowest_offset can be greater than endOffset(), such
364 * as in the case of a range request.
365 */
47f6e231 366 int64_t lowest_offset = lowestMemReaderOffset();
62e76326 367
528b2c61 368 if (endOffset() < lowest_offset ||
ff4b33f4 369 endOffset() - inmem_lo > (int64_t)Config.Store.maxInMemObjSize ||
10aeba1d 370 (swap && !Config.onoff.memory_cache_first))
62e76326 371 return lowest_offset;
372
528b2c61 373 return inmem_lo;
374}
375
376void
377MemObject::trimSwappable()
378{
10aeba1d 379 int64_t new_mem_lo = policyLowestOffsetToKeep(1);
528b2c61 380 /*
381 * We should only free up to what we know has been written
382 * to disk, not what has been queued for writing. Otherwise
383 * there will be a chunk of the data which is not in memory
384 * and is not yet on disk.
385 * The -1 makes sure the page isn't freed until storeSwapOut has
aa1a691e 386 * walked to the next page.
528b2c61 387 */
47f6e231 388 int64_t on_disk;
62e76326 389
528b2c61 390 if ((on_disk = objectBytesOnDisk()) - 1 < new_mem_lo)
62e76326 391 new_mem_lo = on_disk - 1;
392
528b2c61 393 if (new_mem_lo == -1)
62e76326 394 new_mem_lo = 0; /* the above might become -1 */
395
528b2c61 396 data_hdr.freeDataUpto(new_mem_lo);
62e76326 397
528b2c61 398 inmem_lo = new_mem_lo;
399}
400
401void
402MemObject::trimUnSwappable()
403{
10aeba1d 404 int64_t new_mem_lo = policyLowestOffsetToKeep(0);
528b2c61 405 assert (new_mem_lo > 0);
406
407 data_hdr.freeDataUpto(new_mem_lo);
408 inmem_lo = new_mem_lo;
409}
410
411
412bool
413MemObject::isContiguous() const
414{
47f6e231 415 bool result = data_hdr.hasContigousContentRange (Range<int64_t>(inmem_lo, endOffset()));
528b2c61 416 /* XXX : make this higher level */
bf8fe701 417 debugs (19, result ? 4 :3, "MemObject::isContiguous: Returning " << (result ? "true" : "false"));
528b2c61 418 return result;
419}
b67e2c8c 420
421int
384a7590 422MemObject::mostBytesWanted(int max, bool ignoreDelayPools) const
b67e2c8c 423{
9a0a18de 424#if USE_DELAY_POOLS
384a7590
JP
425 if (!ignoreDelayPools) {
426 /* identify delay id with largest allowance */
427 DelayId largestAllowance = mostBytesAllowed ();
428 return largestAllowance.bytesWanted(0, max);
429 }
430#endif
62e76326 431
b67e2c8c 432 return max;
b67e2c8c 433}
434
a46d2c0e 435void
436MemObject::setNoDelay(bool const newValue)
437{
9a0a18de 438#if USE_DELAY_POOLS
a46d2c0e 439
440 for (dlink_node *node = clients.head; node; node = node->next) {
441 store_client *sc = (store_client *) node->data;
442 sc->delayId.setNoDelay(newValue);
443 }
444
445#endif
446}
447
448void
449MemObject::delayRead(DeferredRead const &aRead)
450{
451 deferredReads.delayRead(aRead);
452}
453
454void
455MemObject::kickReads()
456{
457 deferredReads.kickReads(-1);
458}
459
9a0a18de 460#if USE_DELAY_POOLS
b67e2c8c 461DelayId
462MemObject::mostBytesAllowed() const
463{
464 int j;
465 int jmax = -1;
466 DelayId result;
62e76326 467
b67e2c8c 468 for (dlink_node *node = clients.head; node; node = node->next) {
62e76326 469 store_client *sc = (store_client *) node->data;
d576a6a6 470#if 0
62e76326 471 /* This test is invalid because the client may be writing data
472 * and thus will want data immediately.
473 * If we include the test, there is a race condition when too much
474 * data is read - if all sc's are writing when a read is scheduled.
475 * XXX: fixme.
476 */
477
478 if (!sc->callbackPending())
479 /* not waiting for more data */
480 continue;
481
d576a6a6 482#endif
62e76326 483
62e76326 484 j = sc->delayId.bytesWanted(0, sc->copyInto.length);
485
486 if (j > jmax) {
487 jmax = j;
488 result = sc->delayId;
489 }
b67e2c8c 490 }
62e76326 491
b67e2c8c 492 return result;
493}
62e76326 494
b67e2c8c 495#endif
5b55f1f1
CT
496
497int64_t
498MemObject::availableForSwapOut() const
499{
500 return endOffset() - swapout.queue_offset;
501}