]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store.cc
eliminate unneeded tcp_rcv_bufsize
[thirdparty/squid.git] / src / store.cc
CommitLineData
164f7660 1
30a4f2a8 2/*
c40acff3 3 * $Id: store.cc,v 1.472 1998/11/13 22:06:36 rousskov Exp $
30a4f2a8 4 *
8638fc66 5 * DEBUG: section 20 Storage Manager
30a4f2a8 6 * AUTHOR: Harvest Derived
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
e25c139f 13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * 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.
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
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
c943f331 34 */
090089c4 35
f09f5b26 36#include "squid.h"
090089c4 37
38#define REBUILD_TIMESTAMP_DELTA_MAX 2
227fbb74 39
fcf5283d 40#define STORE_IN_MEM_BUCKETS (229)
090089c4 41
0ee4272b 42const char *memStatusStr[] =
e62d2dea 43{
9dfb6c1c 44 "NOT_IN_MEMORY",
9dfb6c1c 45 "IN_MEMORY"
46};
47
0ee4272b 48const char *pingStatusStr[] =
e62d2dea 49{
f17936ab 50 "PING_NONE",
9dfb6c1c 51 "PING_WAITING",
52 "PING_TIMEOUT",
f17936ab 53 "PING_DONE"
9dfb6c1c 54};
55
0ee4272b 56const char *storeStatusStr[] =
e62d2dea 57{
9dfb6c1c 58 "STORE_OK",
59 "STORE_PENDING",
60 "STORE_ABORTED"
61};
62
0ee4272b 63const char *swapStatusStr[] =
e62d2dea 64{
8350fe9b 65 "SWAPOUT_NONE",
66 "SWAPOUT_OPENING",
67 "SWAPOUT_WRITING",
68 "SWAPOUT_DONE"
9dfb6c1c 69};
70
0a0bf5db 71typedef struct lock_ctrl_t {
582b6456 72 SIH *callback;
0a0bf5db 73 void *callback_data;
74 StoreEntry *e;
75} lock_ctrl_t;
76
e3ef2b09 77/*
78 * local function prototypes
79 */
01fe9bf4 80static int storeCheckExpired(const StoreEntry *);
f5b8bbc4 81static int storeEntryLocked(const StoreEntry *);
82static int storeEntryValidLength(const StoreEntry *);
83static void storeGetMemSpace(int);
b93bcace 84static void storeHashDelete(StoreEntry *);
9fb13bb6 85static MemObject *new_MemObject(const char *, const char *);
6cf028ab 86static void destroy_MemObject(StoreEntry *);
ec878047 87static FREE destroy_StoreEntry;
f5b8bbc4 88static void storePurgeMem(StoreEntry *);
007b8be4 89static int getKeyCounter(void);
8350fe9b 90static int storeKeepInMemory(const StoreEntry *);
8423ff74 91static OBJH storeCheckCachableStats;
a21fbb54 92
e3ef2b09 93/*
94 * local variables
95 */
b93bcace 96static dlink_list inmem_list;
e954773d 97static int store_pages_high = 0;
98static int store_pages_low = 0;
58104eab 99static int store_swap_high = 0;
100static int store_swap_low = 0;
d1497906 101static int store_swap_mid = 0;
e924600d 102static int store_maintain_rate;
66cedb85 103
b8d8561b 104static MemObject *
9fb13bb6 105new_MemObject(const char *url, const char *log_url)
227fbb74 106{
7021844c 107 MemObject *mem = memAllocate(MEM_MEMOBJECT);
cb69b4c7 108 mem->reply = httpReplyCreate();
9fb13bb6 109 mem->url = xstrdup(url);
88738790 110 mem->log_url = xstrdup(log_url);
8350fe9b 111 mem->swapout.fd = -1;
07304bf9 112 mem->object_sz = -1;
ed03a839 113 mem->fd = -1;
59c4d35b 114 /* XXX account log_url */
a3d5953d 115 debug(20, 3) ("new_MemObject: returning %p\n", mem);
30a4f2a8 116 return mem;
227fbb74 117}
118
f09f5b26 119StoreEntry *
9fb13bb6 120new_StoreEntry(int mem_obj_flag, const char *url, const char *log_url)
090089c4 121{
122 StoreEntry *e = NULL;
7021844c 123 e = memAllocate(MEM_STOREENTRY);
227fbb74 124 if (mem_obj_flag)
9fb13bb6 125 e->mem_obj = new_MemObject(url, log_url);
a3d5953d 126 debug(20, 3) ("new_StoreEntry: returning %p\n", e);
e17dc75c 127 e->expires = e->lastmod = e->lastref = e->timestamp = -1;
227fbb74 128 return e;
090089c4 129}
130
b8d8561b 131static void
0e473d70 132destroy_MemObject(StoreEntry * e)
090089c4 133{
6cf028ab 134 MemObject *mem = e->mem_obj;
123abbe1 135 const Ctx ctx = ctx_enter(mem->url);
a3d5953d 136 debug(20, 3) ("destroy_MemObject: destroying %p\n", mem);
41f7e38d 137 e->mem_obj = NULL;
9e665466 138 if (!shutting_down)
e82d6d21 139 assert(mem->swapout.fd == -1);
18fe65d0 140 stmemFree(&mem->data_hdr);
141 mem->inmem_hi = 0;
59c4d35b 142 /* XXX account log_url */
6cf028ab 143#if USE_ASYNC_IO
0e473d70 144 while (mem->clients != NULL)
6cf028ab 145 storeUnregister(e, mem->clients->callback_data);
146#endif
6982a226 147 /*
148 * There is no way to abort FD-less clients, so they might
149 * still have mem->clients set if mem->fd == -1
150 */
151 assert(mem->fd == -1 || mem->clients == NULL);
cb69b4c7 152 httpReplyDestroy(mem->reply);
30a4f2a8 153 requestUnlink(mem->request);
154 mem->request = NULL;
2ac76861 155 ctx_exit(ctx); /* must exit before we free mem->url */
48959832 156 safe_free(mem->url);
157 safe_free(mem->log_url);
3f6c0fb2 158 memFree(MEM_MEMOBJECT, mem);
090089c4 159}
160
b8d8561b 161static void
ec878047 162destroy_StoreEntry(void *data)
090089c4 163{
ec878047 164 StoreEntry *e = data;
a3d5953d 165 debug(20, 3) ("destroy_StoreEntry: destroying %p\n", e);
9e975e4e 166 assert(e != NULL);
227fbb74 167 if (e->mem_obj)
6cf028ab 168 destroy_MemObject(e);
043b055b 169 storeHashDelete(e);
9fb13bb6 170 assert(e->key == NULL);
8c128028 171 memFree(MEM_STOREENTRY, e);
227fbb74 172}
090089c4 173
090089c4 174/* ----- INTERFACE BETWEEN STORAGE MANAGER AND HASH TABLE FUNCTIONS --------- */
175
f09f5b26 176void
9fb13bb6 177storeHashInsert(StoreEntry * e, const cache_key * key)
090089c4 178{
a3d5953d 179 debug(20, 3) ("storeHashInsert: Inserting Entry %p key '%s'\n",
9fb13bb6 180 e, storeKeyText(key));
181 e->key = storeKeyDup(key);
b93bcace 182 hash_join(store_table, (hash_link *) e);
66f07209 183 dlinkAdd(e, &e->lru, &store_list);
090089c4 184}
185
b93bcace 186static void
b8d8561b 187storeHashDelete(StoreEntry * e)
090089c4 188{
b93bcace 189 hash_remove_link(store_table, (hash_link *) e);
e3ef2b09 190 dlinkDelete(&e->lru, &store_list);
9fb13bb6 191 storeKeyFree(e->key);
192 e->key = NULL;
090089c4 193}
194
090089c4 195/* -------------------------------------------------------------------------- */
196
090089c4 197
198/* get rid of memory copy of the object */
620da955 199/* Only call this if storeCheckPurgeMem(e) returns 1 */
24382924 200static void
b8d8561b 201storePurgeMem(StoreEntry * e)
090089c4 202{
2aca8433 203 if (e->mem_obj == NULL)
090089c4 204 return;
9fb13bb6 205 debug(20, 3) ("storePurgeMem: Freeing memory-copy of %s\n",
206 storeKeyText(e->key));
090089c4 207 storeSetMemStatus(e, NOT_IN_MEMORY);
6cf028ab 208 destroy_MemObject(e);
06e8899b 209 if (e->swap_status != SWAPOUT_DONE)
8272aded 210 storeRelease(e);
090089c4 211}
212
0a0bf5db 213void
95c4b18f 214storeLockObject(StoreEntry * e)
090089c4 215{
b93bcace 216 if (e->lock_count++ == 0) {
e3ef2b09 217 dlinkDelete(&e->lru, &store_list);
218 dlinkAdd(e, &e->lru, &store_list);
b93bcace 219 }
a3d5953d 220 debug(20, 3) ("storeLockObject: key '%s' count=%d\n",
9fb13bb6 221 storeKeyText(e->key), (int) e->lock_count);
b8de7ebe 222 e->lastref = squid_curtime;
090089c4 223}
224
b8d8561b 225void
226storeReleaseRequest(StoreEntry * e)
2285407f 227{
d46a87a8 228 if (EBIT_TEST(e->flags, RELEASE_REQUEST))
58bcd31b 229 return;
9fb13bb6 230 debug(20, 3) ("storeReleaseRequest: '%s'\n", storeKeyText(e->key));
d46a87a8 231 EBIT_SET(e->flags, RELEASE_REQUEST);
f3e570e9 232 /*
233 * Clear cachable flag here because we might get called before
234 * anyone else even looks at the cachability flag. Also, this
235 * prevents httpMakePublic from really setting a public key.
236 */
d46a87a8 237 EBIT_CLR(e->flags, ENTRY_CACHABLE);
fe54d06d 238 storeSetPrivateKey(e);
2285407f 239}
240
090089c4 241/* unlock object, return -1 if object get released after unlock
242 * otherwise lock_count */
b8d8561b 243int
244storeUnlockObject(StoreEntry * e)
090089c4 245{
6c895381 246 e->lock_count--;
a3d5953d 247 debug(20, 3) ("storeUnlockObject: key '%s' count=%d\n",
9fb13bb6 248 storeKeyText(e->key), e->lock_count);
30a4f2a8 249 if (e->lock_count)
a1e47288 250 return (int) e->lock_count;
5b00be7a 251 if (e->store_status == STORE_PENDING) {
d46a87a8 252 assert(!EBIT_TEST(e->flags, ENTRY_DISPATCHED));
253 EBIT_SET(e->flags, RELEASE_REQUEST);
5b00be7a 254 }
9e975e4e 255 assert(storePendingNClients(e) == 0);
d46a87a8 256 if (EBIT_TEST(e->flags, RELEASE_REQUEST))
30a4f2a8 257 storeRelease(e);
8350fe9b 258 else if (storeKeepInMemory(e)) {
259 storeSetMemStatus(e, IN_MEMORY);
260 requestUnlink(e->mem_obj->request);
261 e->mem_obj->request = NULL;
66f07209 262 } else {
30a4f2a8 263 storePurgeMem(e);
d46a87a8 264 if (EBIT_TEST(e->flags, KEY_PRIVATE)) {
66f07209 265 dlinkDelete(&e->lru, &store_list);
266 dlinkAddTail(e, &e->lru, &store_list);
267 }
268 }
6c895381 269 return 0;
090089c4 270}
271
272/* Lookup an object in the cache.
273 * return just a reference to object, don't start swapping in yet. */
b8d8561b 274StoreEntry *
9fb13bb6 275storeGet(const cache_key * key)
090089c4 276{
9fb13bb6 277 debug(20, 3) ("storeGet: looking up %s\n", storeKeyText(key));
278 return (StoreEntry *) hash_lookup(store_table, key);
090089c4 279}
280
08e5d64f 281StoreEntry *
282storeGetPublic(const char *uri, const method_t method)
283{
674ac814 284 return storeGet(storeKeyPublic(uri, method));
08e5d64f 285}
286
007b8be4 287static int
288getKeyCounter(void)
04e8dbaa 289{
007b8be4 290 static int key_counter = 0;
291 if (++key_counter < 0)
2cc3f720 292 key_counter = 1;
007b8be4 293 return key_counter;
04e8dbaa 294}
295
6c57e268 296void
b8d8561b 297storeSetPrivateKey(StoreEntry * e)
227fbb74 298{
9fb13bb6 299 const cache_key *newkey;
300 MemObject *mem = e->mem_obj;
d46a87a8 301 if (e->key && EBIT_TEST(e->flags, KEY_PRIVATE))
6eb42cae 302 return; /* is already private */
b109de6b 303 if (e->key) {
304 if (e->swap_file_number > -1)
305 storeDirSwapLog(e, SWAP_LOG_DEL);
bc0bce21 306 storeHashDelete(e);
b109de6b 307 }
9fb13bb6 308 if (mem != NULL) {
007b8be4 309 mem->id = getKeyCounter();
310 newkey = storeKeyPrivate(mem->url, mem->method, mem->id);
9fb13bb6 311 } else {
007b8be4 312 newkey = storeKeyPrivate("JUNK", METHOD_NONE, getKeyCounter());
9fb13bb6 313 }
314 assert(hash_lookup(store_table, newkey) == NULL);
d46a87a8 315 EBIT_SET(e->flags, KEY_PRIVATE);
8638fc66 316 storeHashInsert(e, newkey);
227fbb74 317}
318
b8d8561b 319void
320storeSetPublicKey(StoreEntry * e)
227fbb74 321{
6eb42cae 322 StoreEntry *e2 = NULL;
9fb13bb6 323 const cache_key *newkey;
324 MemObject *mem = e->mem_obj;
d46a87a8 325 if (e->key && !EBIT_TEST(e->flags, KEY_PRIVATE))
6eb42cae 326 return; /* is already public */
9fb13bb6 327 assert(mem);
f3e570e9 328 /*
329 * We can't make RELEASE_REQUEST objects public. Depending on
330 * when RELEASE_REQUEST gets set, we might not be swapping out
331 * the object. If we're not swapping out, then subsequent
332 * store clients won't be able to access object data which has
333 * been freed from memory.
d87ebd78 334 *
335 * If RELEASE_REQUEST is set, then ENTRY_CACHABLE should not
336 * be set, and storeSetPublicKey() should not be called.
f3e570e9 337 */
d46a87a8 338 assert(!EBIT_TEST(e->flags, RELEASE_REQUEST));
2ac237e2 339 newkey = storeKeyPublic(mem->url, mem->method);
9fb13bb6 340 if ((e2 = (StoreEntry *) hash_lookup(store_table, newkey))) {
341 debug(20, 3) ("storeSetPublicKey: Making old '%s' private.\n", mem->url);
07622ccd 342 storeSetPrivateKey(e2);
30a4f2a8 343 storeRelease(e2);
2ac237e2 344 newkey = storeKeyPublic(mem->url, mem->method);
6eb42cae 345 }
bc0bce21 346 if (e->key)
347 storeHashDelete(e);
d46a87a8 348 EBIT_CLR(e->flags, KEY_PRIVATE);
8638fc66 349 storeHashInsert(e, newkey);
b109de6b 350 if (e->swap_file_number > -1)
351 storeDirSwapLog(e, SWAP_LOG_ADD);
227fbb74 352}
353
b8d8561b 354StoreEntry *
92695e5e 355storeCreateEntry(const char *url, const char *log_url, request_flags flags, method_t method)
090089c4 356{
090089c4 357 StoreEntry *e = NULL;
30a4f2a8 358 MemObject *mem = NULL;
92695e5e 359 debug(20, 3) ("storeCreateEntry: '%s'\n", url);
090089c4 360
f09f5b26 361 e = new_StoreEntry(STORE_ENTRY_WITH_MEMOBJ, url, log_url);
30a4f2a8 362 e->lock_count = 1; /* Note lock here w/o calling storeLock() */
363 mem = e->mem_obj;
2ac237e2 364 mem->method = method;
92695e5e 365 if (neighbors_do_private_keys || !flags.hierarchical)
86101e40 366 storeSetPrivateKey(e);
367 else
368 storeSetPublicKey(e);
92695e5e 369 if (flags.cachable) {
d46a87a8 370 EBIT_SET(e->flags, ENTRY_CACHABLE);
371 EBIT_CLR(e->flags, RELEASE_REQUEST);
090089c4 372 } else {
d46a87a8 373 EBIT_CLR(e->flags, ENTRY_CACHABLE);
2daae136 374 storeReleaseRequest(e);
090089c4 375 }
234967c9 376 e->store_status = STORE_PENDING;
090089c4 377 storeSetMemStatus(e, NOT_IN_MEMORY);
8350fe9b 378 e->swap_status = SWAPOUT_NONE;
090089c4 379 e->swap_file_number = -1;
090089c4 380 e->refcount = 0;
b8de7ebe 381 e->lastref = squid_curtime;
ca98227c 382 e->timestamp = 0; /* set in storeTimestampsSet() */
30a4f2a8 383 e->ping_status = PING_NONE;
d46a87a8 384 EBIT_SET(e->flags, ENTRY_VALIDATED);
7e3e1d01 385#ifdef PPNR_WIP
d46a87a8 386 EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT);
7e3e1d01 387#endif /* PPNR_WIP */
090089c4 388 return e;
389}
390
6eb42cae 391/* Mark object as expired */
b8d8561b 392void
393storeExpireNow(StoreEntry * e)
9174e204 394{
9fb13bb6 395 debug(20, 3) ("storeExpireNow: '%s'\n", storeKeyText(e->key));
b8de7ebe 396 e->expires = squid_curtime;
9174e204 397}
398
090089c4 399/* Append incoming data from a primary server to an entry. */
b8d8561b 400void
b8014333 401storeAppend(StoreEntry * e, const char *buf, int len)
090089c4 402{
3a1c3e2f 403 MemObject *mem = e->mem_obj;
404 assert(mem != NULL);
405 assert(len >= 0);
090089c4 406 if (len) {
d0e2935f 407 debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n",
408 len,
409 storeKeyText(e->key));
38792624 410 storeGetMemSpace(len);
18fe65d0 411 stmemAppend(&mem->data_hdr, buf, len);
8350fe9b 412 mem->inmem_hi += len;
090089c4 413 }
d46a87a8 414 if (EBIT_TEST(e->flags, DELAY_SENDING))
d0e2935f 415 return;
9d66d521 416#ifdef OPTIMISTIC_IO
417 storeLockObject(e);
418#endif
d0e2935f 419 InvokeHandlers(e);
8350fe9b 420 storeCheckSwapOut(e);
9d66d521 421#ifdef OPTIMISTIC_IO
422 storeUnlockObject(e);
423#endif
090089c4 424}
425
24382924 426#ifdef __STDC__
b8d8561b 427void
fe4e214f 428storeAppendPrintf(StoreEntry * e, const char *fmt,...)
c30c5a73 429{
15c05bb0 430 va_list args;
15c05bb0 431 va_start(args, fmt);
c30c5a73 432#else
b8d8561b 433void
434storeAppendPrintf(va_alist)
15c05bb0 435 va_dcl
436{
437 va_list args;
438 StoreEntry *e = NULL;
0ee4272b 439 const char *fmt = NULL;
15c05bb0 440 va_start(args);
441 e = va_arg(args, StoreEntry *);
442 fmt = va_arg(args, char *);
c30c5a73 443#endif
cb69b4c7 444 storeAppendVPrintf(e, fmt, args);
445 va_end(args);
446}
447
448/* used be storeAppendPrintf and Packer */
449void
450storeAppendVPrintf(StoreEntry * e, const char *fmt, va_list vargs)
451{
452 LOCAL_ARRAY(char, buf, 4096);
15c05bb0 453 buf[0] = '\0';
cb69b4c7 454 vsnprintf(buf, 4096, fmt, vargs);
15c05bb0 455 storeAppend(e, buf, strlen(buf));
c30c5a73 456}
457
8423ff74 458struct _store_check_cachable_hist {
459 struct {
460 int non_get;
461 int not_entry_cachable;
462 int release_request;
463 int wrong_content_length;
464 int negative_cached;
465 int too_big;
466 int private_key;
c5f627c2 467 int too_many_open_files;
8423ff74 468 int lru_age_too_low;
469 } no;
470 struct {
471 int Default;
472 } yes;
473} store_check_cachable_hist;
474
c47511fd 475int
476storeTooManyDiskFilesOpen(void)
477{
478 if (Config.max_open_disk_fds == 0)
479 return 0;
480 if (open_disk_fd > Config.max_open_disk_fds)
481 return 1;
482 return 0;
483}
484
f09f5b26 485int
8350fe9b 486storeCheckCachable(StoreEntry * e)
6602e70e 487{
2ac237e2 488#if CACHE_ALL_METHODS
489 if (e->mem_obj->method != METHOD_GET) {
8350fe9b 490 debug(20, 2) ("storeCheckCachable: NO: non-GET method\n");
8423ff74 491 store_check_cachable_hist.no.non_get++;
2ac237e2 492 } else
493#endif
d46a87a8 494 if (!EBIT_TEST(e->flags, ENTRY_CACHABLE)) {
8350fe9b 495 debug(20, 2) ("storeCheckCachable: NO: not cachable\n");
8423ff74 496 store_check_cachable_hist.no.not_entry_cachable++;
d46a87a8 497 } else if (EBIT_TEST(e->flags, RELEASE_REQUEST)) {
8350fe9b 498 debug(20, 2) ("storeCheckCachable: NO: release requested\n");
8423ff74 499 store_check_cachable_hist.no.release_request++;
d46a87a8 500 } else if (e->store_status == STORE_OK && EBIT_TEST(e->flags, ENTRY_BAD_LENGTH)) {
8350fe9b 501 debug(20, 2) ("storeCheckCachable: NO: wrong content-length\n");
8423ff74 502 store_check_cachable_hist.no.wrong_content_length++;
d46a87a8 503 } else if (EBIT_TEST(e->flags, ENTRY_NEGCACHED)) {
c0dee43f 504 debug(20, 3) ("storeCheckCachable: NO: negative cached\n");
8423ff74 505 store_check_cachable_hist.no.negative_cached++;
3e98df20 506 return 0; /* avoid release call below */
8350fe9b 507 } else if (e->mem_obj->inmem_hi > Config.Store.maxObjectSize) {
508 debug(20, 2) ("storeCheckCachable: NO: too big\n");
8423ff74 509 store_check_cachable_hist.no.too_big++;
d46a87a8 510 } else if (EBIT_TEST(e->flags, KEY_PRIVATE)) {
8350fe9b 511 debug(20, 3) ("storeCheckCachable: NO: private key\n");
8423ff74 512 store_check_cachable_hist.no.private_key++;
c47511fd 513 } else if (storeTooManyDiskFilesOpen()) {
c5f627c2 514 debug(20, 2) ("storeCheckCachable: NO: too many disk files open\n");
515 store_check_cachable_hist.no.too_many_open_files++;
734b57eb 516 } else if (storeExpiredReferenceAge() < 300) {
c8b09b26 517 debug(20, 2) ("storeCheckCachable: NO: LRU Age = %d\n",
518 storeExpiredReferenceAge());
8423ff74 519 store_check_cachable_hist.no.lru_age_too_low++;
d4432957 520 } else {
8423ff74 521 store_check_cachable_hist.yes.Default++;
6602e70e 522 return 1;
d4432957 523 }
2daae136 524 storeReleaseRequest(e);
d46a87a8 525 EBIT_CLR(e->flags, ENTRY_CACHABLE);
6602e70e 526 return 0;
527}
528
8423ff74 529static void
530storeCheckCachableStats(StoreEntry * sentry)
531{
c40acff3 532 storeAppendPrintf(sentry, "Category\t Count\n");
533
8423ff74 534 storeAppendPrintf(sentry, "no.non_get\t%d\n",
535 store_check_cachable_hist.no.non_get);
536 storeAppendPrintf(sentry, "no.not_entry_cachable\t%d\n",
537 store_check_cachable_hist.no.not_entry_cachable);
538 storeAppendPrintf(sentry, "no.release_request\t%d\n",
539 store_check_cachable_hist.no.release_request);
540 storeAppendPrintf(sentry, "no.wrong_content_length\t%d\n",
541 store_check_cachable_hist.no.wrong_content_length);
542 storeAppendPrintf(sentry, "no.negative_cached\t%d\n",
543 store_check_cachable_hist.no.negative_cached);
544 storeAppendPrintf(sentry, "no.too_big\t%d\n",
545 store_check_cachable_hist.no.too_big);
546 storeAppendPrintf(sentry, "no.private_key\t%d\n",
547 store_check_cachable_hist.no.private_key);
c5f627c2 548 storeAppendPrintf(sentry, "no.too_many_open_files\t%d\n",
549 store_check_cachable_hist.no.too_many_open_files);
8423ff74 550 storeAppendPrintf(sentry, "no.lru_age_too_low\t%d\n",
551 store_check_cachable_hist.no.lru_age_too_low);
552 storeAppendPrintf(sentry, "yes.default\t%d\n",
553 store_check_cachable_hist.yes.Default);
554}
555
090089c4 556/* Complete transfer into the local cache. */
b8d8561b 557void
558storeComplete(StoreEntry * e)
090089c4 559{
9fb13bb6 560 debug(20, 3) ("storeComplete: '%s'\n", storeKeyText(e->key));
22955fba 561 assert(e->store_status == STORE_PENDING);
07304bf9 562 e->mem_obj->object_sz = e->mem_obj->inmem_hi;
234967c9 563 e->store_status = STORE_OK;
8350fe9b 564 assert(e->mem_status == NOT_IN_MEMORY);
41587298 565 if (!storeEntryValidLength(e)) {
d46a87a8 566 EBIT_SET(e->flags, ENTRY_BAD_LENGTH);
41587298 567 storeReleaseRequest(e);
568 }
6cfa8966 569#if USE_CACHE_DIGESTS
544b1fd4 570 if (e->mem_obj->request)
571 e->mem_obj->request->hier.store_complete_stop = current_time;
39edba21 572#endif
3a1c3e2f 573 InvokeHandlers(e);
8c123b71 574 storeCheckSwapOut(e);
7e3e1d01 575}
576
1b72bda1 577#ifdef PPNR_WIP
7e3e1d01 578void
e82d6d21 579storePPNR(StoreEntry * e)
7e3e1d01 580{
d46a87a8 581 assert(EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT));
582 EBIT_CLR(e->flags, ENTRY_FWD_HDR_WAIT);
090089c4 583}
5942e8d4 584
1b72bda1 585#endif /* PPNR_WIP */
090089c4 586
587/*
474cac1b 588 * Someone wants to abort this transfer. Set the reason in the
589 * request structure, call the server-side callback and mark the
590 * entry for releasing
090089c4 591 */
b8d8561b 592void
9b312a19 593storeAbort(StoreEntry * e, int cbflag)
090089c4 594{
3e98df20 595 MemObject *mem = e->mem_obj;
6801f8a8 596 STABH *callback;
597 void *data;
8f39b81d 598 assert(e->store_status == STORE_PENDING);
599 assert(mem != NULL);
9fb13bb6 600 debug(20, 6) ("storeAbort: %s\n", storeKeyText(e->key));
3d02186d 601 storeLockObject(e); /* lock while aborting */
79b5cc5f 602 storeNegativeCache(e);
474cac1b 603 storeReleaseRequest(e);
234967c9 604 e->store_status = STORE_ABORTED;
8350fe9b 605 storeSetMemStatus(e, NOT_IN_MEMORY);
090089c4 606 /* No DISK swap for negative cached object */
8350fe9b 607 e->swap_status = SWAPOUT_NONE;
496e1d76 608 /*
609 * We assign an object length here. The only other place we assign
610 * the object length is in storeComplete()
611 */
07304bf9 612 mem->object_sz = mem->inmem_hi;
474cac1b 613 /* Notify the server side */
614 if (cbflag && mem->abort.callback) {
6801f8a8 615 callback = mem->abort.callback;
616 data = mem->abort.data;
bfcaf585 617 mem->abort.callback = NULL;
6801f8a8 618 mem->abort.data = NULL;
619 callback(data);
bfcaf585 620 }
474cac1b 621 /* Notify the client side */
090089c4 622 InvokeHandlers(e);
6e86c3e8 623 /* Do we need to close the swapout file? */
624 /* Not if we never started swapping out */
6cf028ab 625 /* But we may need to cancel an open/stat in progress if using ASYNC */
626#if USE_ASYNC_IO
627 aioCancel(-1, e);
628#endif
3d02186d 629 if (e->swap_file_number > -1) {
6cf028ab 630#if USE_ASYNC_IO
3d02186d 631 /* Need to cancel any pending ASYNC writes right now */
632 if (mem->swapout.fd >= 0)
633 aioCancel(mem->swapout.fd, NULL);
6cf028ab 634#endif
3d02186d 635 /* we have to close the disk file if there is no write pending */
61038223 636 if (!storeSwapOutWriteQueued(mem))
3d02186d 637 storeSwapOutFileClose(e);
638 }
639 storeUnlockObject(e); /* unlock */
090089c4 640}
641
090089c4 642/* Clear Memory storage to accommodate the given object len */
38792624 643static void
d4432957 644storeGetMemSpace(int size)
090089c4 645{
b32508fb 646 StoreEntry *e = NULL;
20cba4b4 647 int released = 0;
b32508fb 648 static time_t last_check = 0;
e954773d 649 int pages_needed;
b93bcace 650 dlink_node *m;
d6ea85ce 651 dlink_node *head;
79d39a72 652 dlink_node *prev = NULL;
b32508fb 653 if (squid_curtime == last_check)
38792624 654 return;
b32508fb 655 last_check = squid_curtime;
e954773d 656 pages_needed = (size / SM_PAGE_SIZE) + 1;
3f6c0fb2 657 if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_high)
38792624 658 return;
311ea387 659 if (store_rebuilding)
38792624 660 return;
a3d5953d 661 debug(20, 2) ("storeGetMemSpace: Starting, need %d pages\n", pages_needed);
d6ea85ce 662 head = inmem_list.head;
b93bcace 663 for (m = inmem_list.tail; m; m = prev) {
d6ea85ce 664 if (m == head)
665 break;
8350fe9b 666 prev = m->prev;
b93bcace 667 e = m->data;
d6ea85ce 668 if (storeEntryLocked(e)) {
5999b776 669 dlinkDelete(m, &inmem_list);
670 dlinkAdd(e, m, &inmem_list);
8350fe9b 671 continue;
d6ea85ce 672 }
20cba4b4 673 released++;
2d51a60e 674 storePurgeMem(e);
d6ea85ce 675 if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_high)
8350fe9b 676 break;
677 }
5e3d4fef 678 debug(20, 3) ("storeGetMemSpace stats:\n");
59c4d35b 679 debug(20, 3) (" %6d HOT objects\n", hot_obj_count);
20cba4b4 680 debug(20, 3) (" %6d were released\n", released);
090089c4 681}
682
090089c4 683/* The maximum objects to scan for maintain storage space */
fcefe642 684#define MAINTAIN_MAX_SCAN 1024
685#define MAINTAIN_MAX_REMOVE 64
090089c4 686
fcefe642 687/*
688 * This routine is to be called by main loop in main.c.
689 * It removes expired objects on only one bucket for each time called.
690 * returns the number of objects removed
691 *
692 * This should get called 1/s from main().
693 */
679ac4f0 694void
79d39a72 695storeMaintainSwapSpace(void *datanotused)
090089c4 696{
b93bcace 697 dlink_node *m;
79d39a72 698 dlink_node *prev = NULL;
a1b0d7cf 699 StoreEntry *e = NULL;
090089c4 700 int scanned = 0;
090089c4 701 int locked = 0;
679ac4f0 702 int expired = 0;
20cba4b4 703 int max_scan;
704 int max_remove;
ec14f197 705 static time_t last_warn_time = 0;
fcefe642 706 /* We can't delete objects while rebuilding swap */
c8b09b26 707 if (store_rebuilding) {
708 eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0, 1);
679ac4f0 709 return;
d1497906 710 } else if (store_swap_size < store_swap_mid) {
711 max_scan = 100;
712 max_remove = 8;
713 eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0, 1);
c8b09b26 714 } else if (store_swap_size < store_swap_high) {
715 max_scan = 200;
716 max_remove = 8;
717 eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 0.1, 1);
20cba4b4 718 } else {
4cb56589 719 max_scan = 500;
c8b09b26 720 max_remove = 32;
721 eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 0.0, 1);
20cba4b4 722 }
fcefe642 723 debug(20, 3) ("storeMaintainSwapSpace\n");
e3ef2b09 724 for (m = store_list.tail; m; m = prev) {
b93bcace 725 prev = m->prev;
726 e = m->data;
d150898a 727 scanned++;
b93bcace 728 if (storeEntryLocked(e)) {
ac2197dc 729 /*
730 * If there is a locked entry at the tail of the LRU list,
731 * move it to the beginning to get it out of the way.
732 * Theoretically, we might have all locked objects at the
733 * tail, and then we'll never remove anything here and the
734 * LRU age will go to zero.
735 */
736 if (memInUse(MEM_STOREENTRY) > max_scan) {
4b4cd312 737 dlinkDelete(&e->lru, &store_list);
738 dlinkAdd(e, &e->lru, &store_list);
ac2197dc 739 }
b93bcace 740 locked++;
01fe9bf4 741 } else if (storeCheckExpired(e)) {
b109de6b 742 expired++;
743 storeRelease(e);
090089c4 744 }
d150898a 745 if (expired >= max_remove)
b93bcace 746 break;
d150898a 747 if (scanned >= max_scan)
b93bcace 748 break;
090089c4 749 }
4cb56589 750 debug(20, 3) ("storeMaintainSwapSpace stats:\n");
751 debug(20, 3) (" %6d objects\n", memInUse(MEM_STOREENTRY));
752 debug(20, 3) (" %6d were scanned\n", scanned);
753 debug(20, 3) (" %6d were locked\n", locked);
754 debug(20, 3) (" %6d were expired\n", expired);
fcefe642 755 if (store_swap_size < Config.Swap.maxSize)
b93bcace 756 return;
757 if (squid_curtime - last_warn_time < 10)
758 return;
759 debug(20, 0) ("WARNING: Disk space over limit: %d KB > %d KB\n",
760 store_swap_size, Config.Swap.maxSize);
761 last_warn_time = squid_curtime;
090089c4 762}
763
764
765/* release an object from a cache */
cc61958c 766/* return number of objects released. */
6c78a099 767void
b8d8561b 768storeRelease(StoreEntry * e)
090089c4 769{
9fb13bb6 770 debug(20, 3) ("storeRelease: Releasing: '%s'\n", storeKeyText(e->key));
090089c4 771 /* If, for any reason we can't discard this object because of an
772 * outstanding request, mark it for pending release */
773 if (storeEntryLocked(e)) {
9174e204 774 storeExpireNow(e);
a3d5953d 775 debug(20, 3) ("storeRelease: Only setting RELEASE_REQUEST bit\n");
2daae136 776 storeReleaseRequest(e);
6c78a099 777 return;
090089c4 778 }
311ea387 779 if (store_rebuilding) {
a3d5953d 780 debug(20, 2) ("storeRelease: Delaying release until store is rebuilt: '%s'\n",
9fb13bb6 781 storeUrl(e));
30a4f2a8 782 storeExpireNow(e);
97dad8a9 783 storeReleaseRequest(e);
6c78a099 784 return;
30a4f2a8 785 }
77059ddf 786#if USE_ASYNC_IO
787 /*
788 * Make sure all forgotten async ops are cancelled
789 */
790 aioCancel(-1, e);
6cf028ab 791#endif
a65ff22e 792 storeLog(STORE_LOG_RELEASE, e);
43fee0b8 793 if (e->swap_file_number > -1) {
25535cbe 794 storeUnlinkFileno(e->swap_file_number);
d961be0a 795 storeDirMapBitReset(e->swap_file_number);
a65ff22e 796 if (e->swap_status == SWAPOUT_DONE)
d46a87a8 797 if (EBIT_TEST(e->flags, ENTRY_VALIDATED))
7b3d6868 798 storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, -1);
d46a87a8 799 if (!EBIT_TEST(e->flags, KEY_PRIVATE))
b109de6b 800 storeDirSwapLog(e, SWAP_LOG_DEL);
090089c4 801 }
8350fe9b 802 storeSetMemStatus(e, NOT_IN_MEMORY);
30a4f2a8 803 destroy_StoreEntry(e);
090089c4 804}
805
090089c4 806/* return 1 if a store entry is locked */
24382924 807static int
fe4e214f 808storeEntryLocked(const StoreEntry * e)
090089c4 809{
30a4f2a8 810 if (e->lock_count)
811 return 1;
6cf028ab 812 if (e->swap_status == SWAPOUT_OPENING)
813 return 1;
8350fe9b 814 if (e->swap_status == SWAPOUT_WRITING)
30a4f2a8 815 return 1;
a1e47288 816 if (e->store_status == STORE_PENDING)
817 return 1;
d46a87a8 818 if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
365cb147 819 return 1;
30a4f2a8 820 return 0;
090089c4 821}
822
24382924 823static int
fe4e214f 824storeEntryValidLength(const StoreEntry * e)
6602e70e 825{
ffe4a367 826 int diff;
d8b249ef 827 const HttpReply *reply;
8a5e92ce 828 assert(e->mem_obj != NULL);
07304bf9 829 reply = e->mem_obj->reply;
9fb13bb6 830 debug(20, 3) ("storeEntryValidLength: Checking '%s'\n", storeKeyText(e->key));
07304bf9 831 debug(20, 5) ("storeEntryValidLength: object_len = %d\n",
832 objectLen(e));
833 debug(20, 5) ("storeEntryValidLength: hdr_sz = %d\n",
834 reply->hdr_sz);
835 debug(20, 5) ("storeEntryValidLength: content_length = %d\n",
d8b249ef 836 reply->content_length);
837 if (reply->content_length < 0) {
1790d392 838 debug(20, 5) ("storeEntryValidLength: Unspecified content length: %s\n",
9fb13bb6 839 storeKeyText(e->key));
ffe4a367 840 return 1;
841 }
07304bf9 842 if (reply->hdr_sz == 0) {
1790d392 843 debug(20, 5) ("storeEntryValidLength: Zero header size: %s\n",
9fb13bb6 844 storeKeyText(e->key));
ffe4a367 845 return 1;
846 }
ebf4efff 847 if (e->mem_obj->method == METHOD_HEAD) {
848 debug(20, 5) ("storeEntryValidLength: HEAD request: %s\n",
9fb13bb6 849 storeKeyText(e->key));
ebf4efff 850 return 1;
ffe4a367 851 }
cb69b4c7 852 if (reply->sline.status == HTTP_NOT_MODIFIED)
ebf4efff 853 return 1;
cb69b4c7 854 if (reply->sline.status == HTTP_NO_CONTENT)
ebf4efff 855 return 1;
d8b249ef 856 diff = reply->hdr_sz + reply->content_length - objectLen(e);
ebf4efff 857 if (diff == 0)
858 return 1;
859 debug(20, 3) ("storeEntryValidLength: %d bytes too %s; '%s'\n",
860 diff < 0 ? -diff : diff,
e69324cd 861 diff < 0 ? "big" : "small",
ebf4efff 862 storeKeyText(e->key));
863 return 0;
ffe4a367 864}
6602e70e 865
66cedb85 866static void
867storeInitHashValues(void)
868{
869 int i;
a7e59001 870 /* Calculate size of hash table (maximum currently 64k buckets). */
38792624 871 i = Config.Swap.maxSize / Config.Store.avgObjectSize;
86101e40 872 debug(20, 1) ("Swap maxSize %d KB, estimated %d objects\n",
66cedb85 873 Config.Swap.maxSize, i);
38792624 874 i /= Config.Store.objectsPerBucket;
a3d5953d 875 debug(20, 1) ("Target number of buckets: %d\n", i);
66cedb85 876 /* ideally the full scan period should be configurable, for the
877 * moment it remains at approximately 24 hours. */
9fb13bb6 878 store_hash_buckets = storeKeyHashBuckets(i);
24ffafb4 879 store_maintain_rate = 86400 / store_hash_buckets;
9fb13bb6 880 assert(store_maintain_rate > 0);
7454a5c2 881 debug(20, 1) ("Using %d Store buckets, replacement runs every %d second%s\n",
9fb13bb6 882 store_hash_buckets,
66cedb85 883 store_maintain_rate,
884 store_maintain_rate == 1 ? null_string : "s");
a47b9029 885 debug(20, 1) ("Max Mem size: %d KB\n", Config.Mem.maxSize >> 10);
886 debug(20, 1) ("Max Swap size: %d KB\n", Config.Swap.maxSize);
66cedb85 887}
888
b8d8561b 889void
890storeInit(void)
c943f331 891{
25535cbe 892 storeKeyInit();
66cedb85 893 storeInitHashValues();
9fb13bb6 894 store_table = hash_create(storeKeyHashCmp,
895 store_hash_buckets, storeKeyHashHash);
8638fc66 896 storeDigestInit();
e3ef2b09 897 storeLogOpen();
85407535 898 if (storeVerifyCacheDirs() < 0) {
d377699f 899 xstrncpy(tmp_error_buf,
900 "\tFailed to verify one of the swap directories, Check cache.log\n"
901 "\tfor details. Run 'squid -z' to create swap directories\n"
902 "\tif needed, or if running Squid for the first time.",
903 ERROR_BUF_SZ);
904 fatal(tmp_error_buf);
905 }
e3ef2b09 906 storeDirOpenSwapLogs();
e3ef2b09 907 store_list.head = store_list.tail = NULL;
b93bcace 908 inmem_list.head = inmem_list.tail = NULL;
5830cdb3 909 storeRebuildStart();
4cb56589 910 cachemgrRegister("storedir",
22f3fd98 911 "Store Directory Stats",
1da3b90b 912 storeDirStats, 0, 1);
8423ff74 913 cachemgrRegister("store_check_cachable_stats",
914 "storeCheckCachable() Stats",
915 storeCheckCachableStats, 0, 1);
b1c0cc67 916}
c943f331 917
b8d8561b 918void
919storeConfigure(void)
b1c0cc67 920{
e954773d 921 int store_mem_high = 0;
922 int store_mem_low = 0;
b6f794d6 923 store_mem_high = (long) (Config.Mem.maxSize / 100) *
924 Config.Mem.highWaterMark;
925 store_mem_low = (long) (Config.Mem.maxSize / 100) *
926 Config.Mem.lowWaterMark;
090089c4 927
b1c0cc67 928 store_swap_high = (long) (((float) Config.Swap.maxSize *
929 (float) Config.Swap.highWaterMark) / (float) 100);
930 store_swap_low = (long) (((float) Config.Swap.maxSize *
931 (float) Config.Swap.lowWaterMark) / (float) 100);
d1497906 932 store_swap_mid = (store_swap_high >> 1) + (store_swap_low >> 1);
e954773d 933
934 store_pages_high = store_mem_high / SM_PAGE_SIZE;
935 store_pages_low = store_mem_low / SM_PAGE_SIZE;
090089c4 936}
937
56f29785 938static int
8350fe9b 939storeKeepInMemory(const StoreEntry * e)
56f29785 940{
8350fe9b 941 MemObject *mem = e->mem_obj;
942 if (mem == NULL)
56f29785 943 return 0;
18fe65d0 944 if (mem->data_hdr.head == NULL)
8350fe9b 945 return 0;
946 return mem->inmem_lo == 0;
56f29785 947}
948
b8d8561b 949static int
01fe9bf4 950storeCheckExpired(const StoreEntry * e)
620da955 951{
952 if (storeEntryLocked(e))
953 return 0;
d46a87a8 954 if (EBIT_TEST(e->flags, RELEASE_REQUEST))
1148b77c 955 return 1;
d46a87a8 956 if (EBIT_TEST(e->flags, ENTRY_NEGCACHED) && squid_curtime >= e->expires)
7cc1830f 957 return 1;
fcefe642 958 if (squid_curtime - e->lastref > storeExpiredReferenceAge())
66cedb85 959 return 1;
66cedb85 960 return 0;
620da955 961}
962
db9ccd5a 963/*
964 * storeExpiredReferenceAge
965 *
429fdbec 966 * The LRU age is scaled exponentially between 1 minute and
967 * Config.referenceAge , when store_swap_low < store_swap_size <
968 * store_swap_high. This keeps store_swap_size within the low and high
969 * water marks. If the cache is very busy then store_swap_size stays
970 * closer to the low water mark, if it is not busy, then it will stay
971 * near the high water mark. The LRU age value can be examined on the
972 * cachemgr 'info' page.
fbdfb3cf 973 */
35feb4aa 974time_t
58104eab 975storeExpiredReferenceAge(void)
976{
58104eab 977 double x;
978 double z;
979 time_t age;
429fdbec 980 x = (double) (store_swap_high - store_swap_size) / (store_swap_high - store_swap_low);
981 x = x < 0.0 ? 0.0 : x > 1.0 ? 1.0 : x;
8ac49cdc 982 z = pow((double) (Config.referenceAge / 60), x);
58104eab 983 age = (time_t) (z * 60.0);
984 if (age < 60)
985 age = 60;
986 else if (age > 31536000)
987 age = 31536000;
988 return age;
0a362c34 989}
2edc2504 990
b8d8561b 991void
992storeNegativeCache(StoreEntry * e)
79b5cc5f 993{
ff5731b1 994 e->expires = squid_curtime + Config.negativeTtl;
d46a87a8 995 EBIT_SET(e->flags, ENTRY_NEGCACHED);
79b5cc5f 996}
0a21bd84 997
998void
999storeFreeMemory(void)
1000{
ec878047 1001 hashFreeItems(store_table, destroy_StoreEntry);
0a21bd84 1002 hashFreeMemory(store_table);
afe95a7e 1003 store_table = NULL;
c68e9c6b 1004#if USE_CACHE_DIGEST
8638fc66 1005 if (store_digest)
1006 cacheDigestDestroy(store_digest);
c68e9c6b 1007#endif
8638fc66 1008 store_digest = NULL;
0a21bd84 1009}
a7e59001 1010
1011int
1012expiresMoreThan(time_t expires, time_t when)
1013{
48f44632 1014 if (expires < 0) /* No Expires given */
1015 return 1;
1016 return (expires > (squid_curtime + when));
a7e59001 1017}
fe54d06d 1018
1019int
1020storeEntryValidToSend(StoreEntry * e)
1021{
d46a87a8 1022 if (EBIT_TEST(e->flags, RELEASE_REQUEST))
fe54d06d 1023 return 0;
d46a87a8 1024 if (EBIT_TEST(e->flags, ENTRY_NEGCACHED))
44f78c24 1025 if (e->expires <= squid_curtime)
fe54d06d 1026 return 0;
1027 if (e->store_status == STORE_ABORTED)
1028 return 0;
1029 return 1;
1030}
62663274 1031
ca98227c 1032void
1033storeTimestampsSet(StoreEntry * entry)
1034{
1035 time_t served_date = -1;
2246b732 1036 const HttpReply *reply = entry->mem_obj->reply;
d8b249ef 1037 served_date = reply->date;
cb69b4c7 1038 if (served_date < 0)
1039 served_date = squid_curtime;
d8b249ef 1040 entry->expires = reply->expires;
1c3e77cd 1041 entry->lastmod = reply->last_modified;
ca98227c 1042 entry->timestamp = served_date;
1043}
429fdbec 1044
bfcaf585 1045void
1046storeRegisterAbort(StoreEntry * e, STABH * cb, void *data)
1047{
1048 MemObject *mem = e->mem_obj;
1049 assert(mem);
1050 assert(mem->abort.callback == NULL);
1051 mem->abort.callback = cb;
1052 mem->abort.data = data;
1053}
1054
1055void
1056storeUnregisterAbort(StoreEntry * e)
1057{
1058 MemObject *mem = e->mem_obj;
1059 assert(mem);
1060 mem->abort.callback = NULL;
1061}
88738790 1062
1063void
1064storeMemObjectDump(MemObject * mem)
1065{
18fe65d0 1066 debug(20, 1) ("MemObject->data.head: %p\n",
1067 mem->data_hdr.head);
1068 debug(20, 1) ("MemObject->data.tail: %p\n",
1069 mem->data_hdr.tail);
1070 debug(20, 1) ("MemObject->data.origin_offset: %d\n",
1071 mem->data_hdr.origin_offset);
88738790 1072 debug(20, 1) ("MemObject->start_ping: %d.%06d\n",
5f6ac48b 1073 (int) mem->start_ping.tv_sec,
1074 (int) mem->start_ping.tv_usec);
8350fe9b 1075 debug(20, 1) ("MemObject->inmem_hi: %d\n",
5f6ac48b 1076 (int) mem->inmem_hi);
8350fe9b 1077 debug(20, 1) ("MemObject->inmem_lo: %d\n",
5f6ac48b 1078 (int) mem->inmem_lo);
88738790 1079 debug(20, 1) ("MemObject->clients: %p\n",
1080 mem->clients);
1081 debug(20, 1) ("MemObject->nclients: %d\n",
1082 mem->nclients);
8350fe9b 1083 debug(20, 1) ("MemObject->swapout.fd: %d\n",
1084 mem->swapout.fd);
88738790 1085 debug(20, 1) ("MemObject->reply: %p\n",
1086 mem->reply);
1087 debug(20, 1) ("MemObject->request: %p\n",
1088 mem->request);
1089 debug(20, 1) ("MemObject->log_url: %p %s\n",
1090 mem->log_url,
1091 checkNullString(mem->log_url));
1092}
8350fe9b 1093
f09f5b26 1094void
e3ef2b09 1095storeEntryDump(StoreEntry * e, int l)
d377699f 1096{
e3ef2b09 1097 debug(20, l) ("StoreEntry->key: %s\n", storeKeyText(e->key));
1098 debug(20, l) ("StoreEntry->next: %p\n", e->next);
1099 debug(20, l) ("StoreEntry->mem_obj: %p\n", e->mem_obj);
1100 debug(20, l) ("StoreEntry->timestamp: %d\n", (int) e->timestamp);
1101 debug(20, l) ("StoreEntry->lastref: %d\n", (int) e->lastref);
1102 debug(20, l) ("StoreEntry->expires: %d\n", (int) e->expires);
1103 debug(20, l) ("StoreEntry->lastmod: %d\n", (int) e->lastmod);
07304bf9 1104 debug(20, l) ("StoreEntry->swap_file_sz: %d\n", (int) e->swap_file_sz);
e3ef2b09 1105 debug(20, l) ("StoreEntry->refcount: %d\n", e->refcount);
415e0dd2 1106 debug(20, l) ("StoreEntry->flags: %s\n", storeEntryFlags(e));
e3ef2b09 1107 debug(20, l) ("StoreEntry->swap_file_number: %d\n", (int) e->swap_file_number);
1108 debug(20, l) ("StoreEntry->lock_count: %d\n", (int) e->lock_count);
1109 debug(20, l) ("StoreEntry->mem_status: %d\n", (int) e->mem_status);
1110 debug(20, l) ("StoreEntry->ping_status: %d\n", (int) e->ping_status);
1111 debug(20, l) ("StoreEntry->store_status: %d\n", (int) e->store_status);
1112 debug(20, l) ("StoreEntry->swap_status: %d\n", (int) e->swap_status);
d377699f 1113}
1114
8350fe9b 1115/* NOTE, this function assumes only two mem states */
f09f5b26 1116void
8350fe9b 1117storeSetMemStatus(StoreEntry * e, int new_status)
1118{
b93bcace 1119 MemObject *mem = e->mem_obj;
8350fe9b 1120 if (new_status == e->mem_status)
1121 return;
b93bcace 1122 assert(mem != NULL);
1123 if (new_status == IN_MEMORY) {
1124 assert(mem->inmem_lo == 0);
2ac237e2 1125 dlinkAdd(e, &mem->lru, &inmem_list);
59c4d35b 1126 hot_obj_count++;
b93bcace 1127 } else {
2ac237e2 1128 dlinkDelete(&mem->lru, &inmem_list);
59c4d35b 1129 hot_obj_count--;
b93bcace 1130 }
8350fe9b 1131 e->mem_status = new_status;
1132}
6e86c3e8 1133
9fb13bb6 1134const char *
1135storeUrl(const StoreEntry * e)
1136{
1137 if (e == NULL)
24ffafb4 1138 return "[null_entry]";
9fb13bb6 1139 else if (e->mem_obj == NULL)
24ffafb4 1140 return "[null_mem_obj]";
9fb13bb6 1141 else
1142 return e->mem_obj->url;
1143}
24ffafb4 1144
1145void
1146storeCreateMemObject(StoreEntry * e, const char *url, const char *log_url)
1147{
1148 if (e->mem_obj)
1149 return;
1150 e->mem_obj = new_MemObject(url, log_url);
1151}
64763c37 1152
438fc1e3 1153/* this just sets DELAY_SENDING */
1154void
8daca701 1155storeBuffer(StoreEntry * e)
438fc1e3 1156{
d46a87a8 1157 EBIT_SET(e->flags, DELAY_SENDING);
438fc1e3 1158}
1159
1160/* this just clears DELAY_SENDING and Invokes the handlers */
1161void
8daca701 1162storeBufferFlush(StoreEntry * e)
438fc1e3 1163{
d46a87a8 1164 EBIT_CLR(e->flags, DELAY_SENDING);
8daca701 1165 InvokeHandlers(e);
d5bd7c41 1166 storeCheckSwapOut(e);
438fc1e3 1167}
25535cbe 1168
1169void
1170storeUnlinkFileno(int fileno)
1171{
07304bf9 1172 debug(20, 5) ("storeUnlinkFileno: %08X\n", fileno);
25535cbe 1173#if USE_ASYNC_IO
1174 safeunlink(storeSwapFullPath(fileno, NULL), 1);
1175#else
1176 unlinkdUnlink(storeSwapFullPath(fileno, NULL));
1177#endif
1178}
07304bf9 1179
1180int
1181objectLen(const StoreEntry * e)
1182{
1183 assert(e->mem_obj != NULL);
1184 return e->mem_obj->object_sz;
1185}
1186
1187int
1188contentLen(const StoreEntry * e)
1189{
1190 assert(e->mem_obj != NULL);
1191 assert(e->mem_obj->reply != NULL);
1192 return e->mem_obj->object_sz - e->mem_obj->reply->hdr_sz;
1193}
f3986a15 1194
1195HttpReply *
1196storeEntryReply(StoreEntry * e)
1197{
1198 if (NULL == e)
3d02186d 1199 return NULL;
f3986a15 1200 if (NULL == e->mem_obj)
3d02186d 1201 return NULL;
f3986a15 1202 return e->mem_obj->reply;
1203}