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