зеркало из https://github.com/mozilla/gecko-dev.git
for bug 103851 "move cache deletion to another thread", r=bryner, sr=darin.
This commit is contained in:
Родитель
f45162d495
Коммит
d8058e79cb
|
@ -26,6 +26,7 @@
|
|||
#include "nsCache.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsDependentSubstring.h"
|
||||
#include "nsString.h"
|
||||
|
||||
|
||||
/**
|
||||
|
@ -35,15 +36,29 @@
|
|||
#if defined(PR_LOGGING)
|
||||
PRLogModuleInfo * gCacheLog = nsnull;
|
||||
|
||||
|
||||
void
|
||||
CacheLogInit()
|
||||
{
|
||||
if (gCacheLog) return;
|
||||
gCacheLog = PR_NewLogModule("cache");
|
||||
NS_ASSERTION(gCacheLog, "\n### failed to allocate cache log.\n");
|
||||
NS_ASSERTION(gCacheLog, "\nfailed to allocate cache log.\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CacheLogPrintPath(PRLogModuleLevel level, char * format, nsIFile * item)
|
||||
{
|
||||
nsCAutoString path;
|
||||
nsresult rv = item->GetNativePath(path);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PR_LOG(gCacheLog, level, (format, path.get()));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
PRUint32
|
||||
SecondsFromPRTime(PRTime prTime)
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#define _nsCache_h_
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsAString.h"
|
||||
#include "prtime.h"
|
||||
#include "nsError.h"
|
||||
|
@ -40,17 +41,23 @@
|
|||
#if defined(PR_LOGGING)
|
||||
extern PRLogModuleInfo * gCacheLog;
|
||||
void CacheLogInit();
|
||||
void CacheLogPrintPath(PRLogModuleLevel level,
|
||||
char * format,
|
||||
nsIFile * item);
|
||||
#define CACHE_LOG_INIT() CacheLogInit()
|
||||
#define CACHE_LOG_ALWAYS(args) PR_LOG(gCacheLog, PR_LOG_ALWAYS, args)
|
||||
#define CACHE_LOG_ERROR(args) PR_LOG(gCacheLog, PR_LOG_ERROR, args)
|
||||
#define CACHE_LOG_WARNING(args) PR_LOG(gCacheLog, PR_LOG_WARNING, args)
|
||||
#define CACHE_LOG_DEBUG(args) PR_LOG(gCacheLog, PR_LOG_DEBUG, args)
|
||||
#define CACHE_LOG_PATH(level, format, item) \
|
||||
CacheLogPrintPath(level, format, item)
|
||||
#else
|
||||
#define CACHE_LOG_INIT() {}
|
||||
#define CACHE_LOG_ALWAYS(args) {}
|
||||
#define CACHE_LOG_ERROR(args) {}
|
||||
#define CACHE_LOG_WARNING(args) {}
|
||||
#define CACHE_LOG_DEBUG(args) {}
|
||||
#define CACHE_LOG_PATH(level, format, item) {}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -322,7 +322,7 @@ nsDiskCacheBindery::AddBinding(nsDiskCacheBinding * binding)
|
|||
if (binding->mGeneration == p->mGeneration) {
|
||||
if (calcGeneration) ++binding->mGeneration; // try the next generation
|
||||
else {
|
||||
NS_ASSERTION(binding->mGeneration != p->mGeneration, "generations collide!");
|
||||
NS_ERROR("### disk cache: generations collide!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ nsDiskCacheBindery::AddBinding(nsDiskCacheBinding * binding)
|
|||
// end of line: insert here or die
|
||||
p = (nsDiskCacheBinding *)PR_PREV_LINK(p); // back up and check generation
|
||||
if (p->mGeneration == 255) {
|
||||
NS_ASSERTION(p->mGeneration < 255, "generation capacity at full, the engines canna take it cap'n");
|
||||
NS_WARNING("### disk cache: generation capacity at full");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
PR_INSERT_BEFORE(binding, hashEntry->mBinding);
|
||||
|
@ -355,16 +355,20 @@ nsDiskCacheBindery::RemoveBinding(nsDiskCacheBinding * binding)
|
|||
HashTableEntry * hashEntry;
|
||||
void * key = (void *)binding->mRecord.HashNumber();
|
||||
|
||||
hashEntry = (HashTableEntry*) PL_DHashTableOperate(&table, (void*) key, PL_DHASH_LOOKUP);
|
||||
hashEntry = (HashTableEntry*) PL_DHashTableOperate(&table,
|
||||
(void*) key,
|
||||
PL_DHASH_LOOKUP);
|
||||
if (!PL_DHASH_ENTRY_IS_BUSY(hashEntry)) {
|
||||
NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(hashEntry), "binding not in disk cache hashtable!");
|
||||
NS_WARNING("### disk cache: binding not in hashtable!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (binding == hashEntry->mBinding) {
|
||||
if (PR_CLIST_IS_EMPTY(binding)) {
|
||||
// remove this hash entry
|
||||
(void) PL_DHashTableOperate(&table, (void*) binding->mRecord.HashNumber(), PL_DHASH_REMOVE);
|
||||
(void) PL_DHashTableOperate(&table,
|
||||
(void*) binding->mRecord.HashNumber(),
|
||||
PL_DHASH_REMOVE);
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
@ -374,3 +378,46 @@ nsDiskCacheBindery::RemoveBinding(nsDiskCacheBinding * binding)
|
|||
}
|
||||
PR_REMOVE_AND_INIT_LINK(binding);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ActiveBinding : PLDHashTable enumerate function to verify active bindings
|
||||
*/
|
||||
|
||||
PLDHashOperator PR_CALLBACK
|
||||
ActiveBinding(PLDHashTable * table,
|
||||
PLDHashEntryHdr * hdr,
|
||||
PRUint32 number,
|
||||
void * arg)
|
||||
{
|
||||
nsDiskCacheBinding * binding = ((HashTableEntry *)hdr)->mBinding;
|
||||
NS_ASSERTION(binding, "### disk cache binding = nsnull!");
|
||||
|
||||
nsDiskCacheBinding * head = binding;
|
||||
do {
|
||||
if (binding->IsActive()) {
|
||||
*((PRBool *)arg) = PR_TRUE;
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
|
||||
} while (binding != head);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ActiveBindings : return PR_TRUE if any bindings have open descriptors
|
||||
*/
|
||||
PRBool
|
||||
nsDiskCacheBindery::ActiveBindings()
|
||||
{
|
||||
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
||||
if (!initialized) return PR_FALSE;
|
||||
|
||||
PRBool activeBinding = PR_FALSE;
|
||||
PL_DHashTableEnumerate(&table, ActiveBinding, &activeBinding);
|
||||
|
||||
return activeBinding;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
virtual ~nsDiskCacheBinding();
|
||||
|
||||
nsresult EnsureStreamIO();
|
||||
PRBool IsActive() { return mCacheEntry != nsnull;}
|
||||
|
||||
// XXX make friends
|
||||
public:
|
||||
|
@ -114,9 +115,11 @@ public:
|
|||
nsDiskCacheBinding * FindBinding(nsDiskCacheRecord * record);
|
||||
nsresult AddBinding(nsDiskCacheBinding * binding);
|
||||
void RemoveBinding(nsDiskCacheBinding * binding);
|
||||
PRBool ActiveBindings();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// member variables
|
||||
static PLDHashTableOps ops;
|
||||
PLDHashTable table;
|
||||
|
|
|
@ -103,11 +103,14 @@ error_exit:
|
|||
* Close
|
||||
*****************************************************************************/
|
||||
nsresult
|
||||
nsDiskCacheBlockFile::Close()
|
||||
nsDiskCacheBlockFile::Close(PRBool flush)
|
||||
{
|
||||
if (!mFD) return NS_OK;
|
||||
|
||||
nsresult rv = FlushBitMap();
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (flush)
|
||||
rv = FlushBitMap();
|
||||
|
||||
PRStatus err = PR_Close(mFD);
|
||||
mFD = nsnull;
|
||||
|
||||
|
@ -285,6 +288,7 @@ nsDiskCacheBlockFile::WriteBlocks( void * buffer,
|
|||
if (bytesWritten < bytesToWrite) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// write the bit map and flush the file
|
||||
// XXX except we would take a severe performance hit
|
||||
// XXX rv = FlushBitMap();
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -46,10 +46,10 @@ public:
|
|||
, mBitMap(nsnull)
|
||||
, mBitMapDirty(PR_FALSE)
|
||||
{}
|
||||
~nsDiskCacheBlockFile() { (void) Close(); }
|
||||
~nsDiskCacheBlockFile() { (void) Close(PR_TRUE); }
|
||||
|
||||
nsresult Open( nsILocalFile * blockFile, PRUint32 blockSize);
|
||||
nsresult Close();
|
||||
nsresult Close(PRBool flush);
|
||||
nsresult Trim();
|
||||
PRInt32 AllocateBlocks( PRInt32 numBlocks);
|
||||
nsresult DeallocateBlocks( PRInt32 startBlock, PRInt32 numBlocks);
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
// XXX add necessary include file for ftruncate (or equivalent)
|
||||
#endif
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "prthread.h"
|
||||
|
||||
#if defined(XP_MAC)
|
||||
#include "pprio.h"
|
||||
#else
|
||||
|
@ -45,6 +48,7 @@
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
#include "nsDiskCacheDevice.h"
|
||||
#include "nsDiskCacheEntry.h"
|
||||
#include "nsDiskCacheMap.h"
|
||||
|
@ -56,13 +60,13 @@
|
|||
#include "nsCache.h"
|
||||
|
||||
#include "nsICacheVisitor.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
static const char DISK_CACHE_DEVICE_ID[] = { "disk" };
|
||||
|
||||
|
@ -134,10 +138,9 @@ nsDiskCacheEvictor::VisitRecord(nsDiskCacheRecord * mapRecord)
|
|||
|
||||
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.
|
||||
// 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
|
||||
|
@ -318,6 +321,7 @@ nsDiskCacheDevice::nsDiskCacheDevice()
|
|||
: mCacheCapacity(0)
|
||||
, mCacheMap(nsnull)
|
||||
, mInitialized(PR_FALSE)
|
||||
, mFirstInit(PR_TRUE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -342,33 +346,19 @@ nsDiskCacheDevice::Init()
|
|||
rv = mBindery.Init();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// XXX we should spawn another thread to do this after startup
|
||||
// delete "Cache.Trash" folder
|
||||
nsCOMPtr<nsIFile> cacheTrashDir;
|
||||
rv = GetCacheTrashDirectory(getter_AddRefs(cacheTrashDir));
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
(void) cacheTrashDir->Remove(PR_TRUE); // ignore errors, we tried...
|
||||
|
||||
// Try opening cache map file.
|
||||
mCacheMap = new nsDiskCacheMap;
|
||||
if (!mCacheMap) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
// Open Disk Cache
|
||||
rv = OpenDiskCache();
|
||||
if (NS_FAILED(rv)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
rv = mCacheMap->Open(mCacheDirectory);
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = InitializeCacheDirectory(); // retry one time
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
}
|
||||
|
||||
mInitialized = PR_TRUE;
|
||||
mFirstInit = PR_FALSE;
|
||||
return NS_OK;
|
||||
|
||||
error_exit:
|
||||
// XXX de-install observers?
|
||||
if (mCacheMap) {
|
||||
(void) mCacheMap->Close();
|
||||
(void) mCacheMap->Close(PR_FALSE);
|
||||
delete mCacheMap;
|
||||
mCacheMap = nsnull;
|
||||
}
|
||||
|
@ -383,12 +373,19 @@ error_exit:
|
|||
nsresult
|
||||
nsDiskCacheDevice::Shutdown()
|
||||
{
|
||||
if (Initialized()) {
|
||||
return Shutdown_Private(PR_TRUE);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheDevice::Shutdown_Private(PRBool flush)
|
||||
{
|
||||
if (Initialized()) {
|
||||
// check cache limits in case we need to evict.
|
||||
EvictDiskCacheEntries((PRInt32)mCacheCapacity);
|
||||
|
||||
// write out persistent information about the cache.
|
||||
(void) mCacheMap->Close();
|
||||
(void) mCacheMap->Close(flush);
|
||||
delete mCacheMap;
|
||||
mCacheMap = nsnull;
|
||||
|
||||
|
@ -401,22 +398,6 @@ nsDiskCacheDevice::Shutdown()
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheDevice::Create(nsCacheDevice **result)
|
||||
{
|
||||
nsDiskCacheDevice * device = new nsDiskCacheDevice();
|
||||
if (!device) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = device->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
delete device;
|
||||
device = nsnull;
|
||||
}
|
||||
*result = device;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
nsDiskCacheDevice::GetDeviceID()
|
||||
{
|
||||
|
@ -444,7 +425,7 @@ nsDiskCacheDevice::FindEntry(nsCString * key)
|
|||
|
||||
#if DEBUG /*because we shouldn't be called for active entries */
|
||||
binding = mBindery.FindActiveBinding(hashNumber);
|
||||
NS_ASSERTION(!binding, "### FindEntry() called for a bound entry.");
|
||||
NS_ASSERTION(!binding, "FindEntry() called for a bound entry.");
|
||||
binding = nsnull;
|
||||
#endif
|
||||
|
||||
|
@ -580,11 +561,12 @@ 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.");
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),"DoomRecord failed.");
|
||||
binding->mDoomed = PR_TRUE; // record in no longer in cache map
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* NOTE: called while holding the cache service lock
|
||||
*/
|
||||
|
@ -609,6 +591,7 @@ nsDiskCacheDevice::OpenInputStreamForEntry(nsCacheEntry * entry,
|
|||
return binding->mStreamIO->GetInputStream(offset, result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* NOTE: called while holding the cache service lock
|
||||
*/
|
||||
|
@ -785,8 +768,17 @@ nsDiskCacheDevice::Visit(nsICacheVisitor * visitor)
|
|||
nsresult
|
||||
nsDiskCacheDevice::EvictEntries(const char * clientID)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (clientID == nsnull) {
|
||||
// we're clearing the entire disk cache
|
||||
rv = ClearDiskCache();
|
||||
if (NS_SUCCEEDED(rv) || (rv != NS_ERROR_CACHE_IN_USE))
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsDiskCacheEvictor evictor(this, mCacheMap, &mBindery, 0, clientID);
|
||||
nsresult rv = mCacheMap->VisitRecords(&evictor);
|
||||
rv = mCacheMap->VisitRecords(&evictor);
|
||||
|
||||
if (clientID == nsnull) // we tried to clear the entire cache
|
||||
rv = mCacheMap->Trim(); // so trim cache block files (if possible)
|
||||
|
@ -802,54 +794,8 @@ nsDiskCacheDevice::EvictEntries(const char * clientID)
|
|||
#pragma mark PRIVATE METHODS
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsDiskCacheDevice::InitializeCacheDirectory()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// recursively delete the disk cache directory.
|
||||
rv = mCacheDirectory->Remove(PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
// try moving it aside
|
||||
|
||||
// create "Cache.Trash" directory if necessary
|
||||
nsCOMPtr<nsIFile> cacheTrashDir;
|
||||
rv = GetCacheTrashDirectory(getter_AddRefs(cacheTrashDir));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRBool exists = PR_FALSE;
|
||||
rv = cacheTrashDir->Exists(&exists);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!exists) {
|
||||
// create the "Cache.Trash" directory
|
||||
rv = cacheTrashDir->Create(nsIFile::DIRECTORY_TYPE,0777);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// create a directory with unique name to contain existing cache directory
|
||||
rv = cacheTrashDir->AppendNative(NS_LITERAL_CSTRING("Cache"));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = cacheTrashDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// move existing cache directory into profileDir/Cache.Trash/CacheUnique
|
||||
nsCOMPtr<nsIFile> existingCacheDir;
|
||||
rv = mCacheDirectory->Clone(getter_AddRefs(existingCacheDir));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = existingCacheDir->MoveToNative(cacheTrashDir, nsCString());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
rv = mCacheDirectory->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// reopen the cache map
|
||||
rv = mCacheMap->Open(mCacheDirectory);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// "Cache.Trash" directory is a sibling of the "Cache" directory
|
||||
nsresult
|
||||
nsDiskCacheDevice::GetCacheTrashDirectory(nsIFile ** result)
|
||||
{
|
||||
|
@ -865,6 +811,261 @@ nsDiskCacheDevice::GetCacheTrashDirectory(nsIFile ** result)
|
|||
}
|
||||
|
||||
|
||||
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 cacheDirExists;
|
||||
rv = mCacheDirectory->Exists(&cacheDirExists);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (cacheDirExists) {
|
||||
rv = mCacheMap->Open(mCacheDirectory);
|
||||
// move "corrupt" caches to trash
|
||||
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
||||
rv = MoveCacheToTrash(nsnull); // ignore returned dir name
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
cacheDirExists = PR_FALSE;
|
||||
|
||||
} else if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// if we don't have a cache directory, create one and open it
|
||||
if (!cacheDirExists) {
|
||||
rv = InitializeCacheDirectory();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (! mFirstInit) return NS_OK; // we're done
|
||||
|
||||
// Empty Cache Trash
|
||||
PRBool trashDirExists;
|
||||
nsCOMPtr<nsIFile> trashDir;
|
||||
rv = GetCacheTrashDirectory(getter_AddRefs(trashDir));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = trashDir->Exists(&trashDirExists);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (trashDirExists) {
|
||||
nsCOMArray<nsIFile> * trashList;
|
||||
rv = ListTrashContents(&trashList);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = DeleteFiles(trashList); // spin up thread to delete contents
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheDevice::ClearDiskCache()
|
||||
{
|
||||
if (mBindery.ActiveBindings()) return NS_ERROR_CACHE_IN_USE;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIFile> trashDir;
|
||||
nsCOMArray<nsIFile> * deleteList = new nsCOMArray<nsIFile>;
|
||||
if (!deleteList) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = Shutdown_Private(PR_FALSE); // false = don't bother flushing
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
|
||||
rv = MoveCacheToTrash(getter_AddRefs(trashDir));
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
rv = deleteList->AppendObject(trashDir);
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
rv = DeleteFiles(deleteList);
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
|
||||
rv = Init();
|
||||
return rv;
|
||||
|
||||
error_exit:
|
||||
delete deleteList;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// function passed to PR_CreateThread
|
||||
void
|
||||
DoDeleteFileList(void *arg)
|
||||
{
|
||||
nsCOMArray<nsIFile> * fileList = NS_STATIC_CAST(nsCOMArray<nsIFile> *, arg);
|
||||
nsresult rv;
|
||||
|
||||
// iterate over items in fileList, recursively deleting each
|
||||
PRInt32 count = fileList->Count();
|
||||
for (PRInt32 i=0; i<count; i++) {
|
||||
nsIFile * item = fileList->ObjectAt(i);
|
||||
CACHE_LOG_PATH(PR_LOG_ALWAYS, "deleting: %s\n", item);
|
||||
|
||||
rv = item->Remove(PR_TRUE);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),"failure cleaning up cache");
|
||||
}
|
||||
|
||||
delete fileList; // destroy nsCOMArray
|
||||
}
|
||||
|
||||
|
||||
#define DEFAULT_STACK_SIZE 0
|
||||
|
||||
nsresult
|
||||
nsDiskCacheDevice::DeleteFiles(nsCOMArray<nsIFile> * fileList)
|
||||
{
|
||||
// start up another thread to delete deleteDir
|
||||
PRThread * thread;
|
||||
thread = PR_CreateThread(PR_USER_THREAD,
|
||||
DoDeleteFileList,
|
||||
fileList,
|
||||
PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD,
|
||||
PR_UNJOINABLE_THREAD,
|
||||
DEFAULT_STACK_SIZE);
|
||||
|
||||
if (!thread) return NS_ERROR_UNEXPECTED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ListTrashContents - return pointer to array of nsIFile to delete
|
||||
*/
|
||||
nsresult
|
||||
nsDiskCacheDevice::ListTrashContents(nsCOMArray<nsIFile> ** result)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIFile> trashDir;
|
||||
*result = nsnull;
|
||||
|
||||
// does "Cache.Trash" directory exist?
|
||||
rv = GetCacheTrashDirectory(getter_AddRefs(trashDir));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
PRBool exists;
|
||||
rv = trashDir->Exists(&exists);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!exists) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMArray<nsIFile> * array = new nsCOMArray<nsIFile>;
|
||||
if (!array) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// iterate over trash directory building array of directory objects
|
||||
nsCOMPtr<nsISimpleEnumerator> dirEntries;
|
||||
nsCOMPtr<nsIFile> item;
|
||||
PRBool more, success;
|
||||
|
||||
rv = trashDir->GetDirectoryEntries(getter_AddRefs(dirEntries));
|
||||
if (NS_FAILED(rv) || !dirEntries) goto error_exit; // !dirEntries returns NS_OK
|
||||
|
||||
rv = dirEntries->HasMoreElements(&more);
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
|
||||
while (more) {
|
||||
rv = dirEntries->GetNext(getter_AddRefs(item));
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
|
||||
success = array->AppendObject(item);
|
||||
if (!success) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
rv = dirEntries->HasMoreElements(&more);
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
}
|
||||
|
||||
// return resulting array
|
||||
*result = array;
|
||||
return NS_OK;
|
||||
|
||||
error_exit:
|
||||
delete array;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// Move 'Cache' dir into unique directory inside 'Cache.Trash', return name of unique directory
|
||||
nsresult
|
||||
nsDiskCacheDevice::MoveCacheToTrash(nsIFile ** result)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIFile> trashDir;
|
||||
|
||||
if (result) *result = nsnull;
|
||||
|
||||
rv = GetCacheTrashDirectory(getter_AddRefs(trashDir));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// verify cache.trash exists and is a directory
|
||||
PRBool exists;
|
||||
rv = trashDir->Exists(&exists);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (exists) {
|
||||
PRBool isDirectory;
|
||||
rv = trashDir->IsDirectory(&isDirectory);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!isDirectory) {
|
||||
// delete file or fail
|
||||
rv = trashDir->Remove(PR_FALSE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
exists = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
// cache.trash doesn't exists, so create it
|
||||
rv = trashDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// create unique directory
|
||||
nsCOMPtr<nsIFile> uniqueDir;
|
||||
rv = trashDir->Clone(getter_AddRefs(uniqueDir));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = uniqueDir->AppendNative(NS_LITERAL_CSTRING("Trash"));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = uniqueDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// move cache directory into unique trash directory
|
||||
nsCOMPtr<nsIFile> cacheDir;
|
||||
rv = mCacheDirectory->Clone(getter_AddRefs(cacheDir));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = cacheDir->MoveToNative(uniqueDir, nsCString());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// return unique directory, in case caller wants specifically delete it
|
||||
if (result)
|
||||
NS_ADDREF(*result = uniqueDir);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheDevice::InitializeCacheDirectory()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = mCacheDirectory->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// reopen the cache map
|
||||
rv = mCacheMap->Open(mCacheDirectory);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheDevice::EvictDiskCacheEntries(PRInt32 targetCapacity)
|
||||
{
|
||||
|
@ -908,7 +1109,7 @@ nsDiskCacheDevice::SetCacheParentDirectory(nsILocalFile * parentDir)
|
|||
if (NS_SUCCEEDED(rv) && !exists)
|
||||
rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
if (NS_FAILED(rv)) return;
|
||||
|
||||
|
||||
// ensure cache directory exists
|
||||
nsCOMPtr<nsIFile> directory;
|
||||
|
||||
|
@ -917,32 +1118,7 @@ nsDiskCacheDevice::SetCacheParentDirectory(nsILocalFile * parentDir)
|
|||
rv = directory->AppendNative(NS_LITERAL_CSTRING("Cache"));
|
||||
if (NS_FAILED(rv)) return;
|
||||
|
||||
rv = directory->Exists(&exists);
|
||||
if (NS_SUCCEEDED(rv) && !exists)
|
||||
rv = directory->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
if (NS_FAILED(rv)) return;
|
||||
|
||||
mCacheDirectory = do_QueryInterface(directory);
|
||||
|
||||
// clean up Cache.Trash directories
|
||||
rv = parentDir->Clone(getter_AddRefs(directory));
|
||||
if (NS_FAILED(rv)) return;
|
||||
rv = directory->AppendNative(NS_LITERAL_CSTRING("Cache.Trash"));
|
||||
if (NS_FAILED(rv)) return;
|
||||
|
||||
rv = directory->Exists(&exists);
|
||||
if (NS_SUCCEEDED(rv) && exists)
|
||||
(void) directory->Remove(PR_TRUE);
|
||||
|
||||
// clean up obsolete NewCache directory
|
||||
rv = parentDir->Clone(getter_AddRefs(directory));
|
||||
if (NS_FAILED(rv)) return;
|
||||
rv = directory->AppendNative(NS_LITERAL_CSTRING("NewCache"));
|
||||
if (NS_FAILED(rv)) return;
|
||||
|
||||
rv = directory->Exists(&exists);
|
||||
if (NS_SUCCEEDED(rv) && exists)
|
||||
(void) directory->Remove(PR_TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -973,11 +1149,13 @@ PRUint32 nsDiskCacheDevice::getCacheCapacity()
|
|||
return mCacheCapacity;
|
||||
}
|
||||
|
||||
|
||||
PRUint32 nsDiskCacheDevice::getCacheSize()
|
||||
{
|
||||
return mCacheMap->TotalSize();
|
||||
}
|
||||
|
||||
|
||||
PRUint32 nsDiskCacheDevice::getEntryCount()
|
||||
{
|
||||
return mCacheMap->EntryCount();
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
class nsDiskCacheMap;
|
||||
|
||||
|
@ -41,8 +42,6 @@ public:
|
|||
nsDiskCacheDevice();
|
||||
virtual ~nsDiskCacheDevice();
|
||||
|
||||
static nsresult Create(nsCacheDevice **result);
|
||||
|
||||
virtual nsresult Init();
|
||||
virtual nsresult Shutdown();
|
||||
|
||||
|
@ -87,13 +86,22 @@ public:
|
|||
|
||||
PRBool Initialized() { return mInitialized; }
|
||||
nsDiskCacheMap * CacheMap() { return mCacheMap; }
|
||||
nsresult Shutdown_Private(PRBool flush);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Private methods
|
||||
*/
|
||||
nsresult InitializeCacheDirectory();
|
||||
|
||||
nsresult GetCacheTrashDirectory(nsIFile ** result);
|
||||
nsresult OpenDiskCache();
|
||||
nsresult ClearDiskCache();
|
||||
nsresult DeleteFiles(nsCOMArray<nsIFile> * fileList);
|
||||
nsresult ListTrashContents(nsCOMArray<nsIFile> ** result);
|
||||
nsresult MoveCacheToTrash(nsIFile ** result);
|
||||
nsresult InitializeCacheDirectory();
|
||||
|
||||
|
||||
nsresult EvictDiskCacheEntries(PRInt32 targetCapacity);
|
||||
|
||||
/**
|
||||
|
@ -104,6 +112,7 @@ private:
|
|||
PRUint32 mCacheCapacity; // XXX need soft/hard limits, currentTotal
|
||||
nsDiskCacheMap * mCacheMap;
|
||||
PRPackedBool mInitialized;
|
||||
PRPackedBool mFirstInit;
|
||||
};
|
||||
|
||||
#endif // _nsDiskCacheDevice_h_
|
||||
|
|
|
@ -60,7 +60,7 @@ nsDiskCacheBucket::Unswap()
|
|||
}
|
||||
|
||||
|
||||
PRUint32
|
||||
PRInt32
|
||||
nsDiskCacheBucket::CountRecords()
|
||||
{
|
||||
if (mRecords[0].HashNumber() == 0) return 0;
|
||||
|
@ -135,6 +135,7 @@ nsDiskCacheBucket::VisitEachRecord(nsDiskCacheRecordVisitor * visitor,
|
|||
* File operations
|
||||
*/
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::Open(nsILocalFile * cacheDirectory)
|
||||
{
|
||||
|
@ -151,19 +152,21 @@ nsDiskCacheMap::Open(nsILocalFile * cacheDirectory)
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
rv = localFile->AppendNative(NS_LITERAL_CSTRING("_CACHE_MAP_"));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
||||
// open the file
|
||||
rv = localFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE, 00666, &mMapFD);
|
||||
if (NS_FAILED(rv)) return rv; // unable to open or create file
|
||||
|
||||
if (NS_FAILED(rv)) return NS_ERROR_FILE_CORRUPTED;
|
||||
|
||||
PRBool cacheFilesExist = CacheFilesExist();
|
||||
rv = NS_ERROR_FILE_CORRUPTED; // presume the worst
|
||||
|
||||
// check size of map file
|
||||
PRInt32 mapSize = PR_Available(mMapFD);
|
||||
if (mapSize < 0) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (mapSize == 0) {
|
||||
PRInt32 mapSize = PR_Available(mMapFD);
|
||||
if (mapSize == 0) { // creating a new _CACHE_MAP_
|
||||
|
||||
// block files shouldn't exist if we're creating the _CACHE_MAP_
|
||||
if (cacheFilesExist) goto error_exit;
|
||||
|
||||
// create the file - initialize in memory
|
||||
mHeader.mVersion = nsDiskCache::kCurrentVersion;
|
||||
mHeader.mDataSize = 0;
|
||||
|
@ -176,28 +179,32 @@ nsDiskCacheMap::Open(nsILocalFile * cacheDirectory)
|
|||
memset(mHeader.reserved, 0, nsDiskCacheHeader::kReservedBytes);
|
||||
memset(mBuckets, 0, sizeof(nsDiskCacheBucket) * kBucketsPerTable);
|
||||
|
||||
} else if (mapSize == kCacheMapSize) {
|
||||
} else if (mapSize == kCacheMapSize) { // read existing _CACHE_MAP_
|
||||
|
||||
// if _CACHE_MAP_ exists, so should the block files
|
||||
if (!cacheFilesExist) goto error_exit;
|
||||
|
||||
// read it in
|
||||
PRUint32 bytesRead = PR_Read(mMapFD, &mHeader, kCacheMapSize);
|
||||
if (kCacheMapSize != bytesRead) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
goto error_exit;
|
||||
}
|
||||
if (kCacheMapSize != bytesRead) goto error_exit;
|
||||
|
||||
mHeader.Unswap();
|
||||
if (mHeader.mIsDirty || mHeader.mVersion != nsDiskCache::kCurrentVersion) {
|
||||
rv = NS_ERROR_FILE_CORRUPTED;
|
||||
if (mHeader.mIsDirty ||
|
||||
mHeader.mVersion != nsDiskCache::kCurrentVersion)
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Unswap each bucket
|
||||
PRInt32 total = 0;
|
||||
for (PRUint32 i = 0; i < kBucketsPerTable; ++i) {
|
||||
mBuckets[i].Unswap();
|
||||
total += mBuckets[i].CountRecords();
|
||||
}
|
||||
|
||||
// XXX verify entry count, check size(?)
|
||||
|
||||
// verify entry count
|
||||
if (total != mHeader.mEntryCount) goto error_exit;
|
||||
|
||||
|
||||
} else {
|
||||
rv = NS_ERROR_FILE_CORRUPTED;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
|
@ -212,7 +219,7 @@ nsDiskCacheMap::Open(nsILocalFile * cacheDirectory)
|
|||
return NS_OK;
|
||||
|
||||
error_exit:
|
||||
(void) CloseBlockFiles();
|
||||
(void) CloseBlockFiles(PR_FALSE);
|
||||
|
||||
if (mMapFD) {
|
||||
(void) PR_Close(mMapFD);
|
||||
|
@ -224,22 +231,24 @@ error_exit:
|
|||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::Close()
|
||||
nsDiskCacheMap::Close(PRBool flush)
|
||||
{
|
||||
if (!mMapFD) return NS_OK;
|
||||
|
||||
// close block files
|
||||
nsresult rv = CloseBlockFiles();
|
||||
nsresult rv = CloseBlockFiles(flush);
|
||||
if (NS_FAILED(rv)) goto exit; // this is going to be a mess...
|
||||
|
||||
// write map record buckets
|
||||
rv = FlushBuckets(PR_FALSE); // don't bother swapping buckets back
|
||||
if (NS_FAILED(rv)) goto exit;
|
||||
if (flush) {
|
||||
// write map record buckets
|
||||
rv = FlushBuckets(PR_FALSE); // don't bother swapping buckets back
|
||||
if (NS_FAILED(rv)) goto exit;
|
||||
|
||||
// clear dirty bit
|
||||
mHeader.mIsDirty = PR_FALSE;
|
||||
// clear dirty bit
|
||||
mHeader.mIsDirty = PR_FALSE;
|
||||
|
||||
rv = FlushHeader();
|
||||
rv = FlushHeader();
|
||||
}
|
||||
|
||||
exit:
|
||||
PRStatus err = PR_Close(mMapFD);
|
||||
|
@ -322,16 +331,12 @@ nsresult
|
|||
nsDiskCacheMap::AddRecord( nsDiskCacheRecord * mapRecord,
|
||||
nsDiskCacheRecord * oldRecord)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 hashNumber = mapRecord->HashNumber();
|
||||
nsDiskCacheBucket * bucket;
|
||||
nsDiskCacheBucket * bucket= GetBucketForHashNumber(hashNumber);
|
||||
PRUint32 bucketIndex = GetBucketIndex(hashNumber);
|
||||
int i;
|
||||
|
||||
oldRecord->SetHashNumber(0); // signify no record
|
||||
|
||||
rv = GetBucketForHashNumber(hashNumber, &bucket);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
oldRecord->SetHashNumber(0); // signify no record
|
||||
|
||||
nsDiskCacheRecord * mostEvictable = &bucket->mRecords[0];
|
||||
for (i = 0; i < kRecordsPerBucket; ++i) {
|
||||
|
@ -373,9 +378,7 @@ nsresult
|
|||
nsDiskCacheMap::UpdateRecord( nsDiskCacheRecord * mapRecord)
|
||||
{
|
||||
PRUint32 hashNumber = mapRecord->HashNumber();
|
||||
nsDiskCacheBucket * bucket;
|
||||
nsresult rv = GetBucketForHashNumber(hashNumber, &bucket);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsDiskCacheBucket * bucket = GetBucketForHashNumber(hashNumber);
|
||||
|
||||
for (int i = 0; i < kRecordsPerBucket; ++i) {
|
||||
if (bucket->mRecords[i].HashNumber() == mapRecord->HashNumber()) {
|
||||
|
@ -403,9 +406,7 @@ NS_ASSERTION(mHeader.mEvictionRank[bucketIndex] == bucket->EvictionRank(0),
|
|||
nsresult
|
||||
nsDiskCacheMap::FindRecord( PRUint32 hashNumber, nsDiskCacheRecord * result)
|
||||
{
|
||||
nsDiskCacheBucket * bucket;
|
||||
nsresult rv = GetBucketForHashNumber(hashNumber, &bucket);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsDiskCacheBucket * bucket = GetBucketForHashNumber(hashNumber);
|
||||
|
||||
for (int i = 0; i < kRecordsPerBucket; ++i) {
|
||||
if (bucket->mRecords[i].HashNumber() == 0) break;
|
||||
|
@ -423,20 +424,20 @@ nsDiskCacheMap::FindRecord( PRUint32 hashNumber, nsDiskCacheRecord * result)
|
|||
nsresult
|
||||
nsDiskCacheMap::DeleteRecord( nsDiskCacheRecord * mapRecord)
|
||||
{
|
||||
nsDiskCacheBucket * bucket;
|
||||
nsresult rv = GetBucketForHashNumber(mapRecord->HashNumber(), &bucket);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsDiskCacheBucket * bucket = GetBucketForHashNumber(mapRecord->HashNumber());
|
||||
|
||||
PRUint32 count = bucket->CountRecords();
|
||||
for (PRUint32 i = 0; i < count; ++i) {
|
||||
PRInt32 count = bucket->CountRecords();
|
||||
for (PRInt32 i = 0; i < count; ++i) {
|
||||
if (bucket->mRecords[i].HashNumber() == mapRecord->HashNumber()) {
|
||||
// found it, now delete it.
|
||||
PRUint32 evictionRank = bucket->mRecords[i].EvictionRank();
|
||||
NS_ASSERTION(evictionRank == mapRecord->EvictionRank(), "evictionRank out of sync");
|
||||
if (i != (count - 1)) { // if not the last record, shift last record into opening
|
||||
NS_ASSERTION(evictionRank == mapRecord->EvictionRank(),
|
||||
"evictionRank out of sync");
|
||||
if (i != (count - 1)) {
|
||||
// if not the last record, shift last record into opening
|
||||
bucket->mRecords[i] = bucket->mRecords[count - 1];
|
||||
}
|
||||
bucket->mRecords[count - 1].SetHashNumber(0); // clear last record
|
||||
bucket->mRecords[count - 1].SetHashNumber(0); // clear last record
|
||||
mHeader.mEntryCount--;
|
||||
// update eviction rank
|
||||
PRUint32 bucketIndex = GetBucketIndex(mapRecord->HashNumber());
|
||||
|
@ -444,8 +445,8 @@ nsDiskCacheMap::DeleteRecord( nsDiskCacheRecord * mapRecord)
|
|||
mHeader.mEvictionRank[bucketIndex] = bucket->EvictionRank(0);
|
||||
}
|
||||
|
||||
NS_ASSERTION(mHeader.mEvictionRank[bucketIndex] == bucket->EvictionRank(0),
|
||||
"eviction rank out of sync");
|
||||
NS_ASSERTION(mHeader.mEvictionRank[bucketIndex] ==
|
||||
bucket->EvictionRank(0), "eviction rank out of sync");
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -548,23 +549,42 @@ nsDiskCacheMap::OpenBlockFiles()
|
|||
return NS_OK;
|
||||
|
||||
error_exit:
|
||||
(void)CloseBlockFiles(); // we already have an error to report
|
||||
(void)CloseBlockFiles(PR_FALSE); // we already have an error to report
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::CloseBlockFiles()
|
||||
nsDiskCacheMap::CloseBlockFiles(PRBool flush)
|
||||
{
|
||||
nsresult rv, rv2 = NS_OK;
|
||||
for (int i=0; i < 3; ++i) {
|
||||
rv = mBlockFile[i].Close();
|
||||
rv = mBlockFile[i].Close(flush);
|
||||
if (NS_FAILED(rv)) rv2 = rv; // if one or more errors, report at least one
|
||||
}
|
||||
return rv2;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsDiskCacheMap::CacheFilesExist()
|
||||
{
|
||||
nsCOMPtr<nsILocalFile> blockFile;
|
||||
nsresult rv;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
PRBool exists;
|
||||
rv = GetBlockFileForIndex(i, getter_AddRefs(blockFile));
|
||||
if (NS_FAILED(rv)) return PR_FALSE;
|
||||
|
||||
rv = blockFile->Exists(&exists);
|
||||
if (NS_FAILED(rv) || !exists) return PR_FALSE;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::ReadDiskCacheEntry(nsDiskCacheRecord * record, nsDiskCacheEntry ** result)
|
||||
{
|
||||
|
|
|
@ -321,7 +321,7 @@ struct nsDiskCacheBucket {
|
|||
|
||||
void Swap();
|
||||
void Unswap();
|
||||
PRUint32 CountRecords();
|
||||
PRInt32 CountRecords();
|
||||
PRUint32 EvictionRank(PRUint32 targetRank); // return largest rank in bucket < targetRank
|
||||
PRInt32 VisitEachRecord( nsDiskCacheRecordVisitor * visitor,
|
||||
PRUint32 evictionRank,
|
||||
|
@ -400,7 +400,7 @@ public:
|
|||
{
|
||||
NS_ASSERTION(sizeof(nsDiskCacheHeader) == sizeof(nsDiskCacheBucket), "structure misalignment");
|
||||
}
|
||||
~nsDiskCacheMap() { (void) Close(); }
|
||||
~nsDiskCacheMap() { (void) Close(PR_TRUE); }
|
||||
|
||||
/**
|
||||
* File Operations
|
||||
|
@ -411,7 +411,7 @@ public:
|
|||
* Returns error if it detects change in format or cache wasn't closed.
|
||||
*/
|
||||
nsresult Open( nsILocalFile * cacheDirectory);
|
||||
nsresult Close();
|
||||
nsresult Close(PRBool flush);
|
||||
nsresult Trim();
|
||||
|
||||
// nsresult Flush();
|
||||
|
@ -480,17 +480,17 @@ private:
|
|||
* Private methods
|
||||
*/
|
||||
nsresult OpenBlockFiles();
|
||||
nsresult CloseBlockFiles();
|
||||
nsresult CloseBlockFiles(PRBool flush);
|
||||
PRBool CacheFilesExist();
|
||||
|
||||
PRUint32 CalculateFileIndex(PRUint32 size);
|
||||
|
||||
nsresult GetBlockFileForIndex( PRUint32 index, nsILocalFile ** result);
|
||||
PRUint32 GetBlockSizeForIndex( PRUint32 index);
|
||||
|
||||
nsresult GetBucketForHashNumber( PRUint32 hashNumber, nsDiskCacheBucket ** result)
|
||||
nsDiskCacheBucket * GetBucketForHashNumber( PRUint32 hashNumber)
|
||||
{
|
||||
*result = &mBuckets[GetBucketIndex(hashNumber)];
|
||||
return NS_OK;
|
||||
return &mBuckets[GetBucketIndex(hashNumber)];
|
||||
}
|
||||
|
||||
PRUint32 GetBucketIndex( PRUint32 hashNumber)
|
||||
|
|
Загрузка…
Ссылка в новой задаче