fixes bug 328196 "nsDiskCacheDevice: Memory and codesize optimisations" patch by Alfred Kayser <alfredkayser@nl.ibm.com>, r=darin

This commit is contained in:
darin%meer.net 2006-02-25 02:58:51 +00:00
Родитель e709b63ba8
Коммит 7c37f72def
5 изменённых файлов: 79 добавлений и 146 удалений

186
netwerk/cache/src/nsDiskCacheDevice.cpp поставляемый
Просмотреть файл

@ -102,77 +102,65 @@ static const char DISK_CACHE_DEVICE_ID[] = { "disk" };
class nsDiskCacheEvictor : public nsDiskCacheRecordVisitor
{
public:
nsDiskCacheEvictor( nsDiskCacheDevice * device,
nsDiskCacheMap * cacheMap,
nsDiskCacheEvictor( nsDiskCacheMap * cacheMap,
nsDiskCacheBindery * cacheBindery,
PRInt32 targetSize,
const char * clientID)
: mDevice(device)
, mCacheMap(cacheMap)
: mCacheMap(cacheMap)
, mBindery(cacheBindery)
, mTargetSize(targetSize)
, mClientID(clientID)
{}
{
mClientIDSize = clientID ? strlen(clientID) : 0;
}
virtual PRInt32 VisitRecord(nsDiskCacheRecord * mapRecord);
private:
nsDiskCacheDevice * mDevice;
nsDiskCacheMap * mCacheMap;
nsDiskCacheBindery * mBindery;
PRInt32 mTargetSize;
const char * mClientID;
PRUint32 mClientIDSize;
};
PRInt32
nsDiskCacheEvictor::VisitRecord(nsDiskCacheRecord * mapRecord)
{
// read disk cache entry
nsDiskCacheEntry * diskEntry = nsnull;
nsDiskCacheBinding * binding = nsnull;
char * clientID = nsnull;
PRInt32 result = kVisitNextRecord;
if (mCacheMap->TotalSize() < mTargetSize)
return kStopVisitingRecords;
if (mClientID) {
// we're just evicting records for a specific client
// we're just evicting records for a specific client
nsDiskCacheEntry * diskEntry = nsnull;
nsresult rv = mCacheMap->ReadDiskCacheEntry(mapRecord, &diskEntry);
if (NS_FAILED(rv)) goto exit; // XXX or delete record?
if (NS_FAILED(rv))
return kVisitNextRecord; // XXX or delete record?
// XXX FIXME compare clientID's without malloc
// get client ID from key
rv = ClientIDFromCacheKey(nsDependentCString(diskEntry->mKeyStart), &clientID);
if (NS_FAILED(rv)) goto exit;
if (nsCRT::strcmp(mClientID, clientID) != 0) goto exit;
// Compare clientID's without malloc
if ((diskEntry->mKeySize <= mClientIDSize) ||
(diskEntry->mKeyStart[mClientIDSize] != ':') ||
(memcmp(diskEntry->mKeyStart, mClientID, mClientIDSize) != 0)) {
delete [] (char *)diskEntry;
return kVisitNextRecord; // clientID doesn't match, skip it
}
delete [] (char *)diskEntry;
}
if (mCacheMap->TotalSize() < mTargetSize) {
result = kStopVisitingRecords;
goto exit;
}
binding = mBindery->FindActiveBinding(mapRecord->HashNumber());
nsDiskCacheBinding * binding = mBindery->FindActiveBinding(mapRecord->HashNumber());
if (binding) {
// We are currently using this entry, so all we can do is doom it.
// Since we're enumerating the records, we don't want to call
// DeleteRecord when nsCacheService::DoomEntry() calls us back.
binding->mDoomed = PR_TRUE; // mark binding record as 'deleted'
nsCacheService::DoomEntry(binding->mCacheEntry);
result = kDeleteRecordAndContinue; // this will REALLY delete the record
} else {
// entry not in use, just delete storage because we're enumerating the records
(void) mCacheMap->DeleteStorage(mapRecord);
result = kDeleteRecordAndContinue; // this will REALLY delete the record
}
exit:
delete clientID;
delete [] (char *)diskEntry;
return result;
return kDeleteRecordAndContinue; // this will REALLY delete the record
}
@ -333,7 +321,6 @@ nsDiskCache::Truncate(PRFileDesc * fd, PRUint32 newEOF)
nsDiskCacheDevice::nsDiskCacheDevice()
: mCacheCapacity(0)
, mCacheMap(nsnull)
, mInitialized(PR_FALSE)
{
}
@ -341,7 +328,6 @@ nsDiskCacheDevice::nsDiskCacheDevice()
nsDiskCacheDevice::~nsDiskCacheDevice()
{
Shutdown();
delete mCacheMap;
}
@ -355,27 +341,22 @@ nsDiskCacheDevice::Init()
NS_ENSURE_TRUE(!Initialized(), NS_ERROR_FAILURE);
if (!mCacheDirectory) return NS_ERROR_FAILURE;
if (!mCacheDirectory)
return NS_ERROR_FAILURE;
rv = mBindery.Init();
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv))
return rv;
// Open Disk Cache
rv = OpenDiskCache();
if (NS_FAILED(rv)) {
goto error_exit;
(void) mCacheMap.Close(PR_FALSE);
return rv;
}
mInitialized = PR_TRUE;
return NS_OK;
error_exit:
if (mCacheMap) {
(void) mCacheMap->Close(PR_FALSE);
delete mCacheMap;
mCacheMap = nsnull;
}
return rv;
}
@ -412,9 +393,7 @@ nsDiskCacheDevice::Shutdown_Private(PRBool flush)
EvictDiskCacheEntries((PRInt32)mCacheCapacity);
// write out persistent information about the cache.
(void) mCacheMap->Close(flush);
delete mCacheMap;
mCacheMap = nsnull;
(void) mCacheMap.Close(flush);
mBindery.Reset();
@ -458,15 +437,15 @@ nsDiskCacheDevice::FindEntry(nsCString * key)
#endif
// lookup hash number in cache map
rv = mCacheMap->FindRecord(hashNumber, &record);
rv = mCacheMap.FindRecord(hashNumber, &record);
if (NS_FAILED(rv)) return nsnull; // XXX log error?
nsDiskCacheEntry * diskEntry;
rv = mCacheMap->ReadDiskCacheEntry(&record, &diskEntry);
rv = mCacheMap.ReadDiskCacheEntry(&record, &diskEntry);
if (NS_FAILED(rv)) return nsnull;
// compare key to be sure
if (nsCRT::strcmp(diskEntry->mKeyStart, key->get()) == 0) {
if (strcmp(diskEntry->mKeyStart, key->get()) == 0) {
entry = diskEntry->CreateCacheEntry(this);
}
delete [] (char *)diskEntry;
@ -497,14 +476,15 @@ nsDiskCacheDevice::DeactivateEntry(nsCacheEntry * entry)
if (entry->IsDoomed()) {
// delete data, entry, record from disk for entry
rv = mCacheMap->DeleteStorage(&binding->mRecord);
rv = mCacheMap.DeleteStorage(&binding->mRecord);
} else {
// save stuff to disk for entry
rv = mCacheMap->WriteDiskCacheEntry(binding);
rv = mCacheMap.WriteDiskCacheEntry(binding);
if (NS_FAILED(rv)) {
// clean up as best we can
(void) mCacheMap->DeleteRecordAndStorage(&binding->mRecord);
(void) mCacheMap.DeleteStorage(&binding->mRecord);
(void) mCacheMap.DeleteRecord(&binding->mRecord);
binding->mDoomed = PR_TRUE; // record is no longer in cache map
}
}
@ -543,7 +523,7 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry * entry)
if (!entry->IsDoomed()) {
// if entry isn't doomed, add it to the cache map
rv = mCacheMap->AddRecord(&record, &oldRecord); // deletes old record, if any
rv = mCacheMap.AddRecord(&record, &oldRecord); // deletes old record, if any
if (NS_FAILED(rv)) return rv;
PRUint32 oldHashNumber = oldRecord.HashNumber();
@ -561,7 +541,7 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry * entry)
} else {
// delete storage
// XXX if debug : compare keys for hashNumber collision
rv = mCacheMap->DeleteStorage(&oldRecord);
rv = mCacheMap.DeleteStorage(&oldRecord);
if (NS_FAILED(rv)) return rv; // XXX delete record we just added?
}
}
@ -589,8 +569,8 @@ nsDiskCacheDevice::DoomEntry(nsCacheEntry * entry)
if (!binding->mDoomed) {
// so it can't be seen by FindEntry() ever again.
nsresult rv = mCacheMap->DoomRecord(&binding->mRecord);
NS_ASSERTION(NS_SUCCEEDED(rv),"DoomRecord failed.");
nsresult rv = mCacheMap.DeleteRecord(&binding->mRecord);
NS_ASSERTION(NS_SUCCEEDED(rv),"DeleteRecord failed.");
binding->mDoomed = PR_TRUE; // record in no longer in cache map
}
}
@ -675,15 +655,15 @@ nsDiskCacheDevice::GetFileForEntry(nsCacheEntry * entry,
binding->mRecord.SetDataFileSize(0); // 1k minimum
if (!binding->mDoomed) {
// record stored in cache map, so update it
rv = mCacheMap->UpdateRecord(&binding->mRecord);
rv = mCacheMap.UpdateRecord(&binding->mRecord);
if (NS_FAILED(rv)) return rv;
}
}
nsCOMPtr<nsIFile> file;
rv = mCacheMap->GetFileForDiskCacheRecord(&binding->mRecord,
nsDiskCache::kData,
getter_AddRefs(file));
rv = mCacheMap.GetFileForDiskCacheRecord(&binding->mRecord,
nsDiskCache::kData,
getter_AddRefs(file));
if (NS_FAILED(rv)) return rv;
NS_IF_ADDREF(*result = file);
@ -733,13 +713,10 @@ nsDiskCacheDevice::OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize)
class EntryInfoVisitor : public nsDiskCacheRecordVisitor
{
public:
EntryInfoVisitor(nsDiskCacheDevice * device,
nsDiskCacheMap * cacheMap,
EntryInfoVisitor(nsDiskCacheMap * cacheMap,
nsICacheVisitor * visitor)
: mDevice(device)
, mCacheMap(cacheMap)
: mCacheMap(cacheMap)
, mVisitor(visitor)
, mResult(NS_OK)
{}
virtual PRInt32 VisitRecord(nsDiskCacheRecord * mapRecord)
@ -750,14 +727,12 @@ public:
nsDiskCacheEntry * diskEntry;
nsresult rv = mCacheMap->ReadDiskCacheEntry(mapRecord, &diskEntry);
if (NS_FAILED(rv)) {
mResult = rv;
return kVisitNextRecord;
}
// create nsICacheEntryInfo
nsDiskCacheEntryInfo * entryInfo = new nsDiskCacheEntryInfo(DISK_CACHE_DEVICE_ID, diskEntry);
if (!entryInfo) {
mResult = NS_ERROR_OUT_OF_MEMORY;
return kStopVisitingRecords;
}
nsCOMPtr<nsICacheEntryInfo> ref(entryInfo);
@ -769,10 +744,8 @@ public:
}
private:
nsDiskCacheDevice * mDevice;
nsDiskCacheMap * mCacheMap;
nsICacheVisitor * mVisitor;
nsresult mResult;
};
@ -788,8 +761,8 @@ nsDiskCacheDevice::Visit(nsICacheVisitor * visitor)
if (NS_FAILED(rv)) return rv;
if (keepGoing) {
EntryInfoVisitor infoVisitor(this, mCacheMap, visitor);
return mCacheMap->VisitRecords(&infoVisitor);
EntryInfoVisitor infoVisitor(&mCacheMap, visitor);
return mCacheMap.VisitRecords(&infoVisitor);
}
return NS_OK;
@ -809,11 +782,11 @@ nsDiskCacheDevice::EvictEntries(const char * clientID)
return rv;
}
nsDiskCacheEvictor evictor(this, mCacheMap, &mBindery, 0, clientID);
rv = mCacheMap->VisitRecords(&evictor);
nsDiskCacheEvictor evictor(&mCacheMap, &mBindery, 0, clientID);
rv = mCacheMap.VisitRecords(&evictor);
if (clientID == nsnull) // we tried to clear the entire cache
rv = mCacheMap->Trim(); // so trim cache block files (if possible)
rv = mCacheMap.Trim(); // so trim cache block files (if possible)
return rv;
}
@ -830,23 +803,16 @@ nsDiskCacheDevice::EvictEntries(const char * clientID)
nsresult
nsDiskCacheDevice::OpenDiskCache()
{
nsresult rv;
// Try opening cache map file.
NS_ASSERTION(mCacheMap == nsnull, "leaking mCacheMap");
mCacheMap = new nsDiskCacheMap;
if (!mCacheMap)
return NS_ERROR_OUT_OF_MEMORY;
// if we don't have a cache directory, create one and open it
PRBool exists;
rv = mCacheDirectory->Exists(&exists);
nsresult rv = mCacheDirectory->Exists(&exists);
if (NS_FAILED(rv))
return rv;
PRBool trashing = PR_FALSE;
if (exists) {
rv = mCacheMap->Open(mCacheDirectory);
// Try opening cache map file.
rv = mCacheMap.Open(mCacheDirectory);
// move "corrupt" caches to trash
if (rv == NS_ERROR_FILE_CORRUPTED) {
rv = DeleteDir(mCacheDirectory, PR_TRUE, PR_FALSE);
@ -861,7 +827,14 @@ nsDiskCacheDevice::OpenDiskCache()
// if we don't have a cache directory, create one and open it
if (!exists) {
rv = InitializeCacheDirectory();
rv = mCacheDirectory->Create(nsIFile::DIRECTORY_TYPE, 0777);
CACHE_LOG_PATH(PR_LOG_ALWAYS, "\ncreate cache directory: %s\n", mCacheDirectory);
CACHE_LOG_ALWAYS(("mCacheDirectory->Create() = %x\n", rv));
if (NS_FAILED(rv))
return rv;
// reopen the cache map
rv = mCacheMap.Open(mCacheDirectory);
if (NS_FAILED(rv))
return rv;
}
@ -901,33 +874,14 @@ nsDiskCacheDevice::ClearDiskCache()
}
nsresult
nsDiskCacheDevice::InitializeCacheDirectory()
{
nsresult rv;
rv = mCacheDirectory->Create(nsIFile::DIRECTORY_TYPE, 0777);
CACHE_LOG_PATH(PR_LOG_ALWAYS, "\ncreate cache directory: %s\n", mCacheDirectory);
CACHE_LOG_ALWAYS(("mCacheDirectory->Create() = %x\n", rv));
if (NS_FAILED(rv)) return rv;
// reopen the cache map
rv = mCacheMap->Open(mCacheDirectory);
return rv;
}
nsresult
nsDiskCacheDevice::EvictDiskCacheEntries(PRInt32 targetCapacity)
{
nsresult rv;
if (mCacheMap->TotalSize() < targetCapacity) return NS_OK;
if (mCacheMap.TotalSize() < targetCapacity)
return NS_OK;
nsDiskCacheEvictor evictor(this, mCacheMap, &mBindery, targetCapacity, nsnull);
rv = mCacheMap->EvictRecords(&evictor);
return rv;
nsDiskCacheEvictor evictor(&mCacheMap, &mBindery, targetCapacity, nsnull);
return mCacheMap.EvictRecords(&evictor);
}
@ -1003,11 +957,11 @@ PRUint32 nsDiskCacheDevice::getCacheCapacity()
PRUint32 nsDiskCacheDevice::getCacheSize()
{
return mCacheMap->TotalSize();
return mCacheMap.TotalSize();
}
PRUint32 nsDiskCacheDevice::getEntryCount()
{
return mCacheMap->EntryCount();
return mCacheMap.EntryCount();
}

16
netwerk/cache/src/nsDiskCacheDevice.h поставляемый
Просмотреть файл

@ -101,21 +101,21 @@ public:
PRUint32 getCacheSize();
PRUint32 getEntryCount();
PRBool Initialized() { return mInitialized; }
nsDiskCacheMap * CacheMap() { return mCacheMap; }
nsresult Shutdown_Private(PRBool flush);
nsDiskCacheMap * CacheMap() { return &mCacheMap; }
private:
/**
* Private methods
*/
nsresult OpenDiskCache();
nsresult ClearDiskCache();
nsresult InitializeCacheDirectory();
PRBool Initialized() { return mInitialized; }
nsresult Shutdown_Private(PRBool flush);
nsresult EvictDiskCacheEntries(PRInt32 targetCapacity);
nsresult OpenDiskCache();
nsresult ClearDiskCache();
nsresult EvictDiskCacheEntries(PRInt32 targetCapacity);
/**
* Member variables
@ -123,7 +123,7 @@ private:
nsCOMPtr<nsILocalFile> mCacheDirectory;
nsDiskCacheBindery mBindery;
PRUint32 mCacheCapacity; // XXX need soft/hard limits, currentTotal
nsDiskCacheMap * mCacheMap;
nsDiskCacheMap mCacheMap;
PRPackedBool mInitialized;
};

19
netwerk/cache/src/nsDiskCacheMap.cpp поставляемый
Просмотреть файл

@ -857,16 +857,6 @@ nsDiskCacheMap::WriteDataCacheBlocks(nsDiskCacheBinding * binding, char * buffer
}
nsresult
nsDiskCacheMap::DoomRecord(nsDiskCacheRecord * record)
{
nsresult rv = DeleteRecord(record);
// XXX future: add record to doomed record journal
return rv;
}
nsresult
nsDiskCacheMap::DeleteStorage(nsDiskCacheRecord * record)
{
@ -909,15 +899,6 @@ nsDiskCacheMap::DeleteStorage(nsDiskCacheRecord * record, PRBool metaData)
}
nsresult
nsDiskCacheMap::DeleteRecordAndStorage(nsDiskCacheRecord * record)
{
nsresult rv1 = DeleteStorage(record);
nsresult rv2 = DeleteRecord(record);
return NS_FAILED(rv1) ? rv1 : rv2;
}
nsresult
nsDiskCacheMap::GetFileForDiskCacheRecord(nsDiskCacheRecord * record,
PRBool meta,

2
netwerk/cache/src/nsDiskCacheMap.h поставляемый
Просмотреть файл

@ -422,9 +422,7 @@ public:
/**
* Disk Entry operations
*/
nsresult DoomRecord( nsDiskCacheRecord * record);
nsresult DeleteStorage( nsDiskCacheRecord * record);
nsresult DeleteRecordAndStorage( nsDiskCacheRecord * record);
nsresult GetFileForDiskCacheRecord( nsDiskCacheRecord * record,
PRBool meta,

2
netwerk/cache/src/nsDiskCacheStreams.cpp поставляемый
Просмотреть файл

@ -511,7 +511,7 @@ nsDiskCacheStreamIO::Flush()
rv = cacheMap->DeleteStorage(record, nsDiskCache::kData);
if (NS_FAILED(rv)) {
NS_WARNING("cacheMap->DeleteStorage() failed.");
cacheMap->DoomRecord(record);
cacheMap->DeleteRecord(record);
return rv;
}
}