trimMemory for unswappable objects Inside StoreEntry::swapOut() the StoreEntry::trimMemory() method called to release unused MemObjects memory. The trimMemory method must called for all store entries, but current code blocks that call for not-swappable objects, at least. This patch trying to fix this bug implementing the following simple logic: { bool weAreOrMayBeSwappingOut = swappingOut() || mayStartSwapout(); trimMemory(weAreOrMayBeSwappingOut); if (!weAreOrMayBeSwappingOut) return; // nothing else to do } === modified file 'src/MemObject.cc' --- src/MemObject.cc 2011-09-06 22:32:30 +0000 +++ src/MemObject.cc 2011-11-23 12:42:07 +0000 @@ -475,20 +475,26 @@ continue; #endif if (sc->getType() != STORE_MEM_CLIENT) /* reading off disk */ continue; j = sc->delayId.bytesWanted(0, sc->copyInto.length); if (j > jmax) { jmax = j; result = sc->delayId; } } return result; } #endif + +int64_t +MemObject::availableForSwapOut() const +{ + return endOffset() - swapout.queue_offset; +} === modified file 'src/MemObject.h' --- src/MemObject.h 2011-04-28 22:45:55 +0000 +++ src/MemObject.h 2012-01-07 09:57:12 +0000 @@ -64,40 +64,41 @@ void write(StoreIOBuffer, STMCB *, void *); void unlinkRequest(); HttpReply const *getReply() const; void replaceHttpReply(HttpReply *newrep); void stat (MemBuf * mb) const; int64_t endOffset () const; void markEndOfReplyHeaders(); ///< sets _reply->hdr_sz to endOffset() /// negative if unknown; otherwise, expected object_sz, expected endOffset /// maximum, and stored reply headers+body size (all three are the same) int64_t expectedReplySize() const; int64_t size() const; void reset(); int64_t lowestMemReaderOffset() const; bool readAheadPolicyCanRead() const; void addClient(store_client *); /* XXX belongs in MemObject::swapout, once swaphdrsz is managed * better */ int64_t objectBytesOnDisk() const; int64_t policyLowestOffsetToKeep(bool swap) const; + int64_t availableForSwapOut() const; ///< buffered bytes we have not swapped out yet void trimSwappable(); void trimUnSwappable(); bool isContiguous() const; int mostBytesWanted(int max) const; void setNoDelay(bool const newValue); #if USE_DELAY_POOLS DelayId mostBytesAllowed() const; #endif #if URL_CHECKSUM_DEBUG void checkUrlChecksum() const; #endif HttpRequestMethod method; char *url; mem_hdr data_hdr; int64_t inmem_lo; dlink_list clients; === modified file 'src/Store.h' --- src/Store.h 2011-11-18 16:53:45 +0000 +++ src/Store.h 2011-11-23 15:23:13 +0000 @@ -75,57 +75,59 @@ public: static DeferredRead::DeferrableRead DeferReader; bool checkDeferRead(int fd) const; virtual const char *getMD5Text() const; StoreEntry(); StoreEntry(const char *url, const char *log_url); virtual ~StoreEntry(); virtual HttpReply const *getReply() const; virtual void write (StoreIOBuffer); virtual _SQUID_INLINE_ bool isEmpty() const; virtual bool isAccepting() const; virtual size_t bytesWanted(Range const) const; virtual void complete(); virtual store_client_t storeClientType() const; virtual char const *getSerialisedMetaData(); void replaceHttpReply(HttpReply *, bool andStartWriting = true); void startWriting(); ///< pack and write reply headers and, maybe, body - virtual bool swapoutPossible(); - virtual void trimMemory(); + /// whether we may start writing to disk (now or in the future) + virtual bool mayStartSwapOut(); + virtual void trimMemory(const bool preserveSwappable); void abort(); void unlink(); void makePublic(); void makePrivate(); void setPublicKey(); void setPrivateKey(); void expireNow(); void releaseRequest(); void negativeCache(); void cacheNegatively(); /** \todo argh, why both? */ void invokeHandlers(); void purgeMem(); void cacheInMemory(); ///< start or continue storing in memory cache void swapOut(); - bool swapOutAble() const; + /// whether we are in the process of writing this entry to disk + bool swappingOut() const { return swap_status == SWAPOUT_WRITING; } void swapOutFileClose(int how); const char *url() const; int checkCachable(); int checkNegativeHit() const; int locked() const; int validToSend() const; bool memoryCachable() const; ///< may be cached in memory void createMemObject(const char *, const char *); void hideMemObject(); ///< no mem_obj for callers until createMemObject void dump(int debug_lvl) const; void hashDelete(); void hashInsert(const cache_key *); void registerAbort(STABH * cb, void *); void reset(); void setMemStatus(mem_status_t); void timestampsSet(); void unregisterAbort(); void destroyMemObject(); int checkTooSmall(); @@ -230,41 +232,41 @@ static NullStoreEntry *getInstance(); bool isNull() { return true; } const char *getMD5Text() const; _SQUID_INLINE_ HttpReply const *getReply() const; void write (StoreIOBuffer) {} bool isEmpty () const {return true;} virtual size_t bytesWanted(Range const aRange) const { assert (aRange.size()); return aRange.end - 1;} void operator delete(void *address); void complete() {} private: store_client_t storeClientType() const {return STORE_MEM_CLIENT;} char const *getSerialisedMetaData(); - bool swapoutPossible() {return false;} + bool mayStartSwapout() {return false;} void trimMemory() {} static NullStoreEntry _instance; }; /// \ingroup StoreAPI typedef void (*STOREGETCLIENT) (StoreEntry *, void *cbdata); /** \ingroup StoreAPI * Abstract base class that will replace the whole store and swapdir interface. */ class Store : public RefCountable { public: /** The root store */ === modified file 'src/client_side.cc' --- src/client_side.cc 2011-12-30 12:26:51 +0000 +++ src/client_side.cc 2012-01-09 11:11:15 +0000 @@ -2685,41 +2685,41 @@ context->mayUseConnection(true); assert(conn->flags.readMore); } } http->calloutContext = new ClientRequestContext(http); http->doCallouts(); finish: if (!notedUseOfBuffer) connNoteUseOfBuffer(conn, http->req_sz); /* * DPW 2007-05-18 * Moved the TCP_RESET feature from clientReplyContext::sendMoreData * to here because calling comm_reset_close() causes http to * be freed and the above connNoteUseOfBuffer() would hit an * assertion, not to mention that we were accessing freed memory. */ - if (http->request->flags.resetTCP() && Comm::IsConnOpen(conn->clientConnection)) { + if (request && request->flags.resetTCP() && Comm::IsConnOpen(conn->clientConnection)) { debugs(33, 3, HERE << "Sending TCP RST on " << conn->clientConnection); conn->flags.readMore = false; comm_reset_close(conn->clientConnection); } } static void connStripBufferWhitespace (ConnStateData * conn) { while (conn->in.notYetUsed > 0 && xisspace(conn->in.buf[0])) { memmove(conn->in.buf, conn->in.buf + 1, conn->in.notYetUsed - 1); --conn->in.notYetUsed; } } static int connOkToAddRequest(ConnStateData * conn) { int result = conn->getConcurrentRequestCount() < (Config.onoff.pipeline_prefetch ? 2 : 1); === modified file 'src/store.cc' --- src/store.cc 2011-12-10 16:29:31 +0000 +++ src/store.cc 2012-01-07 09:34:28 +0000 @@ -1874,139 +1874,52 @@ mem_obj->markEndOfReplyHeaders(); rep->body.packInto(&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() -{ - if (!Config.cacheSwap.n_configured) - return false; - - /* should we swap something out to disk? */ - debugs(20, 7, "storeSwapOut: " << url()); - debugs(20, 7, "storeSwapOut: store_status = " << storeStatusStr[store_status]); - - assert(mem_obj); - MemObject::SwapOut::Decision &decision = mem_obj->swapout.decision; - - // if we decided that swapout is not possible, do not repeat same checks - if (decision == MemObject::SwapOut::swImpossible) { - debugs(20, 3, "storeSwapOut: already rejected"); - return false; - } - - // this flag may change so we must check it even if we already said "yes" - if (EBIT_TEST(flags, ENTRY_ABORTED)) { - assert(EBIT_TEST(flags, RELEASE_REQUEST)); - // StoreEntry::abort() already closed the swap out file, if any - decision = MemObject::SwapOut::swImpossible; - return false; - } - - // if we decided that swapout is possible, do not repeat same checks - if (decision == MemObject::SwapOut::swPossible) { - debugs(20, 3, "storeSwapOut: already allowed"); - return true; - } - - // if we are swapping out already, do not repeat same checks - if (swap_status != SWAPOUT_NONE) { - debugs(20, 3, "storeSwapOut: already started"); - decision = MemObject::SwapOut::swPossible; - return true; - } - - if (!checkCachable()) { - debugs(20, 3, "storeSwapOut: not cachable"); - decision = MemObject::SwapOut::swImpossible; - return false; - } - - if (EBIT_TEST(flags, ENTRY_SPECIAL)) { - debugs(20, 3, "storeSwapOut: " << url() << " SPECIAL"); - decision = MemObject::SwapOut::swImpossible; - return false; - } - - // check cache_dir max-size limit if all cache_dirs have it - if (store_maxobjsize >= 0) { - // TODO: add estimated store metadata size to be conservative - - // use guaranteed maximum if it is known - const int64_t expectedEnd = mem_obj->expectedReplySize(); - debugs(20, 7, "storeSwapOut: expectedEnd = " << expectedEnd); - if (expectedEnd > store_maxobjsize) { - debugs(20, 3, "storeSwapOut: will not fit: " << expectedEnd << - " > " << store_maxobjsize); - decision = MemObject::SwapOut::swImpossible; - return false; // known to outgrow the limit eventually - } - - // use current minimum (always known) - const int64_t currentEnd = mem_obj->endOffset(); - if (currentEnd > store_maxobjsize) { - debugs(20, 3, "storeSwapOut: does not fit: " << currentEnd << - " > " << store_maxobjsize); - decision = MemObject::SwapOut::swImpossible; - return false; // already does not fit and may only get bigger - } - - // prevent default swPossible answer for yet unknown length - if (expectedEnd < 0) { - debugs(20, 3, "storeSwapOut: wait for more info: " << - store_maxobjsize); - return false; // may fit later, but will be rejected now - } - } - - decision = MemObject::SwapOut::swPossible; - return true; -} - void -StoreEntry::trimMemory() +StoreEntry::trimMemory(const bool preserveSwappable) { /* * DPW 2007-05-09 * Bug #1943. We must not let go any data for IN_MEMORY * objects. We have to wait until the mem_status changes. */ if (mem_status == IN_MEMORY) return; - if (!swapOutAble()) { + if (!preserveSwappable) { if (mem_obj->policyLowestOffsetToKeep(0) == 0) { /* Nothing to do */ return; } /* * 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. */ releaseRequest(); mem_obj->trimUnSwappable (); } else { mem_obj->trimSwappable (); } } bool StoreEntry::modifiedSince(HttpRequest * request) const { int object_length; === modified file 'src/store_client.cc' --- src/store_client.cc 2011-12-10 16:29:31 +0000 +++ src/store_client.cc 2012-01-07 09:34:28 +0000 @@ -178,41 +178,41 @@ if (!sc->_callback.pending()) return; storeClientCopy2(sc->entry, sc); } store_client::store_client(StoreEntry *e) : entry (e) #if USE_DELAY_POOLS , delayId() #endif , type (e->storeClientType()) , object_ok(true) { cmp_offset = 0; flags.disk_io_pending = 0; entry->refcount++; if (getType() == STORE_DISK_CLIENT) /* assert we'll be able to get the data we want */ /* maybe we should open swapin_sio here */ - assert(entry->swap_filen > -1 || entry->swapOutAble()); + assert(entry->swap_filen > -1 || entry->swappingOut()); #if STORE_CLIENT_LIST_DEBUG owner = cbdataReference(data); #endif } store_client::~store_client() {} /* copy bytes requested by the client */ void storeClientCopy(store_client * sc, StoreEntry * e, StoreIOBuffer copyInto, STCB * callback, void *data) { assert (sc != NULL); === modified file 'src/store_swapout.cc' --- src/store_swapout.cc 2011-12-10 16:29:31 +0000 +++ src/store_swapout.cc 2012-01-10 09:48:22 +0000 @@ -171,101 +171,84 @@ if (anEntry->store_status == STORE_PENDING) if (swapout_size < SM_PAGE_SIZE) break; if (swapout_size <= 0) return; } while (true); } /* This routine is called every time data is sent to the client side. * It's overhead is therefor, significant. */ void StoreEntry::swapOut() { if (!mem_obj) return; - if (!swapoutPossible()) + // this flag may change so we must check even if we are swappingOut + if (EBIT_TEST(flags, ENTRY_ABORTED)) { + assert(EBIT_TEST(flags, RELEASE_REQUEST)); + // StoreEntry::abort() already closed the swap out file, if any + // no trimming: data producer must stop production if ENTRY_ABORTED return; + } + + const bool weAreOrMayBeSwappingOut = swappingOut() || mayStartSwapOut(); + + trimMemory(weAreOrMayBeSwappingOut); + + if (!weAreOrMayBeSwappingOut) + return; // nothing else to do // Aborted entries have STORE_OK, but swapoutPossible rejects them. Thus, // store_status == STORE_OK below means we got everything we wanted. debugs(20, 7, HERE << "storeSwapOut: mem->inmem_lo = " << mem_obj->inmem_lo); debugs(20, 7, HERE << "storeSwapOut: mem->endOffset() = " << mem_obj->endOffset()); debugs(20, 7, HERE << "storeSwapOut: swapout.queue_offset = " << mem_obj->swapout.queue_offset); if (mem_obj->swapout.sio != NULL) debugs(20, 7, "storeSwapOut: storeOffset() = " << mem_obj->swapout.sio->offset() ); - // buffered bytes we have not swapped out yet - int64_t swapout_maxsize = mem_obj->endOffset() - mem_obj->swapout.queue_offset; - - assert(swapout_maxsize >= 0); - int64_t const lowest_offset = mem_obj->lowestMemReaderOffset(); debugs(20, 7, HERE << "storeSwapOut: lowest_offset = " << lowest_offset); - // Check to see whether we're going to defer the swapout based upon size - if (store_status != STORE_OK) { - const int64_t expectedSize = mem_obj->expectedReplySize(); - const int64_t maxKnownSize = expectedSize < 0 ? - swapout_maxsize : expectedSize; - debugs(20, 7, HERE << "storeSwapOut: maxKnownSize= " << maxKnownSize); - - if (maxKnownSize < store_maxobjsize) { - /* - * NOTE: the store_maxobjsize here is the max of optional - * max-size values from 'cache_dir' lines. It is not the - * same as 'maximum_object_size'. By default, store_maxobjsize - * will be set to -1. However, I am worried that this - * deferance may consume a lot of memory in some cases. - * Should we add an option to limit this memory consumption? - */ - debugs(20, 5, "storeSwapOut: Deferring swapout start for " << - (store_maxobjsize - maxKnownSize) << " bytes"); - return; - } - } - -// TODO: it is better to trim as soon as we swap something out, not before - trimMemory(); #if SIZEOF_OFF_T <= 4 if (mem_obj->endOffset() > 0x7FFF0000) { debugs(20, 0, "WARNING: preventing off_t overflow for " << url()); abort(); return; } #endif if (swap_status == SWAPOUT_WRITING) assert(mem_obj->inmem_lo <= mem_obj->objectBytesOnDisk() ); - if (!swapOutAble()) - return; - + // buffered bytes we have not swapped out yet + const int64_t swapout_maxsize = mem_obj->availableForSwapOut(); + assert(swapout_maxsize >= 0); debugs(20, 7, "storeSwapOut: swapout_size = " << swapout_maxsize); if (swapout_maxsize == 0) { // swapped everything we got if (store_status == STORE_OK) { // got everything we wanted assert(mem_obj->object_sz >= 0); swapOutFileClose(StoreIOState::wroteAll); } // else need more data to swap out return; } if (store_status == STORE_PENDING) { /* wait for a full block to write */ if (swapout_maxsize < SM_PAGE_SIZE) return; /* * Wait until we are below the disk FD limit, only if the * next server-side read won't be deferred. @@ -357,59 +340,154 @@ e->swap_status = SWAPOUT_DONE; e->store()->swappedOut(*e); // XXX: For some Stores, it is pointless to re-check cachability here // and it leads to double counts in store_check_cachable_hist. We need // another way to signal a completed but failed swapout. Or, better, // each Store should handle its own logging and LOG state setting. if (e->checkCachable()) { storeLog(STORE_LOG_SWAPOUT, e); storeDirSwapLog(e, SWAP_LOG_ADD); } ++statCounter.swap.outs; } debugs(20, 3, "storeSwapOutFileClosed: " << __FILE__ << ":" << __LINE__); mem->swapout.sio = NULL; e->unlock(); } -/* - * Is this entry a candidate for writing to disk? - */ bool -StoreEntry::swapOutAble() const +StoreEntry::mayStartSwapOut() { dlink_node *node; - if (mem_obj->swapout.sio != NULL) + // must be checked in the caller + assert(!EBIT_TEST(flags, ENTRY_ABORTED)); + + if (!Config.cacheSwap.n_configured) + return false; + + assert(mem_obj); + MemObject::SwapOut::Decision &decision = mem_obj->swapout.decision; + + // if we decided that swapout is not possible, do not repeat same checks + if (decision == MemObject::SwapOut::swImpossible) { + debugs(20, 3, HERE << " already rejected"); + return false; + } + + // if we decided that swapout is possible, do not repeat same checks + if (decision == MemObject::SwapOut::swPossible) { + debugs(20, 3, HERE << "already allowed"); return true; + } - if (mem_obj->inmem_lo > 0) + // if we are swapping out already, do not repeat same checks + if (swap_status != SWAPOUT_NONE) { + debugs(20, 3, HERE << " already started"); + decision = MemObject::SwapOut::swPossible; + return true; + } + + if (!checkCachable()) { + debugs(20, 3, HERE << "not cachable"); + decision = MemObject::SwapOut::swImpossible; return false; + } + + if (EBIT_TEST(flags, ENTRY_SPECIAL)) { + debugs(20, 3, HERE << url() << " SPECIAL"); + decision = MemObject::SwapOut::swImpossible; + return false; + } + + // check cache_dir max-size limit if all cache_dirs have it + if (store_maxobjsize >= 0) { + // TODO: add estimated store metadata size to be conservative + + // use guaranteed maximum if it is known + const int64_t expectedEnd = mem_obj->expectedReplySize(); + debugs(20, 7, HERE << "expectedEnd = " << expectedEnd); + if (expectedEnd > store_maxobjsize) { + debugs(20, 3, HERE << "will not fit: " << expectedEnd << + " > " << store_maxobjsize); + decision = MemObject::SwapOut::swImpossible; + return false; // known to outgrow the limit eventually + } + + // use current minimum (always known) + const int64_t currentEnd = mem_obj->endOffset(); + if (currentEnd > store_maxobjsize) { + debugs(20, 3, HERE << "does not fit: " << currentEnd << + " > " << store_maxobjsize); + decision = MemObject::SwapOut::swImpossible; + return false; // already does not fit and may only get bigger + } + + // prevent default swPossible answer for yet unknown length + if (expectedEnd < 0) { + debugs(20, 3, HERE << "wait for more info: " << + store_maxobjsize); + return false; // may fit later, but will be rejected now + } + + if (store_status != STORE_OK) { + const int64_t maxKnownSize = expectedEnd < 0 ? + mem_obj->availableForSwapOut() : expectedEnd; + debugs(20, 7, HERE << "maxKnownSize= " << maxKnownSize); + if (maxKnownSize < store_maxobjsize) { + /* + * NOTE: the store_maxobjsize here is the max of optional + * max-size values from 'cache_dir' lines. It is not the + * same as 'maximum_object_size'. By default, store_maxobjsize + * will be set to -1. However, I am worried that this + * deferance may consume a lot of memory in some cases. + * Should we add an option to limit this memory consumption? + */ + debugs(20, 5, HERE << "Deferring swapout start for " << + (store_maxobjsize - maxKnownSize) << " bytes"); + return false; + } + } + } + + if (mem_obj->inmem_lo > 0) { + debugs(20, 3, "storeSwapOut: (inmem_lo > 0) imem_lo:" << mem_obj->inmem_lo); + decision = MemObject::SwapOut::swImpossible; + return false; + } /* * If there are DISK clients, we must write to disk * even if its not cachable * RBC: Surely we should not create disk client on non cacheable objects? * therefore this should be an assert? * RBC 20030708: We can use disk to avoid mem races, so this shouldn't be * an assert. + * + * XXX: Not clear what "mem races" the above refers to, especially when + * dealing with non-cachable objects that cannot have multiple clients. + * + * XXX: If STORE_DISK_CLIENT needs SwapOut::swPossible, we have to check + * for that flag earlier, but forcing swapping may contradict max-size or + * other swapability restrictions. Change storeClientType() and/or its + * callers to take swap-in availability into account. */ for (node = mem_obj->clients.head; node; node = node->next) { - if (((store_client *) node->data)->getType() == STORE_DISK_CLIENT) + if (((store_client *) node->data)->getType() == STORE_DISK_CLIENT) { + debugs(20, 3, HERE << "DISK client found"); + decision = MemObject::SwapOut::swPossible; return true; + } } - /* Don't pollute the disk with icons and other special entries */ - if (EBIT_TEST(flags, ENTRY_SPECIAL)) - return false; - - if (!EBIT_TEST(flags, ENTRY_CACHABLE)) - return false; - - if (!mem_obj->isContiguous()) + if (!mem_obj->isContiguous()) { + debugs(20, 3, "storeSwapOut: not Contiguous"); + decision = MemObject::SwapOut::swImpossible; return false; + } + decision = MemObject::SwapOut::swPossible; return true; } === modified file 'src/tests/stub_MemObject.cc' --- src/tests/stub_MemObject.cc 2011-10-14 16:21:48 +0000 +++ src/tests/stub_MemObject.cc 2012-01-07 10:29:33 +0000 @@ -189,20 +189,27 @@ } void MemObject::resetUrls(char const*, char const*) { fatal ("MemObject.cc required."); } void MemObject::markEndOfReplyHeaders() { fatal ("MemObject.cc required."); } size_t MemObject::inUseCount() { fatal ("MemObject.cc required."); return 0; } + +int64_t +MemObject::availableForSwapOut() const +{ + fatal ("MemObject.cc required."); + return 0; +} === modified file 'src/tests/stub_store.cc' --- src/tests/stub_store.cc 2011-08-10 15:54:51 +0000 +++ src/tests/stub_store.cc 2012-01-07 10:22:54 +0000 @@ -9,56 +9,55 @@ #include "RemovalPolicy.h" RemovalPolicy * createRemovalPolicy(RemovalPolicySettings * settings) STUB_RETVAL(NULL) #include "Store.h" StorePointer Store::CurrentRoot = NULL; StoreIoStats store_io_stats; bool StoreEntry::checkDeferRead(int fd) const STUB_RETVAL(false) const char *StoreEntry::getMD5Text() const STUB_RETVAL(NULL) StoreEntry::StoreEntry() STUB StoreEntry::StoreEntry(const char *url, const char *log_url) STUB StoreEntry::~StoreEntry() STUB HttpReply const *StoreEntry::getReply() const STUB_RETVAL(NULL) void StoreEntry::write(StoreIOBuffer) STUB bool StoreEntry::isAccepting() const STUB_RETVAL(false) size_t StoreEntry::bytesWanted(Range const) const STUB_RETVAL(0) void StoreEntry::complete() STUB store_client_t StoreEntry::storeClientType() const STUB_RETVAL(STORE_NON_CLIENT) char const *StoreEntry::getSerialisedMetaData() STUB_RETVAL(NULL) void StoreEntry::replaceHttpReply(HttpReply *, bool andStartWriting) STUB -bool StoreEntry::swapoutPossible() STUB_RETVAL(false) -void StoreEntry::trimMemory() STUB +bool StoreEntry::mayStartSwapOut() STUB_RETVAL(false) +void StoreEntry::trimMemory(const bool preserveSwappable) STUB void StoreEntry::abort() STUB void StoreEntry::unlink() STUB void StoreEntry::makePublic() STUB void StoreEntry::makePrivate() STUB void StoreEntry::setPublicKey() STUB void StoreEntry::setPrivateKey() STUB void StoreEntry::expireNow() STUB void StoreEntry::releaseRequest() STUB void StoreEntry::negativeCache() STUB void StoreEntry::cacheNegatively() STUB void StoreEntry::invokeHandlers() STUB void StoreEntry::purgeMem() STUB void StoreEntry::swapOut() STUB -bool StoreEntry::swapOutAble() const STUB_RETVAL(false) void StoreEntry::swapOutFileClose(int how) STUB const char *StoreEntry::url() const STUB_RETVAL(NULL) int StoreEntry::checkCachable() STUB_RETVAL(0) int StoreEntry::checkNegativeHit() const STUB_RETVAL(0) int StoreEntry::locked() const STUB_RETVAL(0) int StoreEntry::validToSend() const STUB_RETVAL(0) bool StoreEntry::memoryCachable() const STUB_RETVAL(false) void StoreEntry::createMemObject(const char *, const char *) STUB void StoreEntry::hideMemObject() STUB void StoreEntry::dump(int debug_lvl) const STUB void StoreEntry::hashDelete() STUB void StoreEntry::hashInsert(const cache_key *) STUB void StoreEntry::registerAbort(STABH * cb, void *) STUB void StoreEntry::reset() STUB void StoreEntry::setMemStatus(mem_status_t) STUB void StoreEntry::timestampsSet() STUB void StoreEntry::unregisterAbort() STUB void StoreEntry::destroyMemObject() STUB int StoreEntry::checkTooSmall() STUB_RETVAL(0) void StoreEntry::delayAwareRead(const Comm::ConnectionPointer&, char *buf, int len, AsyncCall::Pointer callback) STUB