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