/*
- * $Id: store.cc,v 1.551 2002/10/15 09:25:33 robertc Exp $
+ * $Id: store.cc,v 1.554 2003/01/23 00:37:26 robertc Exp $
*
* DEBUG: section 20 Storage Manager
* AUTHOR: Harvest Derived
#include "squid.h"
#include "Store.h"
#include "StoreClient.h"
+#include "stmem.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
+#include "MemObject.h"
+#include "mem_node.h"
+#include "StoreMeta.h"
+#include "SwapDir.h"
+
+static STMCB storeWriteComplete;
#define REBUILD_TIMESTAMP_DELTA_MAX 2
/*
* local function prototypes
*/
-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 FREE destroyStoreEntry;
static void storePurgeMem(StoreEntry *);
static void storeEntryReferenced(StoreEntry *);
static void storeEntryDereferenced(StoreEntry *);
* local variables
*/
static Stack LateReleaseStack;
-MemPool *_StoreEntry::pool = NULL;
+MemPool *StoreEntry::pool = NULL;
void *
-_StoreEntry::operator new (size_t bytecount)
+StoreEntry::operator new (size_t bytecount)
{
- assert (bytecount == sizeof (_StoreEntry));
+ assert (bytecount == sizeof (StoreEntry));
if (!pool) {
pool = memPoolCreate ("StoreEntry", bytecount);
memPoolSetChunkSize(pool, 2048 * 1024);
}
void
-_StoreEntry::operator delete (void *address)
+StoreEntry::operator delete (void *address)
{
memPoolFree(pool, address);
}
size_t
-_StoreEntry::inUseCount()
+StoreEntry::inUseCount()
{
if (!pool)
return 0;
}
const char *
-_StoreEntry::getMD5Text() const
+StoreEntry::getMD5Text() const
{
return storeKeyText((const cache_key *)key);
}
-size_t
-storeEntryInUse ()
+int
+StoreEntry::CheckDeferRead(int fd, void *data)
{
- return _StoreEntry::inUseCount();
+ assert (data);
+ return ((StoreEntry *)data)->checkDeferRead(fd);
}
-
+int
+StoreEntry::checkDeferRead(int fd) const
+{
+ int rc = 0;
+ if (mem_obj == NULL)
+ return 0;
#if URL_CHECKSUM_DEBUG
-unsigned int
-url_checksum(const char *url)
-{
- unsigned int ck;
- MD5_CTX M;
- static unsigned char digest[16];
- MD5Init(&M);
- MD5Update(&M, (unsigned char *) url, strlen(url));
- MD5Final(digest, &M);
- xmemcpy(&ck, digest, sizeof(ck));
- return ck;
-}
+ mem_obj->checkUrlChecksum();
+#endif
+#if DELAY_POOLS
+ if (fd < 0)
+ (void) 0;
+ else if (! delayIsNoDelay(fd)) {
+ int i = delayMostBytesWanted(mem_obj, INT_MAX);
+ if (0 == i)
+ return 1;
+ /* was: rc = -(rc != INT_MAX); */
+ else if (INT_MAX == i)
+ rc = 0;
+ else
+ rc = -1;
+ }
#endif
+ if (EBIT_TEST(flags, ENTRY_FWD_HDR_WAIT))
+ return rc;
+ if (mem_obj->readAheadPolicyCanRead())
+ return rc;
+ return 1;
+}
-static MemObject *
-new_MemObject(const char *url, const char *log_url)
+store_client_t
+StoreEntry::storeClientType() const
{
- MemObject *mem = static_cast<MemObject *>(memAllocate(MEM_MEMOBJECT));
- mem->reply = httpReplyCreate();
- mem->url = xstrdup(url);
-#if URL_CHECKSUM_DEBUG
- mem->chksum = url_checksum(mem->url);
-#endif
- mem->log_url = xstrdup(log_url);
- mem->object_sz = -1;
- mem->fd = -1;
- /* XXX account log_url */
- debug(20, 3) ("new_MemObject: returning %p\n", mem);
- return mem;
+ if (mem_obj->inmem_lo)
+ return STORE_DISK_CLIENT;
+ if (EBIT_TEST(flags, ENTRY_ABORTED)) {
+ /* I don't think we should be adding clients to aborted entries */
+ debug(20, 1) ("storeClientType: adding to ENTRY_ABORTED entry\n");
+ return STORE_MEM_CLIENT;
+ }
+ if (store_status == STORE_OK) {
+ if (mem_obj->inmem_lo == 0 && !isEmpty())
+ return STORE_MEM_CLIENT;
+ else
+ return STORE_DISK_CLIENT;
+ }
+ /* here and past, entry is STORE_PENDING */
+ /*
+ * If this is the first client, let it be the mem client
+ */
+ if (mem_obj->nclients == 1)
+ return STORE_MEM_CLIENT;
+ /*
+ * If there is no disk file to open yet, we must make this a
+ * mem client. If we can't open the swapin file before writing
+ * to the client, there is no guarantee that we will be able
+ * to open it later when we really need it.
+ */
+ if (swap_status == SWAPOUT_NONE)
+ return STORE_MEM_CLIENT;
+ /*
+ * otherwise, make subsequent clients read from disk so they
+ * can not delay the first, and vice-versa.
+ */
+ return STORE_DISK_CLIENT;
}
StoreEntry *
new_StoreEntry(int mem_obj_flag, const char *url, const char *log_url)
{
StoreEntry *e = NULL;
- e = new _StoreEntry;
+ e = new StoreEntry;
if (mem_obj_flag)
- e->mem_obj = new_MemObject(url, log_url);
- debug(20, 3) ("new_StoreEntry: returning %p\n", e);
+ e->mem_obj = new MemObject(url, log_url);
+ debug(20, 3) ("newStoreEntry: returning %p\n", e);
e->expires = e->lastmod = e->lastref = e->timestamp = -1;
e->swap_filen = -1;
e->swap_dirn = -1;
static void
destroy_MemObject(StoreEntry * e)
{
+ storeSetMemStatus(e, NOT_IN_MEMORY);
MemObject *mem = e->mem_obj;
- const Ctx ctx = ctx_enter(mem->url);
- debug(20, 3) ("destroy_MemObject: destroying %p\n", mem);
-#if URL_CHECKSUM_DEBUG
- assert(mem->chksum == url_checksum(mem->url));
-#endif
e->mem_obj = NULL;
- if (!shutting_down)
- assert(mem->swapout.sio == NULL);
- stmemFree(&mem->data_hdr);
- mem->inmem_hi = 0;
- /*
- * 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.head == 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); /* XXX account log_url */
- safe_free(mem->vary_headers);
- memFree(mem, MEM_MEMOBJECT);
+ delete mem;
}
static void
-destroy_StoreEntry(void *data)
+destroyStoreEntry(void *data)
{
StoreEntry *e = static_cast<StoreEntry *>(data);
- debug(20, 3) ("destroy_StoreEntry: destroying %p\n", e);
+ debug(20, 3) ("destroyStoreEntry: destroying %p\n", e);
assert(e != NULL);
if (e == NullStoreEntry::getInstance())
return;
- if (e->mem_obj)
- destroy_MemObject(e);
+ destroy_MemObject(e);
storeHashDelete(e);
assert(e->key == NULL);
delete e;
/* get rid of memory copy of the object */
-/* Only call this if storeCheckPurgeMem(e) returns 1 */
static void
storePurgeMem(StoreEntry * e)
{
return;
debug(20, 3) ("storePurgeMem: Freeing memory-copy of %s\n",
e->getMD5Text());
- storeSetMemStatus(e, NOT_IN_MEMORY);
destroy_MemObject(e);
if (e->swap_status != SWAPOUT_DONE)
storeRelease(e);
static void
storeEntryReferenced(StoreEntry * e)
{
- SwapDir *SD;
-
/* Notify the fs that we're referencing this object again */
- if (e->swap_dirn > -1) {
- SD = INDEXSD(e->swap_dirn);
- if (SD->refobj)
- SD->refobj(SD, e);
- }
+ if (e->swap_dirn > -1)
+ INDEXSD(e->swap_dirn)->reference(*e);
/* Notify the memory cache that we're referencing this object again */
if (e->mem_obj) {
if (mem_policy->Referenced)
static void
storeEntryDereferenced(StoreEntry * e)
{
- SwapDir *SD;
-
/* Notify the fs that we're not referencing this object any more */
- if (e->swap_filen > -1) {
- SD = INDEXSD(e->swap_dirn);
- if (SD->unrefobj != NULL)
- SD->unrefobj(SD, e);
- }
+ if (e->swap_filen > -1)
+ INDEXSD(e->swap_dirn)->dereference(*e);
/* Notify the memory cache that we're not referencing this object any more */
if (e->mem_obj) {
if (mem_policy->Dereferenced)
else if (storeKeepInMemory(e)) {
storeEntryDereferenced(e);
storeSetMemStatus(e, IN_MEMORY);
- requestUnlink(e->mem_obj->request);
- e->mem_obj->request = NULL;
+ e->mem_obj->unlinkRequest();
} else {
storePurgeMem(e);
storeEntryDereferenced(e);
}
void
-_StoreEntry::getPublicByRequestMethod (StoreClient *aClient, request_t * request, const method_t method)
+StoreEntry::getPublicByRequestMethod (StoreClient *aClient, request_t * request, const method_t method)
{
assert (aClient);
- _StoreEntry *result = storeGetPublicByRequestMethod( request, method);
+ StoreEntry *result = storeGetPublicByRequestMethod( request, method);
if (!result)
aClient->created (NullStoreEntry::getInstance());
else
}
void
-_StoreEntry::getPublicByRequest (StoreClient *aClient, request_t * request)
+StoreEntry::getPublicByRequest (StoreClient *aClient, request_t * request)
{
assert (aClient);
- _StoreEntry *result = storeGetPublicByRequest (request);
+ StoreEntry *result = storeGetPublicByRequest (request);
if (!result)
result = NullStoreEntry::getInstance();
aClient->created (result);
}
void
-_StoreEntry::getPublic (StoreClient *aClient, const char *uri, const method_t method)
+StoreEntry::getPublic (StoreClient *aClient, const char *uri, const method_t method)
{
assert (aClient);
- _StoreEntry *result = storeGetPublic (uri, method);
+ StoreEntry *result = storeGetPublic (uri, method);
if (!result)
result = NullStoreEntry::getInstance();
aClient->created (result);
}
/* Make sure the request knows the variance status */
if (!request->vary_headers) {
- const char *vary = httpMakeVaryMark(request, mem->reply);
+ const char *vary = httpMakeVaryMark(request, mem->getReply());
if (vary)
request->vary_headers = xstrdup(vary);
}
String vary;
pe = storeCreateEntry(mem->url, mem->log_url, request->flags, request->method);
httpBuildVersion(&version, 1, 0);
- httpReplySetHeaders(pe->mem_obj->reply, version, HTTP_OK, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000);
- vary = httpHeaderGetList(&mem->reply->header, HDR_VARY);
- if (strBuf(vary)) {
- httpHeaderPutStr(&pe->mem_obj->reply->header, HDR_VARY, strBuf(vary));
- stringClean(&vary);
+ /* We are allowed to do this typecast */
+ httpReplySetHeaders((HttpReply *)pe->getReply(), version, HTTP_OK, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000);
+ vary = httpHeaderGetList(&mem->getReply()->header, HDR_VARY);
+ if (vary.size()) {
+ /* Again, we own this structure layout */
+ httpHeaderPutStr((HttpHeader *)&pe->getReply()->header, HDR_VARY, vary.buf());
+ vary.clean();
}
#if X_ACCELERATOR_VARY
- vary = httpHeaderGetList(&mem->reply->header, HDR_X_ACCELERATOR_VARY);
- if (strBuf(vary)) {
- httpHeaderPutStr(&pe->mem_obj->reply->header, HDR_X_ACCELERATOR_VARY, strBuf(vary));
- stringClean(&vary);
+ vary = httpHeaderGetList(&mem->getReply()->header, HDR_X_ACCELERATOR_VARY);
+ if (vary.buf()) {
+ httpHeaderPutStr(&pe->getReply()->header, HDR_X_ACCELERATOR_VARY, vary.buf());
+ vary.clean();
}
#endif
storeSetPublicKey(pe);
- httpReplySwapOut(pe->mem_obj->reply, pe);
+ /* TODO: remove this when the metadata is separated */
+ {
+ Packer p;
+ packerToStoreInit(&p, pe);
+ httpReplyPackHeadersInto(pe->getReply(), &p);
+ packerClean(&p);
+ }
storeBufferFlush(pe);
storeTimestampsSet(pe);
- storeComplete(pe);
+ pe->complete();
storeUnlockObject(pe);
}
newkey = storeKeyPublicByRequest(mem->request);
e->expires = squid_curtime;
}
+void
+storeWriteComplete (void *data, StoreIOBuffer wroteBuffer)
+{
+ StoreEntry *e = (StoreEntry *)data;
+ if (EBIT_TEST(e->flags, DELAY_SENDING))
+ return;
+ InvokeHandlers(e);
+}
+
+void
+StoreEntry::write (StoreIOBuffer writeBuffer)
+{
+ assert(mem_obj != NULL);
+ assert(writeBuffer.length >= 0);
+ /* This assert will change when we teach the store to update */
+ assert(store_status == STORE_PENDING);
+ if (!writeBuffer.length)
+ return;
+
+ debug(20, 5) ("storeWrite: writing %u bytes for '%s'\n",
+ writeBuffer.length, getMD5Text());
+ storeGetMemSpace(writeBuffer.length);
+ mem_obj->write (writeBuffer, storeWriteComplete, this);
+}
+
/* Append incoming data from a primary server to an entry. */
void
storeAppend(StoreEntry * e, const char *buf, int len)
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,
- e->getMD5Text());
- storeGetMemSpace(len);
- stmemAppend(&mem->data_hdr, buf, len);
- mem->inmem_hi += len;
- }
- if (EBIT_TEST(e->flags, DELAY_SENDING))
- return;
- InvokeHandlers(e);
- storeSwapOut(e);
+
+ StoreIOBuffer tempBuffer;
+ tempBuffer.data = (char *)buf;
+ tempBuffer.length = len;
+ tempBuffer.offset = mem->endOffset() - (e->getReply() ? e->getReply()->hdr_sz : 0);
+ e->write(tempBuffer);
}
void
static int
storeCheckTooSmall(StoreEntry * e)
{
- MemObject *mem = e->mem_obj;
+ MemObject * const mem = e->mem_obj;
if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
return 0;
if (STORE_OK == e->store_status)
if (mem->object_sz < 0 ||
static_cast<size_t>(mem->object_sz) < Config.Store.minObjectSize)
return 1;
- if (mem->reply->content_length > -1)
- if (mem->reply->content_length < (int) Config.Store.minObjectSize)
+ if (e->getReply()->content_length > -1)
+ if (e->getReply()->content_length < (int) Config.Store.minObjectSize)
return 1;
return 0;
}
debug(20, 3) ("storeCheckCachable: NO: negative cached\n");
store_check_cachable_hist.no.negative_cached++;
return 0; /* avoid release call below */
- } else if ((e->mem_obj->reply->content_length > 0 &&
- static_cast<size_t>(e->mem_obj->reply->content_length) > Config.Store.maxObjectSize) ||
- static_cast<size_t>(e->mem_obj->inmem_hi) > Config.Store.maxObjectSize) {
+ } else if ((e->getReply()->content_length > 0 &&
+ static_cast<size_t>(e->getReply()->content_length) > Config.Store.maxObjectSize) ||
+ static_cast<size_t>(e->mem_obj->endOffset()) > Config.Store.maxObjectSize) {
debug(20, 2) ("storeCheckCachable: NO: too big\n");
store_check_cachable_hist.no.too_big++;
- } else if (e->mem_obj->reply->content_length > (int) Config.Store.maxObjectSize) {
+ } else if (e->getReply()->content_length > (int) Config.Store.maxObjectSize) {
debug(20, 2) ("storeCheckCachable: NO: too big\n");
store_check_cachable_hist.no.too_big++;
} else if (storeCheckTooSmall(e)) {
store_check_cachable_hist.yes.Default);
}
-/* Complete transfer into the local cache. */
void
-storeComplete(StoreEntry * e)
+StoreEntry::complete()
{
- debug(20, 3) ("storeComplete: '%s'\n", e->getMD5Text());
- if (e->store_status != STORE_PENDING) {
+ debug(20, 3) ("storeComplete: '%s'\n", getMD5Text());
+ if (store_status != STORE_PENDING) {
/*
* if we're not STORE_PENDING, then probably we got aborted
* and there should be NO clients on this entry
*/
- assert(EBIT_TEST(e->flags, ENTRY_ABORTED));
- assert(e->mem_obj->nclients == 0);
+ assert(EBIT_TEST(flags, ENTRY_ABORTED));
+ assert(mem_obj->nclients == 0);
return;
}
- e->mem_obj->object_sz = e->mem_obj->inmem_hi;
- e->store_status = STORE_OK;
- assert(e->mem_status == NOT_IN_MEMORY);
- if (!storeEntryValidLength(e)) {
- EBIT_SET(e->flags, ENTRY_BAD_LENGTH);
- storeReleaseRequest(e);
+ mem_obj->object_sz = mem_obj->endOffset();
+ store_status = STORE_OK;
+ assert(mem_status == NOT_IN_MEMORY);
+ if (!validLength()) {
+ EBIT_SET(flags, ENTRY_BAD_LENGTH);
+ storeReleaseRequest(this);
}
#if USE_CACHE_DIGESTS
- if (e->mem_obj->request)
- e->mem_obj->request->hier.store_complete_stop = current_time;
+ if (mem_obj->request)
+ mem_obj->request->hier.store_complete_stop = current_time;
#endif
/*
* We used to call InvokeHandlers, then storeSwapOut. However,
* responses without content length would sometimes get released
* in client_side, thinking that the response is incomplete.
*/
- storeSwapOut(e);
- InvokeHandlers(e);
+ InvokeHandlers(this);
}
/*
void
storeAbort(StoreEntry * e)
{
+ statCounter.aborted_requests++;
MemObject *mem = e->mem_obj;
assert(e->store_status == STORE_PENDING);
assert(mem != NULL);
* We assign an object length here. The only other place we assign
* the object length is in storeComplete()
*/
- mem->object_sz = mem->inmem_hi;
+ /* RBC: What do we need an object length for? we've just aborted the
+ * request, the request is private and negatively cached. Surely
+ * the object length is inappropriate to set.
+ */
+ mem->object_sz = mem->endOffset();
/* Notify the server side */
if (mem->abort.callback) {
eventAdd("mem->abort.callback",
mem->abort.callback = NULL;
mem->abort.data = NULL;
}
+ /* XXX Should we reverse these two, so that there is no
+ * unneeded disk swapping triggered?
+ */
/* Notify the client side */
InvokeHandlers(e);
/* Close any swapout file */
StoreEntry *e = NULL;
int released = 0;
static time_t last_check = 0;
- int pages_needed;
+ size_t pages_needed;
RemovalPurgeWalker *walker;
if (squid_curtime == last_check)
return;
last_check = squid_curtime;
pages_needed = (size / SM_PAGE_SIZE) + 1;
- if (memInUse(MEM_MEM_NODE) + pages_needed < store_pages_max)
+ if (mem_node::InUseCount() + pages_needed < store_pages_max)
return;
debug(20, 2) ("storeGetMemSpace: Starting, need %d pages\n", pages_needed);
/* XXX what to set as max_scan here? */
while ((e = walker->Next(walker))) {
storePurgeMem(e);
released++;
- if (memInUse(MEM_MEM_NODE) + pages_needed < store_pages_max)
+ if (mem_node::InUseCount() + pages_needed < store_pages_max)
break;
}
walker->Done(walker);
/*
* This routine is to be called by main loop in main.c.
* It removes expired objects on only one bucket for each time called.
- * returns the number of objects removed
*
* This should get called 1/s from main().
*/
/* XXX FixMe: This should be done "in parallell" on the different
* cache_dirs, not one at a time.
*/
- if (SD->maintainfs != NULL)
- SD->maintainfs(SD);
+ SD->maintainfs();
}
if (store_swap_size > Config.Swap.maxSize) {
if (squid_curtime - last_warn_time > 10) {
}
if (store_dirs_rebuilding && e->swap_filen > -1) {
storeSetPrivateKey(e);
- if (e->mem_obj) {
- storeSetMemStatus(e, NOT_IN_MEMORY);
+ if (e->mem_obj)
destroy_MemObject(e);
- }
if (e->swap_filen > -1) {
/*
* Fake a call to storeLockObject(). When rebuilding is done,
PROF_stop(storeRelease);
return;
} else {
- destroy_StoreEntry(e);
+ destroyStoreEntry(e);
}
}
storeLog(STORE_LOG_RELEASE, e);
storeUnlink(e);
if (e->swap_status == SWAPOUT_DONE)
if (EBIT_TEST(e->flags, ENTRY_VALIDATED))
- storeDirUpdateSwapSize(&Config.cacheSwap.swapDirs[e->swap_dirn], e->swap_file_sz, -1);
+ storeDirUpdateSwapSize(INDEXSD(e->swap_dirn), e->swap_file_sz, -1);
if (!EBIT_TEST(e->flags, KEY_PRIVATE))
storeDirSwapLog(e, SWAP_LOG_DEL);
#if 0
#endif
}
storeSetMemStatus(e, NOT_IN_MEMORY);
- destroy_StoreEntry(e);
+ destroyStoreEntry(e);
PROF_stop(storeRelease);
}
return 0;
}
-static int
-storeEntryValidLength(const StoreEntry * e)
+bool
+StoreEntry::validLength() const
{
int diff;
const HttpReply *reply;
- assert(e->mem_obj != NULL);
- reply = e->mem_obj->reply;
- debug(20, 3) ("storeEntryValidLength: Checking '%s'\n", e->getMD5Text());
+ assert(mem_obj != NULL);
+ reply = getReply();
+ debug(20, 3) ("storeEntryValidLength: Checking '%s'\n", getMD5Text());
debug(20, 5) ("storeEntryValidLength: object_len = %d\n",
- objectLen(e));
+ objectLen(this));
debug(20, 5) ("storeEntryValidLength: hdr_sz = %d\n",
reply->hdr_sz);
debug(20, 5) ("storeEntryValidLength: content_length = %d\n",
reply->content_length);
if (reply->content_length < 0) {
debug(20, 5) ("storeEntryValidLength: Unspecified content length: %s\n",
- e->getMD5Text());
+ getMD5Text());
return 1;
}
if (reply->hdr_sz == 0) {
debug(20, 5) ("storeEntryValidLength: Zero header size: %s\n",
- e->getMD5Text());
+ getMD5Text());
return 1;
}
- if (e->mem_obj->method == METHOD_HEAD) {
+ if (mem_obj->method == METHOD_HEAD) {
debug(20, 5) ("storeEntryValidLength: HEAD request: %s\n",
- e->getMD5Text());
+ getMD5Text());
return 1;
}
if (reply->sline.status == HTTP_NOT_MODIFIED)
return 1;
if (reply->sline.status == HTTP_NO_CONTENT)
return 1;
- diff = reply->hdr_sz + reply->content_length - objectLen(e);
+ diff = reply->hdr_sz + reply->content_length - objectLen(this);
if (diff == 0)
return 1;
debug(20, 3) ("storeEntryValidLength: %d bytes too %s; '%s'\n",
diff < 0 ? -diff : diff,
diff < 0 ? "big" : "small",
- e->getMD5Text());
+ getMD5Text());
return 0;
}
void
storeFreeMemory(void)
{
- hashFreeItems(store_table, destroy_StoreEntry);
+ hashFreeItems(store_table, destroyStoreEntry);
hashFreeMemory(store_table);
store_table = NULL;
#if USE_CACHE_DIGESTS
void
storeTimestampsSet(StoreEntry * entry)
{
- const HttpReply *reply = entry->mem_obj->reply;
+ const HttpReply *reply = entry->getReply();
time_t served_date = reply->date;
int age = httpHeaderGetInt(&reply->header, HDR_AGE);
/*
mem->abort.callback = NULL;
}
-void
-storeMemObjectDump(MemObject * mem)
-{
- debug(20, 1) ("MemObject->data.head: %p\n",
- mem->data_hdr.head);
- debug(20, 1) ("MemObject->data.tail: %p\n",
- mem->data_hdr.tail);
- debug(20, 1) ("MemObject->data.origin_offset: %d\n",
- mem->data_hdr.origin_offset);
- debug(20, 1) ("MemObject->start_ping: %d.%06d\n",
- (int) mem->start_ping.tv_sec,
- (int) mem->start_ping.tv_usec);
- debug(20, 1) ("MemObject->inmem_hi: %d\n",
- (int) mem->inmem_hi);
- debug(20, 1) ("MemObject->inmem_lo: %d\n",
- (int) mem->inmem_lo);
- debug(20, 1) ("MemObject->nclients: %d\n",
- mem->nclients);
- debug(20, 1) ("MemObject->reply: %p\n",
- mem->reply);
- debug(20, 1) ("MemObject->request: %p\n",
- mem->request);
- debug(20, 1) ("MemObject->log_url: %p %s\n",
- mem->log_url,
- checkNullString(mem->log_url));
-}
-
void
storeEntryDump(const StoreEntry * e, int l)
{
{
if (e->mem_obj)
return;
- e->mem_obj = new_MemObject(url, log_url);
+ e->mem_obj = new MemObject(url, log_url);
}
/* this just sets DELAY_SENDING */
{
EBIT_CLR(e->flags, DELAY_SENDING);
InvokeHandlers(e);
- storeSwapOut(e);
}
ssize_t
contentLen(const StoreEntry * e)
{
assert(e->mem_obj != NULL);
- assert(e->mem_obj->reply != NULL);
- return e->mem_obj->object_sz - e->mem_obj->reply->hdr_sz;
+ assert(e->getReply() != NULL);
+ return objectLen(e) - e->getReply()->hdr_sz;
+
}
-HttpReply *
-storeEntryReply(StoreEntry * e)
+HttpReply const *
+StoreEntry::getReply () const
{
- if (NULL == e)
+ if (NULL == mem_obj)
return NULL;
- if (NULL == e->mem_obj)
- return NULL;
- return e->mem_obj->reply;
+ return mem_obj->getReply();
}
void
storeEntryReset(StoreEntry * e)
{
MemObject *mem = e->mem_obj;
+ assert (mem);
debug(20, 3) ("storeEntryReset: %s\n", storeUrl(e));
- assert(mem->swapout.sio == NULL);
- stmemFree(&mem->data_hdr);
- mem->inmem_hi = mem->inmem_lo = 0;
- httpReplyDestroy(mem->reply);
- mem->reply = httpReplyCreate();
+ mem->reset();
+ httpReplyReset((HttpReply *)e->getReply());
e->expires = e->lastmod = e->timestamp = -1;
}
/*
* called to add another store fs module
+ * RBC: doesn't belong here. Move IT.
*/
void
-storeFsAdd(const char *type, STSETUP * setup)
+StoreEntry::FsAdd(const char *type, STSETUP * setup)
{
int i;
/* find the number of currently known storefs types */
}
#endif
+/* Replace a store entry with
+ * a new reply. This eats the reply.
+ */
+void
+storeEntryReplaceObject(StoreEntry * e, HttpReply * rep)
+{
+ MemObject * const mem = e->mem_obj;
+ HttpReply *myrep;
+ Packer p;
+ debug(20, 3) ("storeEntryReplaceObject: %s\n", storeUrl(e));
+ if (!mem) {
+ debug (20,0)("Attempt to replace object with no in-memory representation\n");
+ return;
+ }
+ /* TODO: check that there is at most 1 store client ? */
+ myrep = (HttpReply *)e->getReply(); /* we are allowed to do this */
+ /* move info to the mem_obj->reply */
+ httpReplyAbsorb(myrep, rep);
+
+ /* TODO: when we store headers serparately remove the header portion */
+ /* TODO: mark the length of the headers ? */
+ /* We ONLY want the headers */
+ packerToStoreInit(&p, e);
+ assert (e->isEmpty());
+ httpReplyPackHeadersInto(e->getReply(), &p);
+ myrep->hdr_sz = e->mem_obj->endOffset();
+ httpBodyPackInto(&e->getReply()->body, &p);
+ packerClean(&p);
+}
+
+
+char const *
+StoreEntry::getSerialisedMetaData()
+{
+ StoreMeta *tlv_list = storeSwapMetaBuild(this);
+ int swap_hdr_sz;
+ char *result = storeSwapMetaPack(tlv_list, &swap_hdr_sz);
+ storeSwapTLVFree(tlv_list);
+ assert (swap_hdr_sz >= 0);
+ mem_obj->swap_hdr_sz = (size_t) swap_hdr_sz;
+ return result;
+}
+
+bool
+StoreEntry::swapoutPossible()
+{
+ /* should we swap something out to disk? */
+ debug(20, 7) ("storeSwapOut: %s\n", storeUrl(this));
+ debug(20, 7) ("storeSwapOut: store_status = %s\n",
+ storeStatusStr[store_status]);
+ if (EBIT_TEST(flags, ENTRY_ABORTED)) {
+ assert(EBIT_TEST(flags, RELEASE_REQUEST));
+ storeSwapOutFileClose(this);
+ return false;
+ }
+ if (EBIT_TEST(flags, ENTRY_SPECIAL)) {
+ debug(20, 3) ("storeSwapOut: %s SPECIAL\n", storeUrl(this));
+ return false;
+ }
+ return true;
+}
+void
+StoreEntry::trimMemory()
+{
+ if (mem_obj->policyLowestOffsetToKeep() == 0)
+ /* Nothing to do */
+ return;
+ assert (mem_obj->policyLowestOffsetToKeep() > 0);
+ if (!storeSwapOutAble(this)) {
+ /*
+ * Its not swap-able, and we're about to delete a chunk,
+ * so we must make it PRIVATE. This is tricky/ugly because
+ * for the most part, we treat swapable == cachable here.
+ */
+ storeReleaseRequest(this);
+ mem_obj->trimUnSwappable ();
+ } else {
+ mem_obj->trimSwappable ();
+ }
+}
/* NullStoreEntry */
NullStoreEntry NullStoreEntry::_instance;
{
return "N/A";
}
+
+char const *
+NullStoreEntry::getSerialisedMetaData()
+{
+ return NULL;
+}
+
+#ifndef _USE_INLINE_
+#include "Store.cci"
+#endif