// create a brand new store entry and initialize it with stored info
StoreEntry *e = new StoreEntry();
- e->lock_count = 0;
// XXX: We do not know the URLs yet, only the key, but we need to parse and
// store the response for the Root().get() callers to be happy because they
bool
MemStore::updateCollapsed(StoreEntry &collapsed)
{
- assert(collapsed.mem_status == IN_MEMORY);
assert(collapsed.mem_obj);
const sfileno index = collapsed.mem_obj->memCache.index;
if (anchor.complete()) {
e.store_status = STORE_OK;
e.mem_obj->object_sz = e.swap_file_sz;
+ e.setMemStatus(IN_MEMORY);
} else {
e.store_status = STORE_PENDING;
assert(e.mem_obj->object_sz < 0);
+ e.setMemStatus(NOT_IN_MEMORY);
}
- e.setMemStatus(IN_MEMORY);
assert(e.swap_status == SWAPOUT_NONE); // set in StoreEntry constructor
e.ping_status = PING_NONE;
// from StoreEntry::complete()
e.mem_obj->object_sz = e.mem_obj->endOffset();
e.store_status = STORE_OK;
+ e.setMemStatus(IN_MEMORY);
assert(e.mem_obj->object_sz >= 0);
assert(static_cast<uint64_t>(e.mem_obj->object_sz) == anchor.basics.swap_file_sz);
Store::Root().transientsCompleteWriting(e);
}
+void
+MemStore::markForUnlink(StoreEntry &e)
+{
+ assert(e.mem_obj);
+ if (e.mem_obj->memCache.index >= 0)
+ map->freeEntry(e.mem_obj->memCache.index);
+}
+
void
MemStore::unlink(StoreEntry &e)
{
- assert(e.mem_status == IN_MEMORY);
assert(e.mem_obj);
if (e.mem_obj->memCache.index >= 0) {
map->freeEntry(e.mem_obj->memCache.index);
disconnect(*e.mem_obj);
} else {
- // the entry was loaded and then disconnected from the memory cache
+ // the entry may bave been loaded and then disconnected from the cache
map->freeEntryByKey(reinterpret_cast<cache_key*>(e.key));
}
virtual void getStats(StoreInfoStats &stats) const;
virtual void stat(StoreEntry &) const;
virtual StoreSearch *search(String const url, HttpRequest *);
+ virtual void markForUnlink(StoreEntry &e);
virtual void reference(StoreEntry &);
virtual bool dereference(StoreEntry &, bool);
virtual void maintain();
fwd = theFwdState;
entry = fwd->entry;
- entry->lock();
+ entry->lock("ServerStateData");
request = fwd->request;
HTTPMSGLOCK(request);
assert(!adaptedBodySource);
#endif
- entry->unlock();
+ entry->unlock("ServerStateData");
HTTPMSGUNLOCK(request);
HTTPMSGUNLOCK(theVirginReply);
sdirno swap_dirn:7;
- unsigned short lock_count; /* Assume < 65536! */
-
mem_status_t mem_status:3;
ping_status_t ping_status:3;
virtual int64_t objectLen() const;
virtual int64_t contentLen() const;
- /** deprecated: lock() in anonymous context folowed by touch()
- * RBC 20050104 this is wrong- memory ref counting
- * is not at all equivalent to the store 'usage' concept
- * which the replacement policies should be acting upon.
- * specifically, object iteration within stores needs
- * memory ref counting to prevent race conditions,
- * but this should not influence store replacement.
- */
- void lock() { lock("somebody"); touch(); }
-
/// claim shared ownership of this entry (for use in a given context)
void lock(const char *context);
+
/// disclaim shared ownership; may remove entry from store and delete it
/// returns remaning lock level (zero for unlocked and possibly gone entry)
int unlock(const char *context = "somebody");
+
+ /// returns a local concurrent use counter, for debugging
+ int locks() const { return static_cast<int>(lock_count); }
+
/// update last reference timestamp and related Store metadata
void touch();
private:
static MemAllocator *pool;
+ unsigned short lock_count; /* Assume < 65536! */
+
#if USE_ADAPTATION
/// producer callback registered with deferProducer
AsyncCall::Pointer deferredProducer;
virtual void maintain() = 0; /* perform regular maintenance should be private and self registered ... */
+ // XXX: This method belongs to Store::Root/StoreController, but it is here
+ // to avoid casting Root() to StoreController until Root() API is fixed.
+ /// informs stores that this entry will be eventually unlinked
+ virtual void markForUnlink(StoreEntry &e) {}
+
// XXX: This method belongs to Store::Root/StoreController, but it is here
// because test cases use non-StoreController derivatives as Root
/// called when the entry is no longer needed by any transaction
StoreEntry *storeGetPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method);
/// \ingroup StoreAPI
+/// Like storeCreatePureEntry(), but also locks the entry and sets entry key.
StoreEntry *storeCreateEntry(const char *, const char *, const RequestFlags &, const HttpRequestMethod&);
+/// \ingroup StoreAPI
+/// Creates a new StoreEntry with mem_obj and sets initial flags/states.
+StoreEntry *storeCreatePureEntry(const char *storeId, const char *logUrl, const RequestFlags &, const HttpRequestMethod&);
+
/// \ingroup StoreAPI
void storeInit(void);
public:
StoreEntryStreamBuf(StoreEntry *anEntry) : theEntry(anEntry) {
-
- theEntry->lock();
+ theEntry->lock("StoreEntryStreamBuf");
theEntry->buffer();
}
~StoreEntryStreamBuf() {
- theEntry->unlock();
+ theEntry->unlock("StoreEntryStreamBuf");
}
protected:
/**
* The last time that a client requested this object.
- * Strictly speaking, this time is set whenever the StoreEntry
- * is locked (via storeLockObject()).
*/
SwappedTime lastref;
virtual void get(String const, STOREGETCLIENT, void * cbdata);
/* Store parent API */
+ virtual void markForUnlink(StoreEntry &e);
virtual void handleIdleEntry(StoreEntry &e);
virtual void transientsCompleteWriting(StoreEntry &e);
virtual void transientsAbandon(StoreEntry &e);
private:
void createOneStore(Store &aStore);
+ StoreEntry *find(const cache_key *key);
bool keepForLocalMemoryCache(const StoreEntry &e) const;
bool anchorCollapsed(StoreEntry &collapsed, bool &inSync);
bool anchorCollapsedOnDisk(StoreEntry &collapsed, bool &inSync);
*/
#include "squid.h"
+#include "CollapsedForwarding.h" /* XXX: who should broadcast and when? */
#include "base/RunnersRegistry.h"
#include "HttpReply.h"
#include "ipc/mem/Page.h"
return NULL;
sfileno index;
- if (!map->openForReading(key, index))
+ const Ipc::StoreMapAnchor *anchor = map->openForReading(key, index);
+ if (!anchor)
return NULL;
- if (StoreEntry *e = copyFromShm(index))
+ // Without a writer, either the response has been cached already or we will
+ // get stuck waiting for it to be cached (because nobody will cache it).
+ if (!anchor->writing()) {
+ debugs(20, 5, "ignoring writer-less entry " << index);
+ } else if (StoreEntry *e = copyFromShm(index)) {
return e; // keep read lock to receive updates from others
+ }
- // loading failure
+ // missing writer or loading failure
map->closeForReading(index);
return NULL;
}
const TransientsMap::Extras &extras = map->extras(index);
// create a brand new store entry and initialize it with stored info
- StoreEntry *e = storeCreateEntry(extras.url, extras.url,
+ StoreEntry *e = storeCreatePureEntry(extras.url, extras.url,
extras.reqFlags, extras.reqMethod);
- // XXX: overwriting storeCreateEntry() because we are expected to return an unlocked entry
- // TODO: move locking from storeCreateEntry to callers as a mid-term solution
- e->lock_count = 0;
assert(e->mem_obj);
e->mem_obj->method = extras.reqMethod;
e->mem_obj->xitTable.io = MemObject::ioReading;
e->mem_obj->xitTable.index = index;
- // XXX: overwriting storeCreateEntry() which calls setPrivateKey() if
- // neighbors_do_private_keys (which is true in most cases and by default).
- // This is nothing but waste of CPU cycles. Need a better API to avoid it.
e->setPublicKey();
assert(e->key);
{
assert(e.mem_obj && map);
map->freeEntry(e.mem_obj->xitTable.index); // just marks the locked entry
+ CollapsedForwarding::Broadcast(e);
// We do not unlock the entry now because the problem is most likely with
// the server resource rather than a specific cache writer, so we want to
// prevent other readers from collapsing requests for that resource.
return 0;
}
+void
+Transients::markForUnlink(StoreEntry &e)
+{
+ if (e.mem_obj && e.mem_obj->xitTable.io == MemObject::ioWriting)
+ abandon(e);
+}
+
void
Transients::disconnect(MemObject &mem_obj)
{
virtual StoreSearch *search(String const url, HttpRequest *);
virtual void reference(StoreEntry &);
virtual bool dereference(StoreEntry &, bool);
+ virtual void markForUnlink(StoreEntry &e);
virtual void maintain();
static int64_t EntryLimit();
asState->sc = storeClientListAdd(e, asState);
FwdState::fwdStart(Comm::ConnectionPointer(), e, asState->request);
} else {
-
- e->lock();
+ e->lock("Asn");
asState->sc = storeClientListAdd(e, asState);
}
ASState *asState = (ASState *)data;
debugs(53, 3, "asnStateFree: " << asState->entry->url() );
storeUnregister(asState->sc, asState->entry, asState);
- asState->entry->unlock();
+ asState->entry->unlock("Asn");
HTTPMSGUNLOCK(asState->request);
cbdataFree(asState);
}
void clientReplyContext::setReplyToStoreEntry(StoreEntry *entry)
{
- entry->lock(); // removeClientStoreReference() unlocks
+ entry->lock("clientReplyContext::setReplyToStoreEntry"); // removeClientStoreReference() unlocks
sc = storeClientListAdd(entry, this);
#if USE_DELAY_POOLS
sc->setDelayId(DelayId::DelayClient(http));
*ep = NULL;
storeUnregister(sc_tmp, e, this);
*scp = NULL;
- e->unlock();
+ e->unlock("clientReplyContext::removeStoreReference");
}
}
for (HttpRequestMethod m(Http::METHOD_NONE); m != Http::METHOD_ENUM_END; ++m) {
if (m.respMaybeCacheable()) {
if (StoreEntry *entry = storeGetPublic(url, m)) {
- debugs(88, 5, "purging " << RequestMethodStr(m) << ' ' << url);
+ debugs(88, 5, "purging " << *entry << ' ' << RequestMethodStr(m) << ' ' << url);
#if USE_HTCP
neighborsHtcpClear(entry, url, req, m, HTCP_CLR_INVALIDATION);
if (m == Http::METHOD_GET || m == Http::METHOD_HEAD) {
/* Swap in the metadata */
http->storeEntry(entry);
- http->storeEntry()->lock();
+ http->storeEntry()->lock("clientReplyContext::purgeFoundObject");
http->storeEntry()->createMemObject(storeId(), http->log_uri,
http->request->method);
}
if ((done = checkTransferDone()) != 0 || flags.complete) {
- debugs(88, 5, "clientReplyStatus: transfer is DONE");
+ debugs(88, 5, "clientReplyStatus: transfer is DONE: " << done << flags.complete);
/* Ok we're finished, but how? */
const int64_t expectedBodySize =
// now so that we can unlock two lines later (and trigger cleanup).
// Ideally, ClientHttpRequest::storeEntry() should lock/unlock, but it is
// used so inconsistently that simply adding locking there leads to bugs.
- e->lock();
+ e->lock("clientReplyContext::forgetHit");
http->storeEntry(NULL);
- e->unlock(); // may delete e (and release resources associated with it)
+ e->unlock("clientReplyContext::forgetHit"); // may delete e
}
void
/* someone found the object in the cache for us */
StoreIOBuffer localTempBuffer;
- http->storeEntry()->lock();
+ http->storeEntry()->lock("clientReplyContext::doGetMoreData");
MemObject *mem_obj = http->storeEntry()->makeMemObject();
if (!mem_obj->hasUris()) {
ClientHttpRequest::loggingEntry(StoreEntry *newEntry)
{
if (loggingEntry_)
- loggingEntry_->unlock();
+ loggingEntry_->unlock("ClientHttpRequest::loggingEntry");
loggingEntry_ = newEntry;
if (loggingEntry_)
- loggingEntry_->lock();
+ loggingEntry_->lock("ClientHttpRequest::loggingEntry");
}
/*
errorAppendEntry(e, calloutContext->error);
calloutContext->error = NULL;
getConn()->setServerBump(srvBump);
- e->unlock();
+ e->unlock("ClientHttpRequest::doCallouts+sslBumpNeeded");
} else
#endif
{
getConn()->flags.readMore = true; // resume any pipeline reads.
node = (clientStreamNode *)client_stream.tail->data;
clientStreamRead(node, this, node->readBuffer);
- e->unlock();
+ e->unlock("ClientHttpRequest::doCallouts-sslBumpNeeded");
return;
}
}
}
}
- entry->lock();
+ entry->lock("errorAppendEntry");
entry->buffer();
entry->replaceHttpReply( err->BuildHttpReply() );
entry->flush();
entry->complete();
entry->negativeCache();
entry->releaseRequest();
- entry->unlock();
+ entry->unlock("errorAppendEntry");
delete err;
}
pconnRace = raceImpossible;
start_t = squid_curtime;
serverDestinations.reserve(Config.forward_max_tries);
- e->lock();
+ e->lock("FwdState");
EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT);
}
entry->unregisterAbort();
- entry->unlock();
+ entry->unlock("FwdState");
entry = NULL;
/*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
assert(entry->ping_status != PING_WAITING);
- assert(entry->lock_count);
+ assert(entry->locked());
EBIT_SET(entry->flags, ENTRY_DISPATCHED);
// create a brand new store entry and initialize it with stored basics
StoreEntry *e = new StoreEntry();
- e->lock_count = 0;
anchorEntry(*e, filen, *slot);
e->hashInsert(key);
disconnect(e);
}
+void
+Rock::SwapDir::markForUnlink(StoreEntry &e)
+{
+ debugs(47, 5, e);
+ map->freeEntry(e.swap_filen);
+}
+
void
Rock::SwapDir::trackReferences(StoreEntry &e)
{
virtual StoreSearch *search(String const url, HttpRequest *);
virtual StoreEntry *get(const cache_key *key);
virtual void get(String const, STOREGETCLIENT, void * cbdata);
+ virtual void markForUnlink(StoreEntry &e);
virtual void disconnect(StoreEntry &e);
virtual uint64_t currentSize() const;
virtual uint64_t currentCount() const;
e->swap_filen = file_number;
e->swap_dirn = index;
e->swap_file_sz = swap_file_sz;
- e->lock_count = 0;
e->lastref = lastref;
e->timestamp = timestamp;
e->expires = expires;
FtpStateData::completedListing()
{
assert(entry);
- entry->lock();
+ entry->lock("FtpStateData");
ErrorState ferr(ERR_DIR_LISTING, Http::scOkay, request);
ferr.ftp.listing = &listing;
ferr.ftp.cwd_msg = xstrdup(cwd_message.size()? cwd_message.termedBuf() : "");
entry->replaceHttpReply( ferr.BuildHttpReply() );
EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
entry->flush();
- entry->unlock();
+ entry->unlock("FtpStateData");
}
/// \ingroup ServerProtocolFTPInternal
return;
if (gopherState->entry) {
- gopherState->entry->unlock();
+ gopherState->entry->unlock("gopherState");
}
HTTPMSGUNLOCK(gopherState->req);
gopherState = cbdataAlloc(GopherStateData);
gopherState->buf = (char *)memAllocate(MEM_4K_BUF);
- entry->lock();
+ entry->lock("gopherState");
gopherState->entry = entry;
gopherState->fwd = fwd;
Must(entry != NULL);
HTTPMSGLOCK(httpRequest);
- entry->lock();
+ entry->lock("Mgr::Forwarder");
EBIT_SET(entry->flags, ENTRY_FWD_HDR_WAIT);
closer = asyncCall(16, 5, "Mgr::Forwarder::noteCommClosed",
HTTPMSGUNLOCK(httpRequest);
entry->unregisterAbort();
- entry->unlock();
+ entry->unlock("Mgr::Forwarder");
cleanup();
}
return;
}
- if (entry->lock_count == 0) {
+ if (!entry->locked()) {
// TODO: many entries are unlocked; why is this reported at level 1?
debugs(12, DBG_IMPORTANT, "neighborsUdpAck: '" << storeKeyText(key) << "' has no locks");
neighborCountIgnored(p);
return;
}
- if (e->lock_count == 0) {
+ if (!e->locked()) {
// TODO: many entries are unlocked; why is this reported at level 1?
debugs(12, DBG_IMPORTANT, "neighborsUdpAck: '" << storeKeyText(key) << "' has no locks");
neighborCountIgnored(p);
if (psstate->entry) {
assert(psstate->entry->ping_status != PING_WAITING);
- psstate->entry->unlock();
+ psstate->entry->unlock("peerSelect");
psstate->entry = NULL;
}
#endif
if (psstate->entry)
- psstate->entry->lock();
+ psstate->entry->lock("peerSelect");
peerSelectFoo(psstate);
}
const char *uri = urlCanonical(request.getRaw());
if (e) {
entry = e;
- entry->lock();
+ entry->lock("Ssl::ServerBump");
} else
entry = storeCreateEntry(uri, uri, request->flags, request->method);
// We do not need to be a client because the error contents will be used
if (entry) {
debugs(33, 4, HERE << *entry);
storeUnregister(sc, entry, this);
- entry->unlock();
+ entry->unlock("Ssl::ServerBump");
}
cbdataReferenceDone(sslErrors);
}
mb->Printf("\t%s\n", storeEntryFlags(e));
mb->Printf("\t%s\n", describeTimestamps(e));
mb->Printf("\t%d locks, %d clients, %d refs\n",
- (int) e->lock_count,
+ (int) e->locks(),
storePendingNClients(e),
(int) e->refcount);
mb->Printf("\tSwap Dir %d, File %#08X\n",
if (UsingSmp())
storeAppendPrintf(state->sentry, "} by kid%d\n\n", KidIdentifier);
state->sentry->complete();
- state->sentry->unlock();
+ state->sentry->unlock("statObjects+isDone");
cbdataFree(state);
return;
} else if (EBIT_TEST(state->sentry->flags, ENTRY_ABORTED)) {
- state->sentry->unlock();
+ state->sentry->unlock("statObjects+aborted");
cbdataFree(state);
return;
} else if (state->sentry->checkDeferRead(-1)) {
state->sentry = sentry;
state->filter = filter;
- sentry->lock();
+ sentry->lock("statObjects");
state->theSearch = Store::Root().search(NULL, NULL);
eventAdd("statObjects", statObjects, state, 0.0, 1);
flags(0),
swap_filen(-1),
swap_dirn(-1),
- lock_count(0),
mem_status(NOT_IN_MEMORY),
ping_status(PING_NONE),
store_status(STORE_PENDING),
- swap_status(SWAPOUT_NONE)
+ swap_status(SWAPOUT_NONE),
+ lock_count(0)
{
debugs(20, 3, HERE << "new StoreEntry " << this);
}
debugs(20, 3, "StoreEntry::setReleaseFlag: '" << getMD5Text() << "'");
EBIT_SET(flags, RELEASE_REQUEST);
+
+ Store::Root().markForUnlink(*this);
}
void
pe->complete();
- pe->unlock();
+ pe->unlock("StoreEntry::setPublicKey+Vary");
}
newkey = storeKeyPublicByRequest(mem_obj->request);
}
StoreEntry *
-storeCreateEntry(const char *url, const char *log_url, const RequestFlags &flags, const HttpRequestMethod& method)
+storeCreatePureEntry(const char *url, const char *log_url, const RequestFlags &flags, const HttpRequestMethod& method)
{
StoreEntry *e = NULL;
debugs(20, 3, "storeCreateEntry: '" << url << "'");
e = new StoreEntry();
- e->lock_count = 1; /* Note lock here w/o calling storeLock() */
e->makeMemObject();
e->mem_obj->setUris(url, log_url, method);
- if (neighbors_do_private_keys || !flags.hierarchical)
- e->setPrivateKey();
- else
- e->setPublicKey();
-
if (flags.cachable) {
EBIT_SET(e->flags, ENTRY_CACHABLE);
EBIT_CLR(e->flags, RELEASE_REQUEST);
}
e->store_status = STORE_PENDING;
- e->setMemStatus(NOT_IN_MEMORY);
e->refcount = 0;
e->lastref = squid_curtime;
e->timestamp = -1; /* set in StoreEntry::timestampsSet() */
return e;
}
+StoreEntry *
+storeCreateEntry(const char *url, const char *logUrl, const RequestFlags &flags, const HttpRequestMethod& method)
+{
+ StoreEntry *e = storeCreatePureEntry(url, logUrl, flags, method);
+ e->lock("storeCreateEntry");
+
+ if (neighbors_do_private_keys || !flags.hierarchical)
+ e->setPrivateKey();
+ else
+ e->setPublicKey();
+
+ return e;
+}
+
/* Mark object as expired */
void
StoreEntry::expireNow()
assert(mem_obj != NULL);
debugs(20, 6, "storeAbort: " << getMD5Text());
- lock(); /* lock while aborting */
+ lock("StoreEntry::abort"); /* lock while aborting */
negativeCache();
releaseRequest();
// abort swap out, invalidating what was created so far (release follows)
swapOutFileClose(StoreIOState::writerGone);
- unlock(); /* unlock */
+ unlock("StoreEntry::abort"); /* unlock */
}
/**
StoreEntry::release()
{
PROF_start(storeRelease);
- debugs(20, 3, "storeRelease: Releasing: '" << getMD5Text() << "'");
+ debugs(20, 3, "releasing " << *this << ' ' << getMD5Text());
/* If, for any reason we can't discard this object because of an
* outstanding request, mark it for pending release */
* Fake a call to StoreEntry->lock() When rebuilding is done,
* we'll just call StoreEntry->unlock() on these.
*/
- ++lock_count;
+ lock("StoreEntry::release+rebuilding");
setReleaseFlag();
LateReleaseStack.push_back(this);
} else {
return;
}
- e->unlock();
+ e->unlock("storeLateRelease");
++n;
}
if (lock_count)
return 1;
- if (swap_status == SWAPOUT_WRITING)
- return 1;
-
- if (store_status == STORE_PENDING)
- return 1;
-
/*
- * SPECIAL, PUBLIC entries should be "locked"
+ * SPECIAL, PUBLIC entries should be "locked";
+ * XXX: Their owner should lock them then instead of relying on this hack.
*/
if (EBIT_TEST(flags, ENTRY_SPECIAL))
if (!EBIT_TEST(flags, KEY_PRIVATE))
if (e.mem_obj && e.mem_obj->smpCollapsed)
os << 'O';
- return os << '/' << &e << '*' << e.lock_count;
+ return os << '/' << &e << '*' << e.locks();
}
/* NullStoreEntry */
delete sc;
- assert(e->lock_count > 0);
+ assert(e->locked());
if (mem->nclients == 0)
CheckQuickAbort(e);
StoreEntry *
StoreController::get(const cache_key *key)
+{
+ if (StoreEntry *e = find(key)) {
+ // this is not very precise: some get()s are not initiated by clients
+ e->touch();
+ return e;
+ }
+ return NULL;
+}
+
+/// Internal method to implements the guts of the Store::get() API:
+/// returns an in-transit or cached object with a given key, if any.
+StoreEntry *
+StoreController::find(const cache_key *key)
{
if (StoreEntry *e = swapDir->get(key)) {
// TODO: ignore and maybe handleIdleEntry() unlocked intransit entries
return false;
}
+void StoreController::markForUnlink(StoreEntry &e)
+{
+ if (transients && e.mem_obj && e.mem_obj->xitTable.index >= 0)
+ transients->markForUnlink(e);
+ if (memStore && e.mem_obj && e.mem_obj->memCache.index >= 0)
+ memStore->markForUnlink(e);
+ if (e.swap_filen >= 0)
+ e.store()->markForUnlink(e);
+}
+
// move this into [non-shared] memory cache class when we have one
/// whether e should be kept in local RAM for possible future caching
bool
void
StoreController::memoryUnlink(StoreEntry &e)
{
- if (e.mem_status != IN_MEMORY)
- return;
-
if (memStore)
memStore->unlink(e);
else // TODO: move into [non-shared] memory cache class when we have one
return;
}
+ // this must be done before the abandoned() check because we may be looking
+ // at an entry we are writing while abandoned() requires a reading lock.
+ if (!collapsed->mem_obj->smpCollapsed) {
+ // this happens, e.g., when we tried collapsing but rejected the hit
+ // or a stale notification was received (and we are now the writer)
+ debugs(20, 7, "not SMP-syncing not-SMP-collapsed " << *collapsed);
+ return;
+ }
+
assert(transients);
if (transients->abandoned(*collapsed)) {
debugs(20, 3, "aborting abandoned " << *collapsed);
return;
}
- if (!collapsed->mem_obj->smpCollapsed) {
- // this happens, e.g., when we tried collapsing but rejected the hit
- debugs(20, 7, "not SMP-syncing not-SMP-collapsed " << *collapsed);
- return;
- }
-
debugs(20, 7, "syncing " << *collapsed);
bool found = false;
bool inSync = false;
- if (memStore && collapsed->mem_status == IN_MEMORY) {
+ if (memStore && collapsed->mem_obj->memCache.io == MemObject::ioDone) {
+ found = true;
+ inSync = true;
+ debugs(20, 7, "fully mem-loaded " << *collapsed);
+ } else if (memStore && collapsed->mem_obj->memCache.index >= 0) {
found = true;
inSync = memStore->updateCollapsed(*collapsed);
} else if (collapsed->swap_filen >= 0) {
// For some stores, get() creates/unpacks a store entry. Signal
// such stores that we will no longer use the get() result:
- e->lock();
- e->unlock();
+ e->lock("storeRebuildKeepEntry");
+ e->unlock("storeRebuildKeepEntry");
return false;
} else {
/* Don't lock until after create, or the replacement
* code might get confused */
- e->lock();
+ e->lock("storeSwapOutStart");
/* Pick up the file number if it was assigned immediately */
e->swap_filen = mem->swapout.sio->swap_filen;
debugs(20, 3, "storeSwapOutFileClosed: " << __FILE__ << ":" << __LINE__);
mem->swapout.sio = NULL;
- e->unlock();
+ e->unlock("storeSwapOutFileClosed");
}
bool
request = r;
HTTPMSGLOCK(request);
- entry->lock();
+ entry->lock("UrnState::start");
setUriResFromRequest(r);
if (urlres_r == NULL)
FwdState::fwdStart(Comm::ConnectionPointer(), urlres_e, urlres_r);
} else {
- urlres_e->lock();
+ urlres_e->lock("UrnState::created");
sc = storeClientListAdd(urlres_e, this);
}
static void
urnHandleReplyError(UrnState *urnState, StoreEntry *urlres_e)
{
- urlres_e->unlock();
- urnState->entry->unlock();
+ urlres_e->unlock("urnHandleReplyError+res");
+ urnState->entry->unlock("urnHandleReplyError+prime");
HTTPMSGUNLOCK(urnState->request);
HTTPMSGUNLOCK(urnState->urlres_r);
delete urnState;
p->fwd = fwd;
p->dataWritten = false;
- p->entry->lock();
+ p->entry->lock("whoisStart");
comm_add_close_handler(fwd->serverConnection()->fd, whoisClose, p);
l = p->request->urlpath.size() + 3;
{
WhoisState *p = (WhoisState *)params.data;
debugs(75, 3, "whoisClose: FD " << params.fd);
- p->entry->unlock();
+ p->entry->unlock("whoisClose");
cbdataFree(p);
}