Additional refactoring of disk cache.
git-svn-id: svn://10.0.0.236/branches/DISKCACHE2_BRANCH@94893 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
10
mozilla/netwerk/cache/src/nsCacheEntry.cpp
vendored
10
mozilla/netwerk/cache/src/nsCacheEntry.cpp
vendored
@@ -110,11 +110,11 @@ nsCacheEntry::~nsCacheEntry()
|
||||
|
||||
|
||||
nsresult
|
||||
nsCacheEntry::CreateCacheEntry( const char * key,
|
||||
PRBool streamBased,
|
||||
nsCacheStoragePolicy storagePolicy,
|
||||
nsCacheDevice * device,
|
||||
nsCacheEntry ** result)
|
||||
nsCacheEntry::Create( const char * key,
|
||||
PRBool streamBased,
|
||||
nsCacheStoragePolicy storagePolicy,
|
||||
nsCacheDevice * device,
|
||||
nsCacheEntry ** result)
|
||||
{
|
||||
nsCString* newKey = new nsCString(key);
|
||||
if (!newKey) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
10
mozilla/netwerk/cache/src/nsCacheEntry.h
vendored
10
mozilla/netwerk/cache/src/nsCacheEntry.h
vendored
@@ -55,11 +55,11 @@ public:
|
||||
~nsCacheEntry();
|
||||
|
||||
|
||||
static nsresult CreateCacheEntry( const char * key,
|
||||
PRBool streamBased,
|
||||
nsCacheStoragePolicy storagePolicy,
|
||||
nsCacheDevice * device,
|
||||
nsCacheEntry ** result);
|
||||
static nsresult Create( const char * key,
|
||||
PRBool streamBased,
|
||||
nsCacheStoragePolicy storagePolicy,
|
||||
nsCacheDevice * device,
|
||||
nsCacheEntry ** result);
|
||||
|
||||
nsCString * Key() { return mKey; }
|
||||
|
||||
|
||||
17
mozilla/netwerk/cache/src/nsDiskCache.h
vendored
17
mozilla/netwerk/cache/src/nsDiskCache.h
vendored
@@ -26,5 +26,22 @@
|
||||
#ifndef _nsDiskCache_h_
|
||||
#define _nsDiskCache_h_
|
||||
|
||||
#include "nsCacheEntry.h"
|
||||
|
||||
class nsDiskCacheBindData;
|
||||
|
||||
nsDiskCacheBindData *
|
||||
GetBindDataFromCacheEntry(nsCacheEntry * entry);
|
||||
|
||||
class nsDiskCache {
|
||||
public:
|
||||
enum {
|
||||
kCurrentVersion = 0x00010003 // XXX whats the format?
|
||||
};
|
||||
|
||||
enum { kData, kMetaData };
|
||||
|
||||
static PLDHashNumber Hash(const char* key);
|
||||
};
|
||||
|
||||
#endif // _nsDiskCache_h_
|
||||
|
||||
162
mozilla/netwerk/cache/src/nsDiskCacheBindData.cpp
vendored
162
mozilla/netwerk/cache/src/nsDiskCacheBindData.cpp
vendored
@@ -26,27 +26,51 @@
|
||||
|
||||
#include "nsDiskCacheBindData.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Utility Functions
|
||||
*****************************************************************************/
|
||||
|
||||
nsDiskCacheBindData *
|
||||
GetBindDataFromCacheEntry(nsCacheEntry * entry)
|
||||
{
|
||||
nsCOMPtr<nsISupports> data;
|
||||
nsresult rv = entry->GetData(getter_AddRefs(data));
|
||||
if (NS_FAILED(rv)) return nsnull;
|
||||
|
||||
return (nsDiskCacheBindData *)data.get();
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheBindData
|
||||
*****************************************************************************/
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS0(nsDiskCacheBindData);
|
||||
|
||||
PLDHashNumber
|
||||
nsDiskCacheBindData::Hash(const char* key)
|
||||
nsDiskCacheBindData::nsDiskCacheBindData(nsCacheEntry* entry)
|
||||
: mCacheEntry(entry)
|
||||
{
|
||||
PLDHashNumber h = 0;
|
||||
for (const PRUint8* s = (PRUint8*) key; *s != '\0'; ++s)
|
||||
h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ *s;
|
||||
return (h == 0 ? ULONG_MAX : h);
|
||||
NS_INIT_ISUPPORTS();
|
||||
PR_INIT_CLIST(this);
|
||||
mRecord.SetHashNumber(nsDiskCache::Hash(entry->Key()->get()));
|
||||
}
|
||||
|
||||
nsDiskCacheBindData::~nsDiskCacheBindData()
|
||||
{
|
||||
// XXX if PR_CLIST_IS_EMPTY(this) then remove entry from hashtable
|
||||
PR_REMOVE_LINK(this); // XXX why are we still on a list?
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheHashTable
|
||||
* nsDiskCacheBindery
|
||||
*
|
||||
* Keeps track of bound disk cache entries to detect for collisions.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
PLDHashTableOps nsDiskCacheHashTable::ops =
|
||||
PLDHashTableOps nsDiskCacheBindery::ops =
|
||||
{
|
||||
PL_DHashAllocTable,
|
||||
PL_DHashFreeTable,
|
||||
@@ -59,13 +83,13 @@ PLDHashTableOps nsDiskCacheHashTable::ops =
|
||||
};
|
||||
|
||||
|
||||
nsDiskCacheHashTable::nsDiskCacheHashTable()
|
||||
nsDiskCacheBindery::nsDiskCacheBindery()
|
||||
: initialized(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
nsDiskCacheHashTable::~nsDiskCacheHashTable()
|
||||
nsDiskCacheBindery::~nsDiskCacheBindery()
|
||||
{
|
||||
if (initialized)
|
||||
PL_DHashTableFinish(&table);
|
||||
@@ -73,7 +97,7 @@ nsDiskCacheHashTable::~nsDiskCacheHashTable()
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheHashTable::Init()
|
||||
nsDiskCacheBindery::Init()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
initialized = PL_DHashTableInit(&table, &ops, nsnull,
|
||||
@@ -85,137 +109,171 @@ nsDiskCacheHashTable::Init()
|
||||
}
|
||||
|
||||
|
||||
// XXX need to have nsDiskCacheRecord passed in
|
||||
nsDiskCacheBindData *
|
||||
nsDiskCacheHashTable::GetEntry(const char * key)
|
||||
nsDiskCacheBindery::CreateBindDataForCacheEntry(nsCacheEntry * entry)
|
||||
{
|
||||
return GetEntry(nsDiskCacheBindData::Hash(key));
|
||||
nsCOMPtr<nsISupports> data;
|
||||
nsresult rv = entry->GetData(getter_AddRefs(data));
|
||||
if (NS_FAILED(rv) || data) {
|
||||
NS_ASSERTION(!data, "cache entry already has bind data");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsDiskCacheBindData * bindData = new nsDiskCacheBindData(entry);
|
||||
if (!bindData) return nsnull;
|
||||
|
||||
data = bindData; // add ref
|
||||
entry->SetData(data.get()); // XXX why .get() ?
|
||||
|
||||
// XXX add bindData to collision detection system
|
||||
|
||||
return bindData;
|
||||
}
|
||||
|
||||
|
||||
// XXX if we read an entry off of disk (FindEntry)
|
||||
// XXX - it may already have a generation number
|
||||
// XXX - generation number conflict is an error
|
||||
// XXX new entries (BindEntry)
|
||||
// XXX - assign generation number
|
||||
|
||||
// XXX FindActiveBindData(hashNumber) // there can be only one
|
||||
// XXX FindBindData(hashNumber, generation)
|
||||
|
||||
// XXX UnbindEntry(nsDiskCacheBindData * bindData); // called from DeactivateEntry()
|
||||
|
||||
nsDiskCacheBindData *
|
||||
nsDiskCacheBindery::GetEntry(const char * key)
|
||||
{
|
||||
return GetEntry(nsDiskCache::Hash(key));
|
||||
}
|
||||
|
||||
|
||||
nsDiskCacheBindData *
|
||||
nsDiskCacheHashTable::GetEntry(PLDHashNumber key)
|
||||
nsDiskCacheBindery::GetEntry(PLDHashNumber key)
|
||||
{
|
||||
nsDiskCacheBindData * result = nsnull;
|
||||
NS_ASSERTION(initialized, "nsDiskCacheHashTable not initialized");
|
||||
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
||||
HashTableEntry * hashEntry;
|
||||
hashEntry = (HashTableEntry*) PL_DHashTableOperate(&table, (void*) key, PL_DHASH_LOOKUP);
|
||||
if (PL_DHASH_ENTRY_IS_BUSY(hashEntry)) {
|
||||
result = hashEntry->mDiskCacheBindData;
|
||||
result = hashEntry->mBindData;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheHashTable::AddEntry(nsDiskCacheBindData * entry)
|
||||
nsDiskCacheBindery::AddEntry(nsDiskCacheBindData * bindData)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(entry);
|
||||
NS_ASSERTION(initialized, "nsDiskCacheHashTable not initialized");
|
||||
NS_ENSURE_ARG_POINTER(bindData);
|
||||
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
||||
|
||||
HashTableEntry * hashEntry;
|
||||
hashEntry = (HashTableEntry *) PL_DHashTableOperate(&table,
|
||||
(void*) entry->getHashNumber(),
|
||||
(void*) bindData->mRecord.HashNumber(),
|
||||
PL_DHASH_ADD);
|
||||
if (!hashEntry) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(hashEntry->mDiskCacheBindData = entry);
|
||||
NS_ADDREF(hashEntry->mBindData = bindData);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsDiskCacheHashTable::RemoveEntry(nsDiskCacheBindData * entry)
|
||||
nsDiskCacheBindery::RemoveEntry(nsDiskCacheBindData * bindData)
|
||||
{
|
||||
NS_ASSERTION(initialized, "nsDiskCacheHashTable not initialized");
|
||||
NS_ASSERTION(entry, "### cacheEntry == nsnull");
|
||||
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
||||
NS_ASSERTION(bindData, "### bindData == nsnull");
|
||||
|
||||
(void) PL_DHashTableOperate(&table, (void*) entry->getHashNumber(), PL_DHASH_REMOVE);
|
||||
(void) PL_DHashTableOperate(&table, (void*) bindData->mRecord.HashNumber(), PL_DHASH_REMOVE);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsDiskCacheHashTable::VisitEntries(Visitor *visitor)
|
||||
nsDiskCacheBindery::VisitEntries(Visitor *visitor)
|
||||
{
|
||||
PL_DHashTableEnumerate(&table, VisitEntry, visitor);
|
||||
}
|
||||
|
||||
|
||||
PLDHashOperator PR_CALLBACK
|
||||
nsDiskCacheHashTable::VisitEntry(PLDHashTable * table,
|
||||
PLDHashEntryHdr * header,
|
||||
PRUint32 number,
|
||||
void * arg)
|
||||
nsDiskCacheBindery::VisitEntry(PLDHashTable * table,
|
||||
PLDHashEntryHdr * header,
|
||||
PRUint32 number,
|
||||
void * arg)
|
||||
{
|
||||
HashTableEntry* hashEntry = (HashTableEntry *) header;
|
||||
Visitor *visitor = (Visitor*) arg;
|
||||
return (visitor->VisitEntry(hashEntry->mDiskCacheBindData) ? PL_DHASH_NEXT : PL_DHASH_STOP);
|
||||
return (visitor->VisitEntry(hashEntry->mBindData) ? PL_DHASH_NEXT : PL_DHASH_STOP);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash table operation callback functions
|
||||
*/
|
||||
const void * PR_CALLBACK
|
||||
nsDiskCacheHashTable::GetKey(PLDHashTable * /*table*/, PLDHashEntryHdr * header)
|
||||
nsDiskCacheBindery::GetKey(PLDHashTable * /*table*/, PLDHashEntryHdr * header)
|
||||
{
|
||||
HashTableEntry * hashEntry = (HashTableEntry *) header;
|
||||
return (void*) hashEntry->mDiskCacheBindData->getHashNumber();
|
||||
return (void*) hashEntry->mBindData->mRecord.HashNumber();
|
||||
}
|
||||
|
||||
|
||||
PLDHashNumber PR_CALLBACK
|
||||
nsDiskCacheHashTable::HashKey( PLDHashTable *table, const void *key)
|
||||
nsDiskCacheBindery::HashKey( PLDHashTable *table, const void *key)
|
||||
{
|
||||
return (PLDHashNumber) key;
|
||||
}
|
||||
|
||||
|
||||
PRBool PR_CALLBACK
|
||||
nsDiskCacheHashTable::MatchEntry(PLDHashTable * /* table */,
|
||||
const PLDHashEntryHdr * header,
|
||||
const void * key)
|
||||
nsDiskCacheBindery::MatchEntry(PLDHashTable * /* table */,
|
||||
const PLDHashEntryHdr * header,
|
||||
const void * key)
|
||||
{
|
||||
HashTableEntry * hashEntry = (HashTableEntry *) header;
|
||||
return (hashEntry->mDiskCacheBindData->getHashNumber() == (PLDHashNumber) key);
|
||||
return (hashEntry->mBindData->mRecord.HashNumber() == (PLDHashNumber) key);
|
||||
}
|
||||
|
||||
void PR_CALLBACK
|
||||
nsDiskCacheHashTable::MoveEntry(PLDHashTable * /* table */,
|
||||
const PLDHashEntryHdr * fromHeader,
|
||||
PLDHashEntryHdr * toHeader)
|
||||
nsDiskCacheBindery::MoveEntry(PLDHashTable * /* table */,
|
||||
const PLDHashEntryHdr * fromHeader,
|
||||
PLDHashEntryHdr * toHeader)
|
||||
{
|
||||
HashTableEntry * fromEntry = (HashTableEntry *) fromHeader;
|
||||
HashTableEntry * toEntry = (HashTableEntry *) toHeader;
|
||||
toEntry->keyHash = fromEntry->keyHash;
|
||||
toEntry->mDiskCacheBindData = fromEntry->mDiskCacheBindData;
|
||||
fromEntry->mDiskCacheBindData = nsnull;
|
||||
toEntry->mBindData = fromEntry->mBindData;
|
||||
fromEntry->mBindData = nsnull;
|
||||
}
|
||||
|
||||
|
||||
void PR_CALLBACK
|
||||
nsDiskCacheHashTable::ClearEntry(PLDHashTable * /* table */,
|
||||
PLDHashEntryHdr * header)
|
||||
nsDiskCacheBindery::ClearEntry(PLDHashTable * /* table */,
|
||||
PLDHashEntryHdr * header)
|
||||
{
|
||||
HashTableEntry* hashEntry = (HashTableEntry *) header;
|
||||
hashEntry->keyHash = 0;
|
||||
NS_IF_RELEASE(hashEntry->mDiskCacheBindData);
|
||||
NS_IF_RELEASE(hashEntry->mBindData);
|
||||
}
|
||||
|
||||
|
||||
void PR_CALLBACK
|
||||
nsDiskCacheHashTable::Finalize(PLDHashTable * table)
|
||||
nsDiskCacheBindery::Finalize(PLDHashTable * table)
|
||||
{
|
||||
(void) PL_DHashTableEnumerate(table, FreeCacheEntries, nsnull);
|
||||
}
|
||||
|
||||
|
||||
PLDHashOperator PR_CALLBACK
|
||||
nsDiskCacheHashTable::FreeCacheEntries(PLDHashTable * /* table */,
|
||||
PLDHashEntryHdr * header,
|
||||
PRUint32 number,
|
||||
void * arg)
|
||||
nsDiskCacheBindery::FreeCacheEntries(PLDHashTable * /* table */,
|
||||
PLDHashEntryHdr * header,
|
||||
PRUint32 number,
|
||||
void * arg)
|
||||
{
|
||||
HashTableEntry *entry = (HashTableEntry *) header;
|
||||
NS_IF_RELEASE(entry->mDiskCacheBindData);
|
||||
NS_IF_RELEASE(entry->mBindData);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
96
mozilla/netwerk/cache/src/nsDiskCacheBindData.h
vendored
96
mozilla/netwerk/cache/src/nsDiskCacheBindData.h
vendored
@@ -36,6 +36,8 @@
|
||||
#include "nsITransport.h"
|
||||
#endif
|
||||
|
||||
#include "nsDiskCacheMap.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheBindData
|
||||
@@ -50,19 +52,8 @@ class nsDiskCacheBindData : public nsISupports, public PRCList {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsDiskCacheBindData(nsCacheEntry* entry)
|
||||
: mCacheEntry(entry),
|
||||
mGeneration(0)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
PR_INIT_CLIST(this);
|
||||
mHashNumber = Hash(entry->Key()->get());
|
||||
}
|
||||
|
||||
virtual ~nsDiskCacheBindData()
|
||||
{
|
||||
PR_REMOVE_LINK(this);
|
||||
}
|
||||
nsDiskCacheBindData(nsCacheEntry* entry);
|
||||
virtual ~nsDiskCacheBindData();
|
||||
|
||||
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
|
||||
/**
|
||||
@@ -75,62 +66,65 @@ public:
|
||||
return mTransports[mode - 1];
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCacheEntry* getCacheEntry()
|
||||
{
|
||||
return mCacheEntry;
|
||||
}
|
||||
|
||||
PRUint32 getGeneration()
|
||||
{
|
||||
return mGeneration;
|
||||
}
|
||||
|
||||
void setGeneration(PRUint32 generation)
|
||||
{
|
||||
mGeneration = generation;
|
||||
}
|
||||
|
||||
PLDHashNumber getHashNumber()
|
||||
{
|
||||
return mHashNumber;
|
||||
}
|
||||
|
||||
nsrefcnt getRefCount()
|
||||
{
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
static PLDHashNumber Hash(const char* key);
|
||||
|
||||
|
||||
|
||||
// XXX make friends
|
||||
public:
|
||||
nsDiskCacheRecord mRecord;
|
||||
PRInt32 mGeneration; // possibly just reservation
|
||||
nsCacheEntry* mCacheEntry; // back pointer to parent nsCacheEntry
|
||||
|
||||
private:
|
||||
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
|
||||
nsCOMPtr<nsITransport> mTransports[3];
|
||||
#endif
|
||||
nsCacheEntry* mCacheEntry; // back pointer to parent nsCacheEntry
|
||||
PRUint32 mGeneration; // XXX part of nsDiskCacheRecord
|
||||
PLDHashNumber mHashNumber; // XXX part of nsDiskCacheRecord
|
||||
// XXX nsDiskCacheRecord mMapRecord;
|
||||
};
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheHashTable
|
||||
* Utility Functions
|
||||
*****************************************************************************/
|
||||
|
||||
nsDiskCacheBindData * GetBindDataFromCacheEntry(nsCacheEntry * entry);
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheBindery
|
||||
*
|
||||
* Used to keep track of nsDiskCacheEntries associated with active/bound (and
|
||||
* Used to keep track of nsDiskCacheBindData associated with active/bound (and
|
||||
* possibly doomed) entries. Lookups on 4 byte disk hash to find collisions
|
||||
* (which need to be doomed, instead of just evicted. Collisions are linked
|
||||
* using a PRCList to keep track of current generation number.
|
||||
*
|
||||
* Used to detect hash number collisions, and find available generation numbers.
|
||||
*
|
||||
* Not all nsDiskCacheBindData have a generation number.
|
||||
*
|
||||
* Generation numbers may be aquired late, or lost (when data fits in block file)
|
||||
*
|
||||
* Collisions can occur:
|
||||
* BindEntry() - hashnumbers collide (possibly different keys)
|
||||
*
|
||||
* Generation number required:
|
||||
* DeactivateEntry() - metadata written to disk, may require file
|
||||
* GetFileForEntry() - force data to require file
|
||||
* writing to stream - data size may require file
|
||||
*
|
||||
* BindData can be kept in PRCList in order of generation numbers.
|
||||
* BindData with no generation number can be Appended to PRCList (last).
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
class nsDiskCacheHashTable {
|
||||
class nsDiskCacheBindery {
|
||||
public:
|
||||
nsDiskCacheHashTable();
|
||||
~nsDiskCacheHashTable();
|
||||
nsDiskCacheBindery();
|
||||
~nsDiskCacheBindery();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
nsDiskCacheBindData * CreateBindDataForCacheEntry(nsCacheEntry * entry);
|
||||
|
||||
nsDiskCacheBindData * GetEntry(const char * key);
|
||||
nsDiskCacheBindData * GetEntry(PLDHashNumber key);
|
||||
nsresult AddEntry(nsDiskCacheBindData * entry);
|
||||
@@ -145,7 +139,7 @@ public:
|
||||
|
||||
private:
|
||||
struct HashTableEntry : PLDHashEntryHdr {
|
||||
nsDiskCacheBindData * mDiskCacheBindData; // STRONG ref?
|
||||
nsDiskCacheBindData * mBindData;
|
||||
};
|
||||
|
||||
// PLDHashTable operation callbacks
|
||||
|
||||
798
mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp
vendored
798
mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp
vendored
File diff suppressed because it is too large
Load Diff
29
mozilla/netwerk/cache/src/nsDiskCacheDevice.h
vendored
29
mozilla/netwerk/cache/src/nsDiskCacheDevice.h
vendored
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "nsCacheDevice.h"
|
||||
#include "nsDiskCacheBindData.h"
|
||||
#include "nsDiskCacheBlockFile.h"
|
||||
#include "nsDiskCacheEntry.h"
|
||||
|
||||
#include "nsILocalFile.h"
|
||||
@@ -80,6 +81,19 @@ public:
|
||||
PRUint32 getCacheSize();
|
||||
PRUint32 getEntryCount();
|
||||
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* Private methods
|
||||
*/
|
||||
nsresult InitializeCacheDirectory();
|
||||
nsresult GetCacheTrashDirectory(nsIFile ** result);
|
||||
nsresult EvictDiskCacheEntries();
|
||||
|
||||
|
||||
#if 0
|
||||
// Old Code
|
||||
nsresult getFileForHashNumber(PLDHashNumber hashNumber, PRBool meta, PRUint32 generation, nsIFile ** result);
|
||||
nsresult getFileForKey(const char* key, PRBool meta, PRUint32 generation, nsIFile ** result);
|
||||
nsresult getFileForDiskCacheEntry(nsDiskCacheBindData * bindData, PRBool meta, nsIFile ** result);
|
||||
@@ -97,27 +111,26 @@ public:
|
||||
nsresult deleteDiskCacheEntry(nsDiskCacheBindData * bindData);
|
||||
|
||||
nsresult scavengeDiskCacheEntries(nsDiskCacheBindData * bindData);
|
||||
|
||||
nsresult evictDiskCacheEntries();
|
||||
|
||||
nsresult InitializeCacheDirectory();
|
||||
|
||||
nsresult openCacheMap();
|
||||
nsresult readCacheMap();
|
||||
nsresult writeCacheMap();
|
||||
|
||||
nsresult updateCacheMap(nsDiskCacheBindData * bindData);
|
||||
|
||||
nsresult evictDiskCacheRecord(nsDiskCacheRecord * record);
|
||||
#endif
|
||||
|
||||
private:
|
||||
/**
|
||||
* Member variables
|
||||
*/
|
||||
PRBool mInitialized;
|
||||
nsCOMPtr<nsIObserver> mPrefsObserver; // XXX ?
|
||||
nsCOMPtr<nsILocalFile> mCacheDirectory;
|
||||
nsDiskCacheHashTable mBoundEntries; // XXX rename to refer to active entries
|
||||
nsDiskCacheBindery mBindery;
|
||||
PRUint32 mCacheCapacity; // XXX need soft/hard limits, currentTotal
|
||||
nsDiskCacheMap* mCacheMap;
|
||||
nsANSIFileStream* mCacheStream; // XXX should be owned by cache map
|
||||
// XXX need array of cache block files
|
||||
nsDiskCacheMap * mCacheMap;
|
||||
};
|
||||
|
||||
#endif // _nsDiskCacheDevice_h_
|
||||
|
||||
158
mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp
vendored
158
mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp
vendored
@@ -22,79 +22,121 @@
|
||||
* Patrick C. Beard <beard@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsDiskCache.h"
|
||||
#include "nsDiskCacheEntry.h"
|
||||
#include "nsDiskCacheBindData.h"
|
||||
#include "nsDiskCacheMap.h"
|
||||
|
||||
#include "nsCache.h"
|
||||
|
||||
|
||||
nsresult MetaDataFile::Read(nsIInputStream* input)
|
||||
/******************************************************************************
|
||||
* nsDiskCacheEntry
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* CreateCacheEntry()
|
||||
*
|
||||
* Creates an nsCacheEntry and sets all fields except for the bindData.
|
||||
*/
|
||||
nsCacheEntry *
|
||||
nsDiskCacheEntry::CreateCacheEntry(nsCacheDevice * device)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 count;
|
||||
nsCacheEntry * entry = nsnull;
|
||||
nsresult rv = nsCacheEntry::Create(mKeyStart,
|
||||
nsICache::STREAM_BASED,
|
||||
nsICache::STORE_ON_DISK,
|
||||
device,
|
||||
&entry);
|
||||
if (NS_FAILED(rv) || !entry) return nsnull;
|
||||
|
||||
// XXX Is it less expensive to read the file in multiple parts, or
|
||||
// XXX get the size and read it in one chunk?
|
||||
// read in the file header.
|
||||
rv = input->Read((char*)&mHeaderSize, sizeof(MetaDataHeader), &count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
Unswap();
|
||||
entry->SetFetchCount(mFetchCount);
|
||||
entry->SetLastFetched(mLastFetched);
|
||||
entry->SetLastModified(mLastModified);
|
||||
entry->SetExpirationTime(mExpirationTime);
|
||||
entry->SetCacheDevice(device);
|
||||
// XXX why does nsCacheService have to fill out device in BindEntry()?
|
||||
entry->SetDataSize(mDataSize);
|
||||
|
||||
// make sure it is self-consistent.
|
||||
if (mHeaderSize != sizeof(MetaDataHeader)) {
|
||||
NS_ERROR("### CACHE FORMAT CHANGED!!! PLEASE DELETE YOUR NewCache DIRECTORY!!! ###");
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
// read in the key.
|
||||
delete[] mKey;
|
||||
mKey = new char[mKeySize];
|
||||
if (!mKey) return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = input->Read(mKey, mKeySize, &count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// read in the metadata.
|
||||
delete mMetaData;
|
||||
mMetaData = nsnull;
|
||||
if (mMetaDataSize) {
|
||||
mMetaData = new char[mMetaDataSize];
|
||||
if (!mMetaData) return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = input->Read(mMetaData, mMetaDataSize, &count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = entry->UnflattenMetaData(&mKeyStart[mKeySize], mMetaDataSize);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete entry;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return entry;
|
||||
}
|
||||
|
||||
nsresult MetaDataFile::Write(nsIOutputStream* output)
|
||||
|
||||
/**
|
||||
* CheckConsistency()
|
||||
*
|
||||
* Perform a few simple checks to verify the data looks reasonable.
|
||||
*/
|
||||
PRBool
|
||||
nsDiskCacheEntry::CheckConsistency(PRUint32 size)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 count;
|
||||
if ((mHeaderVersion != nsDiskCache::kCurrentVersion) ||
|
||||
(Size() > size) ||
|
||||
(mKeySize == 0) ||
|
||||
(mKeyStart[mKeySize - 1] != 0)) // key is null terminated
|
||||
return PR_FALSE;
|
||||
|
||||
// write the header to the file.
|
||||
Swap();
|
||||
rv = output->Write((char*)&mHeaderSize, sizeof(MetaDataHeader), &count);
|
||||
Unswap();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// write the key to the file.
|
||||
rv = output->Write(mKey, mKeySize, &count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// write the flattened metadata to the file.
|
||||
if (mMetaDataSize) {
|
||||
rv = output->Write(mMetaData, mMetaDataSize, &count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CreateDiskCacheEntry(nsCacheEntry * entry)
|
||||
*
|
||||
* Prepare an nsCacheEntry for writing to disk
|
||||
*/
|
||||
nsDiskCacheEntry *
|
||||
CreateDiskCacheEntry(nsDiskCacheBindData * bindData)
|
||||
{
|
||||
nsCacheEntry * entry = bindData->mCacheEntry;
|
||||
if (!entry) return nsnull;
|
||||
|
||||
PRUint32 keySize = entry->Key()->Length() + 1;
|
||||
PRUint32 size = sizeof(nsDiskCacheEntry) +
|
||||
keySize + entry->MetaDataSize();
|
||||
|
||||
nsDiskCacheEntry * diskEntry = (nsDiskCacheEntry *)new char[size];
|
||||
if (!diskEntry) return nsnull;
|
||||
|
||||
diskEntry->mHeaderVersion = nsDiskCache::kCurrentVersion;
|
||||
diskEntry->mMetaLocation = bindData->mRecord.MetaLocation();
|
||||
diskEntry->mFetchCount = entry->FetchCount();
|
||||
diskEntry->mLastFetched = entry->LastFetched();
|
||||
diskEntry->mLastModified = entry->LastModified();
|
||||
diskEntry->mExpirationTime = entry->ExpirationTime();
|
||||
diskEntry->mDataSize = entry->DataSize();
|
||||
diskEntry->mKeySize = keySize;
|
||||
diskEntry->mMetaDataSize = entry->MetaDataSize();
|
||||
|
||||
nsCRT::memcpy(diskEntry->mKeyStart, entry->Key()->get(),keySize);
|
||||
|
||||
char * metaData = nsnull;
|
||||
PRUint32 metaSize = 0;
|
||||
nsresult rv = entry->FlattenMetaData(&metaData, &metaSize);
|
||||
diskEntry->mMetaDataSize = metaSize;
|
||||
if (metaSize)
|
||||
nsCRT::memcpy(&diskEntry->mKeyStart[keySize], metaData, metaSize);
|
||||
|
||||
return diskEntry;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheEntryInfo
|
||||
*****************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsDiskCacheEntryInfo, nsICacheEntryInfo);
|
||||
|
||||
NS_IMETHODIMP nsDiskCacheEntryInfo::GetClientID(char ** clientID)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(clientID);
|
||||
return ClientIDFromCacheKey(nsLiteralCString(mMetaDataFile.mKey), clientID);
|
||||
return ClientIDFromCacheKey(nsLiteralCString(mDiskEntry->mKeyStart), clientID);
|
||||
}
|
||||
|
||||
extern const char DISK_CACHE_DEVICE_ID[];
|
||||
@@ -109,30 +151,30 @@ NS_IMETHODIMP nsDiskCacheEntryInfo::GetDeviceID(char ** deviceID)
|
||||
NS_IMETHODIMP nsDiskCacheEntryInfo::GetKey(char ** clientKey)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(clientKey);
|
||||
return ClientKeyFromCacheKey(nsLiteralCString(mMetaDataFile.mKey), clientKey);
|
||||
return ClientKeyFromCacheKey(nsLiteralCString(mDiskEntry->mKeyStart), clientKey);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDiskCacheEntryInfo::GetFetchCount(PRInt32 *aFetchCount)
|
||||
{
|
||||
return *aFetchCount = mMetaDataFile.mFetchCount;
|
||||
return *aFetchCount = mDiskEntry->mFetchCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDiskCacheEntryInfo::GetLastFetched(PRUint32 *aLastFetched)
|
||||
{
|
||||
*aLastFetched = mMetaDataFile.mLastFetched;
|
||||
*aLastFetched = mDiskEntry->mLastFetched;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDiskCacheEntryInfo::GetLastModified(PRUint32 *aLastModified)
|
||||
{
|
||||
*aLastModified = mMetaDataFile.mLastModified;
|
||||
*aLastModified = mDiskEntry->mLastModified;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDiskCacheEntryInfo::GetExpirationTime(PRUint32 *aExpirationTime)
|
||||
{
|
||||
*aExpirationTime = mMetaDataFile.mExpirationTime;
|
||||
*aExpirationTime = mDiskEntry->mExpirationTime;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -144,6 +186,6 @@ NS_IMETHODIMP nsDiskCacheEntryInfo::IsStreamBased(PRBool *aStreamBased)
|
||||
|
||||
NS_IMETHODIMP nsDiskCacheEntryInfo::GetDataSize(PRUint32 *aDataSize)
|
||||
{
|
||||
*aDataSize = mMetaDataFile.mDataSize;
|
||||
*aDataSize = mDiskEntry->mDataSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
144
mozilla/netwerk/cache/src/nsDiskCacheEntry.h
vendored
144
mozilla/netwerk/cache/src/nsDiskCacheEntry.h
vendored
@@ -25,121 +25,73 @@
|
||||
#ifndef _nsDiskCacheEntry_h_
|
||||
#define _nsDiskCacheEntry_h_
|
||||
|
||||
#include "nsDiskCacheMap.h"
|
||||
|
||||
#include "nsCacheEntry.h"
|
||||
|
||||
#include "nsICacheVisitor.h"
|
||||
|
||||
#include "nspr.h"
|
||||
#include "nscore.h"
|
||||
#include "nsError.h"
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsICacheVisitor.h"
|
||||
|
||||
#include "nsCacheEntry.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* MetaData
|
||||
* nsDiskCacheEntry
|
||||
*****************************************************************************/
|
||||
struct MetaDataHeader {
|
||||
PRUint32 mHeaderSize;
|
||||
// PRUint32 mHashNumber; // XXX
|
||||
// PRUint32 mMetaLocation; // XXX
|
||||
struct nsDiskCacheEntry {
|
||||
PRUint32 mHeaderVersion; // useful for stand-alone metadata files
|
||||
PRUint32 mMetaLocation; // for verification
|
||||
PRInt32 mFetchCount;
|
||||
PRUint32 mLastFetched;
|
||||
PRUint32 mLastModified;
|
||||
PRUint32 mExpirationTime;
|
||||
PRUint32 mDataSize;
|
||||
PRUint32 mKeySize;
|
||||
PRUint32 mMetaDataSize;
|
||||
// void * mKeyPtrSpace; // XXX don't need this
|
||||
// void * mMetaDataPtrSpace; // XXX don't need this, we'll calculate it when necessary
|
||||
// followed by null-terminated key and metadata string values.
|
||||
PRUint32 mKeySize; // includes terminating null byte
|
||||
PRUint32 mMetaDataSize; // includes terminating null byte
|
||||
char mKeyStart[1]; // start of key data
|
||||
// mMetaDataStart = mKeyStart[mKeySize];
|
||||
|
||||
MetaDataHeader()
|
||||
: mHeaderSize(sizeof(MetaDataHeader)),
|
||||
mFetchCount(0),
|
||||
mLastFetched(0),
|
||||
mLastModified(0),
|
||||
mExpirationTime(0),
|
||||
mDataSize(0),
|
||||
mKeySize(0),
|
||||
mMetaDataSize(0)
|
||||
{
|
||||
}
|
||||
PRUint32 Size() { return sizeof(nsDiskCacheEntry) + mKeySize + mMetaDataSize; }
|
||||
|
||||
MetaDataHeader(nsCacheEntry* entry)
|
||||
: mHeaderSize(sizeof(MetaDataHeader)),
|
||||
mFetchCount(entry->FetchCount()),
|
||||
mLastFetched(entry->LastFetched()),
|
||||
mLastModified(entry->LastModified()),
|
||||
mExpirationTime(entry->ExpirationTime()),
|
||||
mDataSize(entry->DataSize()),
|
||||
mKeySize(entry->Key()->Length() + 1),
|
||||
mMetaDataSize(0)
|
||||
nsCacheEntry * CreateCacheEntry(nsCacheDevice * device);
|
||||
|
||||
PRBool CheckConsistency(PRUint32 size);
|
||||
|
||||
void Swap() // host to network (memory to disk)
|
||||
{
|
||||
}
|
||||
|
||||
void Swap()
|
||||
{
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
mHeaderSize = ::PR_htonl(mHeaderSize);
|
||||
mFetchCount = ::PR_htonl(mFetchCount);
|
||||
mLastFetched = ::PR_htonl(mLastFetched);
|
||||
mLastModified = ::PR_htonl(mLastModified);
|
||||
mExpirationTime = ::PR_htonl(mExpirationTime);
|
||||
mDataSize = ::PR_htonl(mDataSize);
|
||||
mKeySize = ::PR_htonl(mKeySize);
|
||||
mMetaDataSize = ::PR_htonl(mMetaDataSize);
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
mHeaderVersion = ::PR_htonl(mHeaderVersion);
|
||||
mMetaLocation = ::PR_htonl(mMetaLocation);
|
||||
mFetchCount = ::PR_htonl(mFetchCount);
|
||||
mLastFetched = ::PR_htonl(mLastFetched);
|
||||
mLastModified = ::PR_htonl(mLastModified);
|
||||
mExpirationTime = ::PR_htonl(mExpirationTime);
|
||||
mDataSize = ::PR_htonl(mDataSize);
|
||||
mKeySize = ::PR_htonl(mKeySize);
|
||||
mMetaDataSize = ::PR_htonl(mMetaDataSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Unswap()
|
||||
void Unswap() // network to host (disk to memory)
|
||||
{
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
mHeaderSize = ::PR_ntohl(mHeaderSize);
|
||||
mFetchCount = ::PR_ntohl(mFetchCount);
|
||||
mLastFetched = ::PR_ntohl(mLastFetched);
|
||||
mLastModified = ::PR_ntohl(mLastModified);
|
||||
mExpirationTime = ::PR_ntohl(mExpirationTime);
|
||||
mDataSize = ::PR_ntohl(mDataSize);
|
||||
mKeySize = ::PR_ntohl(mKeySize);
|
||||
mMetaDataSize = ::PR_ntohl(mMetaDataSize);
|
||||
mHeaderVersion = ::PR_ntohl(mHeaderSize);
|
||||
mMetaLocation = ::PR_ntohl(mMetaLocation);
|
||||
mFetchCount = ::PR_ntohl(mFetchCount);
|
||||
mLastFetched = ::PR_ntohl(mLastFetched);
|
||||
mLastModified = ::PR_ntohl(mLastModified);
|
||||
mExpirationTime = ::PR_ntohl(mExpirationTime);
|
||||
mDataSize = ::PR_ntohl(mDataSize);
|
||||
mKeySize = ::PR_ntohl(mKeySize);
|
||||
mMetaDataSize = ::PR_ntohl(mMetaDataSize);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
struct MetaDataFile : MetaDataHeader {
|
||||
char* mKey;
|
||||
char* mMetaData;
|
||||
nsDiskCacheEntry * CreateDiskCacheEntry(nsDiskCacheBindData * bindData);
|
||||
|
||||
MetaDataFile()
|
||||
: mKey(nsnull), mMetaData(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
MetaDataFile(nsCacheEntry* entry)
|
||||
: MetaDataHeader(entry),
|
||||
mKey(nsnull), mMetaData(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
~MetaDataFile()
|
||||
{
|
||||
delete[] mKey;
|
||||
delete[] mMetaData;
|
||||
}
|
||||
|
||||
nsresult Init(nsCacheEntry* entry)
|
||||
{
|
||||
PRUint32 size = 1 + entry->Key()->Length();
|
||||
mKey = new char[size];
|
||||
if (!mKey) return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsCRT::memcpy(mKey, entry->Key()->get(), size);
|
||||
return entry->FlattenMetaData(&mMetaData, &mMetaDataSize);
|
||||
}
|
||||
|
||||
nsresult Read(nsIInputStream* input);
|
||||
nsresult Write(nsIOutputStream* output);
|
||||
};
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
@@ -150,24 +102,20 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICACHEENTRYINFO
|
||||
|
||||
nsDiskCacheEntryInfo(const char * deviceID)
|
||||
nsDiskCacheEntryInfo(const char * deviceID, nsDiskCacheEntry * diskEntry)
|
||||
: mDeviceID(deviceID)
|
||||
, mDiskEntry(diskEntry)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
virtual ~nsDiskCacheEntryInfo() {}
|
||||
|
||||
nsresult Read(nsIInputStream * input)
|
||||
{
|
||||
return mMetaDataFile.Read(input);
|
||||
}
|
||||
|
||||
const char* Key() { return mMetaDataFile.mKey; }
|
||||
const char* Key() { return mDiskEntry->mKeyStart; }
|
||||
|
||||
private:
|
||||
const char * mDeviceID;
|
||||
MetaDataFile mMetaDataFile;
|
||||
const char * mDeviceID;
|
||||
nsDiskCacheEntry * mDiskEntry;
|
||||
};
|
||||
|
||||
|
||||
|
||||
571
mozilla/netwerk/cache/src/nsDiskCacheMap.cpp
vendored
571
mozilla/netwerk/cache/src/nsDiskCacheMap.cpp
vendored
@@ -23,94 +23,166 @@
|
||||
*/
|
||||
|
||||
#include "nsDiskCacheMap.h"
|
||||
#include "nsDiskCacheEntry.h"
|
||||
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
nsDiskCacheMap::nsDiskCacheMap()
|
||||
: mStream(nsnull)
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheBucket
|
||||
*****************************************************************************/
|
||||
|
||||
void
|
||||
nsDiskCacheBucket::Swap()
|
||||
{
|
||||
nsDiskCacheRecord * record = &mRecords[0];
|
||||
for (int i = 0; i < kRecordsPerBucket; ++i) {
|
||||
if (record->HashNumber() == 0)
|
||||
break;
|
||||
record->Swap();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDiskCacheBucket::Unswap()
|
||||
{
|
||||
nsDiskCacheRecord * record = &mRecords[0];
|
||||
for (int i = 0; i < kRecordsPerBucket; ++i) {
|
||||
if (record->HashNumber() == 0)
|
||||
break;
|
||||
record->Unswap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsDiskCacheMap::~nsDiskCacheMap()
|
||||
PRUint32
|
||||
nsDiskCacheBucket::CountRecords()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::Open(nsILocalFile * mapFile)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(mapFile);
|
||||
if (mStream) return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
// create stream for cache map file
|
||||
mStream = new nsANSIFileStream;
|
||||
if (!mStream) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(mStream);
|
||||
if (mRecords[0].HashNumber() == 0) return 0;
|
||||
|
||||
// open the stream
|
||||
nsresult rv = mStream->Open(mapFile);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(mStream);
|
||||
mStream = nsnull;
|
||||
return rv;
|
||||
PRUint32 i = kRecordsPerBucket << 1;
|
||||
PRUint32 offset = kRecordsPerBucket << 2;
|
||||
|
||||
while (offset > 0) {
|
||||
if (mRecords[i].HashNumber()) i += offset;
|
||||
else i -= offset;
|
||||
offset <<= 1;
|
||||
}
|
||||
|
||||
if (mRecords[i].HashNumber() != 0)
|
||||
++i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
PRInt32
|
||||
nsDiskCacheBucket::VisitEachRecordInBucket(nsDiskCacheRecordVisitor * visitor,
|
||||
PRBool * dirty)
|
||||
{
|
||||
PRInt32 count = CountRecords();
|
||||
*dirty = PR_FALSE;
|
||||
|
||||
if (count == 0) return kVisitNextRecord; // bucket is empty
|
||||
|
||||
// XXX call visitor for each entry
|
||||
PRInt32 i = count - 1;
|
||||
PRInt32 result = visitor->VisitRecord(&mRecords[i]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheMap
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* File operations
|
||||
*/
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::Open(nsILocalFile * cacheDirectory)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(cacheDirectory);
|
||||
if (mMapFD) return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
mCacheDirectory = cacheDirectory; // save a reference for ourselves
|
||||
|
||||
// create nsILocalFile for _CACHE_MAP_
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = cacheDirectory->Clone(getter_AddRefs(file));
|
||||
nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file, &rv));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = localFile->Append("_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
|
||||
|
||||
// check size of map file
|
||||
PRUint32 mapSize;
|
||||
rv = mStream->Available(&mapSize);
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
PRUint32 mapSize = PR_Available(mMapFD);
|
||||
if (mapSize < 0) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (mapSize == 0) {
|
||||
// create the file - initialize in memory
|
||||
|
||||
mHeader.mVersion = kCurrentVersion;
|
||||
mHeader.mDataSize = kCacheMapSize;
|
||||
mHeader.mVersion = nsDiskCache::kCurrentVersion;
|
||||
mHeader.mDataSize = 0;
|
||||
mHeader.mEntryCount = 0;
|
||||
mHeader.mIsDirty = PR_TRUE;
|
||||
nsCRT::zero(mBuckets, sizeof(nsDiskCacheBucket) * kBucketsPerTable);
|
||||
mHeader.mIsDirty = PR_TRUE;
|
||||
|
||||
// XXX FlushCacheMap();
|
||||
PRUint32 bytesWritten = 0;
|
||||
mHeader.Swap();
|
||||
rv = mStream->Write((char *)&mHeader, kCacheMapSize, &bytesWritten);
|
||||
mHeader.Unswap();
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
if (kCacheMapSize != bytesWritten) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
goto error_exit;
|
||||
}
|
||||
nsCRT::zero(mHeader.reserved, nsDiskCacheHeader::kReservedBytes);
|
||||
nsCRT::zero(mBuckets, sizeof(nsDiskCacheBucket) * kBucketsPerTable);
|
||||
|
||||
} else if (mapSize == kCacheMapSize) {
|
||||
// read it in
|
||||
PRUint32 bytesRead =0;
|
||||
rv = mStream->Read((char *)&mHeader, kCacheMapSize, &bytesRead);
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
PRUint32 bytesRead = PR_Read(mMapFD, &mHeader, kCacheMapSize);
|
||||
if (kCacheMapSize != bytesRead) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
goto error_exit;
|
||||
}
|
||||
mHeader.Unswap();
|
||||
if (IsDirty() || mHeader.mVersion != kCurrentVersion) {
|
||||
if (mHeader.mIsDirty || mHeader.mVersion != nsDiskCache::kCurrentVersion) {
|
||||
rv = NS_ERROR_FILE_CORRUPTED;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// XXX Unswap each bucket
|
||||
// Unswap each bucket
|
||||
for (PRUint32 i = 0; i < kBucketsPerTable; ++i) {
|
||||
mBuckets[i].Unswap();
|
||||
}
|
||||
|
||||
// XXX verify entry count, check size(?)
|
||||
|
||||
} else {
|
||||
rv = NS_ERROR_FILE_CORRUPTED;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
rv = OpenBlockFiles();
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
|
||||
// set dirty bit and flush header
|
||||
mHeader.mIsDirty = PR_TRUE;
|
||||
rv = FlushHeader();
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
error_exit:
|
||||
if (mStream) {
|
||||
(void) mStream->Close();
|
||||
NS_RELEASE(mStream);
|
||||
mStream = nsnull;
|
||||
// XXX close block files
|
||||
|
||||
if (mMapFD) {
|
||||
(void) PR_Close(mMapFD);
|
||||
mMapFD = nsnull;
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -120,38 +192,138 @@ error_exit:
|
||||
nsresult
|
||||
nsDiskCacheMap::Close()
|
||||
{
|
||||
if (!mStream) return NS_OK;
|
||||
if (!mMapFD) return NS_OK;
|
||||
|
||||
// close block files
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
(void) mBlockFile[i].Close(); // XXX report rv
|
||||
}
|
||||
|
||||
// write map record buckets
|
||||
nsresult rv = FlushBuckets(PR_FALSE); // don't bother swapping buckets back
|
||||
if (NS_FAILED(rv)) goto exit;
|
||||
|
||||
// XXX nsresult rv = FlushCacheMap();
|
||||
// clear dirty bit
|
||||
mHeader.mIsDirty = PR_FALSE;
|
||||
|
||||
rv = FlushHeader();
|
||||
|
||||
exit:
|
||||
PRStatus err = PR_Close(mMapFD);
|
||||
mMapFD = nsnull;
|
||||
|
||||
nsresult rv2 = mStream->Close();
|
||||
NS_RELEASE(mStream);
|
||||
mStream = nsnull;
|
||||
|
||||
// XXX dealloc cache map memory?
|
||||
|
||||
// return rv ? rv : rv2;
|
||||
return rv2;
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return err == PR_SUCCESS ? NS_OK : NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::FlushHeader()
|
||||
{
|
||||
if (!mMapFD) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// seek to beginning of cache map
|
||||
PRInt32 filePos = PR_Seek(mMapFD, 0, PR_SEEK_SET);
|
||||
if (filePos != 0) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// write the header
|
||||
mHeader.Swap();
|
||||
PRInt32 bytesWritten = PR_Write(mMapFD, &mHeader, sizeof(nsDiskCacheHeader));
|
||||
mHeader.Unswap();
|
||||
if (sizeof(nsDiskCacheHeader) != bytesWritten) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::FlushBuckets(PRBool unswap)
|
||||
{
|
||||
if (!mMapFD) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// seek to beginning of buckets
|
||||
PRInt32 filePos = PR_Seek(mMapFD, sizeof(nsDiskCacheHeader), PR_SEEK_SET);
|
||||
if (filePos != sizeof(nsDiskCacheHeader)) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Swap each bucket
|
||||
for (PRUint32 i = 0; i < kBucketsPerTable; ++i) {
|
||||
mBuckets[i].Swap();
|
||||
}
|
||||
|
||||
PRInt32 bytesWritten = PR_Write(mMapFD, &mBuckets, sizeof(nsDiskCacheBucket) * kBucketsPerTable);
|
||||
|
||||
if (unswap) {
|
||||
// Unswap each bucket
|
||||
for (PRUint32 i = 0; i < kBucketsPerTable; ++i) {
|
||||
mBuckets[i].Unswap();
|
||||
}
|
||||
}
|
||||
|
||||
if (sizeof(nsDiskCacheHeader) != bytesWritten) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record operations
|
||||
*/
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::AddRecord( nsDiskCacheRecord * mapRecord,
|
||||
nsDiskCacheRecord * oldRecord)
|
||||
{
|
||||
PRUint32 hashNumber = mapRecord->HashNumber();
|
||||
nsDiskCacheBucket * bucket;
|
||||
nsresult rv = GetBucketForHashNumber(hashNumber, &bucket);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsDiskCacheRecord * mostEvictable = &bucket->mRecords[0];
|
||||
for (int i = 0; i < kRecordsPerBucket; ++i) {
|
||||
if (bucket->mRecords[i].HashNumber() == 0) {
|
||||
// stick the new record here
|
||||
bucket->mRecords[i] = *mapRecord;
|
||||
oldRecord->SetHashNumber(0); // signify no record
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (bucket->mRecords[i].EvictionRank() > mostEvictable->EvictionRank())
|
||||
mostEvictable = &bucket->mRecords[i];
|
||||
}
|
||||
|
||||
*oldRecord = *mostEvictable; // i == kRecordsPerBucket, so evict the mostEvictable
|
||||
*mostEvictable = *mapRecord; // replace it with the new record
|
||||
|
||||
// XXX recalc mostEvictable
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::UpdateRecord( nsDiskCacheRecord * mapRecord)
|
||||
{
|
||||
PRUint32 hashNumber = mapRecord->HashNumber();
|
||||
nsDiskCacheBucket * bucket;
|
||||
nsresult rv = GetBucketForHashNumber(hashNumber, &bucket);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
for (int i = 0; i < kRecordsPerBucket; ++i) {
|
||||
if (bucket->mRecords[i].HashNumber() == mapRecord->HashNumber()) {
|
||||
// stick the new record here
|
||||
bucket->mRecords[i] = *mapRecord;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::FindRecord( PRUint32 hashNumber, nsDiskCacheRecord * mapRecord)
|
||||
nsDiskCacheMap::FindRecord( PRUint32 hashNumber, nsDiskCacheRecord * result)
|
||||
{
|
||||
nsDiskCacheBucket * bucket;
|
||||
nsresult rv = GetBucketForHashNumber(hashNumber, &bucket);
|
||||
@@ -159,73 +331,259 @@ nsDiskCacheMap::FindRecord( PRUint32 hashNumber, nsDiskCacheRecord * mapRecord
|
||||
|
||||
for (int i = 0; i < kRecordsPerBucket; ++i) {
|
||||
if (bucket->mRecords[i].HashNumber() == 0) break;
|
||||
if (bucket->mRecords[i].HashNumber() == mapRecord->HashNumber()) {
|
||||
*mapRecord = bucket->mRecords[i]; // copy the record
|
||||
|
||||
if (bucket->mRecords[i].HashNumber() == hashNumber) {
|
||||
*result = bucket->mRecords[i]; // copy the record
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// XXX ? mapRecord->hashNumber == 0;
|
||||
return NS_OK;
|
||||
return NS_ERROR_CACHE_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::DeleteRecord2( nsDiskCacheRecord * mapRecord)
|
||||
nsDiskCacheMap::DeleteRecord( nsDiskCacheRecord * mapRecord)
|
||||
{
|
||||
nsDiskCacheBucket * bucket;
|
||||
nsresult rv = GetBucketForHashNumber(mapRecord->HashNumber(), &bucket);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
for (int i = 0; i < kRecordsPerBucket; ++i) {
|
||||
if (bucket->mRecords[i].HashNumber() == 0) {
|
||||
mapRecord->SetHashNumber(0);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
PRUint32 count = bucket->CountRecords();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (bucket->mRecords[i].HashNumber() == mapRecord->HashNumber()) {
|
||||
// found it, now delete it.
|
||||
|
||||
|
||||
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
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// XXX ? mapRecord->hashNumber == 0;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::EvictRecords( nsDiskCacheRecordVisitor * visitor)
|
||||
nsDiskCacheMap::VisitRecords( nsDiskCacheRecordVisitor * visitor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Private methods
|
||||
*****************************************************************************/
|
||||
|
||||
void nsDiskCacheMap::Reset()
|
||||
{
|
||||
mHeader.mDataSize = 0;
|
||||
mHeader.mEntryCount = 0;
|
||||
mHeader.mIsDirty = PR_TRUE;
|
||||
|
||||
for (PRUint32 b = 0; b < kBucketsPerTable; ++b) {
|
||||
nsDiskCacheBucket * bucket = &mBuckets[b];
|
||||
::memset(bucket, 0, sizeof(nsDiskCacheBucket));
|
||||
for (PRUint32 i = 0; i < kBucketsPerTable; ++i) {
|
||||
// get bucket
|
||||
PRBool dirty;
|
||||
PRBool continueFlag = mBuckets[i].VisitEachRecordInBucket(visitor, &dirty);
|
||||
if (dirty) {
|
||||
// XXX write bucket
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::GetBucketForHashNumber(PRUint32 hashNumber, nsDiskCacheBucket ** result)
|
||||
nsDiskCacheMap::OpenBlockFiles()
|
||||
{
|
||||
*result = &mBuckets[GetBucketIndex(hashNumber)];
|
||||
// create nsILocalFile for block file
|
||||
nsCOMPtr<nsILocalFile> blockFile;
|
||||
nsresult rv;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
rv = GetBlockFileForIndex(i, getter_AddRefs(blockFile));
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
|
||||
PRUint32 blockSize = GetBlockSizeForIndex(i);
|
||||
rv = mBlockFile[i].Open(blockFile, blockSize);
|
||||
if (NS_FAILED(rv)) goto error_exit;
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
error_exit:
|
||||
(void)CloseBlockFiles(); // we already have an error to report
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::CloseBlockFiles()
|
||||
{
|
||||
nsresult rv, rv2 = NS_OK;
|
||||
for (int i=0; i < 3; ++i) {
|
||||
rv = mBlockFile[i].Close();
|
||||
if (NS_FAILED(rv)) rv2 = rv; // if one or more errors, report at least one
|
||||
}
|
||||
return rv2;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::ReadDiskCacheEntry(nsDiskCacheRecord * record, nsDiskCacheEntry ** result)
|
||||
{
|
||||
nsresult rv;
|
||||
nsDiskCacheEntry * diskEntry = nsnull;
|
||||
PRUint16 generation = record->Generation();
|
||||
PRUint32 hashNumber = record->HashNumber();
|
||||
PRUint32 metaFile = record->MetaFile();
|
||||
PRFileDesc * fd = nsnull;
|
||||
*result = nsnull;
|
||||
|
||||
if (metaFile == 0) { // entry/metadata stored in separate file
|
||||
// open and read the file
|
||||
nsCOMPtr<nsILocalFile> file;
|
||||
rv = GetLocalFileForDiskCacheRecord(record, nsDiskCache::kMetaData, getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRFileDesc * fd = nsnull;
|
||||
nsresult rv = file->OpenNSPRFileDesc(PR_RDONLY, 00666, &fd);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 fileSize = PR_Available(fd);
|
||||
if (fileSize < 0) {
|
||||
// XXX an error occurred. We could call PR_GetError(), but how would that help?
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
diskEntry = (nsDiskCacheEntry *) new char[fileSize];
|
||||
if (!diskEntry) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PRInt32 bytesRead = PR_Read(fd, diskEntry, fileSize);
|
||||
if (bytesRead < fileSize) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
} else if (metaFile < 4) { // XXX magic number: use constant
|
||||
// entry/metadata stored in cache block file
|
||||
|
||||
// allocate buffer
|
||||
PRUint32 blockSize = GetBlockSizeForIndex(metaFile - 1);
|
||||
PRUint32 blockCount = record->MetaBlockCount();
|
||||
diskEntry = (nsDiskCacheEntry *) new char[blockSize * blockCount];
|
||||
|
||||
// read diskEntry
|
||||
rv = mBlockFile[metaFile - 1].ReadBlocks((char *)diskEntry,
|
||||
record->MetaStartBlock(),
|
||||
blockCount);
|
||||
if (NS_FAILED(rv)) goto exit;
|
||||
}
|
||||
|
||||
|
||||
// pass ownership to caller
|
||||
*result = diskEntry;
|
||||
diskEntry = nsnull;
|
||||
|
||||
exit:
|
||||
// XXX auto ptr would be nice
|
||||
if (fd) (void) PR_Close(fd);
|
||||
delete diskEntry;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::WriteDiskCacheEntry(nsDiskCacheEntry * diskEntry,
|
||||
nsDiskCacheBindData * bindData)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (diskEntry->Size() < 1024) { // block size 256
|
||||
|
||||
} else if (diskEntry->Size() < 4096) { // block size 1024
|
||||
|
||||
} else if (diskEntry->Size() < 16384) { // block size 4096
|
||||
|
||||
} else { // separate file
|
||||
|
||||
}
|
||||
|
||||
// XXX if block file != reallocate
|
||||
// XXX if block size != reallocate
|
||||
// XXX deallocate previously used blocks
|
||||
// XXX allocate new blocks
|
||||
// XXX update bindData so caller can update cache map
|
||||
// XXX write data
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::GetFileForDiskCacheRecord(nsDiskCacheRecord * record,
|
||||
PRBool meta,
|
||||
nsIFile ** result)
|
||||
{
|
||||
if (!mCacheDirectory) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = mCacheDirectory->Clone(getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt16 generation = record->Generation();
|
||||
char name[32];
|
||||
::sprintf(name, "%08x%c%02x", record->HashNumber(), (meta ? 'M' : 'D'), generation);
|
||||
rv = file->Append(name);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::GetLocalFileForDiskCacheRecord(nsDiskCacheRecord * record,
|
||||
PRBool meta,
|
||||
nsILocalFile ** result)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = GetFileForDiskCacheRecord(record, meta, getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(file, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_IF_ADDREF(*result = localFile);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDiskCacheMap::GetBlockFileForIndex(PRUint32 index, nsILocalFile ** result)
|
||||
{
|
||||
if (!mCacheDirectory) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = mCacheDirectory->Clone(getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
char name[32];
|
||||
::sprintf(name, "_CACHE_%03d_", index + 1);
|
||||
rv = file->Append(name);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(file, &rv);
|
||||
NS_IF_ADDREF(*result = localFile);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
PRUint32
|
||||
nsDiskCacheMap::GetBlockSizeForIndex(PRUint32 index)
|
||||
{
|
||||
return 256 << (2 * (index)); // XXX magic numbers
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/******************************************************************************
|
||||
* old code
|
||||
*****************************************************************************/
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#pragma mark OLD CODE
|
||||
#endif
|
||||
|
||||
nsDiskCacheRecord* nsDiskCacheMap::GetRecord(PRUint32 hashNumber)
|
||||
{
|
||||
nsDiskCacheBucket& bucket = mBuckets[GetBucketIndex(hashNumber)];
|
||||
@@ -242,7 +600,6 @@ nsDiskCacheRecord* nsDiskCacheMap::GetRecord(PRUint32 hashNumber)
|
||||
return oldestRecord;
|
||||
}
|
||||
|
||||
|
||||
void nsDiskCacheMap::DeleteRecord(nsDiskCacheRecord* deletedRecord)
|
||||
{
|
||||
PRUint32 hashNumber = deletedRecord->HashNumber();
|
||||
@@ -271,7 +628,6 @@ void nsDiskCacheMap::DeleteRecord(nsDiskCacheRecord* deletedRecord)
|
||||
mHeader.mEntryCount--;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsDiskCacheMap::Read(nsIInputStream* input)
|
||||
{
|
||||
nsresult rv;
|
||||
@@ -421,24 +777,5 @@ nsresult nsDiskCacheMap::WriteBucket(nsIOutputStream* output, PRUint32 index)
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsDiskCacheMap::WriteHeader(nsIOutputStream* output)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 count;
|
||||
|
||||
// can only do this if the stream is seekable.
|
||||
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(output, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
#endif
|
||||
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// write the header.
|
||||
nsDiskCacheHeader header = mHeader;
|
||||
header.Swap();
|
||||
rv = output->Write((char*)&header, sizeof(header), &count);
|
||||
output->Flush();
|
||||
if (count != sizeof(header)) return NS_ERROR_FAILURE;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
312
mozilla/netwerk/cache/src/nsDiskCacheMap.h
vendored
312
mozilla/netwerk/cache/src/nsDiskCacheMap.h
vendored
@@ -30,17 +30,24 @@
|
||||
#include "nsDebug.h"
|
||||
#include "nsError.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsANSIFileStreams.h"
|
||||
|
||||
class nsIInputStream;
|
||||
class nsIOutputStream;
|
||||
#include "nsDiskCache.h"
|
||||
#include "nsDiskCacheBlockFile.h"
|
||||
|
||||
|
||||
class nsDiskCacheBindData;
|
||||
class nsDiskCacheEntry;
|
||||
|
||||
/**
|
||||
/******************************************************************************
|
||||
* nsDiskCacheRecord
|
||||
*
|
||||
* Cache Location Format
|
||||
*
|
||||
* 1000 0000 0000 0000 0000 0000 0000 0000 : initialized bit
|
||||
*
|
||||
* 0011 0000 0000 0000 0000 0000 0000 0000 : File Selector (0 = separate file)
|
||||
* 0000 0011 0000 0000 0000 0000 0000 0000 : number of extra contiguous blocks 1-4
|
||||
* 1100 1100 0000 0000 0000 0000 0000 0000 : reserved bits
|
||||
* 0100 1100 0000 0000 0000 0000 0000 0000 : reserved bits
|
||||
* 0000 0000 1111 1111 1111 1111 1111 1111 : block# 0-16777216 (2^24)
|
||||
*
|
||||
* 0000 0000 1111 1111 1111 1111 0000 0000 : eFileReservedMask
|
||||
@@ -51,107 +58,171 @@ class nsIOutputStream;
|
||||
* 1 = 256 byte block file
|
||||
* 2 = 1k block file
|
||||
* 3 = 4k block file
|
||||
*/
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheRecord
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
class nsDiskCacheRecord {
|
||||
|
||||
private:
|
||||
PRUint32 mHashNumber;
|
||||
PRUint32 mEvictionRank;
|
||||
PRUint32 mLocation;
|
||||
PRUint32 mDataLocation;
|
||||
PRUint32 mMetaLocation;
|
||||
|
||||
enum {
|
||||
eLocationSelectorMask = 0x30000000,
|
||||
eLocationSelectorOffset = 28,
|
||||
eLocationInitializedMask = 0x80000000,
|
||||
|
||||
eExtraBlocksMask = 0x03000000,
|
||||
eExtraBlocksOffset = 24,
|
||||
eLocationSelectorMask = 0x30000000,
|
||||
eLocationSelectorOffset = 28,
|
||||
|
||||
eReservedMask = 0xCC000000,
|
||||
eExtraBlocksMask = 0x03000000,
|
||||
eExtraBlocksOffset = 24,
|
||||
|
||||
eBlockNumberMask = 0x00FFFFFF,
|
||||
eReservedMask = 0xCC000000,
|
||||
|
||||
eBlockNumberMask = 0x00FFFFFF,
|
||||
|
||||
eFileReservedMask = 0x00FFFF00,
|
||||
eFileGenerationMask = 0x000000FF
|
||||
eFileReservedMask = 0x00FFFF00,
|
||||
eFileGenerationMask = 0x000000FF
|
||||
};
|
||||
|
||||
public:
|
||||
nsDiskCacheRecord()
|
||||
: mHashNumber(0), mEvictionRank(0), mLocation(0), mMetaLocation(0)
|
||||
: mHashNumber(0), mEvictionRank(0), mDataLocation(0), mMetaLocation(0)
|
||||
{
|
||||
}
|
||||
|
||||
PRUint32 HashNumber() const
|
||||
{
|
||||
return mHashNumber;
|
||||
}
|
||||
// HashNumber accessors
|
||||
PRUint32 HashNumber() const { return mHashNumber; }
|
||||
void SetHashNumber(PRUint32 hashNumber) { mHashNumber = hashNumber; }
|
||||
|
||||
// EvictionRank accessors
|
||||
PRUint32 EvictionRank() const { return mEvictionRank; }
|
||||
void SetEvictionRank(PRUint32 rank) { mEvictionRank = rank; }
|
||||
|
||||
// DataLocation accessors
|
||||
PRBool DataLocationInitialized() { return mDataLocation & eLocationInitializedMask; }
|
||||
|
||||
void SetHashNumber(PRUint32 hashNumber)
|
||||
PRUint32 DataLocation() { return mDataLocation; }
|
||||
void SetDataLocation(PRUint32 location) { mDataLocation = location; }
|
||||
|
||||
PRUint32 DataFile() const
|
||||
{
|
||||
mHashNumber = hashNumber;
|
||||
return (PRUint32)(mDataLocation & eLocationSelectorMask) >> eLocationSelectorOffset;
|
||||
}
|
||||
|
||||
PRUint32 EvictionRank() const
|
||||
void SetDataBlocks(PRUint32 index, PRUint32 startBlock, PRUint32 blockCount)
|
||||
{
|
||||
return mEvictionRank;
|
||||
// clear everything
|
||||
mDataLocation = 0;
|
||||
|
||||
// set file index
|
||||
NS_ASSERTION( index < 4,"invalid location index");
|
||||
NS_ASSERTION( index > 0,"invalid location index");
|
||||
mDataLocation |= (index << eLocationSelectorOffset) & eLocationSelectorMask;
|
||||
|
||||
// set startBlock
|
||||
NS_ASSERTION(startBlock == (startBlock & eBlockNumberMask), "invalid block number");
|
||||
mDataLocation |= startBlock & eBlockNumberMask;
|
||||
|
||||
// set blockCount
|
||||
NS_ASSERTION( (blockCount>=1) && (blockCount<=4),"invalid block count");
|
||||
blockCount = --blockCount;
|
||||
mDataLocation |= (blockCount & eExtraBlocksMask) << eExtraBlocksOffset;
|
||||
|
||||
mDataLocation |= eLocationInitializedMask;
|
||||
}
|
||||
|
||||
void SetEvictionRank(PRUint32 rank)
|
||||
PRUint32 DataBlockCount() const
|
||||
{
|
||||
mEvictionRank = rank;
|
||||
return (PRUint32)((mDataLocation & eExtraBlocksMask) >> eExtraBlocksOffset) + 1;
|
||||
}
|
||||
|
||||
PRUint32 LocationSelector() const
|
||||
PRUint32 DataStartBlock() const
|
||||
{
|
||||
return (PRUint32)(mLocation & eLocationSelectorMask) >> eLocationSelectorOffset;
|
||||
return (mDataLocation & eBlockNumberMask);
|
||||
}
|
||||
|
||||
void SetLocationSelector(PRUint32 selector)
|
||||
PRUint16 DataGeneration() const
|
||||
{
|
||||
mLocation &= ~eLocationSelectorMask; // clear location selector bits
|
||||
mLocation |= (selector & eLocationSelectorMask) << eLocationSelectorOffset;
|
||||
return (mDataLocation & eFileGenerationMask);
|
||||
}
|
||||
|
||||
PRUint32 BlockCount() const
|
||||
void SetDataFileGeneration(PRUint16 generation)
|
||||
{
|
||||
return (PRUint32)((mLocation & eExtraBlocksMask) >> eExtraBlocksOffset) + 1;
|
||||
// clear everything, (separate file index = 0)
|
||||
mDataLocation = 0;
|
||||
mDataLocation |= generation & eFileGenerationMask;
|
||||
mDataLocation |= eLocationInitializedMask;
|
||||
}
|
||||
|
||||
void SetBlockCount(PRUint32 count)
|
||||
// MetaLocation accessors
|
||||
PRBool MetaLocationInitialized() { return mMetaLocation & eLocationInitializedMask; }
|
||||
|
||||
PRUint32 MetaLocation() { return mMetaLocation; }
|
||||
void SetMetaLocation(PRUint32 location) { mMetaLocation = location; }
|
||||
|
||||
PRUint32 MetaFile() const
|
||||
{
|
||||
NS_ASSERTION( (count>=1) && (count<=4),"invalid block count");
|
||||
count = --count;
|
||||
mLocation &= ~eExtraBlocksMask; // clear extra blocks bits
|
||||
mLocation |= (count & eExtraBlocksMask) << eExtraBlocksOffset;
|
||||
return (PRUint32)(mMetaLocation & eLocationSelectorMask) >> eLocationSelectorOffset;
|
||||
}
|
||||
|
||||
PRUint32 BlockNumber() const
|
||||
void SetMetaBlocks(PRUint32 index, PRUint32 startBlock, PRUint32 blockCount)
|
||||
{
|
||||
return (mLocation & eBlockNumberMask);
|
||||
// clear everything
|
||||
mMetaLocation = 0;
|
||||
|
||||
// set file index
|
||||
NS_ASSERTION( index < 4, "invalid location index");
|
||||
NS_ASSERTION( index > 0, "invalid location index");
|
||||
mMetaLocation |= (index << eLocationSelectorOffset) & eLocationSelectorMask;
|
||||
|
||||
// set startBlock
|
||||
NS_ASSERTION(startBlock == (startBlock & eBlockNumberMask), "invalid block number");
|
||||
mMetaLocation |= startBlock & eBlockNumberMask;
|
||||
|
||||
// set blockCount
|
||||
NS_ASSERTION( (blockCount>=1) && (blockCount<=4),"invalid block count");
|
||||
blockCount = --blockCount;
|
||||
mMetaLocation |= (blockCount & eExtraBlocksMask) << eExtraBlocksOffset;
|
||||
|
||||
mMetaLocation |= eLocationInitializedMask;
|
||||
}
|
||||
|
||||
void SetBlockNumber(PRUint32 blockNumber)
|
||||
PRUint32 MetaBlockCount() const
|
||||
{
|
||||
mLocation &= ~eBlockNumberMask; // clear block number bits
|
||||
mLocation |= blockNumber & eBlockNumberMask;
|
||||
return (PRUint32)((mMetaLocation & eExtraBlocksMask) >> eExtraBlocksOffset) + 1;
|
||||
}
|
||||
|
||||
PRUint16 FileGeneration() const
|
||||
PRUint32 MetaStartBlock() const
|
||||
{
|
||||
return (mLocation & eFileGenerationMask);
|
||||
return (mMetaLocation & eBlockNumberMask);
|
||||
}
|
||||
|
||||
void SetFileGeneration(PRUint16 generation)
|
||||
PRUint16 MetaGeneration() const
|
||||
{
|
||||
mLocation &= ~eFileGenerationMask; // clear file generation bits
|
||||
mLocation |= generation & eFileGenerationMask;
|
||||
return (mMetaLocation & eFileGenerationMask);
|
||||
}
|
||||
|
||||
void SetMetaFileGeneration(PRUint16 generation)
|
||||
{
|
||||
// clear everything, (separate file index = 0)
|
||||
mMetaLocation = 0;
|
||||
mMetaLocation |= generation & eFileGenerationMask;
|
||||
mMetaLocation |= eLocationInitializedMask;
|
||||
}
|
||||
|
||||
|
||||
PRUint16 Generation() const
|
||||
{
|
||||
if (DataFile() == 0) return DataGeneration();
|
||||
else if (MetaFile() == 0) return MetaGeneration();
|
||||
|
||||
return -1; // no generation
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Swap()
|
||||
{
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
@@ -185,7 +256,9 @@ enum { kDeleteRecordAndContinue = -1,
|
||||
};
|
||||
|
||||
class nsDiskCacheRecordVisitor {
|
||||
PRInt32 VisitRecord(nsDiskCacheRecord * mapRecord);
|
||||
public:
|
||||
|
||||
virtual PRInt32 VisitRecord(nsDiskCacheRecord * mapRecord) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -198,27 +271,33 @@ enum {
|
||||
|
||||
struct nsDiskCacheBucket {
|
||||
nsDiskCacheRecord mRecords[kRecordsPerBucket];
|
||||
|
||||
void Swap();
|
||||
void Unswap();
|
||||
PRUint32 CountRecords();
|
||||
PRInt32 VisitEachRecordInBucket(nsDiskCacheRecordVisitor * visitor,
|
||||
PRBool * dirty);
|
||||
};
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheHeader
|
||||
*****************************************************************************/
|
||||
enum { kCurrentVersion = 0x00010002 };
|
||||
|
||||
struct nsDiskCacheHeader {
|
||||
PRUint32 mVersion; // cache version.
|
||||
PRUint32 mDataSize; // size of cache in bytes.
|
||||
PRUint32 mEntryCount; // number of entries stored in cache.
|
||||
PRInt32 mDataSize; // size of cache in bytes.
|
||||
PRInt32 mEntryCount; // number of entries stored in cache.
|
||||
PRUint32 mIsDirty; // dirty flag.
|
||||
|
||||
// pad to blocksize
|
||||
PRUint8 reserved[sizeof(nsDiskCacheBucket) - 4 * sizeof(PRUint32)];
|
||||
enum { kReservedBytes = sizeof(nsDiskCacheBucket) - 4 * sizeof(PRUint32) };
|
||||
PRUint8 reserved[kReservedBytes];
|
||||
|
||||
// XXX need a bitmap?
|
||||
|
||||
nsDiskCacheHeader()
|
||||
: mVersion(kCurrentVersion), mDataSize(0),
|
||||
: mVersion(nsDiskCache::kCurrentVersion), mDataSize(0),
|
||||
mEntryCount(0), mIsDirty(PR_TRUE)
|
||||
{
|
||||
}
|
||||
@@ -247,10 +326,10 @@ struct nsDiskCacheHeader {
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheMap
|
||||
*
|
||||
* // XXX initial capacity, enough for 8192 distinct entries.
|
||||
*****************************************************************************/
|
||||
|
||||
// XXX initial capacity, enough for 8192 distinct entries.
|
||||
|
||||
enum {
|
||||
kBucketsPerTable = (1 << 5), // must be a power of 2!
|
||||
kCacheMapSize = sizeof(nsDiskCacheHeader) +
|
||||
@@ -260,72 +339,105 @@ enum {
|
||||
|
||||
class nsDiskCacheMap {
|
||||
public:
|
||||
nsDiskCacheMap();
|
||||
~nsDiskCacheMap();
|
||||
|
||||
nsDiskCacheMap()
|
||||
: mCacheDirectory(nsnull)
|
||||
, mMapFD(nsnull)
|
||||
{}
|
||||
~nsDiskCacheMap() { (void) Close(); }
|
||||
|
||||
/**
|
||||
* File Operations
|
||||
*
|
||||
* Open
|
||||
*
|
||||
* Creates a new cache map file if one doesn't exist.
|
||||
* Returns error if it detects change in format or cache wasn't closed.
|
||||
*/
|
||||
// nsresult Open(nsIFile * cacheDirectory);
|
||||
nsresult Open(nsILocalFile * mapFile);
|
||||
nsresult Close();
|
||||
nsresult Open(nsILocalFile * cacheDirectory);
|
||||
nsresult Close();
|
||||
|
||||
// nsresult Flush();
|
||||
// nsresult Flush();
|
||||
nsresult FlushHeader();
|
||||
nsresult FlushBuckets(PRBool unswap);
|
||||
|
||||
/**
|
||||
* Record operations
|
||||
*
|
||||
* AddRecord -
|
||||
*/
|
||||
nsresult AddRecord( nsDiskCacheRecord * mapRecord, nsDiskCacheRecord * oldRecord);
|
||||
nsresult UpdateRecord( nsDiskCacheRecord * mapRecord);
|
||||
nsresult FindRecord( PRUint32 hashNumber, nsDiskCacheRecord * mapRecord);
|
||||
nsresult DeleteRecord2( nsDiskCacheRecord * mapRecord);
|
||||
nsresult EvictRecords( nsDiskCacheRecordVisitor * visitor);
|
||||
nsresult DeleteRecord( nsDiskCacheRecord * mapRecord);
|
||||
nsresult VisitRecords( nsDiskCacheRecordVisitor * visitor);
|
||||
|
||||
//private:
|
||||
|
||||
|
||||
void Reset();
|
||||
/**
|
||||
* Disk Entry operations
|
||||
*/
|
||||
nsresult OpenBlockFiles();
|
||||
nsresult CloseBlockFiles();
|
||||
|
||||
PRUint32& DataSize() { return mHeader.mDataSize; }
|
||||
PRUint32& EntryCount() { return mHeader.mEntryCount; }
|
||||
PRUint32& IsDirty() { return mHeader.mIsDirty; }
|
||||
|
||||
nsDiskCacheRecord* GetRecord(PRUint32 hashNumber);
|
||||
void DeleteRecord(nsDiskCacheRecord* record);
|
||||
|
||||
nsresult GetBucketForHashNumber(PRUint32 hashNumber, nsDiskCacheBucket ** result);
|
||||
nsresult GetFileForDiskCacheRecord(nsDiskCacheRecord * record,
|
||||
PRBool meta,
|
||||
nsIFile ** result);
|
||||
|
||||
nsresult GetLocalFileForDiskCacheRecord(nsDiskCacheRecord * record,
|
||||
PRBool meta,
|
||||
nsILocalFile ** result);
|
||||
|
||||
nsDiskCacheRecord* GetBucket(PRUint32 index)
|
||||
nsresult GetBlockFileForIndex(PRUint32 index, nsILocalFile ** result);
|
||||
PRUint32 GetBlockSizeForIndex(PRUint32 index);
|
||||
|
||||
nsresult ReadDiskCacheEntry( nsDiskCacheRecord * record, nsDiskCacheEntry ** result);
|
||||
|
||||
nsresult WriteDiskCacheEntry( nsDiskCacheEntry * diskEntry,
|
||||
nsDiskCacheBindData * bindData);
|
||||
|
||||
/**
|
||||
* Statistical Operations
|
||||
*/
|
||||
void IncrementTotalSize(PRInt32 delta)
|
||||
{
|
||||
mHeader.mDataSize += delta;
|
||||
mHeader.mIsDirty = PR_TRUE;
|
||||
}
|
||||
|
||||
void DecrementTotalSize(PRInt32 delta)
|
||||
{
|
||||
mHeader.mDataSize -= delta;
|
||||
mHeader.mIsDirty = PR_TRUE;
|
||||
}
|
||||
|
||||
PRInt32 TotalSize() { return mHeader.mDataSize; }
|
||||
|
||||
PRInt32 EntryCount() { return mHeader.mEntryCount; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Private methods
|
||||
*/
|
||||
|
||||
nsresult GetBucketForHashNumber(PRUint32 hashNumber, nsDiskCacheBucket ** result)
|
||||
{
|
||||
return mBuckets[index].mRecords;
|
||||
*result = &mBuckets[GetBucketIndex(hashNumber)];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
PRUint32 GetBucketIndex(PRUint32 hashNumber)
|
||||
{
|
||||
return (hashNumber & (kBucketsPerTable - 1));
|
||||
}
|
||||
|
||||
|
||||
PRUint32 GetBucketIndex(nsDiskCacheRecord* record)
|
||||
{
|
||||
return GetBucketIndex(record->HashNumber());
|
||||
}
|
||||
|
||||
nsresult Read(nsIInputStream* input);
|
||||
nsresult Write(nsIOutputStream* output);
|
||||
|
||||
nsresult ReadBucket(nsIInputStream* input, PRUint32 index);
|
||||
nsresult WriteBucket(nsIOutputStream* output, PRUint32 index);
|
||||
|
||||
nsresult ReadHeader(nsIInputStream* input);
|
||||
nsresult WriteHeader(nsIOutputStream* output);
|
||||
|
||||
|
||||
/**
|
||||
* data members
|
||||
*/
|
||||
private:
|
||||
nsANSIFileStream * mStream;
|
||||
nsCOMPtr<nsILocalFile> mCacheDirectory;
|
||||
PRFileDesc * mMapFD;
|
||||
nsDiskCacheBlockFile mBlockFile[3];
|
||||
nsDiskCacheHeader mHeader;
|
||||
nsDiskCacheBucket mBuckets[kBucketsPerTable];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user