store.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:35k
源码类别:

代理服务器

开发平台:

Unix_Linux

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