]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store.cc
Correct buffer calculation for snprintf
[thirdparty/squid.git] / src / store.cc
CommitLineData
164f7660 1
30a4f2a8 2/*
262a0e14 3 * $Id$
30a4f2a8 4 *
8638fc66 5 * DEBUG: section 20 Storage Manager
30a4f2a8 6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 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.
30a4f2a8 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 *
30a4f2a8 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 *
30a4f2a8 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
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
c943f331 34 */
090089c4 35
f09f5b26 36#include "squid.h"
a553a5a3 37#include "event.h"
04f55905 38#include "fde.h"
e6ccf245 39#include "Store.h"
62ee09ca 40#include "CacheManager.h"
e6ccf245 41#include "StoreClient.h"
528b2c61 42#include "stmem.h"
43#include "HttpReply.h"
44#include "HttpRequest.h"
45#include "MemObject.h"
46#include "mem_node.h"
47#include "StoreMeta.h"
d3b3ab85 48#include "SwapDir.h"
b67e2c8c 49#if DELAY_POOLS
50#include "DelayPools.h"
51#endif
91caca83 52#include "Stack.h"
985c86bc 53#include "SquidTime.h"
4b981814 54#include "swap_log_op.h"
090089c4 55
528b2c61 56static STMCB storeWriteComplete;
57
090089c4 58#define REBUILD_TIMESTAMP_DELTA_MAX 2
227fbb74 59
c21ad0f5 60#define STORE_IN_MEM_BUCKETS (229)
090089c4 61
4b981814
AJ
62
63/** \todo Convert these string constants to enum string-arrays generated */
64
26ac0430
AJ
65const char *memStatusStr[] = {
66 "NOT_IN_MEMORY",
67 "IN_MEMORY"
68};
69
70const char *pingStatusStr[] = {
71 "PING_NONE",
72 "PING_WAITING",
73 "PING_DONE"
74};
75
76const char *storeStatusStr[] = {
77 "STORE_OK",
78 "STORE_PENDING"
79};
80
81const char *swapStatusStr[] = {
82 "SWAPOUT_NONE",
83 "SWAPOUT_WRITING",
84 "SWAPOUT_DONE"
85};
9dfb6c1c 86
65a53c8e 87extern OBJH storeIOStats;
88
25b6a907 89
90/*
91 * This defines an repl type
92 */
93
94typedef struct _storerepl_entry storerepl_entry_t;
95
26ac0430 96struct _storerepl_entry {
25b6a907 97 const char *typestr;
98 REMOVALPOLICYCREATE *create;
99};
100
101static storerepl_entry_t *storerepl_list = NULL;
102
103
e3ef2b09 104/*
105 * local function prototypes
106 */
007b8be4 107static int getKeyCounter(void);
8423ff74 108static OBJH storeCheckCachableStats;
e42d5181 109static EVH storeLateRelease;
a21fbb54 110
e3ef2b09 111/*
112 * local variables
113 */
91caca83 114static Stack<StoreEntry*> LateReleaseStack;
04eb0689 115MemAllocator *StoreEntry::pool = NULL;
e6ccf245 116
c8f4eac4 117StorePointer Store::CurrentRoot = NULL;
118
119void
120Store::Root(Store * aRoot)
121{
122 CurrentRoot = aRoot;
123}
124
125void
126Store::Root(StorePointer aRoot)
127{
128 Root(aRoot.getRaw());
129}
130
131void
132Store::Stats(StoreEntry * output)
133{
134 assert (output);
135 Root().stat(*output);
136}
137
138void
139Store::create()
140{}
141
142void
143Store::diskFull()
144{}
145
146void
147Store::sync()
148{}
149
150void
151Store::unlink (StoreEntry &anEntry)
152{
153 fatal("Store::unlink on invalid Store\n");
154}
155
e6ccf245 156void *
3b13a8fd 157StoreEntry::operator new (size_t bytecount)
e6ccf245 158{
3b13a8fd 159 assert (bytecount == sizeof (StoreEntry));
62e76326 160
e6ccf245 161 if (!pool) {
04eb0689 162 pool = memPoolCreate ("StoreEntry", bytecount);
b001e822 163 pool->setChunkSize(2048 * 1024);
e6ccf245 164 }
62e76326 165
b001e822 166 return pool->alloc();
e6ccf245 167}
168
169void
3b13a8fd 170StoreEntry::operator delete (void *address)
e6ccf245 171{
b001e822 172 pool->free(address);
e6ccf245 173}
174
5ed72359 175void
176StoreEntry::makePublic()
177{
178 /* This object can be cached for a long time */
179
180 if (EBIT_TEST(flags, ENTRY_CACHABLE))
d88e3c49 181 setPublicKey();
5ed72359 182}
183
184void
185StoreEntry::makePrivate()
186{
187 /* This object should never be cached at all */
d88e3c49 188 expireNow();
189 releaseRequest(); /* delete object when not used */
190 /* releaseRequest clears ENTRY_CACHABLE flag */
5ed72359 191}
192
193void
194StoreEntry::cacheNegatively()
195{
196 /* This object may be negatively cached */
d88e3c49 197 negativeCache();
5ed72359 198
199 if (EBIT_TEST(flags, ENTRY_CACHABLE))
d88e3c49 200 setPublicKey();
5ed72359 201}
202
e6ccf245 203size_t
3b13a8fd 204StoreEntry::inUseCount()
e6ccf245 205{
206 if (!pool)
62e76326 207 return 0;
9f9e06f3 208 return pool->getInUseCount();
e6ccf245 209}
210
332dafa2 211const char *
3b13a8fd 212StoreEntry::getMD5Text() const
332dafa2 213{
214 return storeKeyText((const cache_key *)key);
215}
216
a46d2c0e 217#include "comm.h"
218
219void
220StoreEntry::DeferReader(void *theContext, CommRead const &aRead)
e6ccf245 221{
a46d2c0e 222 StoreEntry *anEntry = (StoreEntry *)theContext;
223 anEntry->delayAwareRead(aRead.fd,
224 aRead.buf,
225 aRead.len,
65517dc8 226 aRead.callback);
e6ccf245 227}
66cedb85 228
a46d2c0e 229void
65517dc8 230StoreEntry::delayAwareRead(int fd, char *buf, int len, AsyncCall::Pointer callback)
a46d2c0e 231{
232 size_t amountToRead = bytesWanted(Range<size_t>(0, len));
233 /* sketch: readdeferer* = getdeferer.
65517dc8 234 * ->deferRead (fd, buf, len, callback, DelayAwareRead, this)
a46d2c0e 235 */
236
237 if (amountToRead == 0) {
238 assert (mem_obj);
239 /* read ahead limit */
240 /* Perhaps these two calls should both live in MemObject */
a5f42284 241#if DELAY_POOLS
a46d2c0e 242
243 if (!mem_obj->readAheadPolicyCanRead()) {
a5f42284 244#endif
65517dc8 245 mem_obj->delayRead(DeferredRead(DeferReader, this, CommRead(fd, buf, len, callback)));
a46d2c0e 246 return;
a5f42284 247#if DELAY_POOLS
248
a46d2c0e 249 }
250
251 /* delay id limit */
65517dc8 252 mem_obj->mostBytesAllowed().delayRead(DeferredRead(DeferReader, this, CommRead(fd, buf, len, callback)));
a46d2c0e 253
254 return;
a5f42284 255
256#endif
257
a46d2c0e 258 }
259
65517dc8 260 comm_read(fd, buf, amountToRead, callback);
a46d2c0e 261}
262
263size_t
264StoreEntry::bytesWanted (Range<size_t> const aRange) const
528b2c61 265{
a46d2c0e 266 assert (aRange.size());
62e76326 267
528b2c61 268 if (mem_obj == NULL)
a46d2c0e 269 return aRange.end - 1;
62e76326 270
bc87dc25 271#if URL_CHECKSUM_DEBUG
62e76326 272
528b2c61 273 mem_obj->checkUrlChecksum();
62e76326 274
528b2c61 275#endif
62e76326 276
a46d2c0e 277 /* Always read *something* here - we haven't got the header yet */
278 if (EBIT_TEST(flags, ENTRY_FWD_HDR_WAIT))
279 return aRange.end - 1;
62e76326 280
a46d2c0e 281 if (!mem_obj->readAheadPolicyCanRead())
282 return 0;
62e76326 283
a46d2c0e 284 return mem_obj->mostBytesWanted(aRange.end - 1);
285}
62e76326 286
a46d2c0e 287bool
288StoreEntry::checkDeferRead(int fd) const
289{
290 return (bytesWanted(Range<size_t>(0,INT_MAX)) == 0);
291}
62e76326 292
a46d2c0e 293void
294StoreEntry::setNoDelay (bool const newValue)
295{
296 if (mem_obj)
297 mem_obj->setNoDelay(newValue);
528b2c61 298}
bc87dc25 299
528b2c61 300store_client_t
301StoreEntry::storeClientType() const
227fbb74 302{
7d31d5fa 303 /* The needed offset isn't in memory
304 * XXX TODO: this is wrong for range requests
305 * as the needed offset may *not* be 0, AND
306 * offset 0 in the memory object is the HTTP headers.
307 */
308
528b2c61 309 if (mem_obj->inmem_lo)
62e76326 310 return STORE_DISK_CLIENT;
311
528b2c61 312 if (EBIT_TEST(flags, ENTRY_ABORTED)) {
62e76326 313 /* I don't think we should be adding clients to aborted entries */
bf8fe701 314 debugs(20, 1, "storeClientType: adding to ENTRY_ABORTED entry");
62e76326 315 return STORE_MEM_CLIENT;
528b2c61 316 }
62e76326 317
528b2c61 318 if (store_status == STORE_OK) {
7d31d5fa 319 /* the object has completed. */
320
344a9006 321 if (mem_obj->inmem_lo == 0 && !isEmpty()) {
47ce0a58 322 if (swap_status == SWAPOUT_DONE) {
e1381638
AJ
323 if (mem_obj->endOffset() == mem_obj->object_sz) {
324 /* hot object fully swapped in */
325 return STORE_MEM_CLIENT;
326 }
47ce0a58 327 } else {
e1381638
AJ
328 /* Memory-only, or currently being swapped out */
329 return STORE_MEM_CLIENT;
47ce0a58
HN
330 }
331 }
332 return STORE_DISK_CLIENT;
528b2c61 333 }
62e76326 334
528b2c61 335 /* here and past, entry is STORE_PENDING */
336 /*
337 * If this is the first client, let it be the mem client
338 */
339 if (mem_obj->nclients == 1)
62e76326 340 return STORE_MEM_CLIENT;
341
528b2c61 342 /*
343 * If there is no disk file to open yet, we must make this a
344 * mem client. If we can't open the swapin file before writing
345 * to the client, there is no guarantee that we will be able
346 * to open it later when we really need it.
347 */
348 if (swap_status == SWAPOUT_NONE)
62e76326 349 return STORE_MEM_CLIENT;
350
528b2c61 351 /*
352 * otherwise, make subsequent clients read from disk so they
353 * can not delay the first, and vice-versa.
354 */
355 return STORE_DISK_CLIENT;
227fbb74 356}
357
c8f4eac4 358StoreEntry::StoreEntry()
090089c4 359{
59dbbc5c 360 debugs(20, 3, HERE << "new StoreEntry " << this);
c8f4eac4 361 mem_obj = NULL;
62e76326 362
c8f4eac4 363 expires = lastmod = lastref = timestamp = -1;
62e76326 364
c8f4eac4 365 swap_filen = -1;
366 swap_dirn = -1;
367}
62e76326 368
d5f8d05f 369StoreEntry::StoreEntry(const char *aUrl, const char *aLogUrl)
c8f4eac4 370{
59dbbc5c 371 debugs(20, 3, HERE << "new StoreEntry " << this);
d5f8d05f 372 mem_obj = new MemObject(aUrl, aLogUrl);
62e76326 373
c8f4eac4 374 expires = lastmod = lastref = timestamp = -1;
375
376 swap_filen = -1;
377 swap_dirn = -1;
090089c4 378}
379
3900307b 380void
381StoreEntry::destroyMemObject()
090089c4 382{
3900307b 383 debugs(20, 3, HERE << "destroyMemObject " << mem_obj);
384 setMemStatus(NOT_IN_MEMORY);
385 MemObject *mem = mem_obj;
386 mem_obj = NULL;
528b2c61 387 delete mem;
090089c4 388}
389
c8f4eac4 390void
528b2c61 391destroyStoreEntry(void *data)
090089c4 392{
59dbbc5c 393 debugs(20, 3, HERE << "destroyStoreEntry: destroying " << data);
c8f4eac4 394 StoreEntry *e = static_cast<StoreEntry *>(static_cast<hash_link *>(data));
9e975e4e 395 assert(e != NULL);
62e76326 396
e6ccf245 397 if (e == NullStoreEntry::getInstance())
62e76326 398 return;
399
3900307b 400 e->destroyMemObject();
62e76326 401
3900307b 402 e->hashDelete();
62e76326 403
332dafa2 404 assert(e->key == NULL);
62e76326 405
e6ccf245 406 delete e;
227fbb74 407}
090089c4 408
090089c4 409/* ----- INTERFACE BETWEEN STORAGE MANAGER AND HASH TABLE FUNCTIONS --------- */
410
f09f5b26 411void
3900307b 412StoreEntry::hashInsert(const cache_key * someKey)
090089c4 413{
bf8fe701 414 debugs(20, 3, "StoreEntry::hashInsert: Inserting Entry " << this << " key '" << storeKeyText(someKey) << "'");
3900307b 415 key = storeKeyDup(someKey);
416 hash_join(store_table, this);
090089c4 417}
418
3900307b 419void
420StoreEntry::hashDelete()
090089c4 421{
3900307b 422 hash_remove_link(store_table, this);
423 storeKeyFree((const cache_key *)key);
424 key = NULL;
090089c4 425}
426
090089c4 427/* -------------------------------------------------------------------------- */
428
090089c4 429
430/* get rid of memory copy of the object */
d88e3c49 431void
432StoreEntry::purgeMem()
090089c4 433{
d88e3c49 434 if (mem_obj == NULL)
62e76326 435 return;
436
bf8fe701 437 debugs(20, 3, "StoreEntry::purgeMem: Freeing memory-copy of " << getMD5Text());
62e76326 438
3900307b 439 destroyMemObject();
62e76326 440
d88e3c49 441 if (swap_status != SWAPOUT_DONE)
442 release();
090089c4 443}
444
c8f4eac4 445/* RBC 20050104 this is wrong- memory ref counting
446 * is not at all equivalent to the store 'usage' concept
447 * which the replacement policies should be acting upon.
448 * specifically, object iteration within stores needs
449 * memory ref counting to prevent race conditions,
450 * but this should not influence store replacement.
451 */
6a566b9c 452void
c21ad0f5 453
454StoreEntry::lock()
6a566b9c 455{
c21ad0f5 456 lock_count++;
34266cde 457 debugs(20, 3, "StoreEntry::lock: key '" << getMD5Text() <<"' count=" <<
bf8fe701 458 lock_count );
c21ad0f5 459 lastref = squid_curtime;
460 Store::Root().reference(*this);
090089c4 461}
462
43ae1d95 463void
464StoreEntry::setReleaseFlag()
465{
466 if (EBIT_TEST(flags, RELEASE_REQUEST))
467 return;
468
bf8fe701 469 debugs(20, 3, "StoreEntry::setReleaseFlag: '" << getMD5Text() << "'");
43ae1d95 470
471 EBIT_SET(flags, RELEASE_REQUEST);
472}
473
b8d8561b 474void
d88e3c49 475StoreEntry::releaseRequest()
2285407f 476{
d88e3c49 477 if (EBIT_TEST(flags, RELEASE_REQUEST))
62e76326 478 return;
479
d88e3c49 480 setReleaseFlag();
62e76326 481
f3e570e9 482 /*
483 * Clear cachable flag here because we might get called before
484 * anyone else even looks at the cachability flag. Also, this
485 * prevents httpMakePublic from really setting a public key.
486 */
d88e3c49 487 EBIT_CLR(flags, ENTRY_CACHABLE);
62e76326 488
d88e3c49 489 setPrivateKey();
2285407f 490}
491
090089c4 492/* unlock object, return -1 if object get released after unlock
493 * otherwise lock_count */
b8d8561b 494int
c21ad0f5 495StoreEntry::unlock()
090089c4 496{
c21ad0f5 497 lock_count--;
bf8fe701 498 debugs(20, 3, "StoreEntry::unlock: key '" << getMD5Text() << "' count=" << lock_count);
62e76326 499
c21ad0f5 500 if (lock_count)
501 return (int) lock_count;
62e76326 502
c21ad0f5 503 if (store_status == STORE_PENDING)
504 setReleaseFlag();
62e76326 505
c21ad0f5 506 assert(storePendingNClients(this) == 0);
62e76326 507
c21ad0f5 508 if (EBIT_TEST(flags, RELEASE_REQUEST))
5f33b71d 509 this->release();
3900307b 510 else if (keepInMemory()) {
c21ad0f5 511 Store::Root().dereference(*this);
3900307b 512 setMemStatus(IN_MEMORY);
c21ad0f5 513 mem_obj->unlinkRequest();
66f07209 514 } else {
c21ad0f5 515 Store::Root().dereference(*this);
62e76326 516
c21ad0f5 517 if (EBIT_TEST(flags, KEY_PRIVATE))
bf8fe701 518 debugs(20, 1, "WARNING: " << __FILE__ << ":" << __LINE__ << ": found KEY_PRIVATE");
42fc2858 519
d88e3c49 520 /* StoreEntry::purgeMem may free e */
521 purgeMem();
66f07209 522 }
62e76326 523
6c895381 524 return 0;
090089c4 525}
526
e6ccf245 527void
60745f24 528StoreEntry::getPublicByRequestMethod (StoreClient *aClient, HttpRequest * request, const HttpRequestMethod& method)
e6ccf245 529{
530 assert (aClient);
3b13a8fd 531 StoreEntry *result = storeGetPublicByRequestMethod( request, method);
62e76326 532
e6ccf245 533 if (!result)
62e76326 534 aClient->created (NullStoreEntry::getInstance());
e6ccf245 535 else
62e76326 536 aClient->created (result);
e6ccf245 537}
538
539void
190154cf 540StoreEntry::getPublicByRequest (StoreClient *aClient, HttpRequest * request)
e6ccf245 541{
542 assert (aClient);
3b13a8fd 543 StoreEntry *result = storeGetPublicByRequest (request);
62e76326 544
e6ccf245 545 if (!result)
62e76326 546 result = NullStoreEntry::getInstance();
547
e6ccf245 548 aClient->created (result);
549}
550
551void
60745f24 552StoreEntry::getPublic (StoreClient *aClient, const char *uri, const HttpRequestMethod& method)
e6ccf245 553{
554 assert (aClient);
3b13a8fd 555 StoreEntry *result = storeGetPublic (uri, method);
62e76326 556
e6ccf245 557 if (!result)
62e76326 558 result = NullStoreEntry::getInstance();
559
e6ccf245 560 aClient->created (result);
561}
562
08e5d64f 563StoreEntry *
60745f24 564storeGetPublic(const char *uri, const HttpRequestMethod& method)
08e5d64f 565{
c8f4eac4 566 return Store::Root().get(storeKeyPublic(uri, method));
08e5d64f 567}
568
f66a9ef4 569StoreEntry *
60745f24 570storeGetPublicByRequestMethod(HttpRequest * req, const HttpRequestMethod& method)
f66a9ef4 571{
c8f4eac4 572 return Store::Root().get(storeKeyPublicByRequestMethod(req, method));
f66a9ef4 573}
574
575StoreEntry *
190154cf 576storeGetPublicByRequest(HttpRequest * req)
f66a9ef4 577{
578 StoreEntry *e = storeGetPublicByRequestMethod(req, req->method);
62e76326 579
f66a9ef4 580 if (e == NULL && req->method == METHOD_HEAD)
62e76326 581 /* We can generate a HEAD reply from a cached GET object */
582 e = storeGetPublicByRequestMethod(req, METHOD_GET);
583
f66a9ef4 584 return e;
585}
586
007b8be4 587static int
588getKeyCounter(void)
04e8dbaa 589{
007b8be4 590 static int key_counter = 0;
62e76326 591
007b8be4 592 if (++key_counter < 0)
62e76326 593 key_counter = 1;
594
007b8be4 595 return key_counter;
04e8dbaa 596}
597
c8f4eac4 598/* RBC 20050104 AFAICT this should become simpler:
599 * rather than reinserting with a special key it should be marked
600 * as 'released' and then cleaned up when refcounting indicates.
601 * the StoreHashIndex could well implement its 'released' in the
602 * current manner.
603 * Also, clean log writing should skip over ia,t
604 * Otherwise, we need a 'remove from the index but not the store
605 * concept'.
606 */
6c57e268 607void
d88e3c49 608StoreEntry::setPrivateKey()
227fbb74 609{
9fb13bb6 610 const cache_key *newkey;
62e76326 611
d88e3c49 612 if (key && EBIT_TEST(flags, KEY_PRIVATE))
c21ad0f5 613 return; /* is already private */
62e76326 614
d88e3c49 615 if (key) {
616 if (swap_filen > -1)
617 storeDirSwapLog(this, SWAP_LOG_DEL);
62e76326 618
3900307b 619 hashDelete();
b109de6b 620 }
62e76326 621
d88e3c49 622 if (mem_obj != NULL) {
623 mem_obj->id = getKeyCounter();
624 newkey = storeKeyPrivate(mem_obj->url, mem_obj->method, mem_obj->id);
9fb13bb6 625 } else {
62e76326 626 newkey = storeKeyPrivate("JUNK", METHOD_NONE, getKeyCounter());
9fb13bb6 627 }
62e76326 628
9fb13bb6 629 assert(hash_lookup(store_table, newkey) == NULL);
d88e3c49 630 EBIT_SET(flags, KEY_PRIVATE);
3900307b 631 hashInsert(newkey);
227fbb74 632}
633
b8d8561b 634void
d88e3c49 635StoreEntry::setPublicKey()
227fbb74 636{
6eb42cae 637 StoreEntry *e2 = NULL;
9fb13bb6 638 const cache_key *newkey;
62e76326 639
d88e3c49 640 if (key && !EBIT_TEST(flags, KEY_PRIVATE))
c21ad0f5 641 return; /* is already public */
62e76326 642
d88e3c49 643 assert(mem_obj);
62e76326 644
f3e570e9 645 /*
646 * We can't make RELEASE_REQUEST objects public. Depending on
647 * when RELEASE_REQUEST gets set, we might not be swapping out
648 * the object. If we're not swapping out, then subsequent
649 * store clients won't be able to access object data which has
650 * been freed from memory.
d87ebd78 651 *
652 * If RELEASE_REQUEST is set, then ENTRY_CACHABLE should not
d88e3c49 653 * be set, and StoreEntry::setPublicKey() should not be called.
f3e570e9 654 */
6a566b9c 655#if MORE_DEBUG_OUTPUT
62e76326 656
d88e3c49 657 if (EBIT_TEST(flags, RELEASE_REQUEST))
308652fc 658 debugs(20, 1, "assertion failed: RELEASE key " << key << ", url " << mem_obj->url);
62e76326 659
2b906e48 660#endif
62e76326 661
d88e3c49 662 assert(!EBIT_TEST(flags, RELEASE_REQUEST));
62e76326 663
d88e3c49 664 if (mem_obj->request) {
665 HttpRequest *request = mem_obj->request;
62e76326 666
d88e3c49 667 if (!mem_obj->vary_headers) {
62e76326 668 /* First handle the case where the object no longer varies */
669 safe_free(request->vary_headers);
670 } else {
d88e3c49 671 if (request->vary_headers && strcmp(request->vary_headers, mem_obj->vary_headers) != 0) {
62e76326 672 /* Oops.. the variance has changed. Kill the base object
673 * to record the new variance key
674 */
c21ad0f5 675 safe_free(request->vary_headers); /* free old "bad" variance key */
d88e3c49 676 StoreEntry *pe = storeGetPublic(mem_obj->url, mem_obj->method);
62e76326 677
678 if (pe)
5f33b71d 679 pe->release();
62e76326 680 }
681
682 /* Make sure the request knows the variance status */
683 if (!request->vary_headers) {
d88e3c49 684 const char *vary = httpMakeVaryMark(request, mem_obj->getReply());
62e76326 685
686 if (vary)
687 request->vary_headers = xstrdup(vary);
688 }
689 }
690
d88e3c49 691 if (mem_obj->vary_headers && !storeGetPublic(mem_obj->url, mem_obj->method)) {
62e76326 692 /* Create "vary" base object */
30abd221 693 String vary;
d88e3c49 694 StoreEntry *pe = storeCreateEntry(mem_obj->url, mem_obj->log_url, request->flags, request->method);
62e76326 695 /* We are allowed to do this typecast */
eab8dcfa 696 HttpReply *rep = new HttpReply;
11992b6f 697 rep->setHeaders(HTTP_OK, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000);
d88e3c49 698 vary = mem_obj->getReply()->header.getList(HDR_VARY);
62e76326 699
30abd221 700 if (vary.size()) {
62e76326 701 /* Again, we own this structure layout */
b4f2886c 702 rep->header.putStr(HDR_VARY, vary.termedBuf());
30abd221 703 vary.clean();
62e76326 704 }
705
f66a9ef4 706#if X_ACCELERATOR_VARY
d88e3c49 707 vary = mem_obj->getReply()->header.getList(HDR_X_ACCELERATOR_VARY);
62e76326 708
b4197865 709 if (vary.defined()) {
62e76326 710 /* Again, we own this structure layout */
b4197865 711 rep->header.putStr(HDR_X_ACCELERATOR_VARY, vary.termedBuf());
30abd221 712 vary.clean();
62e76326 713 }
714
f66a9ef4 715#endif
eab8dcfa 716 pe->replaceHttpReply(rep);
62e76326 717
3900307b 718 pe->timestampsSet();
ba27c9a0 719
eab8dcfa 720 pe->makePublic();
62e76326 721
62e76326 722 pe->complete();
eab8dcfa 723
97b5e68f 724 pe->unlock();
62e76326 725 }
726
d88e3c49 727 newkey = storeKeyPublicByRequest(mem_obj->request);
f66a9ef4 728 } else
d88e3c49 729 newkey = storeKeyPublic(mem_obj->url, mem_obj->method);
62e76326 730
9fb13bb6 731 if ((e2 = (StoreEntry *) hash_lookup(store_table, newkey))) {
bf8fe701 732 debugs(20, 3, "StoreEntry::setPublicKey: Making old '" << mem_obj->url << "' private.");
d88e3c49 733 e2->setPrivateKey();
5f33b71d 734 e2->release();
62e76326 735
d88e3c49 736 if (mem_obj->request)
737 newkey = storeKeyPublicByRequest(mem_obj->request);
62e76326 738 else
d88e3c49 739 newkey = storeKeyPublic(mem_obj->url, mem_obj->method);
6eb42cae 740 }
62e76326 741
d88e3c49 742 if (key)
3900307b 743 hashDelete();
62e76326 744
d88e3c49 745 EBIT_CLR(flags, KEY_PRIVATE);
62e76326 746
3900307b 747 hashInsert(newkey);
62e76326 748
d88e3c49 749 if (swap_filen > -1)
750 storeDirSwapLog(this, SWAP_LOG_ADD);
227fbb74 751}
752
b8d8561b 753StoreEntry *
60745f24 754storeCreateEntry(const char *url, const char *log_url, request_flags flags, const HttpRequestMethod& method)
090089c4 755{
090089c4 756 StoreEntry *e = NULL;
30a4f2a8 757 MemObject *mem = NULL;
bf8fe701 758 debugs(20, 3, "storeCreateEntry: '" << url << "'");
090089c4 759
c8f4eac4 760 e = new StoreEntry(url, log_url);
c21ad0f5 761 e->lock_count = 1; /* Note lock here w/o calling storeLock() */
30a4f2a8 762 mem = e->mem_obj;
2ac237e2 763 mem->method = method;
62e76326 764
92695e5e 765 if (neighbors_do_private_keys || !flags.hierarchical)
d88e3c49 766 e->setPrivateKey();
86101e40 767 else
d88e3c49 768 e->setPublicKey();
62e76326 769
92695e5e 770 if (flags.cachable) {
62e76326 771 EBIT_SET(e->flags, ENTRY_CACHABLE);
772 EBIT_CLR(e->flags, RELEASE_REQUEST);
090089c4 773 } else {
d88e3c49 774 /* StoreEntry::releaseRequest() clears ENTRY_CACHABLE */
775 e->releaseRequest();
090089c4 776 }
62e76326 777
234967c9 778 e->store_status = STORE_PENDING;
3900307b 779 e->setMemStatus(NOT_IN_MEMORY);
8350fe9b 780 e->swap_status = SWAPOUT_NONE;
cd748f27 781 e->swap_filen = -1;
782 e->swap_dirn = -1;
090089c4 783 e->refcount = 0;
b8de7ebe 784 e->lastref = squid_curtime;
3900307b 785 e->timestamp = -1; /* set in StoreEntry::timestampsSet() */
30a4f2a8 786 e->ping_status = PING_NONE;
d46a87a8 787 EBIT_SET(e->flags, ENTRY_VALIDATED);
090089c4 788 return e;
789}
790
6eb42cae 791/* Mark object as expired */
b8d8561b 792void
d88e3c49 793StoreEntry::expireNow()
9174e204 794{
bf8fe701 795 debugs(20, 3, "StoreEntry::expireNow: '" << getMD5Text() << "'");
d88e3c49 796 expires = squid_curtime;
9174e204 797}
798
528b2c61 799void
800storeWriteComplete (void *data, StoreIOBuffer wroteBuffer)
801{
1d5161bd 802 PROF_start(storeWriteComplete);
528b2c61 803 StoreEntry *e = (StoreEntry *)data;
62e76326 804
1d5161bd 805 if (EBIT_TEST(e->flags, DELAY_SENDING)) {
806 PROF_stop(storeWriteComplete);
62e76326 807 return;
1d5161bd 808 }
62e76326 809
d88e3c49 810 e->invokeHandlers();
1d5161bd 811 PROF_stop(storeWriteComplete);
528b2c61 812}
813
814void
815StoreEntry::write (StoreIOBuffer writeBuffer)
816{
817 assert(mem_obj != NULL);
818 assert(writeBuffer.length >= 0);
819 /* This assert will change when we teach the store to update */
d2639a5b 820 PROF_start(StoreEntry_write);
528b2c61 821 assert(store_status == STORE_PENDING);
62e76326 822
26ac0430 823 if (!writeBuffer.length) {
2324cda2 824 /* the headers are received already, but we have not received
43785884 825 * any body data. There are BROKEN abuses of HTTP which require
826 * the headers to be passed along before any body data - see
827 * http://developer.apple.com/documentation/QuickTime/QTSS/Concepts/chapter_2_section_14.html
828 * for an example of such bad behaviour. To accomodate this, if
829 * we have a empty write arrive, we flush to our clients.
830 * -RBC 20060903
831 */
d2639a5b 832 PROF_stop(StoreEntry_write);
d88e3c49 833 invokeHandlers();
62e76326 834 return;
26ac0430 835 }
62e76326 836
d2639a5b 837 debugs(20, 5, "storeWrite: writing " << writeBuffer.length << " bytes for '" << getMD5Text() << "'");
838 PROF_stop(StoreEntry_write);
528b2c61 839 storeGetMemSpace(writeBuffer.length);
840 mem_obj->write (writeBuffer, storeWriteComplete, this);
841}
842
c21ad0f5 843/* Append incoming data from a primary server to an entry. */
844void
845StoreEntry::append(char const *buf, int len)
846{
847 assert(mem_obj != NULL);
3a1c3e2f 848 assert(len >= 0);
c21ad0f5 849 assert(store_status == STORE_PENDING);
528b2c61 850
851 StoreIOBuffer tempBuffer;
852 tempBuffer.data = (char *)buf;
853 tempBuffer.length = len;
aa18a4ca 854 /*
855 * XXX sigh, offset might be < 0 here, but it gets "corrected"
856 * later. This offset crap is such a mess.
857 */
c21ad0f5 858 tempBuffer.offset = mem_obj->endOffset() - (getReply() ? getReply()->hdr_sz : 0);
859 write(tempBuffer);
090089c4 860}
861
c21ad0f5 862
b8d8561b 863void
fe4e214f 864storeAppendPrintf(StoreEntry * e, const char *fmt,...)
15c05bb0 865{
62d32805 866 va_list args;
867 va_start(args, fmt);
62e76326 868
cb69b4c7 869 storeAppendVPrintf(e, fmt, args);
870 va_end(args);
871}
872
873/* used be storeAppendPrintf and Packer */
874void
875storeAppendVPrintf(StoreEntry * e, const char *fmt, va_list vargs)
876{
877 LOCAL_ARRAY(char, buf, 4096);
15c05bb0 878 buf[0] = '\0';
cb69b4c7 879 vsnprintf(buf, 4096, fmt, vargs);
3900307b 880 e->append(buf, strlen(buf));
c30c5a73 881}
882
26ac0430 883struct _store_check_cachable_hist {
62e76326 884
26ac0430 885 struct {
62e76326 886 int non_get;
887 int not_entry_cachable;
888 int wrong_content_length;
889 int negative_cached;
890 int too_big;
891 int too_small;
892 int private_key;
893 int too_many_open_files;
894 int too_many_open_fds;
2fadd50d 895 } no;
62e76326 896
26ac0430 897 struct {
62e76326 898 int Default;
2fadd50d
HN
899 } yes;
900} store_check_cachable_hist;
8423ff74 901
c47511fd 902int
903storeTooManyDiskFilesOpen(void)
904{
905 if (Config.max_open_disk_fds == 0)
62e76326 906 return 0;
907
83a29c95 908 if (store_open_disk_fd > Config.max_open_disk_fds)
62e76326 909 return 1;
910
c47511fd 911 return 0;
912}
913
3900307b 914int
915StoreEntry::checkTooSmall()
d20b1cd0 916{
3900307b 917 if (EBIT_TEST(flags, ENTRY_SPECIAL))
62e76326 918 return 0;
919
3900307b 920 if (STORE_OK == store_status)
921 if (mem_obj->object_sz < 0 ||
26ac0430 922 mem_obj->object_sz < Config.Store.minObjectSize)
62e76326 923 return 1;
3900307b 924 if (getReply()->content_length > -1)
47f6e231 925 if (getReply()->content_length < Config.Store.minObjectSize)
62e76326 926 return 1;
d20b1cd0 927 return 0;
928}
929
f09f5b26 930int
3900307b 931StoreEntry::checkCachable()
6602e70e 932{
2ac237e2 933#if CACHE_ALL_METHODS
62e76326 934
3900307b 935 if (mem_obj->method != METHOD_GET) {
bf8fe701 936 debugs(20, 2, "StoreEntry::checkCachable: NO: non-GET method");
62e76326 937 store_check_cachable_hist.no.non_get++;
2ac237e2 938 } else
939#endif
3900307b 940 if (store_status == STORE_OK && EBIT_TEST(flags, ENTRY_BAD_LENGTH)) {
bf8fe701 941 debugs(20, 2, "StoreEntry::checkCachable: NO: wrong content-length");
62e76326 942 store_check_cachable_hist.no.wrong_content_length++;
3900307b 943 } else if (!EBIT_TEST(flags, ENTRY_CACHABLE)) {
bf8fe701 944 debugs(20, 2, "StoreEntry::checkCachable: NO: not cachable");
be3b12f0 945 store_check_cachable_hist.no.not_entry_cachable++;
3900307b 946 } else if (EBIT_TEST(flags, ENTRY_NEGCACHED)) {
bf8fe701 947 debugs(20, 3, "StoreEntry::checkCachable: NO: negative cached");
62e76326 948 store_check_cachable_hist.no.negative_cached++;
c21ad0f5 949 return 0; /* avoid release call below */
3900307b 950 } else if ((getReply()->content_length > 0 &&
47f6e231 951 getReply()->content_length
62e76326 952 > Config.Store.maxObjectSize) ||
47f6e231 953 mem_obj->endOffset() > Config.Store.maxObjectSize) {
bf8fe701 954 debugs(20, 2, "StoreEntry::checkCachable: NO: too big");
62e76326 955 store_check_cachable_hist.no.too_big++;
47f6e231 956 } else if (getReply()->content_length > Config.Store.maxObjectSize) {
bf8fe701 957 debugs(20, 2, "StoreEntry::checkCachable: NO: too big");
62e76326 958 store_check_cachable_hist.no.too_big++;
3900307b 959 } else if (checkTooSmall()) {
bf8fe701 960 debugs(20, 2, "StoreEntry::checkCachable: NO: too small");
62e76326 961 store_check_cachable_hist.no.too_small++;
3900307b 962 } else if (EBIT_TEST(flags, KEY_PRIVATE)) {
bf8fe701 963 debugs(20, 3, "StoreEntry::checkCachable: NO: private key");
62e76326 964 store_check_cachable_hist.no.private_key++;
3900307b 965 } else if (swap_status != SWAPOUT_NONE) {
62e76326 966 /*
967 * here we checked the swap_status because the remaining
968 * cases are only relevant only if we haven't started swapping
969 * out the object yet.
970 */
971 return 1;
972 } else if (storeTooManyDiskFilesOpen()) {
bf8fe701 973 debugs(20, 2, "StoreEntry::checkCachable: NO: too many disk files open");
62e76326 974 store_check_cachable_hist.no.too_many_open_files++;
975 } else if (fdNFree() < RESERVED_FD) {
bf8fe701 976 debugs(20, 2, "StoreEntry::checkCachable: NO: too many FD's open");
62e76326 977 store_check_cachable_hist.no.too_many_open_fds++;
978 } else {
979 store_check_cachable_hist.yes.Default++;
980 return 1;
981 }
982
3900307b 983 releaseRequest();
d88e3c49 984 /* StoreEntry::releaseRequest() cleared ENTRY_CACHABLE */
6602e70e 985 return 0;
986}
987
3900307b 988void
989storeCheckCachableStats(StoreEntry *sentry)
8423ff74 990{
c40acff3 991 storeAppendPrintf(sentry, "Category\t Count\n");
992
a0cd8f99 993#if CACHE_ALL_METHODS
62e76326 994
8423ff74 995 storeAppendPrintf(sentry, "no.non_get\t%d\n",
62e76326 996 store_check_cachable_hist.no.non_get);
a0cd8f99 997#endif
62e76326 998
8423ff74 999 storeAppendPrintf(sentry, "no.not_entry_cachable\t%d\n",
62e76326 1000 store_check_cachable_hist.no.not_entry_cachable);
8423ff74 1001 storeAppendPrintf(sentry, "no.wrong_content_length\t%d\n",
62e76326 1002 store_check_cachable_hist.no.wrong_content_length);
8423ff74 1003 storeAppendPrintf(sentry, "no.negative_cached\t%d\n",
62e76326 1004 store_check_cachable_hist.no.negative_cached);
8423ff74 1005 storeAppendPrintf(sentry, "no.too_big\t%d\n",
62e76326 1006 store_check_cachable_hist.no.too_big);
d20b1cd0 1007 storeAppendPrintf(sentry, "no.too_small\t%d\n",
62e76326 1008 store_check_cachable_hist.no.too_small);
8423ff74 1009 storeAppendPrintf(sentry, "no.private_key\t%d\n",
62e76326 1010 store_check_cachable_hist.no.private_key);
c5f627c2 1011 storeAppendPrintf(sentry, "no.too_many_open_files\t%d\n",
62e76326 1012 store_check_cachable_hist.no.too_many_open_files);
59ffcdf8 1013 storeAppendPrintf(sentry, "no.too_many_open_fds\t%d\n",
62e76326 1014 store_check_cachable_hist.no.too_many_open_fds);
8423ff74 1015 storeAppendPrintf(sentry, "yes.default\t%d\n",
62e76326 1016 store_check_cachable_hist.yes.Default);
8423ff74 1017}
1018
b8d8561b 1019void
528b2c61 1020StoreEntry::complete()
090089c4 1021{
bf8fe701 1022 debugs(20, 3, "storeComplete: '" << getMD5Text() << "'");
62e76326 1023
528b2c61 1024 if (store_status != STORE_PENDING) {
62e76326 1025 /*
1026 * if we're not STORE_PENDING, then probably we got aborted
1027 * and there should be NO clients on this entry
1028 */
1029 assert(EBIT_TEST(flags, ENTRY_ABORTED));
1030 assert(mem_obj->nclients == 0);
1031 return;
b6403fac 1032 }
62e76326 1033
7d31d5fa 1034 /* This is suspect: mem obj offsets include the headers. do we adjust for that
1035 * in use of object_sz?
1036 */
528b2c61 1037 mem_obj->object_sz = mem_obj->endOffset();
7d31d5fa 1038
528b2c61 1039 store_status = STORE_OK;
7d31d5fa 1040
528b2c61 1041 assert(mem_status == NOT_IN_MEMORY);
62e76326 1042
528b2c61 1043 if (!validLength()) {
62e76326 1044 EBIT_SET(flags, ENTRY_BAD_LENGTH);
d88e3c49 1045 releaseRequest();
41587298 1046 }
62e76326 1047
6cfa8966 1048#if USE_CACHE_DIGESTS
528b2c61 1049 if (mem_obj->request)
62e76326 1050 mem_obj->request->hier.store_complete_stop = current_time;
1051
39edba21 1052#endif
d20b1cd0 1053 /*
d88e3c49 1054 * We used to call invokeHandlers, then storeSwapOut. However,
d20b1cd0 1055 * Madhukar Reddy <myreddy@persistence.com> reported that
1056 * responses without content length would sometimes get released
1057 * in client_side, thinking that the response is incomplete.
1058 */
d88e3c49 1059 invokeHandlers();
7e3e1d01 1060}
1061
090089c4 1062/*
474cac1b 1063 * Someone wants to abort this transfer. Set the reason in the
1064 * request structure, call the server-side callback and mark the
2b906e48 1065 * entry for releasing
090089c4 1066 */
b8d8561b 1067void
bfb55b6f 1068StoreEntry::abort()
090089c4 1069{
528b2c61 1070 statCounter.aborted_requests++;
bfb55b6f 1071 assert(store_status == STORE_PENDING);
1072 assert(mem_obj != NULL);
bf8fe701 1073 debugs(20, 6, "storeAbort: " << getMD5Text());
34266cde 1074
ac9cc053 1075 lock(); /* lock while aborting */
d88e3c49 1076 negativeCache();
34266cde 1077
d88e3c49 1078 releaseRequest();
34266cde 1079
bfb55b6f 1080 EBIT_SET(flags, ENTRY_ABORTED);
34266cde 1081
3900307b 1082 setMemStatus(NOT_IN_MEMORY);
34266cde 1083
bfb55b6f 1084 store_status = STORE_OK;
34266cde 1085
496e1d76 1086 /*
1087 * We assign an object length here. The only other place we assign
1088 * the object length is in storeComplete()
1089 */
528b2c61 1090 /* RBC: What do we need an object length for? we've just aborted the
1091 * request, the request is private and negatively cached. Surely
1092 * the object length is inappropriate to set.
1093 */
bfb55b6f 1094 mem_obj->object_sz = mem_obj->endOffset();
34266cde 1095
474cac1b 1096 /* Notify the server side */
62e76326 1097
8ea67c2b 1098 /*
1099 * DPW 2007-05-07
1100 * Should we check abort.data for validity?
1101 */
bfb55b6f 1102 if (mem_obj->abort.callback) {
26ac0430
AJ
1103 if (!cbdataReferenceValid(mem_obj->abort.data))
1104 debugs(20,1,HERE << "queueing event when abort.data is not valid");
bfb55b6f 1105 eventAdd("mem_obj->abort.callback",
1106 mem_obj->abort.callback,
1107 mem_obj->abort.data,
62e76326 1108 0.0,
8ea67c2b 1109 true);
26ac0430 1110 unregisterAbort();
bfcaf585 1111 }
62e76326 1112
1113 /* XXX Should we reverse these two, so that there is no
26ac0430 1114 * unneeded disk swapping triggered?
528b2c61 1115 */
474cac1b 1116 /* Notify the client side */
d88e3c49 1117 invokeHandlers();
62e76326 1118
cd748f27 1119 /* Close any swapout file */
bfb55b6f 1120 swapOutFileClose();
62e76326 1121
bfb55b6f 1122 unlock(); /* unlock */
090089c4 1123}
1124
6d3c2758
HN
1125/**
1126 * Clear Memory storage to accommodate the given object len
1127 */
1128void
d4432957 1129storeGetMemSpace(int size)
090089c4 1130{
1d5161bd 1131 PROF_start(storeGetMemSpace);
b32508fb 1132 StoreEntry *e = NULL;
20cba4b4 1133 int released = 0;
b32508fb 1134 static time_t last_check = 0;
528b2c61 1135 size_t pages_needed;
6a566b9c 1136 RemovalPurgeWalker *walker;
62e76326 1137
1d5161bd 1138 if (squid_curtime == last_check) {
1139 PROF_stop(storeGetMemSpace);
62e76326 1140 return;
1d5161bd 1141 }
62e76326 1142
b32508fb 1143 last_check = squid_curtime;
62e76326 1144
e954773d 1145 pages_needed = (size / SM_PAGE_SIZE) + 1;
62e76326 1146
1d5161bd 1147 if (mem_node::InUseCount() + pages_needed < store_pages_max) {
1148 PROF_stop(storeGetMemSpace);
62e76326 1149 return;
1d5161bd 1150 }
62e76326 1151
e4049756 1152 debugs(20, 2, "storeGetMemSpace: Starting, need " << pages_needed <<
1153 " pages");
62e76326 1154
6a566b9c 1155 /* XXX what to set as max_scan here? */
1156 walker = mem_policy->PurgeInit(mem_policy, 100000);
62e76326 1157
c1dd71ae 1158 while ((e = walker->Next(walker))) {
d88e3c49 1159 e->purgeMem();
62e76326 1160 released++;
1161
1162 if (mem_node::InUseCount() + pages_needed < store_pages_max)
1163 break;
8350fe9b 1164 }
62e76326 1165
6a566b9c 1166 walker->Done(walker);
bf8fe701 1167 debugs(20, 3, "storeGetMemSpace stats:");
1168 debugs(20, 3, " " << std::setw(6) << hot_obj_count << " HOT objects");
1169 debugs(20, 3, " " << std::setw(6) << released << " were released");
1d5161bd 1170 PROF_stop(storeGetMemSpace);
090089c4 1171}
1172
c8f4eac4 1173
1174/* thunk through to Store::Root().maintain(). Note that this would be better still
26ac0430
AJ
1175 * if registered against the root store itself, but that requires more complex
1176 * update logic - bigger fish to fry first. Long term each store when
c8f4eac4 1177 * it becomes active will self register
1178 */
1179void
1180Store::Maintain(void *notused)
1181{
1182 Store::Root().maintain();
1183
1184 /* Reregister a maintain event .. */
1185 eventAdd("MaintainSwapSpace", Maintain, NULL, 1.0, 1);
1186
1187}
1188
090089c4 1189/* The maximum objects to scan for maintain storage space */
c21ad0f5 1190#define MAINTAIN_MAX_SCAN 1024
1191#define MAINTAIN_MAX_REMOVE 64
090089c4 1192
2b906e48 1193/*
fcefe642 1194 * This routine is to be called by main loop in main.c.
1195 * It removes expired objects on only one bucket for each time called.
fcefe642 1196 *
1197 * This should get called 1/s from main().
1198 */
679ac4f0 1199void
c8f4eac4 1200StoreController::maintain()
090089c4 1201{
6a566b9c 1202 static time_t last_warn_time = 0;
cd748f27 1203
88bfe092 1204 PROF_start(storeMaintainSwapSpace);
c8f4eac4 1205 swapDir->maintain();
62e76326 1206
c8f4eac4 1207 /* this should be emitted by the oversize dir, not globally */
62e76326 1208
c8f4eac4 1209 if (store_swap_size > Store::Root().maxSize()) {
62e76326 1210 if (squid_curtime - last_warn_time > 10) {
c8f4eac4 1211 debugs(20, 0, "WARNING: Disk space over limit: " << store_swap_size << " KB > "
1212 << Store::Root().maxSize() << " KB");
62e76326 1213 last_warn_time = squid_curtime;
1214 }
6a566b9c 1215 }
62e76326 1216
88bfe092 1217 PROF_stop(storeMaintainSwapSpace);
090089c4 1218}
1219
090089c4 1220/* release an object from a cache */
6c78a099 1221void
5f33b71d 1222StoreEntry::release()
090089c4 1223{
88bfe092 1224 PROF_start(storeRelease);
bf8fe701 1225 debugs(20, 3, "storeRelease: Releasing: '" << getMD5Text() << "'");
090089c4 1226 /* If, for any reason we can't discard this object because of an
1227 * outstanding request, mark it for pending release */
62e76326 1228
3900307b 1229 if (locked()) {
d88e3c49 1230 expireNow();
bf8fe701 1231 debugs(20, 3, "storeRelease: Only setting RELEASE_REQUEST bit");
d88e3c49 1232 releaseRequest();
62e76326 1233 PROF_stop(storeRelease);
1234 return;
090089c4 1235 }
62e76326 1236
bef81ea5 1237 if (StoreController::store_dirs_rebuilding && swap_filen > -1) {
d88e3c49 1238 setPrivateKey();
62e76326 1239
5f33b71d 1240 if (mem_obj)
3900307b 1241 destroyMemObject();
62e76326 1242
5f33b71d 1243 if (swap_filen > -1) {
62e76326 1244 /*
34266cde 1245 * Fake a call to StoreEntry->lock() When rebuilding is done,
1246 * we'll just call StoreEntry->unlock() on these.
62e76326 1247 */
5f33b71d 1248 lock_count++;
1249 setReleaseFlag();
1250 LateReleaseStack.push_back(this);
62e76326 1251 PROF_stop(storeRelease);
1252 return;
1253 } else {
5f33b71d 1254 destroyStoreEntry(static_cast<hash_link *>(this));
62e76326 1255 }
43d9cf56 1256 }
62e76326 1257
5f33b71d 1258 storeLog(STORE_LOG_RELEASE, this);
62e76326 1259
5f33b71d 1260 if (swap_filen > -1) {
1261 unlink();
62e76326 1262
5f33b71d 1263 if (swap_status == SWAPOUT_DONE)
1264 if (EBIT_TEST(flags, ENTRY_VALIDATED))
1265 store()->updateSize(swap_file_sz, -1);
62e76326 1266
5f33b71d 1267 if (!EBIT_TEST(flags, KEY_PRIVATE))
1268 storeDirSwapLog(this, SWAP_LOG_DEL);
62e76326 1269
cd748f27 1270#if 0
62e76326 1271 /* From 2.4. I think we do this in storeUnlink? */
5f33b71d 1272 storeSwapFileNumberSet(this, -1);
62e76326 1273
cd748f27 1274#endif
62e76326 1275
090089c4 1276 }
62e76326 1277
3900307b 1278 setMemStatus(NOT_IN_MEMORY);
5f33b71d 1279 destroyStoreEntry(static_cast<hash_link *>(this));
88bfe092 1280 PROF_stop(storeRelease);
090089c4 1281}
1282
e42d5181 1283static void
1284storeLateRelease(void *unused)
1285{
1286 StoreEntry *e;
1287 int i;
1288 static int n = 0;
62e76326 1289
bef81ea5 1290 if (StoreController::store_dirs_rebuilding) {
62e76326 1291 eventAdd("storeLateRelease", storeLateRelease, NULL, 1.0, 1);
1292 return;
e42d5181 1293 }
62e76326 1294
e42d5181 1295 for (i = 0; i < 10; i++) {
91caca83 1296 e = LateReleaseStack.pop();
62e76326 1297
1298 if (e == NULL) {
1299 /* done! */
bf8fe701 1300 debugs(20, 1, "storeLateRelease: released " << n << " objects");
62e76326 1301 return;
1302 }
1303
97b5e68f 1304 e->unlock();
62e76326 1305 n++;
e42d5181 1306 }
62e76326 1307
e42d5181 1308 eventAdd("storeLateRelease", storeLateRelease, NULL, 0.0, 1);
1309}
1310
090089c4 1311/* return 1 if a store entry is locked */
cd748f27 1312int
3900307b 1313StoreEntry::locked() const
090089c4 1314{
3900307b 1315 if (lock_count)
62e76326 1316 return 1;
1317
3900307b 1318 if (swap_status == SWAPOUT_WRITING)
62e76326 1319 return 1;
1320
3900307b 1321 if (store_status == STORE_PENDING)
62e76326 1322 return 1;
1323
b8890359 1324 /*
1325 * SPECIAL, PUBLIC entries should be "locked"
1326 */
3900307b 1327 if (EBIT_TEST(flags, ENTRY_SPECIAL))
1328 if (!EBIT_TEST(flags, KEY_PRIVATE))
62e76326 1329 return 1;
1330
30a4f2a8 1331 return 0;
090089c4 1332}
1333
528b2c61 1334bool
1335StoreEntry::validLength() const
6602e70e 1336{
47f6e231 1337 int64_t diff;
d8b249ef 1338 const HttpReply *reply;
528b2c61 1339 assert(mem_obj != NULL);
1340 reply = getReply();
bf8fe701 1341 debugs(20, 3, "storeEntryValidLength: Checking '" << getMD5Text() << "'");
e4049756 1342 debugs(20, 5, "storeEntryValidLength: object_len = " <<
707fdc47 1343 objectLen());
bf8fe701 1344 debugs(20, 5, "storeEntryValidLength: hdr_sz = " << reply->hdr_sz);
1345 debugs(20, 5, "storeEntryValidLength: content_length = " << reply->content_length);
62e76326 1346
d8b249ef 1347 if (reply->content_length < 0) {
bf8fe701 1348 debugs(20, 5, "storeEntryValidLength: Unspecified content length: " << getMD5Text());
62e76326 1349 return 1;
ffe4a367 1350 }
62e76326 1351
07304bf9 1352 if (reply->hdr_sz == 0) {
bf8fe701 1353 debugs(20, 5, "storeEntryValidLength: Zero header size: " << getMD5Text());
62e76326 1354 return 1;
ffe4a367 1355 }
62e76326 1356
528b2c61 1357 if (mem_obj->method == METHOD_HEAD) {
bf8fe701 1358 debugs(20, 5, "storeEntryValidLength: HEAD request: " << getMD5Text());
62e76326 1359 return 1;
ffe4a367 1360 }
62e76326 1361
cb69b4c7 1362 if (reply->sline.status == HTTP_NOT_MODIFIED)
62e76326 1363 return 1;
1364
cb69b4c7 1365 if (reply->sline.status == HTTP_NO_CONTENT)
62e76326 1366 return 1;
1367
707fdc47 1368 diff = reply->hdr_sz + reply->content_length - objectLen();
62e76326 1369
ebf4efff 1370 if (diff == 0)
62e76326 1371 return 1;
1372
bf8fe701 1373 debugs(20, 3, "storeEntryValidLength: " << (diff < 0 ? -diff : diff) << " bytes too " << (diff < 0 ? "big" : "small") <<"; '" << getMD5Text() << "'" );
62e76326 1374
ebf4efff 1375 return 0;
ffe4a367 1376}
6602e70e 1377
6b7d87bb
FC
1378static void
1379storeRegisterWithCacheManager(void)
1380{
1381 CacheManager *manager=CacheManager::GetInstance();
1382 manager->registerAction("storedir", "Store Directory Stats", Store::Stats, 0, 1);
1383 manager->registerAction("store_io", "Store IO Interface Stats", storeIOStats, 0, 1);
1384 manager->registerAction("store_check_cachable_stats", "storeCheckCachable() Stats",
26ac0430 1385 storeCheckCachableStats, 0, 1);
6b7d87bb
FC
1386}
1387
b8d8561b 1388void
1389storeInit(void)
c943f331 1390{
25535cbe 1391 storeKeyInit();
6a566b9c 1392 mem_policy = createRemovalPolicy(Config.memPolicy);
8638fc66 1393 storeDigestInit();
e3ef2b09 1394 storeLogOpen();
e42d5181 1395 eventAdd("storeLateRelease", storeLateRelease, NULL, 1.0, 1);
c8f4eac4 1396 Store::Root().init();
b2c141d4 1397 storeRebuildStart();
d120ed12
FC
1398
1399 storeRegisterWithCacheManager();
62ee09ca 1400}
1401
b8d8561b 1402void
1403storeConfigure(void)
b1c0cc67 1404{
c8f4eac4 1405 store_swap_high = (long) (((float) Store::Root().maxSize() *
62e76326 1406 (float) Config.Swap.highWaterMark) / (float) 100);
c8f4eac4 1407 store_swap_low = (long) (((float) Store::Root().maxSize() *
62e76326 1408 (float) Config.Swap.lowWaterMark) / (float) 100);
505d4821 1409 store_pages_max = Config.memMaxSize / sizeof(mem_node);
090089c4 1410}
1411
3900307b 1412int
1413StoreEntry::keepInMemory() const
56f29785 1414{
3900307b 1415 if (mem_obj == NULL)
62e76326 1416 return 0;
1417
3900307b 1418 if (mem_obj->data_hdr.size() == 0)
62e76326 1419 return 0;
1420
19fdd3f3 1421 if (mem_obj->inmem_lo != 0)
e1381638 1422 return 0;
19fdd3f3 1423
d227e181 1424 if (!Config.onoff.memory_cache_first && swap_status == SWAPOUT_DONE && refcount == 1)
e1381638 1425 return 0;
19fdd3f3
HN
1426
1427 return 1;
56f29785 1428}
1429
edce4d98 1430int
3900307b 1431StoreEntry::checkNegativeHit() const
edce4d98 1432{
3900307b 1433 if (!EBIT_TEST(flags, ENTRY_NEGCACHED))
62e76326 1434 return 0;
1435
3900307b 1436 if (expires <= squid_curtime)
62e76326 1437 return 0;
1438
3900307b 1439 if (store_status != STORE_OK)
62e76326 1440 return 0;
1441
edce4d98 1442 return 1;
1443}
1444
ac9cc053
AJ
1445/**
1446 * Set object for negative caching.
1447 * Preserves any expiry information given by the server.
1448 * In absence of proper expiry info it will set to expire immediately,
1449 * or with HTTP-violations enabled the configured negative-TTL is observed
1450 */
b8d8561b 1451void
d88e3c49 1452StoreEntry::negativeCache()
79b5cc5f 1453{
26ac0430 1454 if (expires == 0)
ac9cc053
AJ
1455#if HTTP_VIOLATIONS
1456 expires = squid_curtime + Config.negativeTtl;
1457#else
1458 expires = squid_curtime;
1459#endif
d88e3c49 1460 EBIT_SET(flags, ENTRY_NEGCACHED);
79b5cc5f 1461}
0a21bd84 1462
1463void
1464storeFreeMemory(void)
1465{
c8f4eac4 1466 Store::Root(NULL);
9bc73deb 1467#if USE_CACHE_DIGESTS
62e76326 1468
8638fc66 1469 if (store_digest)
62e76326 1470 cacheDigestDestroy(store_digest);
1471
c68e9c6b 1472#endif
62e76326 1473
8638fc66 1474 store_digest = NULL;
0a21bd84 1475}
a7e59001 1476
1477int
1478expiresMoreThan(time_t expires, time_t when)
1479{
c21ad0f5 1480 if (expires < 0) /* No Expires given */
62e76326 1481 return 1;
1482
48f44632 1483 return (expires > (squid_curtime + when));
a7e59001 1484}
fe54d06d 1485
1486int
3900307b 1487StoreEntry::validToSend() const
fe54d06d 1488{
3900307b 1489 if (EBIT_TEST(flags, RELEASE_REQUEST))
62e76326 1490 return 0;
1491
3900307b 1492 if (EBIT_TEST(flags, ENTRY_NEGCACHED))
1493 if (expires <= squid_curtime)
62e76326 1494 return 0;
1495
3900307b 1496 if (EBIT_TEST(flags, ENTRY_ABORTED))
62e76326 1497 return 0;
1498
fe54d06d 1499 return 1;
1500}
62663274 1501
ca98227c 1502void
3900307b 1503StoreEntry::timestampsSet()
ca98227c 1504{
3900307b 1505 const HttpReply *reply = getReply();
2f58241d 1506 time_t served_date = reply->date;
a9925b40 1507 int age = reply->header.getInt(HDR_AGE);
efd900cb 1508 /*
1509 * The timestamp calculations below tries to mimic the properties
1510 * of the age calculation in RFC2616 section 13.2.3. The implementaion
1511 * isn't complete, and the most notable exception from the RFC is that
1512 * this does not account for response_delay, but it probably does
1513 * not matter much as this is calculated immediately when the headers
1514 * are received, not when the whole response has been received.
1515 */
2f58241d 1516 /* make sure that 0 <= served_date <= squid_curtime */
62e76326 1517
2f58241d 1518 if (served_date < 0 || served_date > squid_curtime)
62e76326 1519 served_date = squid_curtime;
1520
efd900cb 1521 /*
212cbb48 1522 * Compensate with Age header if origin server clock is ahead
1523 * of us and there is a cache in between us and the origin
1524 * server. But DONT compensate if the age value is larger than
1525 * squid_curtime because it results in a negative served_date.
efd900cb 1526 */
1527 if (age > squid_curtime - served_date)
62e76326 1528 if (squid_curtime > age)
1529 served_date = squid_curtime - age;
1530
0d465a25 1531 if (reply->expires > 0 && reply->date > -1)
26ac0430 1532 expires = served_date + (reply->expires - reply->date);
0d465a25 1533 else
26ac0430 1534 expires = reply->expires;
62e76326 1535
3900307b 1536 lastmod = reply->last_modified;
62e76326 1537
3900307b 1538 timestamp = served_date;
ca98227c 1539}
429fdbec 1540
bfcaf585 1541void
3900307b 1542StoreEntry::registerAbort(STABH * cb, void *data)
bfcaf585 1543{
3900307b 1544 assert(mem_obj);
1545 assert(mem_obj->abort.callback == NULL);
1546 mem_obj->abort.callback = cb;
8ea67c2b 1547 mem_obj->abort.data = cbdataReference(data);
bfcaf585 1548}
1549
1550void
3900307b 1551StoreEntry::unregisterAbort()
bfcaf585 1552{
3900307b 1553 assert(mem_obj);
8ea67c2b 1554 if (mem_obj->abort.callback) {
26ac0430
AJ
1555 mem_obj->abort.callback = NULL;
1556 cbdataReferenceDone(mem_obj->abort.data);
8ea67c2b 1557 }
bfcaf585 1558}
88738790 1559
f09f5b26 1560void
3900307b 1561StoreEntry::dump(int l) const
1562{
bf8fe701 1563 debugs(20, l, "StoreEntry->key: " << getMD5Text());
1564 debugs(20, l, "StoreEntry->next: " << next);
1565 debugs(20, l, "StoreEntry->mem_obj: " << mem_obj);
4a7a3d56 1566 debugs(20, l, "StoreEntry->timestamp: " << timestamp);
1567 debugs(20, l, "StoreEntry->lastref: " << lastref);
1568 debugs(20, l, "StoreEntry->expires: " << expires);
1569 debugs(20, l, "StoreEntry->lastmod: " << lastmod);
1570 debugs(20, l, "StoreEntry->swap_file_sz: " << swap_file_sz);
bf8fe701 1571 debugs(20, l, "StoreEntry->refcount: " << refcount);
1572 debugs(20, l, "StoreEntry->flags: " << storeEntryFlags(this));
4a7a3d56 1573 debugs(20, l, "StoreEntry->swap_dirn: " << swap_dirn);
1574 debugs(20, l, "StoreEntry->swap_filen: " << swap_filen);
1575 debugs(20, l, "StoreEntry->lock_count: " << lock_count);
1576 debugs(20, l, "StoreEntry->mem_status: " << mem_status);
1577 debugs(20, l, "StoreEntry->ping_status: " << ping_status);
1578 debugs(20, l, "StoreEntry->store_status: " << store_status);
1579 debugs(20, l, "StoreEntry->swap_status: " << swap_status);
d377699f 1580}
1581
1f38f50a 1582/*
1583 * NOTE, this function assumes only two mem states
1584 */
f09f5b26 1585void
3900307b 1586StoreEntry::setMemStatus(mem_status_t new_status)
8350fe9b 1587{
3900307b 1588 if (new_status == mem_status)
62e76326 1589 return;
1590
3900307b 1591 assert(mem_obj != NULL);
62e76326 1592
b93bcace 1593 if (new_status == IN_MEMORY) {
3900307b 1594 assert(mem_obj->inmem_lo == 0);
62e76326 1595
3900307b 1596 if (EBIT_TEST(flags, ENTRY_SPECIAL)) {
bf8fe701 1597 debugs(20, 4, "StoreEntry::setMemStatus: not inserting special " << mem_obj->url << " into policy");
62e76326 1598 } else {
3900307b 1599 mem_policy->Add(mem_policy, this, &mem_obj->repl);
bf8fe701 1600 debugs(20, 4, "StoreEntry::setMemStatus: inserted mem node " << mem_obj->url);
62e76326 1601 }
1602
1603 hot_obj_count++;
b93bcace 1604 } else {
3900307b 1605 if (EBIT_TEST(flags, ENTRY_SPECIAL)) {
bf8fe701 1606 debugs(20, 4, "StoreEntry::setMemStatus: special entry " << mem_obj->url);
62e76326 1607 } else {
3900307b 1608 mem_policy->Remove(mem_policy, this, &mem_obj->repl);
bf8fe701 1609 debugs(20, 4, "StoreEntry::setMemStatus: removed mem node " << mem_obj->url);
62e76326 1610 }
1611
1612 hot_obj_count--;
b93bcace 1613 }
62e76326 1614
3900307b 1615 mem_status = new_status;
8350fe9b 1616}
6e86c3e8 1617
9fb13bb6 1618const char *
3900307b 1619StoreEntry::url() const
9fb13bb6 1620{
3900307b 1621 if (this == NULL)
62e76326 1622 return "[null_entry]";
3900307b 1623 else if (mem_obj == NULL)
62e76326 1624 return "[null_mem_obj]";
9fb13bb6 1625 else
3900307b 1626 return mem_obj->url;
9fb13bb6 1627}
24ffafb4 1628
1629void
d5f8d05f 1630StoreEntry::createMemObject(const char *aUrl, const char *aLogUrl)
24ffafb4 1631{
3900307b 1632 if (mem_obj)
62e76326 1633 return;
1634
d5f8d05f 1635 mem_obj = new MemObject(aUrl, aLogUrl);
c21ad0f5 1636}
1637
1638/* this just sets DELAY_SENDING */
1639void
1640StoreEntry::buffer()
1641{
1642 EBIT_SET(flags, DELAY_SENDING);
1643}
1644
438fc1e3 1645/* this just clears DELAY_SENDING and Invokes the handlers */
1646void
c21ad0f5 1647StoreEntry::flush()
438fc1e3 1648{
c21ad0f5 1649 if (EBIT_TEST(flags, DELAY_SENDING)) {
1650 EBIT_CLR(flags, DELAY_SENDING);
d88e3c49 1651 invokeHandlers();
b66315e4 1652 }
25535cbe 1653}
07304bf9 1654
47f6e231 1655int64_t
707fdc47 1656StoreEntry::objectLen() const
07304bf9 1657{
707fdc47 1658 assert(mem_obj != NULL);
1659 return mem_obj->object_sz;
07304bf9 1660}
1661
47f6e231 1662int64_t
b37bde1e 1663StoreEntry::contentLen() const
07304bf9 1664{
b37bde1e 1665 assert(mem_obj != NULL);
1666 assert(getReply() != NULL);
1667 return objectLen() - getReply()->hdr_sz;
07304bf9 1668}
f3986a15 1669
528b2c61 1670HttpReply const *
1671StoreEntry::getReply () const
f3986a15 1672{
528b2c61 1673 if (NULL == mem_obj)
62e76326 1674 return NULL;
1675
528b2c61 1676 return mem_obj->getReply();
f3986a15 1677}
db1cd23c 1678
1679void
3900307b 1680StoreEntry::reset()
db1cd23c 1681{
3900307b 1682 assert (mem_obj);
bf8fe701 1683 debugs(20, 3, "StoreEntry::reset: " << url());
3900307b 1684 mem_obj->reset();
1685 HttpReply *rep = (HttpReply *) getReply(); // bypass const
06a5ae20 1686 rep->reset();
3900307b 1687 expires = lastmod = timestamp = -1;
db1cd23c 1688}
2b906e48 1689
cd748f27 1690/*
1691 * storeFsInit
1692 *
1693 * This routine calls the SETUP routine for each fs type.
1694 * I don't know where the best place for this is, and I'm not going to shuffle
1695 * around large chunks of code right now (that can be done once its working.)
1696 */
1697void
1698storeFsInit(void)
1699{
22d38e05 1700 storeReplSetup();
cd748f27 1701}
1702
22d38e05 1703/*
1704 * called to add another store removal policy module
1705 */
1706void
a2c963ae 1707storeReplAdd(const char *type, REMOVALPOLICYCREATE * create)
22d38e05 1708{
1709 int i;
1710 /* find the number of currently known repl types */
62e76326 1711
22d38e05 1712 for (i = 0; storerepl_list && storerepl_list[i].typestr; i++) {
62e76326 1713 assert(strcmp(storerepl_list[i].typestr, type) != 0);
22d38e05 1714 }
62e76326 1715
22d38e05 1716 /* add the new type */
e6ccf245 1717 storerepl_list = static_cast<storerepl_entry_t *>(xrealloc(storerepl_list, (i + 2) * sizeof(storerepl_entry_t)));
62e76326 1718
22d38e05 1719 memset(&storerepl_list[i + 1], 0, sizeof(storerepl_entry_t));
62e76326 1720
22d38e05 1721 storerepl_list[i].typestr = type;
62e76326 1722
22d38e05 1723 storerepl_list[i].create = create;
1724}
1725
1726/*
1727 * Create a removal policy instance
1728 */
1729RemovalPolicy *
1730createRemovalPolicy(RemovalPolicySettings * settings)
1731{
1732 storerepl_entry_t *r;
62e76326 1733
22d38e05 1734 for (r = storerepl_list; r && r->typestr; r++) {
62e76326 1735 if (strcmp(r->typestr, settings->type) == 0)
1736 return r->create(settings->args);
22d38e05 1737 }
62e76326 1738
bf8fe701 1739 debugs(20, 1, "ERROR: Unknown policy " << settings->type);
1740 debugs(20, 1, "ERROR: Be sure to have set cache_replacement_policy");
1741 debugs(20, 1, "ERROR: and memory_replacement_policy in squid.conf!");
0c5ccf11 1742 fatalf("ERROR: Unknown policy %s\n", settings->type);
c21ad0f5 1743 return NULL; /* NOTREACHED */
22d38e05 1744}
1745
cd748f27 1746#if 0
fc8b9fc0 1747void
1748storeSwapFileNumberSet(StoreEntry * e, sfileno filn)
1749{
1750 if (e->swap_file_number == filn)
62e76326 1751 return;
1752
fc8b9fc0 1753 if (filn < 0) {
62e76326 1754 assert(-1 == filn);
1755 storeDirMapBitReset(e->swap_file_number);
1756 storeDirLRUDelete(e);
1757 e->swap_file_number = -1;
fc8b9fc0 1758 } else {
62e76326 1759 assert(-1 == e->swap_file_number);
1760 storeDirMapBitSet(e->swap_file_number = filn);
1761 storeDirLRUAdd(e);
fc8b9fc0 1762 }
1763}
62e76326 1764
cd748f27 1765#endif
e6ccf245 1766
4a56ee8d 1767
db237875 1768/*
1769 * Replace a store entry with
528b2c61 1770 * a new reply. This eats the reply.
1771 */
4a56ee8d 1772void
1773StoreEntry::replaceHttpReply(HttpReply *rep)
1774{
bf8fe701 1775 debugs(20, 3, "StoreEntry::replaceHttpReply: " << url());
528b2c61 1776 Packer p;
62e76326 1777
4a56ee8d 1778 if (!mem_obj) {
bf8fe701 1779 debugs(20, 0, "Attempt to replace object with no in-memory representation");
62e76326 1780 return;
528b2c61 1781 }
62e76326 1782
4a56ee8d 1783 mem_obj->replaceHttpReply(rep);
1784
528b2c61 1785 /* TODO: when we store headers serparately remove the header portion */
1786 /* TODO: mark the length of the headers ? */
1787 /* We ONLY want the headers */
4a56ee8d 1788 packerToStoreInit(&p, this);
62e76326 1789
4a56ee8d 1790 assert (isEmpty());
62e76326 1791
4a56ee8d 1792 getReply()->packHeadersInto(&p);
62e76326 1793
4a56ee8d 1794 rep->hdr_sz = mem_obj->endOffset();
62e76326 1795
4a56ee8d 1796 httpBodyPackInto(&getReply()->body, &p);
62e76326 1797
528b2c61 1798 packerClean(&p);
1799}
62e76326 1800
e6ccf245 1801
528b2c61 1802char const *
1803StoreEntry::getSerialisedMetaData()
1804{
1805 StoreMeta *tlv_list = storeSwapMetaBuild(this);
1806 int swap_hdr_sz;
1807 char *result = storeSwapMetaPack(tlv_list, &swap_hdr_sz);
1808 storeSwapTLVFree(tlv_list);
1809 assert (swap_hdr_sz >= 0);
1810 mem_obj->swap_hdr_sz = (size_t) swap_hdr_sz;
1811 return result;
1812}
1813
1814bool
1815StoreEntry::swapoutPossible()
1816{
1817 /* should we swap something out to disk? */
bf8fe701 1818 debugs(20, 7, "storeSwapOut: " << url());
1819 debugs(20, 7, "storeSwapOut: store_status = " << storeStatusStr[store_status]);
62e76326 1820
528b2c61 1821 if (EBIT_TEST(flags, ENTRY_ABORTED)) {
62e76326 1822 assert(EBIT_TEST(flags, RELEASE_REQUEST));
c07cbbf4 1823 swapOutFileClose();
62e76326 1824 return false;
528b2c61 1825 }
62e76326 1826
528b2c61 1827 if (EBIT_TEST(flags, ENTRY_SPECIAL)) {
bf8fe701 1828 debugs(20, 3, "storeSwapOut: " << url() << " SPECIAL");
62e76326 1829 return false;
528b2c61 1830 }
62e76326 1831
528b2c61 1832 return true;
1833}
1834
1835void
1836StoreEntry::trimMemory()
1837{
7fef2365 1838 /*
1839 * DPW 2007-05-09
1840 * Bug #1943. We must not let go any data for IN_MEMORY
1841 * objects. We have to wait until the mem_status changes.
1842 */
1843 if (mem_status == IN_MEMORY)
26ac0430 1844 return;
7fef2365 1845
c07cbbf4 1846 if (!swapOutAble()) {
e1381638
AJ
1847 if (mem_obj->policyLowestOffsetToKeep(0) == 0) {
1848 /* Nothing to do */
1849 return;
1850 }
62e76326 1851 /*
1852 * Its not swap-able, and we're about to delete a chunk,
1853 * so we must make it PRIVATE. This is tricky/ugly because
1854 * for the most part, we treat swapable == cachable here.
1855 */
d88e3c49 1856 releaseRequest();
62e76326 1857 mem_obj->trimUnSwappable ();
528b2c61 1858 } else {
62e76326 1859 mem_obj->trimSwappable ();
528b2c61 1860 }
1861}
62e76326 1862
0655fa4d 1863bool
190154cf 1864StoreEntry::modifiedSince(HttpRequest * request) const
0655fa4d 1865{
1866 int object_length;
1867 time_t mod_time = lastmod;
1868
1869 if (mod_time < 0)
1870 mod_time = timestamp;
1871
bf8fe701 1872 debugs(88, 3, "modifiedSince: '" << url() << "'");
0655fa4d 1873
4a7a3d56 1874 debugs(88, 3, "modifiedSince: mod_time = " << mod_time);
0655fa4d 1875
1876 if (mod_time < 0)
1877 return true;
1878
1879 /* Find size of the object */
1880 object_length = getReply()->content_length;
1881
1882 if (object_length < 0)
b37bde1e 1883 object_length = contentLen();
0655fa4d 1884
1885 if (mod_time > request->ims) {
bf8fe701 1886 debugs(88, 3, "--> YES: entry newer than client");
0655fa4d 1887 return true;
1888 } else if (mod_time < request->ims) {
bf8fe701 1889 debugs(88, 3, "--> NO: entry older than client");
0655fa4d 1890 return false;
1891 } else if (request->imslen < 0) {
bf8fe701 1892 debugs(88, 3, "--> NO: same LMT, no client length");
0655fa4d 1893 return false;
1894 } else if (request->imslen == object_length) {
bf8fe701 1895 debugs(88, 3, "--> NO: same LMT, same length");
0655fa4d 1896 return false;
1897 } else {
bf8fe701 1898 debugs(88, 3, "--> YES: same LMT, different length");
0655fa4d 1899 return true;
1900 }
1901}
1902
c8f4eac4 1903StorePointer
1904StoreEntry::store() const
1905{
1906 assert(0 <= swap_dirn && swap_dirn < Config.cacheSwap.n_configured);
1907 return INDEXSD(swap_dirn);
1908}
1909
1910void
1911StoreEntry::unlink()
1912{
1913 store()->unlink(*this);
1914}
0655fa4d 1915
aa18a4ca 1916/*
1917 * return true if the entry is in a state where
1918 * it can accept more data (ie with write() method)
1919 */
1920bool
1921StoreEntry::isAccepting() const
1922{
1923 if (STORE_PENDING != store_status)
1924 return false;
1925
1926 if (EBIT_TEST(flags, ENTRY_ABORTED))
1927 return false;
1928
1929 return true;
1930}
1931
e6ccf245 1932/* NullStoreEntry */
1933
1934NullStoreEntry NullStoreEntry::_instance;
1935
1936NullStoreEntry *
1937NullStoreEntry::getInstance()
1938{
1939 return &_instance;
1940}
332dafa2 1941
1942char const *
1943NullStoreEntry::getMD5Text() const
1944{
1945 return "N/A";
1946}
528b2c61 1947
43ae1d95 1948void
1949NullStoreEntry::operator delete(void*)
1950{
1951 fatal ("Attempt to delete NullStoreEntry\n");
1952}
1953
528b2c61 1954char const *
1955NullStoreEntry::getSerialisedMetaData()
1956{
1957 return NULL;
1958}
1959
1960#ifndef _USE_INLINE_
1961#include "Store.cci"
1962#endif