зеркало из https://github.com/mozilla/gecko-dev.git
Fix #21660 (Browser buster crash in cache). a:chofmann
This commit is contained in:
Родитель
cc7ea1bbf1
Коммит
94eddbd362
|
@ -63,6 +63,15 @@ nsCachedNetData::operator new (size_t aSize, nsIArena *aArena)
|
|||
return entry;
|
||||
}
|
||||
|
||||
// Placement new for recycling of arena-based nsCachedNetData
|
||||
// instances, clears all instance variables.
|
||||
void *
|
||||
nsCachedNetData::operator new (size_t aSize, nsCachedNetData *aEntry)
|
||||
{
|
||||
nsCRT::zero(aEntry, aSize);
|
||||
return aEntry;
|
||||
}
|
||||
|
||||
// One element in a linked list of nsIStreamAsFileObserver's
|
||||
class StreamAsFileObserverClosure
|
||||
{
|
||||
|
@ -1087,6 +1096,10 @@ public:
|
|||
mCacheEntry->ClearFlag(nsCachedNetData::TRUNCATED_CONTENT);
|
||||
mCacheEntry->ClearFlag(nsCachedNetData::VESTIGIAL);
|
||||
mCacheEntry->ClearFlag(nsCachedNetData::UPDATE_IN_PROGRESS);
|
||||
|
||||
// Tell any stream-as-file observers that the file has been completely written
|
||||
mCacheEntry->Notify(nsIStreamAsFileObserver::NOTIFY_AVAILABLE, NS_OK);
|
||||
|
||||
return mOriginalListener->OnStopRequest(channel, ctxt, status, errorMsg);
|
||||
}
|
||||
|
||||
|
|
|
@ -124,6 +124,9 @@ protected:
|
|||
// placement new for arena-allocation
|
||||
void *operator new (size_t aSize, nsIArena *aArena);
|
||||
|
||||
// placement new for recycling of arena-allocated nsCachedNetData instances
|
||||
void *operator new (size_t aSize, nsCachedNetData *aEntry);
|
||||
|
||||
friend class nsReplacementPolicy;
|
||||
friend class nsCacheManager;
|
||||
friend class StreamAsFile;
|
||||
|
|
|
@ -67,7 +67,8 @@ nsReplacementPolicy::Init(PRUint32 aMaxCacheEntries)
|
|||
|
||||
mMaxEntries = aMaxCacheEntries;
|
||||
|
||||
mHashArrayLength = PR_CeilingLog2(aMaxCacheEntries) >> 3;
|
||||
// Hash array length must be power-of-two
|
||||
mHashArrayLength = (1 << PR_CeilingLog2(aMaxCacheEntries)) >> 3;
|
||||
size_t numBytes = mHashArrayLength * sizeof(*mMapRecordIdToEntry);
|
||||
mMapRecordIdToEntry = (nsCachedNetData**)nsAllocator::Alloc(numBytes);
|
||||
if (!mMapRecordIdToEntry)
|
||||
|
@ -374,20 +375,6 @@ nsReplacementPolicy::RankRecords()
|
|||
{
|
||||
PRUint32 i, now;
|
||||
|
||||
// Add all cache records if this is the first ranking
|
||||
if (!mLastRankTime) {
|
||||
nsresult rv;
|
||||
CacheInfo *cacheInfo;
|
||||
|
||||
cacheInfo = mCaches;
|
||||
while (cacheInfo) {
|
||||
rv = AddAllRecordsInCache(cacheInfo->mCache);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
cacheInfo = cacheInfo->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
// Get current time and convert to seconds since the epoch
|
||||
now = now32();
|
||||
|
||||
|
@ -427,7 +414,10 @@ nsReplacementPolicy::CompactRankedEntriesArray()
|
|||
nsresult
|
||||
nsReplacementPolicy::CheckForTooManyCacheEntries()
|
||||
{
|
||||
if (mCapacityRankedEntriesArray == mMaxEntries) {
|
||||
PRUint32 undeletedEntries;
|
||||
undeletedEntries = mNumEntries - mRecordsRemovedSinceLastRanking;
|
||||
|
||||
if (undeletedEntries >= mMaxEntries) {
|
||||
return DeleteOneEntry(0);
|
||||
} else {
|
||||
nsresult rv;
|
||||
|
@ -481,6 +471,10 @@ nsReplacementPolicy::AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecor
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// If number of tracked cache entries exceeds limits, delete one
|
||||
rv = CheckForTooManyCacheEntries();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Compact the array of cache entry statistics, so that free entries appear
|
||||
// at the end, for possible reuse.
|
||||
if (mNumEntries && (mNumEntries == mCapacityRankedEntriesArray))
|
||||
|
@ -491,9 +485,6 @@ nsReplacementPolicy::AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecor
|
|||
if (mNumEntries == mCapacityRankedEntriesArray) {
|
||||
PRUint32 newCapacity;
|
||||
|
||||
rv = CheckForTooManyCacheEntries();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
newCapacity = mCapacityRankedEntriesArray + STATS_GROWTH_INCREMENT;
|
||||
if (newCapacity > mMaxEntries)
|
||||
newCapacity = mMaxEntries;
|
||||
|
@ -515,7 +506,7 @@ nsReplacementPolicy::AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecor
|
|||
|
||||
// Recycle the record after the last in-use record in the array
|
||||
nsCachedNetData *entry = mRankedEntries[mNumEntries];
|
||||
NS_ASSERTION(!entry || !entry->GetFlag(nsCachedNetData::RECYCLED),
|
||||
NS_ASSERTION(!entry || entry->GetFlag(nsCachedNetData::RECYCLED),
|
||||
"Only deleted cache entries should appear at end of array");
|
||||
|
||||
if (!entry) {
|
||||
|
@ -525,7 +516,7 @@ nsReplacementPolicy::AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecor
|
|||
mRankedEntries[mNumEntries] = entry;
|
||||
} else {
|
||||
// Clear out recycled data structure
|
||||
nsCRT::zero(entry, sizeof(*entry));
|
||||
entry = new(entry) nsCachedNetData;
|
||||
}
|
||||
|
||||
entry->Init(aRecord, aCache);
|
||||
|
@ -570,12 +561,16 @@ nsReplacementPolicy::DeleteOneEntry(nsINetDataCache *aCache)
|
|||
nsresult rv;
|
||||
nsCachedNetData *entry;
|
||||
|
||||
// It's not possible to rank cache entries by their profitability
|
||||
// until all of them are known to the replacement policy.
|
||||
LoadAllRecordsInAllCacheDatabases();
|
||||
|
||||
i = 0;
|
||||
MaybeRerankRecords();
|
||||
while (1) {
|
||||
MaybeRerankRecords();
|
||||
for (; i < mNumEntries; i++) {
|
||||
entry = mRankedEntries[i];
|
||||
if (!entry || entry->GetFlag(nsCachedNetData::RECYCLED))
|
||||
if (!entry || entry->GetFlag(nsCachedNetData::RECYCLED) || (entry->mRefCnt > 1))
|
||||
continue;
|
||||
if (!aCache || (entry->mCache == aCache))
|
||||
break;
|
||||
|
@ -587,8 +582,10 @@ nsReplacementPolicy::DeleteOneEntry(nsINetDataCache *aCache)
|
|||
rv = entry->Delete();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = DeleteCacheEntry(entry);
|
||||
mRecordsRemovedSinceLastRanking++;
|
||||
return rv;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -611,6 +608,32 @@ nsReplacementPolicy::GetStorageInUse(PRUint32* aStorageInUse)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// When true, all cache database records have been loaded into the
|
||||
// mRankedEntries array. Until this occurs, it is not possible to rank
|
||||
// cache entries against each other to determine which is the best
|
||||
// candidate for eviction from the cache.
|
||||
nsresult
|
||||
nsReplacementPolicy::LoadAllRecordsInAllCacheDatabases()
|
||||
{
|
||||
// We been here before ?
|
||||
if (mLoadedAllDatabaseRecords)
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv;
|
||||
CacheInfo *cacheInfo;
|
||||
|
||||
cacheInfo = mCaches;
|
||||
while (cacheInfo) {
|
||||
rv = AddAllRecordsInCache(cacheInfo->mCache);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
cacheInfo = cacheInfo->mNext;
|
||||
}
|
||||
mLoadedAllDatabaseRecords = PR_TRUE;
|
||||
return RankRecords();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete the least desirable records from the cache until the occupancy of the
|
||||
* cache has been reduced by the given number of KB. This is used when the
|
||||
|
@ -626,7 +649,12 @@ nsReplacementPolicy::Evict(PRUint32 aTargetOccupancy)
|
|||
PRInt32 truncatedLength;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
|
||||
// It's not possible to rank cache entries by their profitability
|
||||
// until all of them are known to the replacement policy.
|
||||
LoadAllRecordsInAllCacheDatabases();
|
||||
|
||||
MaybeRerankRecords();
|
||||
|
||||
for (i = 0; i < mNumEntries; i++) {
|
||||
rv = GetStorageInUse(&occupancy);
|
||||
if (!NS_SUCCEEDED(rv)) return rv;
|
||||
|
|
|
@ -84,6 +84,7 @@ private:
|
|||
|
||||
nsresult AddAllRecordsInCache(nsINetDataCache *aCache);
|
||||
nsresult CheckForTooManyCacheEntries();
|
||||
nsresult LoadAllRecordsInAllCacheDatabases();
|
||||
|
||||
class CacheInfo;
|
||||
|
||||
|
@ -130,6 +131,12 @@ private:
|
|||
|
||||
// Time at which cache entries were last ranked by profitability
|
||||
PRUint32 mLastRankTime;
|
||||
|
||||
// When true, all cache database records have been loaded into the
|
||||
// mRankedEntries array. Until this occurs, it is not possible to rank
|
||||
// cache entries against each other to determine which is the best
|
||||
// candidate for eviction from the cache.
|
||||
PRBool mLoadedAllDatabaseRecords;
|
||||
};
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче