Merge the backout of bug 466586

This commit is contained in:
Joe Drew 2009-02-13 18:26:05 -05:00
Родитель c994c463b1 1aa5533d04
Коммит 6c852312d0
4 изменённых файлов: 49 добавлений и 316 удалений

Просмотреть файл

@ -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;
} }
@ -249,26 +247,16 @@ imgCacheEntry::imgCacheEntry(imgRequest *request, PRBool mustValidateIfExpired /
mTouchedTime(SecondsFromPRTime(PR_Now())), mTouchedTime(SecondsFromPRTime(PR_Now())),
mExpiryTime(0), mExpiryTime(0),
mMustValidateIfExpired(mustValidateIfExpired), mMustValidateIfExpired(mustValidateIfExpired),
mEvicted(PR_FALSE), mEvicted(PR_FALSE)
mHasNoProxies(PR_TRUE)
{} {}
imgCacheEntry::~imgCacheEntry()
{
LOG_FUNC(gImgLog, "imgCacheEntry::~imgCacheEntry()");
}
void imgCacheEntry::TouchWithSize(PRInt32 diff) void imgCacheEntry::TouchWithSize(PRInt32 diff)
{ {
LOG_SCOPE(gImgLog, "imgCacheEntry::TouchWithSize"); LOG_SCOPE(gImgLog, "imgCacheEntry::TouchWithSize");
mTouchedTime = SecondsFromPRTime(PR_Now()); mTouchedTime = SecondsFromPRTime(PR_Now());
// Don't update the cache if we've been removed from it or it doesn't care if (!Evicted()) {
// about our size or usage.
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);
@ -282,34 +270,13 @@ void imgCacheEntry::Touch(PRBool updateTime /* = PR_TRUE */)
if (updateTime) if (updateTime)
mTouchedTime = SecondsFromPRTime(PR_Now()); mTouchedTime = SecondsFromPRTime(PR_Now());
// Don't update the cache if we've been removed from it or it doesn't care if (!Evicted()) {
// about our size or usage.
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);
} }
} }
void imgCacheEntry::SetHasNoProxies(PRBool hasNoProxies)
{
#if defined(PR_LOGGING)
nsCOMPtr<nsIURI> uri;
mRequest->GetKeyURI(getter_AddRefs(uri));
nsCAutoString spec;
if (uri)
uri->GetSpec(spec);
if (hasNoProxies)
LOG_FUNC_WITH_PARAM(gImgLog, "imgCacheEntry::SetHasNoProxies true", "uri", spec.get());
else
LOG_FUNC_WITH_PARAM(gImgLog, "imgCacheEntry::SetHasNoProxies false", "uri", spec.get());
#endif
mHasNoProxies = hasNoProxies;
}
imgCacheQueue::imgCacheQueue() imgCacheQueue::imgCacheQueue()
: mDirty(PR_FALSE), : mDirty(PR_FALSE),
mSize(0) mSize(0)
@ -482,17 +449,6 @@ imgCacheExpirationTracker::imgCacheExpirationTracker()
void imgCacheExpirationTracker::NotifyExpired(imgCacheEntry *entry) void imgCacheExpirationTracker::NotifyExpired(imgCacheEntry *entry)
{ {
#if defined(PR_LOGGING)
nsRefPtr<imgRequest> req(entry->GetRequest());
if (req) {
nsCOMPtr<nsIURI> uri;
req->GetKeyURI(getter_AddRefs(uri));
nsCAutoString spec;
uri->GetSpec(spec);
LOG_FUNC_WITH_PARAM(gImgLog, "imgCacheExpirationTracker::NotifyExpired", "entry", spec.get());
}
#endif
// We can be called multiple times on the same entry. Don't do work multiple // We can be called multiple times on the same entry. Don't do work multiple
// times. // times.
if (!entry->Evicted()) if (!entry->Evicted())
@ -533,13 +489,13 @@ void imgLoader::VerifyCacheSizes()
if (!gCacheTracker) if (!gCacheTracker)
return; return;
PRUint32 cachesize = sCache.Count() + sChromeCache.Count();
PRUint32 queuesize = sCacheQueue.GetNumElements() + sChromeCacheQueue.GetNumElements(); PRUint32 queuesize = sCacheQueue.GetNumElements() + sChromeCacheQueue.GetNumElements();
PRUint32 cachesize = sCache.Count() + sChromeCache.Count();
PRUint32 trackersize = 0; PRUint32 trackersize = 0;
for (nsExpirationTracker<imgCacheEntry, 3>::Iterator it(gCacheTracker); it.Next(); ) for (nsExpirationTracker<imgCacheEntry, 3>::Iterator it(gCacheTracker); it.Next(); )
trackersize++; trackersize++;
NS_ABORT_IF_FALSE(queuesize == trackersize, "Queue and tracker sizes out of sync!"); NS_ASSERTION(queuesize == cachesize, "Queue and cache sizes out of sync!");
NS_ABORT_IF_FALSE(queuesize <= cachesize, "Queue has more elements than cache!"); NS_ASSERTION(queuesize == trackersize, "Queue and tracker sizes out of sync!");
} }
imgLoader::imgCacheTable & imgLoader::GetCache(nsIURI *aURI) imgLoader::imgCacheTable & imgLoader::GetCache(nsIURI *aURI)
@ -637,9 +593,8 @@ NS_IMETHODIMP imgLoader::FindEntryProperties(nsIURI *uri, nsIProperties **_retva
*_retval = nsnull; *_retval = nsnull;
if (cache.Get(spec, getter_AddRefs(entry)) && entry) { if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
if (gCacheTracker && entry->HasNoProxies()) if (gCacheTracker)
gCacheTracker->MarkUsed(entry); gCacheTracker->MarkUsed(entry);
nsRefPtr<imgRequest> request = getter_AddRefs(entry->GetRequest()); nsRefPtr<imgRequest> request = getter_AddRefs(entry->GetRequest());
if (request) { if (request) {
*_retval = request->Properties(); *_retval = request->Properties();
@ -671,13 +626,13 @@ nsresult imgLoader::ClearImageCache()
PRBool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry) PRBool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
{ {
LOG_STATIC_FUNC(gImgLog, "imgLoader::PutIntoCache");
imgCacheTable &cache = GetCache(key); imgCacheTable &cache = GetCache(key);
nsCAutoString spec; nsCAutoString spec;
key->GetSpec(spec); key->GetSpec(spec);
LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::PutIntoCache", "uri", spec.get());
// Check to see if this request already exists in the cache and is being // Check to see if this request already exists in the cache and is being
// loaded on a different thread. If so, don't allow this entry to be added to // loaded on a different thread. If so, don't allow this entry to be added to
// the cache. // the cache.
@ -705,66 +660,17 @@ PRBool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
if (!cache.Put(spec, entry)) if (!cache.Put(spec, entry))
return PR_FALSE; return PR_FALSE;
return PR_TRUE;
}
PRBool imgLoader::SetHasNoProxies(nsIURI *key, imgCacheEntry *entry)
{
#if defined(PR_LOGGING)
nsCAutoString spec;
key->GetSpec(spec);
LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::SetHasNoProxies", "uri", spec.get());
#endif
if (entry->Evicted())
return PR_FALSE;
imgCacheQueue &queue = GetCacheQueue(key); imgCacheQueue &queue = GetCacheQueue(key);
queue.Push(entry);
nsresult addrv = NS_OK;
if (gCacheTracker) if (gCacheTracker)
addrv = gCacheTracker->AddObject(entry); gCacheTracker->AddObject(entry);
if (NS_SUCCEEDED(addrv)) {
queue.Push(entry);
entry->SetHasNoProxies(PR_TRUE);
}
imgCacheTable &cache = GetCache(key);
CheckCacheLimits(cache, queue); CheckCacheLimits(cache, queue);
return PR_TRUE; return PR_TRUE;
} }
PRBool imgLoader::SetHasProxies(nsIURI *key)
{
VerifyCacheSizes();
imgCacheTable &cache = GetCache(key);
nsCAutoString spec;
key->GetSpec(spec);
LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::SetHasProxies", "uri", spec.get());
nsRefPtr<imgCacheEntry> entry;
if (cache.Get(spec, getter_AddRefs(entry)) && entry && entry->HasNoProxies()) {
imgCacheQueue &queue = GetCacheQueue(key);
queue.Remove(entry);
if (gCacheTracker)
gCacheTracker->RemoveObject(entry);
entry->SetHasNoProxies(PR_FALSE);
return PR_TRUE;
}
return PR_FALSE;
}
void imgLoader::CacheEntriesChanged(nsIURI *uri, PRInt32 sizediff /* = 0 */) void imgLoader::CacheEntriesChanged(nsIURI *uri, PRInt32 sizediff /* = 0 */)
{ {
imgCacheQueue &queue = GetCacheQueue(uri); imgCacheQueue &queue = GetCacheQueue(uri);
@ -785,17 +691,6 @@ void imgLoader::CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue)
NS_ASSERTION(entry, "imgLoader::CheckCacheLimits -- NULL entry pointer"); NS_ASSERTION(entry, "imgLoader::CheckCacheLimits -- NULL entry pointer");
#if defined(PR_LOGGING)
nsRefPtr<imgRequest> req(entry->GetRequest());
if (req) {
nsCOMPtr<nsIURI> uri;
req->GetKeyURI(getter_AddRefs(uri));
nsCAutoString spec;
uri->GetSpec(spec);
LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::CheckCacheLimits", "entry", spec.get());
}
#endif
if (entry) if (entry)
RemoveFromCache(entry); RemoveFromCache(entry);
} }
@ -818,8 +713,6 @@ PRBool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
nsresult rv; nsresult rv;
// If we're currently in the middle of validating this request, just hand
// back a proxy to it; the required work will be done for us.
if (request->mValidator) { if (request->mValidator) {
rv = CreateNewProxyForRequest(request, aLoadGroup, aObserver, rv = CreateNewProxyForRequest(request, aLoadGroup, aObserver,
aLoadFlags, aExistingRequest, aLoadFlags, aExistingRequest,
@ -1008,6 +901,7 @@ PRBool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
PRBool imgLoader::RemoveFromCache(nsIURI *aKey) PRBool imgLoader::RemoveFromCache(nsIURI *aKey)
{ {
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache uri");
if (!aKey) return PR_FALSE; if (!aKey) return PR_FALSE;
imgCacheTable &cache = GetCache(aKey); imgCacheTable &cache = GetCache(aKey);
@ -1016,23 +910,13 @@ PRBool imgLoader::RemoveFromCache(nsIURI *aKey)
nsCAutoString spec; nsCAutoString spec;
aKey->GetSpec(spec); aKey->GetSpec(spec);
LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::RemoveFromCache", "uri", spec.get());
nsRefPtr<imgCacheEntry> entry; nsRefPtr<imgCacheEntry> entry;
if (cache.Get(spec, getter_AddRefs(entry)) && entry) { if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
if (gCacheTracker)
gCacheTracker->RemoveObject(entry);
cache.Remove(spec); cache.Remove(spec);
queue.Remove(entry);
NS_ABORT_IF_FALSE(!entry->Evicted(), "Evicting an already-evicted cache entry!");
// Entries with no proxies are in the tracker.
if (entry->HasNoProxies()) {
if (gCacheTracker)
gCacheTracker->RemoveObject(entry);
queue.Remove(entry);
}
entry->SetEvicted(PR_TRUE); entry->SetEvicted(PR_TRUE);
return PR_TRUE; return PR_TRUE;
} }
else else
@ -1042,46 +926,15 @@ PRBool imgLoader::RemoveFromCache(nsIURI *aKey)
PRBool imgLoader::RemoveFromCache(imgCacheEntry *entry) PRBool imgLoader::RemoveFromCache(imgCacheEntry *entry)
{ {
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache entry"); LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache entry");
PRBool ret = PR_FALSE;
nsRefPtr<imgRequest> request(getter_AddRefs(entry->GetRequest())); nsRefPtr<imgRequest> request(getter_AddRefs(entry->GetRequest()));
if (request) { if (request) {
nsCOMPtr<nsIURI> key; nsCOMPtr<nsIURI> key;
if (NS_SUCCEEDED(request->GetKeyURI(getter_AddRefs(key))) && key) { if (NS_SUCCEEDED(request->GetKeyURI(getter_AddRefs(key))) && key)
imgCacheTable &cache = GetCache(key); ret = RemoveFromCache(key);
imgCacheQueue &queue = GetCacheQueue(key);
nsCAutoString spec;
key->GetSpec(spec);
LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::RemoveFromCache", "entry's uri", spec.get());
cache.Remove(spec);
if (entry->HasNoProxies()) {
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache removing from tracker");
if (gCacheTracker)
gCacheTracker->RemoveObject(entry);
queue.Remove(entry);
}
entry->SetEvicted(PR_TRUE);
return PR_TRUE;
}
} }
return PR_FALSE; return ret;
}
static PLDHashOperator EnumEvictEntries(const nsACString&,
nsRefPtr<imgCacheEntry> &aData,
void *data)
{
nsTArray<nsRefPtr<imgCacheEntry> > *entries =
reinterpret_cast<nsTArray<nsRefPtr<imgCacheEntry> > *>(data);
entries->AppendElement(aData);
return PL_DHASH_NEXT;
} }
nsresult imgLoader::EvictEntries(imgCacheTable &aCacheToClear, imgCacheQueue &aQueueToClear) nsresult imgLoader::EvictEntries(imgCacheTable &aCacheToClear, imgCacheQueue &aQueueToClear)
@ -1091,9 +944,10 @@ nsresult imgLoader::EvictEntries(imgCacheTable &aCacheToClear, imgCacheQueue &aQ
// We have to make a temporary, since RemoveFromCache removes the element // We have to make a temporary, since RemoveFromCache removes the element
// from the queue, invalidating iterators. // from the queue, invalidating iterators.
nsTArray<nsRefPtr<imgCacheEntry> > entries; nsTArray<nsRefPtr<imgCacheEntry> > entries;
aCacheToClear.Enumerate(EnumEvictEntries, &entries); for (imgCacheQueue::iterator it = aQueueToClear.begin(); it != aQueueToClear.end(); ++it)
entries.AppendElement(*it);
for (PRUint32 i = 0; i < entries.Length(); ++i)
for (PRUint32 i = 0; i < entries.Length(); ++i)
if (!RemoveFromCache(entries[i])) if (!RemoveFromCache(entries[i]))
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -1184,22 +1038,14 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
aURI->GetSpec(spec); aURI->GetSpec(spec);
if (cache.Get(spec, getter_AddRefs(entry)) && entry) { if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
if (gCacheTracker)
gCacheTracker->MarkUsed(entry);
if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI, aLoadGroup, aObserver, aCX, if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI, aLoadGroup, aObserver, aCX,
requestFlags, PR_TRUE, aRequest, _retval)) { requestFlags, PR_TRUE, aRequest, _retval)) {
request = getter_AddRefs(entry->GetRequest()); request = getter_AddRefs(entry->GetRequest());
// If this entry has no proxies, its request has no reference to the entry.
if (entry->HasNoProxies()) {
LOG_FUNC_WITH_PARAM(gImgLog, "imgLoader::LoadImage() adding proxyless entry", "uri", spec.get());
NS_ABORT_IF_FALSE(!request->HasCacheEntry(), "Proxyless entry's request has cache entry!");
request->SetCacheEntry(entry);
if (gCacheTracker)
gCacheTracker->MarkUsed(entry);
}
entry->Touch(); entry->Touch();
#ifdef DEBUG_joe #ifdef DEBUG_joe
printf("CACHEGET: %d %s %d\n", time(NULL), spec.get(), entry->GetDataSize()); printf("CACHEGET: %d %s %d\n", time(NULL), spec.get(), entry->GetDataSize());
#endif #endif
@ -1327,6 +1173,9 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
uri->GetSpec(spec); uri->GetSpec(spec);
if (cache.Get(spec, getter_AddRefs(entry)) && entry) { if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
if (gCacheTracker)
gCacheTracker->MarkUsed(entry);
// We don't want to kick off another network load. So we ask // We don't want to kick off another network load. So we ask
// ValidateEntry to only do validation without creating a new proxy. If // ValidateEntry to only do validation without creating a new proxy. If
// it says that the entry isn't valid any more, we'll only use the entry // it says that the entry isn't valid any more, we'll only use the entry
@ -1352,18 +1201,6 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
request = getter_AddRefs(entry->GetRequest()); request = getter_AddRefs(entry->GetRequest());
} }
} }
if (request && entry) {
// If this entry has no proxies, its request has no reference to the entry.
if (entry->HasNoProxies()) {
LOG_FUNC_WITH_PARAM(gImgLog, "imgLoader::LoadImageWithChannel() adding proxyless entry", "uri", spec.get());
NS_ABORT_IF_FALSE(!request->HasCacheEntry(), "Proxyless entry's request has cache entry!");
request->SetCacheEntry(entry);
if (gCacheTracker)
gCacheTracker->MarkUsed(entry);
}
}
} }
} }
@ -1377,8 +1214,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
*listener = nsnull; // give them back a null nsIStreamListener *listener = nsnull; // give them back a null nsIStreamListener
} else { } else {
if (!NewRequestAndEntry(uri, getter_AddRefs(request), getter_AddRefs(entry))) NewRequestAndEntry(uri, getter_AddRefs(request), getter_AddRefs(entry));
return NS_ERROR_OUT_OF_MEMORY;
// We use originalURI here to fulfil the imgIRequest contract on GetURI. // We use originalURI here to fulfil the imgIRequest contract on GetURI.
nsCOMPtr<nsIURI> originalURI; nsCOMPtr<nsIURI> originalURI;
@ -1386,10 +1222,8 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
request->Init(originalURI, uri, channel, channel, entry, NS_GetCurrentThread(), aCX); request->Init(originalURI, uri, channel, channel, entry, NS_GetCurrentThread(), aCX);
ProxyListener *pl = new ProxyListener(static_cast<nsIStreamListener *>(request.get())); ProxyListener *pl = new ProxyListener(static_cast<nsIStreamListener *>(request.get()));
if (!pl) { if (!pl)
request->CancelAndAbort(NS_ERROR_OUT_OF_MEMORY);
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(pl); NS_ADDREF(pl);
@ -1412,6 +1246,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
return rv; return rv;
} }
NS_IMETHODIMP imgLoader::SupportImageWithMimeType(const char* aMimeType, PRBool *_retval) NS_IMETHODIMP imgLoader::SupportImageWithMimeType(const char* aMimeType, PRBool *_retval)
{ {
*_retval = PR_FALSE; *_retval = PR_FALSE;
@ -1636,23 +1471,16 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
} }
} }
// We can't load out of cache. We have to create a whole new request for the // fun stuff.
// data that's coming in off the channel.
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
nsRefPtr<imgCacheEntry> entry; nsRefPtr<imgCacheEntry> entry;
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
mRequest->GetURI(getter_AddRefs(uri));
#if defined(PR_LOGGING)
nsCAutoString spec;
uri->GetSpec(spec);
LOG_MSG_WITH_PARAM(gImgLog, "imgCacheValidator::OnStartRequest creating new request", "uri", spec.get());
#endif
// Doom the old request's cache entry // Doom the old request's cache entry
mRequest->RemoveFromCache(); mRequest->RemoveFromCache();
mRequest->GetURI(getter_AddRefs(uri));
mRequest->mValidator = nsnull; mRequest->mValidator = nsnull;
mRequest = nsnull; mRequest = nsnull;
@ -1668,18 +1496,12 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
ProxyListener *pl = new ProxyListener(static_cast<nsIStreamListener *>(request)); ProxyListener *pl = new ProxyListener(static_cast<nsIStreamListener *>(request));
if (!pl) { if (!pl) {
request->CancelAndAbort(NS_ERROR_OUT_OF_MEMORY);
NS_RELEASE(request); NS_RELEASE(request);
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
mDestListener = static_cast<nsIStreamListener*>(pl); mDestListener = static_cast<nsIStreamListener*>(pl);
// 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
// changes the caching behaviour for imgRequests.
sImgLoader.PutIntoCache(uri, entry);
PRUint32 count = mProxies.Count(); PRUint32 count = mProxies.Count();
for (PRInt32 i = count-1; i>=0; i--) { for (PRInt32 i = count-1; i>=0; i--) {
imgRequestProxy *proxy = static_cast<imgRequestProxy *>(mProxies[i]); imgRequestProxy *proxy = static_cast<imgRequestProxy *>(mProxies[i]);
@ -1687,6 +1509,9 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
request->NotifyProxyListener(proxy); request->NotifyProxyListener(proxy);
} }
// Try to add the new request into the cache.
sImgLoader.PutIntoCache(uri, entry);
NS_RELEASE(request); NS_RELEASE(request);
if (!mDestListener) if (!mDestListener)

Просмотреть файл

@ -61,7 +61,6 @@ class imgCacheEntry
{ {
public: public:
imgCacheEntry(imgRequest *request, PRBool mustValidateIfExpired = PR_FALSE); imgCacheEntry(imgRequest *request, PRBool mustValidateIfExpired = PR_FALSE);
~imgCacheEntry();
nsrefcnt AddRef() nsrefcnt AddRef()
{ {
@ -144,11 +143,6 @@ public:
return &mExpirationState; return &mExpirationState;
} }
PRBool HasNoProxies() const
{
return mHasNoProxies;
}
private: // methods private: // methods
friend class imgLoader; friend class imgLoader;
friend class imgCacheQueue; friend class imgCacheQueue;
@ -158,24 +152,18 @@ private: // methods
{ {
mEvicted = evict; mEvicted = evict;
} }
void SetHasNoProxies(PRBool hasNoProxies);
// Private, unimplemented copy constructor.
imgCacheEntry(const imgCacheEntry &);
private: // data private: // data
nsAutoRefCnt mRefCnt; nsAutoRefCnt mRefCnt;
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;
nsExpirationState mExpirationState; nsExpirationState mExpirationState;
PRPackedBool mMustValidateIfExpired : 1; PRBool mMustValidateIfExpired;
PRPackedBool mEvicted : 1; PRBool mEvicted;
PRPackedBool mHasNoProxies : 1;
}; };
#include <vector> #include <vector>
@ -262,20 +250,6 @@ public:
static void VerifyCacheSizes(); static void VerifyCacheSizes();
// The image loader maintains a hash table of all imgCacheEntries. However,
// only some of them will be evicted from the cache: those who have no
// imgRequestProxies watching their imgRequests.
//
// Once an imgRequest has no imgRequestProxies, it should notify us by
// calling HasNoObservers(), and null out its cache entry pointer.
//
// Upon having a proxy start observing again, it should notify us by calling
// HasObservers(). The request's cache entry will be re-set before this
// happens, by calling imgRequest::SetCacheEntry() when an entry with no
// observers is re-requested.
static PRBool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry);
static PRBool SetHasProxies(nsIURI *key);
private: // methods private: // methods

Просмотреть файл

@ -92,12 +92,7 @@ imgRequest::imgRequest() :
imgRequest::~imgRequest() imgRequest::~imgRequest()
{ {
if (mKeyURI) { /* destructor code */
nsCAutoString spec;
mKeyURI->GetSpec(spec);
LOG_FUNC_WITH_PARAM(gImgLog, "imgRequest::~imgRequest()", "keyuri", spec.get());
} else
LOG_FUNC(gImgLog, "imgRequest::~imgRequest()");
} }
nsresult imgRequest::Init(nsIURI *aURI, nsresult imgRequest::Init(nsIURI *aURI,
@ -110,17 +105,15 @@ nsresult imgRequest::Init(nsIURI *aURI,
{ {
LOG_FUNC(gImgLog, "imgRequest::Init"); LOG_FUNC(gImgLog, "imgRequest::Init");
NS_ABORT_IF_FALSE(!mImage, "Multiple calls to init"); NS_ASSERTION(!mImage, "Multiple calls to init");
NS_ABORT_IF_FALSE(aURI, "No uri"); NS_ASSERTION(aURI, "No uri");
NS_ABORT_IF_FALSE(aKeyURI, "No key uri"); NS_ASSERTION(aRequest, "No request");
NS_ABORT_IF_FALSE(aRequest, "No request"); NS_ASSERTION(aChannel, "No channel");
NS_ABORT_IF_FALSE(aChannel, "No channel");
mProperties = do_CreateInstance("@mozilla.org/properties;1"); mProperties = do_CreateInstance("@mozilla.org/properties;1");
if (!mProperties) if (!mProperties)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
mURI = aURI; mURI = aURI;
mKeyURI = aKeyURI; mKeyURI = aKeyURI;
mRequest = aRequest; mRequest = aRequest;
@ -148,28 +141,11 @@ nsresult imgRequest::Init(nsIURI *aURI,
return NS_OK; return NS_OK;
} }
void imgRequest::SetCacheEntry(imgCacheEntry *entry)
{
mCacheEntry = entry;
}
PRBool imgRequest::HasCacheEntry() const
{
return mCacheEntry != nsnull;
}
nsresult imgRequest::AddProxy(imgRequestProxy *proxy) nsresult imgRequest::AddProxy(imgRequestProxy *proxy)
{ {
NS_PRECONDITION(proxy, "null imgRequestProxy passed in"); NS_PRECONDITION(proxy, "null imgRequestProxy passed in");
LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::AddProxy", "proxy", proxy); LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::AddProxy", "proxy", proxy);
// If we're empty before adding, we have to tell the loader we now have
// proxies.
if (mObservers.IsEmpty()) {
NS_ABORT_IF_FALSE(mKeyURI, "Trying to SetHasProxies without key uri.");
imgLoader::SetHasProxies(mKeyURI);
}
return mObservers.AppendElementUnlessExists(proxy) ? return mObservers.AppendElementUnlessExists(proxy) ?
NS_OK : NS_ERROR_OUT_OF_MEMORY; NS_OK : NS_ERROR_OUT_OF_MEMORY;
} }
@ -206,22 +182,6 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, PRBoo
} }
if (mObservers.IsEmpty()) { if (mObservers.IsEmpty()) {
// If we have no observers, there's nothing holding us alive. If we haven't
// been cancelled and thus removed from the cache, tell the image loader so
// we can be evicted from the cache.
if (mCacheEntry) {
NS_ABORT_IF_FALSE(mKeyURI, "Removing last observer without key uri.");
imgLoader::SetHasNoProxies(mKeyURI, mCacheEntry);
}
#if defined(PR_LOGGING)
else {
nsCAutoString spec;
mKeyURI->GetSpec(spec);
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::RemoveProxy no cache entry", "uri", spec.get());
}
#endif
/* If |aStatus| is a failure code, then cancel the load if it is still in progress. /* If |aStatus| is a failure code, then cancel the load if it is still in progress.
Otherwise, let the load continue, keeping 'this' in the cache with no observers. Otherwise, let the load continue, keeping 'this' in the cache with no observers.
This way, if a proxy is destroyed without calling cancel on it, it won't leak This way, if a proxy is destroyed without calling cancel on it, it won't leak
@ -354,8 +314,6 @@ void imgRequest::Cancel(nsresult aStatus)
void imgRequest::CancelAndAbort(nsresult aStatus) void imgRequest::CancelAndAbort(nsresult aStatus)
{ {
LOG_SCOPE(gImgLog, "imgRequest::CancelAndAbort");
Cancel(aStatus); Cancel(aStatus);
// It's possible for the channel to fail to open after we've set our // It's possible for the channel to fail to open after we've set our
@ -419,12 +377,10 @@ void imgRequest::RemoveFromCache()
{ {
LOG_SCOPE(gImgLog, "imgRequest::RemoveFromCache"); LOG_SCOPE(gImgLog, "imgRequest::RemoveFromCache");
if (mCacheEntry) if (mCacheEntry) {
imgLoader::RemoveFromCache(mCacheEntry); imgLoader::RemoveFromCache(mURI);
else mCacheEntry = nsnull;
imgLoader::RemoveFromCache(mKeyURI); }
mCacheEntry = nsnull;
} }
PRBool imgRequest::HaveProxyWithObserver(imgRequestProxy* aProxyToIgnore) const PRBool imgRequest::HaveProxyWithObserver(imgRequestProxy* aProxyToIgnore) const
@ -1066,25 +1022,12 @@ 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(); RemoveFromCache();
mChannel = newChannel; mChannel = newChannel;
newChannel->GetOriginalURI(getter_AddRefs(mKeyURI)); newChannel->GetOriginalURI(getter_AddRefs(mKeyURI));
#if defined(PR_LOGGING)
mKeyURI->GetSpec(spec);
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect", "new", spec.get());
#endif
// If we don't still have a cache entry, we don't want to refresh the cache. // If we don't still have a cache entry, we don't want to refresh the cache.
if (mKeyURI && mCacheEntry) if (mKeyURI && mCacheEntry)
imgLoader::PutIntoCache(mKeyURI, mCacheEntry); imgLoader::PutIntoCache(mKeyURI, mCacheEntry);

Просмотреть файл

@ -120,7 +120,6 @@ private:
friend class imgRequestProxy; friend class imgRequestProxy;
friend class imgLoader; friend class imgLoader;
friend class imgCacheValidator; friend class imgCacheValidator;
friend class imgCacheExpirationTracker;
inline void SetLoadId(void *aLoadId) { inline void SetLoadId(void *aLoadId) {
mLoadId = aLoadId; mLoadId = aLoadId;
@ -141,14 +140,6 @@ private:
return mProperties; return mProperties;
} }
// Reset the cache entry after we've dropped our reference to it. Used by the
// imgLoader when our cache entry is re-requested after we've dropped our
// reference to it.
void SetCacheEntry(imgCacheEntry *entry);
// Returns whether we've got a reference to the cache entry.
PRBool HasCacheEntry() const;
// Return true if at least one of our proxies, excluding // Return true if at least one of our proxies, excluding
// aProxyToIgnore, has an observer. aProxyToIgnore may be null. // aProxyToIgnore, has an observer. aProxyToIgnore may be null.
PRBool HaveProxyWithObserver(imgRequestProxy* aProxyToIgnore) const; PRBool HaveProxyWithObserver(imgRequestProxy* aProxyToIgnore) const;