]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store.cc
Added STDC Defines for portability
[thirdparty/squid.git] / src / store.cc
CommitLineData
164f7660 1
30a4f2a8 2/*
674ac814 3 * $Id: store.cc,v 1.471 1998/11/13 20:50:57 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{
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{
532 storeAppendPrintf(sentry, "no.non_get\t%d\n",
533 store_check_cachable_hist.no.non_get);
534 storeAppendPrintf(sentry, "no.not_entry_cachable\t%d\n",
535 store_check_cachable_hist.no.not_entry_cachable);
536 storeAppendPrintf(sentry, "no.release_request\t%d\n",
537 store_check_cachable_hist.no.release_request);
538 storeAppendPrintf(sentry, "no.wrong_content_length\t%d\n",
539 store_check_cachable_hist.no.wrong_content_length);
540 storeAppendPrintf(sentry, "no.negative_cached\t%d\n",
541 store_check_cachable_hist.no.negative_cached);
542 storeAppendPrintf(sentry, "no.too_big\t%d\n",
543 store_check_cachable_hist.no.too_big);
544 storeAppendPrintf(sentry, "no.private_key\t%d\n",
545 store_check_cachable_hist.no.private_key);
c5f627c2 546 storeAppendPrintf(sentry, "no.too_many_open_files\t%d\n",
547 store_check_cachable_hist.no.too_many_open_files);
8423ff74 548 storeAppendPrintf(sentry, "no.lru_age_too_low\t%d\n",
549 store_check_cachable_hist.no.lru_age_too_low);
550 storeAppendPrintf(sentry, "yes.default\t%d\n",
551 store_check_cachable_hist.yes.Default);
552}
553
090089c4 554/* Complete transfer into the local cache. */
b8d8561b 555void
556storeComplete(StoreEntry * e)
090089c4 557{
9fb13bb6 558 debug(20, 3) ("storeComplete: '%s'\n", storeKeyText(e->key));
22955fba 559 assert(e->store_status == STORE_PENDING);
07304bf9 560 e->mem_obj->object_sz = e->mem_obj->inmem_hi;
234967c9 561 e->store_status = STORE_OK;
8350fe9b 562 assert(e->mem_status == NOT_IN_MEMORY);
41587298 563 if (!storeEntryValidLength(e)) {
d46a87a8 564 EBIT_SET(e->flags, ENTRY_BAD_LENGTH);
41587298 565 storeReleaseRequest(e);
566 }
6cfa8966 567#if USE_CACHE_DIGESTS
544b1fd4 568 if (e->mem_obj->request)
569 e->mem_obj->request->hier.store_complete_stop = current_time;
39edba21 570#endif
3a1c3e2f 571 InvokeHandlers(e);
8c123b71 572 storeCheckSwapOut(e);
7e3e1d01 573}
574
1b72bda1 575#ifdef PPNR_WIP
7e3e1d01 576void
e82d6d21 577storePPNR(StoreEntry * e)
7e3e1d01 578{
d46a87a8 579 assert(EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT));
580 EBIT_CLR(e->flags, ENTRY_FWD_HDR_WAIT);
090089c4 581}
5942e8d4 582
1b72bda1 583#endif /* PPNR_WIP */
090089c4 584
585/*
474cac1b 586 * Someone wants to abort this transfer. Set the reason in the
587 * request structure, call the server-side callback and mark the
588 * entry for releasing
090089c4 589 */
b8d8561b 590void
9b312a19 591storeAbort(StoreEntry * e, int cbflag)
090089c4 592{
3e98df20 593 MemObject *mem = e->mem_obj;
6801f8a8 594 STABH *callback;
595 void *data;
8f39b81d 596 assert(e->store_status == STORE_PENDING);
597 assert(mem != NULL);
9fb13bb6 598 debug(20, 6) ("storeAbort: %s\n", storeKeyText(e->key));
3d02186d 599 storeLockObject(e); /* lock while aborting */
79b5cc5f 600 storeNegativeCache(e);
474cac1b 601 storeReleaseRequest(e);
234967c9 602 e->store_status = STORE_ABORTED;
8350fe9b 603 storeSetMemStatus(e, NOT_IN_MEMORY);
090089c4 604 /* No DISK swap for negative cached object */
8350fe9b 605 e->swap_status = SWAPOUT_NONE;
496e1d76 606 /*
607 * We assign an object length here. The only other place we assign
608 * the object length is in storeComplete()
609 */
07304bf9 610 mem->object_sz = mem->inmem_hi;
474cac1b 611 /* Notify the server side */
612 if (cbflag && mem->abort.callback) {
6801f8a8 613 callback = mem->abort.callback;
614 data = mem->abort.data;
bfcaf585 615 mem->abort.callback = NULL;
6801f8a8 616 mem->abort.data = NULL;
617 callback(data);
bfcaf585 618 }
474cac1b 619 /* Notify the client side */
090089c4 620 InvokeHandlers(e);
6e86c3e8 621 /* Do we need to close the swapout file? */
622 /* Not if we never started swapping out */
6cf028ab 623 /* But we may need to cancel an open/stat in progress if using ASYNC */
624#if USE_ASYNC_IO
625 aioCancel(-1, e);
626#endif
3d02186d 627 if (e->swap_file_number > -1) {
6cf028ab 628#if USE_ASYNC_IO
3d02186d 629 /* Need to cancel any pending ASYNC writes right now */
630 if (mem->swapout.fd >= 0)
631 aioCancel(mem->swapout.fd, NULL);
6cf028ab 632#endif
3d02186d 633 /* we have to close the disk file if there is no write pending */
61038223 634 if (!storeSwapOutWriteQueued(mem))
3d02186d 635 storeSwapOutFileClose(e);
636 }
637 storeUnlockObject(e); /* unlock */
090089c4 638}
639
090089c4 640/* Clear Memory storage to accommodate the given object len */
38792624 641static void
d4432957 642storeGetMemSpace(int size)
090089c4 643{
b32508fb 644 StoreEntry *e = NULL;
20cba4b4 645 int released = 0;
b32508fb 646 static time_t last_check = 0;
e954773d 647 int pages_needed;
b93bcace 648 dlink_node *m;
d6ea85ce 649 dlink_node *head;
79d39a72 650 dlink_node *prev = NULL;
b32508fb 651 if (squid_curtime == last_check)
38792624 652 return;
b32508fb 653 last_check = squid_curtime;
e954773d 654 pages_needed = (size / SM_PAGE_SIZE) + 1;
3f6c0fb2 655 if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_high)
38792624 656 return;
311ea387 657 if (store_rebuilding)
38792624 658 return;
a3d5953d 659 debug(20, 2) ("storeGetMemSpace: Starting, need %d pages\n", pages_needed);
d6ea85ce 660 head = inmem_list.head;
b93bcace 661 for (m = inmem_list.tail; m; m = prev) {
d6ea85ce 662 if (m == head)
663 break;
8350fe9b 664 prev = m->prev;
b93bcace 665 e = m->data;
d6ea85ce 666 if (storeEntryLocked(e)) {
5999b776 667 dlinkDelete(m, &inmem_list);
668 dlinkAdd(e, m, &inmem_list);
8350fe9b 669 continue;
d6ea85ce 670 }
20cba4b4 671 released++;
2d51a60e 672 storePurgeMem(e);
d6ea85ce 673 if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_high)
8350fe9b 674 break;
675 }
5e3d4fef 676 debug(20, 3) ("storeGetMemSpace stats:\n");
59c4d35b 677 debug(20, 3) (" %6d HOT objects\n", hot_obj_count);
20cba4b4 678 debug(20, 3) (" %6d were released\n", released);
090089c4 679}
680
090089c4 681/* The maximum objects to scan for maintain storage space */
fcefe642 682#define MAINTAIN_MAX_SCAN 1024
683#define MAINTAIN_MAX_REMOVE 64
090089c4 684
fcefe642 685/*
686 * This routine is to be called by main loop in main.c.
687 * It removes expired objects on only one bucket for each time called.
688 * returns the number of objects removed
689 *
690 * This should get called 1/s from main().
691 */
679ac4f0 692void
79d39a72 693storeMaintainSwapSpace(void *datanotused)
090089c4 694{
b93bcace 695 dlink_node *m;
79d39a72 696 dlink_node *prev = NULL;
a1b0d7cf 697 StoreEntry *e = NULL;
090089c4 698 int scanned = 0;
090089c4 699 int locked = 0;
679ac4f0 700 int expired = 0;
20cba4b4 701 int max_scan;
702 int max_remove;
ec14f197 703 static time_t last_warn_time = 0;
fcefe642 704 /* We can't delete objects while rebuilding swap */
c8b09b26 705 if (store_rebuilding) {
706 eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0, 1);
679ac4f0 707 return;
d1497906 708 } else if (store_swap_size < store_swap_mid) {
709 max_scan = 100;
710 max_remove = 8;
711 eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0, 1);
c8b09b26 712 } else if (store_swap_size < store_swap_high) {
713 max_scan = 200;
714 max_remove = 8;
715 eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 0.1, 1);
20cba4b4 716 } else {
4cb56589 717 max_scan = 500;
c8b09b26 718 max_remove = 32;
719 eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 0.0, 1);
20cba4b4 720 }
fcefe642 721 debug(20, 3) ("storeMaintainSwapSpace\n");
e3ef2b09 722 for (m = store_list.tail; m; m = prev) {
b93bcace 723 prev = m->prev;
724 e = m->data;
d150898a 725 scanned++;
b93bcace 726 if (storeEntryLocked(e)) {
ac2197dc 727 /*
728 * If there is a locked entry at the tail of the LRU list,
729 * move it to the beginning to get it out of the way.
730 * Theoretically, we might have all locked objects at the
731 * tail, and then we'll never remove anything here and the
732 * LRU age will go to zero.
733 */
734 if (memInUse(MEM_STOREENTRY) > max_scan) {
4b4cd312 735 dlinkDelete(&e->lru, &store_list);
736 dlinkAdd(e, &e->lru, &store_list);
ac2197dc 737 }
b93bcace 738 locked++;
01fe9bf4 739 } else if (storeCheckExpired(e)) {
b109de6b 740 expired++;
741 storeRelease(e);
090089c4 742 }
d150898a 743 if (expired >= max_remove)
b93bcace 744 break;
d150898a 745 if (scanned >= max_scan)
b93bcace 746 break;
090089c4 747 }
4cb56589 748 debug(20, 3) ("storeMaintainSwapSpace stats:\n");
749 debug(20, 3) (" %6d objects\n", memInUse(MEM_STOREENTRY));
750 debug(20, 3) (" %6d were scanned\n", scanned);
751 debug(20, 3) (" %6d were locked\n", locked);
752 debug(20, 3) (" %6d were expired\n", expired);
fcefe642 753 if (store_swap_size < Config.Swap.maxSize)
b93bcace 754 return;
755 if (squid_curtime - last_warn_time < 10)
756 return;
757 debug(20, 0) ("WARNING: Disk space over limit: %d KB > %d KB\n",
758 store_swap_size, Config.Swap.maxSize);
759 last_warn_time = squid_curtime;
090089c4 760}
761
762
763/* release an object from a cache */
cc61958c 764/* return number of objects released. */
6c78a099 765void
b8d8561b 766storeRelease(StoreEntry * e)
090089c4 767{
9fb13bb6 768 debug(20, 3) ("storeRelease: Releasing: '%s'\n", storeKeyText(e->key));
090089c4 769 /* If, for any reason we can't discard this object because of an
770 * outstanding request, mark it for pending release */
771 if (storeEntryLocked(e)) {
9174e204 772 storeExpireNow(e);
a3d5953d 773 debug(20, 3) ("storeRelease: Only setting RELEASE_REQUEST bit\n");
2daae136 774 storeReleaseRequest(e);
6c78a099 775 return;
090089c4 776 }
311ea387 777 if (store_rebuilding) {
a3d5953d 778 debug(20, 2) ("storeRelease: Delaying release until store is rebuilt: '%s'\n",
9fb13bb6 779 storeUrl(e));
30a4f2a8 780 storeExpireNow(e);
97dad8a9 781 storeReleaseRequest(e);
6c78a099 782 return;
30a4f2a8 783 }
77059ddf 784#if USE_ASYNC_IO
785 /*
786 * Make sure all forgotten async ops are cancelled
787 */
788 aioCancel(-1, e);
6cf028ab 789#endif
a65ff22e 790 storeLog(STORE_LOG_RELEASE, e);
43fee0b8 791 if (e->swap_file_number > -1) {
25535cbe 792 storeUnlinkFileno(e->swap_file_number);
d961be0a 793 storeDirMapBitReset(e->swap_file_number);
a65ff22e 794 if (e->swap_status == SWAPOUT_DONE)
d46a87a8 795 if (EBIT_TEST(e->flags, ENTRY_VALIDATED))
7b3d6868 796 storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, -1);
d46a87a8 797 if (!EBIT_TEST(e->flags, KEY_PRIVATE))
b109de6b 798 storeDirSwapLog(e, SWAP_LOG_DEL);
090089c4 799 }
8350fe9b 800 storeSetMemStatus(e, NOT_IN_MEMORY);
30a4f2a8 801 destroy_StoreEntry(e);
090089c4 802}
803
090089c4 804/* return 1 if a store entry is locked */
24382924 805static int
fe4e214f 806storeEntryLocked(const StoreEntry * e)
090089c4 807{
30a4f2a8 808 if (e->lock_count)
809 return 1;
6cf028ab 810 if (e->swap_status == SWAPOUT_OPENING)
811 return 1;
8350fe9b 812 if (e->swap_status == SWAPOUT_WRITING)
30a4f2a8 813 return 1;
a1e47288 814 if (e->store_status == STORE_PENDING)
815 return 1;
d46a87a8 816 if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
365cb147 817 return 1;
30a4f2a8 818 return 0;
090089c4 819}
820
24382924 821static int
fe4e214f 822storeEntryValidLength(const StoreEntry * e)
6602e70e 823{
ffe4a367 824 int diff;
d8b249ef 825 const HttpReply *reply;
8a5e92ce 826 assert(e->mem_obj != NULL);
07304bf9 827 reply = e->mem_obj->reply;
9fb13bb6 828 debug(20, 3) ("storeEntryValidLength: Checking '%s'\n", storeKeyText(e->key));
07304bf9 829 debug(20, 5) ("storeEntryValidLength: object_len = %d\n",
830 objectLen(e));
831 debug(20, 5) ("storeEntryValidLength: hdr_sz = %d\n",
832 reply->hdr_sz);
833 debug(20, 5) ("storeEntryValidLength: content_length = %d\n",
d8b249ef 834 reply->content_length);
835 if (reply->content_length < 0) {
1790d392 836 debug(20, 5) ("storeEntryValidLength: Unspecified content length: %s\n",
9fb13bb6 837 storeKeyText(e->key));
ffe4a367 838 return 1;
839 }
07304bf9 840 if (reply->hdr_sz == 0) {
1790d392 841 debug(20, 5) ("storeEntryValidLength: Zero header size: %s\n",
9fb13bb6 842 storeKeyText(e->key));
ffe4a367 843 return 1;
844 }
ebf4efff 845 if (e->mem_obj->method == METHOD_HEAD) {
846 debug(20, 5) ("storeEntryValidLength: HEAD request: %s\n",
9fb13bb6 847 storeKeyText(e->key));
ebf4efff 848 return 1;
ffe4a367 849 }
cb69b4c7 850 if (reply->sline.status == HTTP_NOT_MODIFIED)
ebf4efff 851 return 1;
cb69b4c7 852 if (reply->sline.status == HTTP_NO_CONTENT)
ebf4efff 853 return 1;
d8b249ef 854 diff = reply->hdr_sz + reply->content_length - objectLen(e);
ebf4efff 855 if (diff == 0)
856 return 1;
857 debug(20, 3) ("storeEntryValidLength: %d bytes too %s; '%s'\n",
858 diff < 0 ? -diff : diff,
e69324cd 859 diff < 0 ? "big" : "small",
ebf4efff 860 storeKeyText(e->key));
861 return 0;
ffe4a367 862}
6602e70e 863
66cedb85 864static void
865storeInitHashValues(void)
866{
867 int i;
a7e59001 868 /* Calculate size of hash table (maximum currently 64k buckets). */
38792624 869 i = Config.Swap.maxSize / Config.Store.avgObjectSize;
86101e40 870 debug(20, 1) ("Swap maxSize %d KB, estimated %d objects\n",
66cedb85 871 Config.Swap.maxSize, i);
38792624 872 i /= Config.Store.objectsPerBucket;
a3d5953d 873 debug(20, 1) ("Target number of buckets: %d\n", i);
66cedb85 874 /* ideally the full scan period should be configurable, for the
875 * moment it remains at approximately 24 hours. */
9fb13bb6 876 store_hash_buckets = storeKeyHashBuckets(i);
24ffafb4 877 store_maintain_rate = 86400 / store_hash_buckets;
9fb13bb6 878 assert(store_maintain_rate > 0);
7454a5c2 879 debug(20, 1) ("Using %d Store buckets, replacement runs every %d second%s\n",
9fb13bb6 880 store_hash_buckets,
66cedb85 881 store_maintain_rate,
882 store_maintain_rate == 1 ? null_string : "s");
a47b9029 883 debug(20, 1) ("Max Mem size: %d KB\n", Config.Mem.maxSize >> 10);
884 debug(20, 1) ("Max Swap size: %d KB\n", Config.Swap.maxSize);
66cedb85 885}
886
b8d8561b 887void
888storeInit(void)
c943f331 889{
25535cbe 890 storeKeyInit();
66cedb85 891 storeInitHashValues();
9fb13bb6 892 store_table = hash_create(storeKeyHashCmp,
893 store_hash_buckets, storeKeyHashHash);
8638fc66 894 storeDigestInit();
e3ef2b09 895 storeLogOpen();
85407535 896 if (storeVerifyCacheDirs() < 0) {
d377699f 897 xstrncpy(tmp_error_buf,
898 "\tFailed to verify one of the swap directories, Check cache.log\n"
899 "\tfor details. Run 'squid -z' to create swap directories\n"
900 "\tif needed, or if running Squid for the first time.",
901 ERROR_BUF_SZ);
902 fatal(tmp_error_buf);
903 }
e3ef2b09 904 storeDirOpenSwapLogs();
e3ef2b09 905 store_list.head = store_list.tail = NULL;
b93bcace 906 inmem_list.head = inmem_list.tail = NULL;
5830cdb3 907 storeRebuildStart();
4cb56589 908 cachemgrRegister("storedir",
22f3fd98 909 "Store Directory Stats",
1da3b90b 910 storeDirStats, 0, 1);
8423ff74 911 cachemgrRegister("store_check_cachable_stats",
912 "storeCheckCachable() Stats",
913 storeCheckCachableStats, 0, 1);
b1c0cc67 914}
c943f331 915
b8d8561b 916void
917storeConfigure(void)
b1c0cc67 918{
e954773d 919 int store_mem_high = 0;
920 int store_mem_low = 0;
b6f794d6 921 store_mem_high = (long) (Config.Mem.maxSize / 100) *
922 Config.Mem.highWaterMark;
923 store_mem_low = (long) (Config.Mem.maxSize / 100) *
924 Config.Mem.lowWaterMark;
090089c4 925
b1c0cc67 926 store_swap_high = (long) (((float) Config.Swap.maxSize *
927 (float) Config.Swap.highWaterMark) / (float) 100);
928 store_swap_low = (long) (((float) Config.Swap.maxSize *
929 (float) Config.Swap.lowWaterMark) / (float) 100);
d1497906 930 store_swap_mid = (store_swap_high >> 1) + (store_swap_low >> 1);
e954773d 931
932 store_pages_high = store_mem_high / SM_PAGE_SIZE;
933 store_pages_low = store_mem_low / SM_PAGE_SIZE;
090089c4 934}
935
56f29785 936static int
8350fe9b 937storeKeepInMemory(const StoreEntry * e)
56f29785 938{
8350fe9b 939 MemObject *mem = e->mem_obj;
940 if (mem == NULL)
56f29785 941 return 0;
18fe65d0 942 if (mem->data_hdr.head == NULL)
8350fe9b 943 return 0;
944 return mem->inmem_lo == 0;
56f29785 945}
946
b8d8561b 947static int
01fe9bf4 948storeCheckExpired(const StoreEntry * e)
620da955 949{
950 if (storeEntryLocked(e))
951 return 0;
d46a87a8 952 if (EBIT_TEST(e->flags, RELEASE_REQUEST))
1148b77c 953 return 1;
d46a87a8 954 if (EBIT_TEST(e->flags, ENTRY_NEGCACHED) && squid_curtime >= e->expires)
7cc1830f 955 return 1;
fcefe642 956 if (squid_curtime - e->lastref > storeExpiredReferenceAge())
66cedb85 957 return 1;
66cedb85 958 return 0;
620da955 959}
960
db9ccd5a 961/*
962 * storeExpiredReferenceAge
963 *
429fdbec 964 * The LRU age is scaled exponentially between 1 minute and
965 * Config.referenceAge , when store_swap_low < store_swap_size <
966 * store_swap_high. This keeps store_swap_size within the low and high
967 * water marks. If the cache is very busy then store_swap_size stays
968 * closer to the low water mark, if it is not busy, then it will stay
969 * near the high water mark. The LRU age value can be examined on the
970 * cachemgr 'info' page.
fbdfb3cf 971 */
35feb4aa 972time_t
58104eab 973storeExpiredReferenceAge(void)
974{
58104eab 975 double x;
976 double z;
977 time_t age;
429fdbec 978 x = (double) (store_swap_high - store_swap_size) / (store_swap_high - store_swap_low);
979 x = x < 0.0 ? 0.0 : x > 1.0 ? 1.0 : x;
8ac49cdc 980 z = pow((double) (Config.referenceAge / 60), x);
58104eab 981 age = (time_t) (z * 60.0);
982 if (age < 60)
983 age = 60;
984 else if (age > 31536000)
985 age = 31536000;
986 return age;
0a362c34 987}
2edc2504 988
b8d8561b 989void
990storeNegativeCache(StoreEntry * e)
79b5cc5f 991{
ff5731b1 992 e->expires = squid_curtime + Config.negativeTtl;
d46a87a8 993 EBIT_SET(e->flags, ENTRY_NEGCACHED);
79b5cc5f 994}
0a21bd84 995
996void
997storeFreeMemory(void)
998{
ec878047 999 hashFreeItems(store_table, destroy_StoreEntry);
0a21bd84 1000 hashFreeMemory(store_table);
afe95a7e 1001 store_table = NULL;
c68e9c6b 1002#if USE_CACHE_DIGEST
8638fc66 1003 if (store_digest)
1004 cacheDigestDestroy(store_digest);
c68e9c6b 1005#endif
8638fc66 1006 store_digest = NULL;
0a21bd84 1007}
a7e59001 1008
1009int
1010expiresMoreThan(time_t expires, time_t when)
1011{
48f44632 1012 if (expires < 0) /* No Expires given */
1013 return 1;
1014 return (expires > (squid_curtime + when));
a7e59001 1015}
fe54d06d 1016
1017int
1018storeEntryValidToSend(StoreEntry * e)
1019{
d46a87a8 1020 if (EBIT_TEST(e->flags, RELEASE_REQUEST))
fe54d06d 1021 return 0;
d46a87a8 1022 if (EBIT_TEST(e->flags, ENTRY_NEGCACHED))
44f78c24 1023 if (e->expires <= squid_curtime)
fe54d06d 1024 return 0;
1025 if (e->store_status == STORE_ABORTED)
1026 return 0;
1027 return 1;
1028}
62663274 1029
ca98227c 1030void
1031storeTimestampsSet(StoreEntry * entry)
1032{
1033 time_t served_date = -1;
2246b732 1034 const HttpReply *reply = entry->mem_obj->reply;
d8b249ef 1035 served_date = reply->date;
cb69b4c7 1036 if (served_date < 0)
1037 served_date = squid_curtime;
d8b249ef 1038 entry->expires = reply->expires;
1c3e77cd 1039 entry->lastmod = reply->last_modified;
ca98227c 1040 entry->timestamp = served_date;
1041}
429fdbec 1042
bfcaf585 1043void
1044storeRegisterAbort(StoreEntry * e, STABH * cb, void *data)
1045{
1046 MemObject *mem = e->mem_obj;
1047 assert(mem);
1048 assert(mem->abort.callback == NULL);
1049 mem->abort.callback = cb;
1050 mem->abort.data = data;
1051}
1052
1053void
1054storeUnregisterAbort(StoreEntry * e)
1055{
1056 MemObject *mem = e->mem_obj;
1057 assert(mem);
1058 mem->abort.callback = NULL;
1059}
88738790 1060
1061void
1062storeMemObjectDump(MemObject * mem)
1063{
18fe65d0 1064 debug(20, 1) ("MemObject->data.head: %p\n",
1065 mem->data_hdr.head);
1066 debug(20, 1) ("MemObject->data.tail: %p\n",
1067 mem->data_hdr.tail);
1068 debug(20, 1) ("MemObject->data.origin_offset: %d\n",
1069 mem->data_hdr.origin_offset);
88738790 1070 debug(20, 1) ("MemObject->start_ping: %d.%06d\n",
5f6ac48b 1071 (int) mem->start_ping.tv_sec,
1072 (int) mem->start_ping.tv_usec);
8350fe9b 1073 debug(20, 1) ("MemObject->inmem_hi: %d\n",
5f6ac48b 1074 (int) mem->inmem_hi);
8350fe9b 1075 debug(20, 1) ("MemObject->inmem_lo: %d\n",
5f6ac48b 1076 (int) mem->inmem_lo);
88738790 1077 debug(20, 1) ("MemObject->clients: %p\n",
1078 mem->clients);
1079 debug(20, 1) ("MemObject->nclients: %d\n",
1080 mem->nclients);
8350fe9b 1081 debug(20, 1) ("MemObject->swapout.fd: %d\n",
1082 mem->swapout.fd);
88738790 1083 debug(20, 1) ("MemObject->reply: %p\n",
1084 mem->reply);
1085 debug(20, 1) ("MemObject->request: %p\n",
1086 mem->request);
1087 debug(20, 1) ("MemObject->log_url: %p %s\n",
1088 mem->log_url,
1089 checkNullString(mem->log_url));
1090}
8350fe9b 1091
f09f5b26 1092void
e3ef2b09 1093storeEntryDump(StoreEntry * e, int l)
d377699f 1094{
e3ef2b09 1095 debug(20, l) ("StoreEntry->key: %s\n", storeKeyText(e->key));
1096 debug(20, l) ("StoreEntry->next: %p\n", e->next);
1097 debug(20, l) ("StoreEntry->mem_obj: %p\n", e->mem_obj);
1098 debug(20, l) ("StoreEntry->timestamp: %d\n", (int) e->timestamp);
1099 debug(20, l) ("StoreEntry->lastref: %d\n", (int) e->lastref);
1100 debug(20, l) ("StoreEntry->expires: %d\n", (int) e->expires);
1101 debug(20, l) ("StoreEntry->lastmod: %d\n", (int) e->lastmod);
07304bf9 1102 debug(20, l) ("StoreEntry->swap_file_sz: %d\n", (int) e->swap_file_sz);
e3ef2b09 1103 debug(20, l) ("StoreEntry->refcount: %d\n", e->refcount);
415e0dd2 1104 debug(20, l) ("StoreEntry->flags: %s\n", storeEntryFlags(e));
e3ef2b09 1105 debug(20, l) ("StoreEntry->swap_file_number: %d\n", (int) e->swap_file_number);
1106 debug(20, l) ("StoreEntry->lock_count: %d\n", (int) e->lock_count);
1107 debug(20, l) ("StoreEntry->mem_status: %d\n", (int) e->mem_status);
1108 debug(20, l) ("StoreEntry->ping_status: %d\n", (int) e->ping_status);
1109 debug(20, l) ("StoreEntry->store_status: %d\n", (int) e->store_status);
1110 debug(20, l) ("StoreEntry->swap_status: %d\n", (int) e->swap_status);
d377699f 1111}
1112
8350fe9b 1113/* NOTE, this function assumes only two mem states */
f09f5b26 1114void
8350fe9b 1115storeSetMemStatus(StoreEntry * e, int new_status)
1116{
b93bcace 1117 MemObject *mem = e->mem_obj;
8350fe9b 1118 if (new_status == e->mem_status)
1119 return;
b93bcace 1120 assert(mem != NULL);
1121 if (new_status == IN_MEMORY) {
1122 assert(mem->inmem_lo == 0);
2ac237e2 1123 dlinkAdd(e, &mem->lru, &inmem_list);
59c4d35b 1124 hot_obj_count++;
b93bcace 1125 } else {
2ac237e2 1126 dlinkDelete(&mem->lru, &inmem_list);
59c4d35b 1127 hot_obj_count--;
b93bcace 1128 }
8350fe9b 1129 e->mem_status = new_status;
1130}
6e86c3e8 1131
9fb13bb6 1132const char *
1133storeUrl(const StoreEntry * e)
1134{
1135 if (e == NULL)
24ffafb4 1136 return "[null_entry]";
9fb13bb6 1137 else if (e->mem_obj == NULL)
24ffafb4 1138 return "[null_mem_obj]";
9fb13bb6 1139 else
1140 return e->mem_obj->url;
1141}
24ffafb4 1142
1143void
1144storeCreateMemObject(StoreEntry * e, const char *url, const char *log_url)
1145{
1146 if (e->mem_obj)
1147 return;
1148 e->mem_obj = new_MemObject(url, log_url);
1149}
64763c37 1150
438fc1e3 1151/* this just sets DELAY_SENDING */
1152void
8daca701 1153storeBuffer(StoreEntry * e)
438fc1e3 1154{
d46a87a8 1155 EBIT_SET(e->flags, DELAY_SENDING);
438fc1e3 1156}
1157
1158/* this just clears DELAY_SENDING and Invokes the handlers */
1159void
8daca701 1160storeBufferFlush(StoreEntry * e)
438fc1e3 1161{
d46a87a8 1162 EBIT_CLR(e->flags, DELAY_SENDING);
8daca701 1163 InvokeHandlers(e);
d5bd7c41 1164 storeCheckSwapOut(e);
438fc1e3 1165}
25535cbe 1166
1167void
1168storeUnlinkFileno(int fileno)
1169{
07304bf9 1170 debug(20, 5) ("storeUnlinkFileno: %08X\n", fileno);
25535cbe 1171#if USE_ASYNC_IO
1172 safeunlink(storeSwapFullPath(fileno, NULL), 1);
1173#else
1174 unlinkdUnlink(storeSwapFullPath(fileno, NULL));
1175#endif
1176}
07304bf9 1177
1178int
1179objectLen(const StoreEntry * e)
1180{
1181 assert(e->mem_obj != NULL);
1182 return e->mem_obj->object_sz;
1183}
1184
1185int
1186contentLen(const StoreEntry * e)
1187{
1188 assert(e->mem_obj != NULL);
1189 assert(e->mem_obj->reply != NULL);
1190 return e->mem_obj->object_sz - e->mem_obj->reply->hdr_sz;
1191}
f3986a15 1192
1193HttpReply *
1194storeEntryReply(StoreEntry * e)
1195{
1196 if (NULL == e)
3d02186d 1197 return NULL;
f3986a15 1198 if (NULL == e->mem_obj)
3d02186d 1199 return NULL;
f3986a15 1200 return e->mem_obj->reply;
1201}