📄 store.c
字号:
/* * $Id: store.c,v 1.488.2.2 1999/05/10 16:02:04 wessels Exp $ * * DEBUG: section 20 Storage Manager * AUTHOR: Harvest Derived * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from the * Internet community. Development is led by Duane Wessels of the * National Laboratory for Applied Network Research and funded by the * National Science Foundation. Squid is Copyrighted (C) 1998 by * Duane Wessels and the University of California San Diego. Please * see the COPYRIGHT file for full details. Squid incorporates * software developed and/or copyrighted by other sources. Please see * the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */#include "squid.h"#define REBUILD_TIMESTAMP_DELTA_MAX 2#define STORE_IN_MEM_BUCKETS (229)const char *memStatusStr[] ={ "NOT_IN_MEMORY", "IN_MEMORY"};const char *pingStatusStr[] ={ "PING_NONE", "PING_WAITING", "PING_DONE"};const char *storeStatusStr[] ={ "STORE_OK", "STORE_PENDING"};const char *swapStatusStr[] ={ "SWAPOUT_NONE", "SWAPOUT_OPENING", "SWAPOUT_WRITING", "SWAPOUT_DONE"};typedef struct lock_ctrl_t { SIH *callback; void *callback_data; StoreEntry *e;} lock_ctrl_t;/* * local function prototypes */static int storeCheckExpired(const StoreEntry *);static int storeEntryLocked(const StoreEntry *);static int storeEntryValidLength(const StoreEntry *);static void storeGetMemSpace(int);static void storeHashDelete(StoreEntry *);static MemObject *new_MemObject(const char *, const char *);static void destroy_MemObject(StoreEntry *);static FREE destroy_StoreEntry;static void storePurgeMem(StoreEntry *);static int getKeyCounter(void);static int storeKeepInMemory(const StoreEntry *);static OBJH storeCheckCachableStats;static EVH storeLateRelease;/* * local variables */static dlink_list inmem_list;static int store_pages_max = 0;static int store_swap_high = 0;static int store_swap_low = 0;static int store_swap_mid = 0;static int store_maintain_rate;static Stack LateReleaseStack;static MemObject *new_MemObject(const char *url, const char *log_url){ MemObject *mem = memAllocate(MEM_MEMOBJECT); mem->reply = httpReplyCreate(); mem->url = xstrdup(url); mem->log_url = xstrdup(log_url); mem->swapout.fd = -1; mem->object_sz = -1; mem->fd = -1; /* XXX account log_url */ debug(20, 3) ("new_MemObject: returning %p\n", mem); return mem;}StoreEntry *new_StoreEntry(int mem_obj_flag, const char *url, const char *log_url){ StoreEntry *e = NULL; e = memAllocate(MEM_STOREENTRY); if (mem_obj_flag) e->mem_obj = new_MemObject(url, log_url); debug(20, 3) ("new_StoreEntry: returning %p\n", e); e->expires = e->lastmod = e->lastref = e->timestamp = -1; return e;}static voiddestroy_MemObject(StoreEntry * e){ MemObject *mem = e->mem_obj; const Ctx ctx = ctx_enter(mem->url); debug(20, 3) ("destroy_MemObject: destroying %p\n", mem); e->mem_obj = NULL; if (!shutting_down) assert(mem->swapout.fd == -1); stmemFree(&mem->data_hdr); mem->inmem_hi = 0; /* XXX account log_url */#if USE_ASYNC_IO while (mem->clients != NULL) storeUnregister(e, mem->clients->callback_data);#endif /* * There is no way to abort FD-less clients, so they might * still have mem->clients set if mem->fd == -1 */ assert(mem->fd == -1 || mem->clients == NULL); httpReplyDestroy(mem->reply); requestUnlink(mem->request); mem->request = NULL; ctx_exit(ctx); /* must exit before we free mem->url */ safe_free(mem->url); safe_free(mem->log_url); memFree(mem, MEM_MEMOBJECT);}static voiddestroy_StoreEntry(void *data){ StoreEntry *e = data; debug(20, 3) ("destroy_StoreEntry: destroying %p\n", e); assert(e != NULL); if (e->mem_obj) destroy_MemObject(e); storeHashDelete(e); assert(e->key == NULL); memFree(e, MEM_STOREENTRY);}/* ----- INTERFACE BETWEEN STORAGE MANAGER AND HASH TABLE FUNCTIONS --------- */voidstoreHashInsert(StoreEntry * e, const cache_key * key){ debug(20, 3) ("storeHashInsert: Inserting Entry %p key '%s'\n", e, storeKeyText(key)); e->key = storeKeyDup(key); hash_join(store_table, (hash_link *) e); dlinkAdd(e, &e->lru, &store_list);}static voidstoreHashDelete(StoreEntry * e){ hash_remove_link(store_table, (hash_link *) e); dlinkDelete(&e->lru, &store_list); storeKeyFree(e->key); e->key = NULL;}/* -------------------------------------------------------------------------- *//* get rid of memory copy of the object *//* Only call this if storeCheckPurgeMem(e) returns 1 */static voidstorePurgeMem(StoreEntry * e){ if (e->mem_obj == NULL) return; debug(20, 3) ("storePurgeMem: Freeing memory-copy of %s\n", storeKeyText(e->key)); storeSetMemStatus(e, NOT_IN_MEMORY); destroy_MemObject(e); if (e->swap_status != SWAPOUT_DONE) storeRelease(e);}voidstoreLockObject(StoreEntry * e){ if (e->lock_count++ == 0) { dlinkDelete(&e->lru, &store_list); dlinkAdd(e, &e->lru, &store_list); } debug(20, 3) ("storeLockObject: key '%s' count=%d\n", storeKeyText(e->key), (int) e->lock_count); e->lastref = squid_curtime;}voidstoreReleaseRequest(StoreEntry * e){ if (EBIT_TEST(e->flags, RELEASE_REQUEST)) return; debug(20, 3) ("storeReleaseRequest: '%s'\n", storeKeyText(e->key)); EBIT_SET(e->flags, RELEASE_REQUEST); /* * Clear cachable flag here because we might get called before * anyone else even looks at the cachability flag. Also, this * prevents httpMakePublic from really setting a public key. */ EBIT_CLR(e->flags, ENTRY_CACHABLE); storeSetPrivateKey(e);}/* unlock object, return -1 if object get released after unlock * otherwise lock_count */intstoreUnlockObject(StoreEntry * e){ e->lock_count--; debug(20, 3) ("storeUnlockObject: key '%s' count=%d\n", storeKeyText(e->key), e->lock_count); if (e->lock_count) return (int) e->lock_count; if (e->store_status == STORE_PENDING) EBIT_SET(e->flags, RELEASE_REQUEST); assert(storePendingNClients(e) == 0); if (EBIT_TEST(e->flags, RELEASE_REQUEST)) storeRelease(e); else if (storeKeepInMemory(e)) { storeSetMemStatus(e, IN_MEMORY); requestUnlink(e->mem_obj->request); e->mem_obj->request = NULL; } else { storePurgeMem(e); if (EBIT_TEST(e->flags, KEY_PRIVATE)) { dlinkDelete(&e->lru, &store_list); dlinkAddTail(e, &e->lru, &store_list); } } return 0;}/* Lookup an object in the cache. * return just a reference to object, don't start swapping in yet. */StoreEntry *storeGet(const cache_key * key){ debug(20, 3) ("storeGet: looking up %s\n", storeKeyText(key)); return (StoreEntry *) hash_lookup(store_table, key);}StoreEntry *storeGetPublic(const char *uri, const method_t method){ return storeGet(storeKeyPublic(uri, method));}static intgetKeyCounter(void){ static int key_counter = 0; if (++key_counter < 0) key_counter = 1; return key_counter;}voidstoreSetPrivateKey(StoreEntry * e){ const cache_key *newkey; MemObject *mem = e->mem_obj; if (e->key && EBIT_TEST(e->flags, KEY_PRIVATE)) return; /* is already private */ if (e->key) { if (e->swap_file_number > -1) storeDirSwapLog(e, SWAP_LOG_DEL); storeHashDelete(e); } if (mem != NULL) { mem->id = getKeyCounter(); newkey = storeKeyPrivate(mem->url, mem->method, mem->id); } else { newkey = storeKeyPrivate("JUNK", METHOD_NONE, getKeyCounter()); } assert(hash_lookup(store_table, newkey) == NULL); EBIT_SET(e->flags, KEY_PRIVATE); storeHashInsert(e, newkey);}voidstoreSetPublicKey(StoreEntry * e){ StoreEntry *e2 = NULL; const cache_key *newkey; MemObject *mem = e->mem_obj; if (e->key && !EBIT_TEST(e->flags, KEY_PRIVATE)) return; /* is already public */ assert(mem); /* * We can't make RELEASE_REQUEST objects public. Depending on * when RELEASE_REQUEST gets set, we might not be swapping out * the object. If we're not swapping out, then subsequent * store clients won't be able to access object data which has * been freed from memory. * * If RELEASE_REQUEST is set, then ENTRY_CACHABLE should not * be set, and storeSetPublicKey() should not be called. */ assert(!EBIT_TEST(e->flags, RELEASE_REQUEST)); newkey = storeKeyPublic(mem->url, mem->method); if ((e2 = (StoreEntry *) hash_lookup(store_table, newkey))) { debug(20, 3) ("storeSetPublicKey: Making old '%s' private.\n", mem->url); storeSetPrivateKey(e2); storeRelease(e2); newkey = storeKeyPublic(mem->url, mem->method); } if (e->key) storeHashDelete(e); EBIT_CLR(e->flags, KEY_PRIVATE); storeHashInsert(e, newkey); if (e->swap_file_number > -1) storeDirSwapLog(e, SWAP_LOG_ADD);}StoreEntry *storeCreateEntry(const char *url, const char *log_url, request_flags flags, method_t method){ StoreEntry *e = NULL; MemObject *mem = NULL; debug(20, 3) ("storeCreateEntry: '%s'\n", url); e = new_StoreEntry(STORE_ENTRY_WITH_MEMOBJ, url, log_url); e->lock_count = 1; /* Note lock here w/o calling storeLock() */ mem = e->mem_obj; mem->method = method; if (neighbors_do_private_keys || !flags.hierarchical) storeSetPrivateKey(e); else storeSetPublicKey(e); if (flags.cachable) { EBIT_SET(e->flags, ENTRY_CACHABLE); EBIT_CLR(e->flags, RELEASE_REQUEST); } else { EBIT_CLR(e->flags, ENTRY_CACHABLE); storeReleaseRequest(e); } e->store_status = STORE_PENDING; storeSetMemStatus(e, NOT_IN_MEMORY); e->swap_status = SWAPOUT_NONE; e->swap_file_number = -1; e->refcount = 0; e->lastref = squid_curtime; e->timestamp = 0; /* set in storeTimestampsSet() */ e->ping_status = PING_NONE; EBIT_SET(e->flags, ENTRY_VALIDATED); return e;}/* Mark object as expired */voidstoreExpireNow(StoreEntry * e){ debug(20, 3) ("storeExpireNow: '%s'\n", storeKeyText(e->key)); e->expires = squid_curtime;}/* Append incoming data from a primary server to an entry. */voidstoreAppend(StoreEntry * e, const char *buf, int len){ MemObject *mem = e->mem_obj; assert(mem != NULL); assert(len >= 0); assert(e->store_status == STORE_PENDING); if (len) { debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n", len, storeKeyText(e->key)); storeGetMemSpace(len); stmemAppend(&mem->data_hdr, buf, len); mem->inmem_hi += len; } if (EBIT_TEST(e->flags, DELAY_SENDING)) return;#ifdef OPTIMISTIC_IO storeLockObject(e);#endif InvokeHandlers(e); storeCheckSwapOut(e);#ifdef OPTIMISTIC_IO
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -