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