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