Bug 479328 and bug 481753 - Ensure imgRequest always knows when it's in the cache, and doesn't try to do cache manipulation when it isn't. Also, fix redirect handling to not simply invalidate the cache entry. r=vlad, sr=bzbarsky

This commit is contained in:
Joe Drew 2009-03-17 17:07:16 -04:00
parent 2a9c7ac66c
commit cc15c830d3
5 changed files with 75 additions and 46 deletions

View File

@ -128,8 +128,6 @@ static PRBool NewRequestAndEntry(nsIURI *uri, imgRequest **request, imgCacheEntr
NS_ADDREF(*request); NS_ADDREF(*request);
NS_ADDREF(*entry); NS_ADDREF(*entry);
imgLoader::SetHasNoProxies(uri, *entry);
return PR_TRUE; return PR_TRUE;
} }
@ -267,8 +265,6 @@ void imgCacheEntry::TouchWithSize(PRInt32 diff)
// Don't update the cache if we've been removed from it or it doesn't care // Don't update the cache if we've been removed from it or it doesn't care
// about our size or usage. // about our size or usage.
if (!Evicted() && HasNoProxies()) { if (!Evicted() && HasNoProxies()) {
// We can't use mKeyURI here, because we're not guaranteed to be updated if
// the request has no observers and has thus dropped its reference to us.
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
mRequest->GetKeyURI(getter_AddRefs(uri)); mRequest->GetKeyURI(getter_AddRefs(uri));
imgLoader::CacheEntriesChanged(uri, diff); imgLoader::CacheEntriesChanged(uri, diff);
@ -285,8 +281,6 @@ void imgCacheEntry::Touch(PRBool updateTime /* = PR_TRUE */)
// Don't update the cache if we've been removed from it or it doesn't care // Don't update the cache if we've been removed from it or it doesn't care
// about our size or usage. // about our size or usage.
if (!Evicted() && HasNoProxies()) { if (!Evicted() && HasNoProxies()) {
// We can't use mKeyURI here, because we're not guaranteed to be updated if
// the request has no observers and has thus dropped its reference to us.
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
mRequest->GetKeyURI(getter_AddRefs(uri)); mRequest->GetKeyURI(getter_AddRefs(uri));
imgLoader::CacheEntriesChanged(uri); imgLoader::CacheEntriesChanged(uri);
@ -711,6 +705,27 @@ PRBool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
if (!cache.Put(spec, entry)) if (!cache.Put(spec, entry))
return PR_FALSE; return PR_FALSE;
// We can be called to resurrect an evicted entry.
if (entry->Evicted())
entry->SetEvicted(PR_FALSE);
// If we're resurrecting an entry with no proxies, put it back in the
// tracker and queue.
if (entry->HasNoProxies()) {
nsresult addrv = NS_OK;
if (gCacheTracker)
addrv = gCacheTracker->AddObject(entry);
if (NS_SUCCEEDED(addrv)) {
imgCacheQueue &queue = GetCacheQueue(key);
queue.Push(entry);
}
}
nsRefPtr<imgRequest> request(getter_AddRefs(entry->GetRequest()));
request->SetIsInCache(PR_TRUE);
return PR_TRUE; return PR_TRUE;
} }
@ -1039,6 +1054,9 @@ PRBool imgLoader::RemoveFromCache(nsIURI *aKey)
entry->SetEvicted(PR_TRUE); entry->SetEvicted(PR_TRUE);
nsRefPtr<imgRequest> request(getter_AddRefs(entry->GetRequest()));
request->SetIsInCache(PR_FALSE);
return PR_TRUE; return PR_TRUE;
} }
else else
@ -1070,6 +1088,7 @@ PRBool imgLoader::RemoveFromCache(imgCacheEntry *entry)
} }
entry->SetEvicted(PR_TRUE); entry->SetEvicted(PR_TRUE);
request->SetIsInCache(PR_FALSE);
return PR_TRUE; return PR_TRUE;
} }
@ -1269,8 +1288,7 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
} }
// Try to add the new request into the cache. // Try to add the new request into the cache.
if (!PutIntoCache(aURI, entry)) PutIntoCache(aURI, entry);
request->SetCacheable(PR_FALSE);
// If we did get a cache hit, use it. // If we did get a cache hit, use it.
} else { } else {
@ -1406,8 +1424,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
NS_RELEASE(pl); NS_RELEASE(pl);
// Try to add the new request into the cache. // Try to add the new request into the cache.
if (!PutIntoCache(uri, entry)) PutIntoCache(uri, entry);
request->SetCacheable(PR_FALSE);
} }
// XXX: It looks like the wrong load flags are being passed in... // XXX: It looks like the wrong load flags are being passed in...
@ -1686,8 +1703,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
// Try to add the new request into the cache. Note that the entry must be in // Try to add the new request into the cache. Note that the entry must be in
// the cache before the proxies' ownership changes, because adding a proxy // the cache before the proxies' ownership changes, because adding a proxy
// changes the caching behaviour for imgRequests. // changes the caching behaviour for imgRequests.
if (!sImgLoader.PutIntoCache(uri, entry)) sImgLoader.PutIntoCache(uri, entry);
request->SetCacheable(PR_FALSE);
PRUint32 count = mProxies.Count(); PRUint32 count = mProxies.Count();
for (PRInt32 i = count-1; i>=0; i--) { for (PRInt32 i = count-1; i>=0; i--) {

View File

@ -168,7 +168,6 @@ private: // data
NS_DECL_OWNINGTHREAD NS_DECL_OWNINGTHREAD
nsRefPtr<imgRequest> mRequest; nsRefPtr<imgRequest> mRequest;
nsCOMPtr<nsIURI> mKeyURI;
PRUint32 mDataSize; PRUint32 mDataSize;
PRInt32 mTouchedTime; PRInt32 mTouchedTime;
PRInt32 mExpiryTime; PRInt32 mExpiryTime;

View File

@ -85,7 +85,7 @@ imgRequest::imgRequest() :
mImageStatus(imgIRequest::STATUS_NONE), mState(0), mCacheId(0), mImageStatus(imgIRequest::STATUS_NONE), mState(0), mCacheId(0),
mValidator(nsnull), mImageSniffers("image-sniffing-services"), mValidator(nsnull), mImageSniffers("image-sniffing-services"),
mIsMultiPartChannel(PR_FALSE), mLoading(PR_FALSE), mProcessing(PR_FALSE), mIsMultiPartChannel(PR_FALSE), mLoading(PR_FALSE), mProcessing(PR_FALSE),
mHadLastPart(PR_FALSE), mGotData(PR_FALSE), mIsCacheable(PR_TRUE) mHadLastPart(PR_FALSE), mGotData(PR_FALSE), mIsInCache(PR_FALSE)
{ {
/* member initializers and constructor code */ /* member initializers and constructor code */
} }
@ -419,14 +419,15 @@ void imgRequest::RemoveFromCache()
{ {
LOG_SCOPE(gImgLog, "imgRequest::RemoveFromCache"); LOG_SCOPE(gImgLog, "imgRequest::RemoveFromCache");
if (mIsCacheable) { if (mIsInCache) {
// mCacheEntry is nulled out when we have no more observers.
if (mCacheEntry) if (mCacheEntry)
imgLoader::RemoveFromCache(mCacheEntry); imgLoader::RemoveFromCache(mCacheEntry);
else else
imgLoader::RemoveFromCache(mKeyURI); imgLoader::RemoveFromCache(mKeyURI);
mCacheEntry = nsnull;
} }
mCacheEntry = nsnull;
} }
PRBool imgRequest::HaveProxyWithObserver(imgRequestProxy* aProxyToIgnore) const PRBool imgRequest::HaveProxyWithObserver(imgRequestProxy* aProxyToIgnore) const
@ -473,13 +474,10 @@ void imgRequest::AdjustPriority(imgRequestProxy *proxy, PRInt32 delta)
p->AdjustPriority(delta); p->AdjustPriority(delta);
} }
void imgRequest::SetCacheable(PRBool cacheable) void imgRequest::SetIsInCache(PRBool incache)
{ {
LOG_FUNC_WITH_PARAM(gImgLog, "imgRequest::SetIsCacheable", "cacheable", cacheable); LOG_FUNC_WITH_PARAM(gImgLog, "imgRequest::SetIsCacheable", "incache", incache);
mIsCacheable = cacheable; mIsInCache = incache;
if (!mIsCacheable)
mCacheEntry = nsnull;
} }
/** imgILoad methods **/ /** imgILoad methods **/
@ -1079,29 +1077,42 @@ imgRequest::OnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel, PR
return rv; return rv;
} }
#if defined(PR_LOGGING)
nsCAutoString spec;
mKeyURI->GetSpec(spec);
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect", "old", spec.get());
#endif
RemoveFromCache();
mChannel = newChannel; mChannel = newChannel;
newChannel->GetOriginalURI(getter_AddRefs(mKeyURI)); // Don't make any cache changes if we're going to point to the same thing. We
// compare specs and not just URIs here because URIs that compare as
// .Equals() might have different hashes.
nsCAutoString oldspec;
if (mKeyURI)
mKeyURI->GetSpec(oldspec);
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect", "old", oldspec.get());
#if defined(PR_LOGGING) nsCOMPtr<nsIURI> newURI;
mKeyURI->GetSpec(spec); newChannel->GetOriginalURI(getter_AddRefs(newURI));
nsCAutoString newspec;
if (newURI)
newURI->GetSpec(newspec);
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect", "new", newspec.get());
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect", "new", spec.get()); if (oldspec != newspec) {
#endif if (mIsInCache) {
// Remove the cache entry from the cache, but don't null out mCacheEntry
// (as imgRequest::RemoveFromCache() does), because we need it to put
// ourselves back in the cache.
if (mCacheEntry)
imgLoader::RemoveFromCache(mCacheEntry);
else
imgLoader::RemoveFromCache(mKeyURI);
}
if (mIsCacheable) { mKeyURI = newURI;
// If we don't still have a cache entry, we don't want to refresh the cache.
if (mKeyURI && mCacheEntry) if (mIsInCache) {
imgLoader::PutIntoCache(mKeyURI, mCacheEntry); // If we don't still have a URI or cache entry, we don't want to put
// ourselves back into the cache.
if (mKeyURI && mCacheEntry)
imgLoader::PutIntoCache(mKeyURI, mCacheEntry);
}
} }
return rv; return rv;

View File

@ -164,10 +164,10 @@ private:
// Return whether we've seen some data at this point // Return whether we've seen some data at this point
PRBool HasTransferredData() const { return mGotData; } PRBool HasTransferredData() const { return mGotData; }
// Set whether this request is cacheable. By default, all requests are // Set whether this request is stored in the cache. If it isn't, regardless
// cacheable, but they might not be if there is already a request with this // of whether this request has a non-null mCacheEntry, this imgRequest won't
// key URI in the cache. // try to update or modify the image cache.
void SetCacheable(PRBool cacheable); void SetIsInCache(PRBool cacheable);
public: public:
NS_DECL_IMGILOAD NS_DECL_IMGILOAD
@ -213,7 +213,7 @@ private:
PRPackedBool mProcessing : 1; PRPackedBool mProcessing : 1;
PRPackedBool mHadLastPart : 1; PRPackedBool mHadLastPart : 1;
PRPackedBool mGotData : 1; PRPackedBool mGotData : 1;
PRPackedBool mIsCacheable : 1; PRPackedBool mIsInCache : 1;
}; };
#endif #endif

View File

@ -467,6 +467,9 @@ Are you executing $objdir/_tests/testing/mochitest/runtests.py?"""
testURL += "?" + "&".join(urlOpts) testURL += "?" + "&".join(urlOpts)
browserEnv["XPCOM_MEM_BLOAT_LOG"] = LEAK_REPORT_FILE browserEnv["XPCOM_MEM_BLOAT_LOG"] = LEAK_REPORT_FILE
if options.a11y:
browserEnv["XPCOM_MEM_REFCNT_LOG"] = PROFILE_DIRECTORY + "/refcnt.log"
browserEnv["XPCOM_MEM_LOG_CLASSES"] = "imgRequest,imgCacheEntry"
if options.fatalAssertions: if options.fatalAssertions:
browserEnv["XPCOM_DEBUG_BREAK"] = "stack-and-abort" browserEnv["XPCOM_DEBUG_BREAK"] = "stack-and-abort"