Land DISKCACHE1_BRANCH, implementing first draft of cache map file for more efficient eviction and cache miss detection. Fixed some problems with overeager setting of lastModified time stamp. Read cache enable prefs on startup. r=beard, sr=darin.

This commit is contained in:
gordon%netscape.com 2001-03-29 05:54:58 +00:00
Родитель fe77b957e7
Коммит 62a76fce9f
21 изменённых файлов: 1062 добавлений и 520 удалений

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

@ -37,6 +37,7 @@ EXPORTS = \
$(NULL)
CPPSRCS = \
nsANSIFileStreams.cpp \
nsCache.cpp \
nsCacheEntry.cpp \
nsCacheEntryDescriptor.cpp \
@ -46,6 +47,7 @@ CPPSRCS = \
nsCacheSession.cpp \
nsDiskCacheDevice.cpp \
nsDiskCacheEntry.cpp \
nsDiskCacheMap.cpp \
nsMemoryCacheDevice.cpp \
$(NULL)

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

@ -45,6 +45,8 @@ CPP_OBJS = \
.\$(OBJDIR)\nsCacheSession.obj \
.\$(OBJDIR)\nsDiskCacheDevice.obj \
.\$(OBJDIR)\nsDiskCacheEntry.obj \
.\$(OBJDIR)\nsDiskCacheMap.obj \
.\$(OBJDIR)\nsANSIFileStreams.obj \
.\$(OBJDIR)\nsMemoryCacheDevice.obj \
$(NULL)

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

@ -23,11 +23,16 @@
#include "nsANSIFileStreams.h"
NS_IMPL_ISUPPORTS1(nsANSIInputStream, nsIInputStream);
NS_IMPL_ISUPPORTS2(nsANSIInputStream, nsIInputStream, nsISeekableStream);
nsANSIInputStream::nsANSIInputStream(FILE* file) : mFile(file)
nsANSIInputStream::nsANSIInputStream(FILE* file) : mFile(file), mSize(0)
{
NS_INIT_ISUPPORTS();
if (file) {
::fseek(file, 0, SEEK_END);
mSize = ::ftell(file);
::fseek(file, 0, SEEK_SET);
}
}
nsANSIInputStream::~nsANSIInputStream()
@ -35,7 +40,6 @@ nsANSIInputStream::~nsANSIInputStream()
Close();
}
/* void close (); */
NS_IMETHODIMP nsANSIInputStream::Close()
{
if (mFile) {
@ -46,13 +50,15 @@ NS_IMETHODIMP nsANSIInputStream::Close()
return NS_BASE_STREAM_CLOSED;
}
/* unsigned long available (); */
NS_IMETHODIMP nsANSIInputStream::Available(PRUint32 *_retval)
NS_IMETHODIMP nsANSIInputStream::Available(PRUint32 * result)
{
return NS_ERROR_NOT_IMPLEMENTED;
if (mFile) {
*result = (mSize - ::ftell(mFile));
return NS_OK;
}
return NS_BASE_STREAM_CLOSED;
}
/* [noscript] unsigned long read (in charPtr buf, in unsigned long count); */
NS_IMETHODIMP nsANSIInputStream::Read(char * buf, PRUint32 count, PRUint32 *result)
{
if (mFile) {
@ -62,30 +68,46 @@ NS_IMETHODIMP nsANSIInputStream::Read(char * buf, PRUint32 count, PRUint32 *resu
return NS_BASE_STREAM_CLOSED;
}
/* [noscript] unsigned long readSegments (in nsWriteSegmentFun writer, in voidPtr closure, in unsigned long count); */
NS_IMETHODIMP nsANSIInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute boolean nonBlocking; */
NS_IMETHODIMP nsANSIInputStream::GetNonBlocking(PRBool *aNonBlocking)
{
*aNonBlocking = PR_FALSE;
return NS_OK;
}
/* attribute nsIInputStreamObserver observer; */
NS_IMETHODIMP nsANSIInputStream::GetObserver(nsIInputStreamObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsANSIInputStream::SetObserver(nsIInputStreamObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMPL_ISUPPORTS1(nsANSIOutputStream, nsIOutputStream);
NS_IMETHODIMP nsANSIInputStream::Seek(PRInt32 whence, PRInt32 offset)
{
if (mFile) {
::fseek(mFile, offset, whence);
return NS_OK;
}
return NS_BASE_STREAM_CLOSED;
}
NS_IMETHODIMP nsANSIInputStream::Tell(PRUint32 * result)
{
if (mFile) {
*result = ::ftell(mFile);
return NS_OK;
}
return NS_BASE_STREAM_CLOSED;
}
NS_IMPL_ISUPPORTS2(nsANSIOutputStream, nsIOutputStream, nsISeekableStream);
nsANSIOutputStream::nsANSIOutputStream(FILE* file) : mFile(file)
{
@ -97,7 +119,6 @@ nsANSIOutputStream::~nsANSIOutputStream()
Close();
}
/* void close (); */
NS_IMETHODIMP nsANSIOutputStream::Close()
{
if (mFile) {
@ -108,7 +129,6 @@ NS_IMETHODIMP nsANSIOutputStream::Close()
return NS_BASE_STREAM_CLOSED;
}
/* void flush (); */
NS_IMETHODIMP nsANSIOutputStream::Flush()
{
if (mFile) {
@ -118,7 +138,6 @@ NS_IMETHODIMP nsANSIOutputStream::Flush()
return NS_BASE_STREAM_CLOSED;
}
/* unsigned long write (in string buf, in unsigned long count); */
NS_IMETHODIMP nsANSIOutputStream::Write(const char *buffer, PRUint32 count, PRUint32 *result)
{
if (mFile) {
@ -128,7 +147,6 @@ NS_IMETHODIMP nsANSIOutputStream::Write(const char *buffer, PRUint32 count, PRUi
return NS_BASE_STREAM_CLOSED;
}
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
NS_IMETHODIMP nsANSIOutputStream::WriteFrom(nsIInputStream *input, PRUint32 count, PRUint32 *actualCount)
{
char buffer[BUFSIZ];
@ -145,13 +163,11 @@ NS_IMETHODIMP nsANSIOutputStream::WriteFrom(nsIInputStream *input, PRUint32 coun
return NS_OK;
}
/* [noscript] unsigned long writeSegments (in nsReadSegmentFun reader, in voidPtr closure, in unsigned long count); */
NS_IMETHODIMP nsANSIOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute boolean nonBlocking; */
NS_IMETHODIMP nsANSIOutputStream::GetNonBlocking(PRBool *aNonBlocking)
{
*aNonBlocking = PR_FALSE;
@ -162,7 +178,6 @@ NS_IMETHODIMP nsANSIOutputStream::SetNonBlocking(PRBool aNonBlocking)
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIOutputStreamObserver observer; */
NS_IMETHODIMP nsANSIOutputStream::GetObserver(nsIOutputStreamObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
@ -171,3 +186,21 @@ NS_IMETHODIMP nsANSIOutputStream::SetObserver(nsIOutputStreamObserver * aObserve
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsANSIOutputStream::Seek(PRInt32 whence, PRInt32 offset)
{
if (mFile) {
::fseek(mFile, offset, whence);
return NS_OK;
}
return NS_BASE_STREAM_CLOSED;
}
NS_IMETHODIMP nsANSIOutputStream::Tell(PRUint32 * result)
{
if (mFile) {
*result = ::ftell(mFile);
return NS_OK;
}
return NS_BASE_STREAM_CLOSED;
}

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

@ -26,24 +26,26 @@
#include <stdio.h>
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIFileStreams.h"
class nsANSIInputStream : public nsIInputStream {
FILE* mFile;
class nsANSIInputStream : public nsIInputStream, public nsISeekableStream {
FILE* mFile;
PRUint32 mSize;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIINPUTSTREAM
NS_DECL_NSISEEKABLESTREAM
nsANSIInputStream(FILE* file);
virtual ~nsANSIInputStream();
};
class nsANSIOutputStream : public nsIOutputStream {
class nsANSIOutputStream : public nsIOutputStream, public nsISeekableStream {
FILE* mFile;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOUTPUTSTREAM
NS_DECL_NSISEEKABLESTREAM
nsANSIOutputStream(FILE* file);
virtual ~nsANSIOutputStream();

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

@ -42,6 +42,7 @@ public:
virtual ~nsCacheDevice() {}
virtual nsresult Init() = 0;
virtual nsresult Shutdown() = 0;
virtual const char * GetDeviceID(void) = 0;
virtual nsCacheEntry * FindEntry( nsCString * key ) = 0;
@ -59,9 +60,13 @@ public:
virtual nsresult OnDataSizeChange( nsCacheEntry * entry, PRInt32 deltaSize ) = 0;
// XXX need to define methods for enumerating entries
virtual nsresult Visit(nsICacheVisitor * visitor) = 0;
/**
* Device must evict entries associated with clientID. If clientID == nsnull, all
* entries must be evicted. Active entries must be doomed, rather than evicted.
*/
virtual nsresult EvictEntries(const char * clientID) = 0;
};
#endif // _nsCacheDevice_h_

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

@ -36,8 +36,8 @@ nsCacheEntry::nsCacheEntry(nsCString * key,
PRBool streamBased,
nsCacheStoragePolicy storagePolicy)
: mKey(key),
mFetchCount(1),
mLastValidated(0),
mFetchCount(0),
mLastFetched(0),
mExpirationTime(0),
mFlags(0),
mDataSize(0),
@ -50,8 +50,6 @@ nsCacheEntry::nsCacheEntry(nsCString * key,
PR_INIT_CLIST(&mRequestQ);
PR_INIT_CLIST(&mDescriptorQ);
mLastFetched = SecondsFromPRTime(PR_Now());
if (streamBased) MarkStreamBased();
SetStoragePolicy(storagePolicy);
}
@ -65,51 +63,30 @@ nsCacheEntry::~nsCacheEntry()
void
nsCacheEntry::SetDataSize( PRUint32 size)
nsCacheEntry::Fetched()
{
mDataSize = size;
mLastModified = SecondsFromPRTime(PR_Now());
MarkEntryDirty();
}
nsresult
nsCacheEntry::GetSecurityInfo( nsISupports ** result)
{
NS_ENSURE_ARG_POINTER(result);
NS_IF_ADDREF(*result = mSecurityInfo);
return NS_OK;
}
nsresult
nsCacheEntry::SetSecurityInfo( nsISupports * info)
{
mSecurityInfo = info;
return NS_OK;
mLastFetched = SecondsFromPRTime(PR_Now());
++mFetchCount;
}
nsresult
nsCacheEntry::GetData(nsISupports **result)
{
if (!result)
return NS_ERROR_NULL_POINTER;
NS_ENSURE_ARG_POINTER(result);
NS_IF_ADDREF(*result = mData);
return NS_OK;
}
nsresult
nsCacheEntry::SetData(nsISupports * data)
void
nsCacheEntry::TouchData()
{
mLastModified = SecondsFromPRTime(PR_Now());
mData = data;
return NS_OK;
MarkDataDirty();
}
nsresult
nsCacheEntry::GetMetaDataElement( const nsAReadableCString& key,
nsAReadableCString ** value)
@ -133,28 +110,10 @@ nsCacheEntry::SetMetaDataElement( const nsAReadableCString& key,
return rv;
mMetaSize = mMetaData->Size(); // calc new meta data size
mLastModified = SecondsFromPRTime(PR_Now()); // time stamp the entry
MarkMetaDataDirty(); // mark it dirty
return rv;
}
#if 0
nsresult
nsCacheEntry::GetKeyValueArray(nsCacheMetaDataKeyValuePair ** array,
PRUint32 * count)
{
if (!array || !count) return NS_ERROR_NULL_POINTER;
if (!mMetaData) {
*array = nsnull;
*count = 0;
return NS_OK;
}
return mMetaData->GetKeyValueArray(array, count);
}
#endif
nsresult
nsCacheEntry::FlattenMetaData(char ** data, PRUint32 * size)
{
@ -176,9 +135,46 @@ nsCacheEntry::UnflattenMetaData(char * data, PRUint32 size)
mMetaData = nsCacheMetaData::Create();
if (!mMetaData)
return NS_ERROR_OUT_OF_MEMORY;
return mMetaData->UnflattenMetaData(data, size);
nsresult rv = mMetaData->UnflattenMetaData(data, size);
if (NS_SUCCEEDED(rv))
mMetaSize = mMetaData->Size();
return rv;
}
void
nsCacheEntry::TouchMetaData()
{
mLastModified = SecondsFromPRTime(PR_Now());
MarkMetaDataDirty();
}
#if 0
nsresult
nsCacheEntry::GetKeyValueArray(nsCacheMetaDataKeyValuePair ** array,
PRUint32 * count)
{
if (!array || !count) return NS_ERROR_NULL_POINTER;
if (!mMetaData) {
*array = nsnull;
*count = 0;
return NS_OK;
}
return mMetaData->GetKeyValueArray(array, count);
}
#endif
nsresult
nsCacheEntry::GetSecurityInfo( nsISupports ** result)
{
NS_ENSURE_ARG_POINTER(result);
NS_IF_ADDREF(*result = mSecurityInfo);
return NS_OK;
}
/**
* cache entry states
* 0 descriptors (new entry)
@ -360,17 +356,6 @@ nsCacheEntryInfo::GetLastModified(PRUint32 * lastModified)
}
NS_IMETHODIMP
nsCacheEntryInfo::GetLastValidated(PRUint32 * lastValidated)
{
NS_ENSURE_ARG_POINTER(lastValidated);
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
*lastValidated = mCacheEntry->LastValidated();
return NS_OK;
}
NS_IMETHODIMP
nsCacheEntryInfo::GetExpirationTime(PRUint32 * expirationTime)
{
@ -423,14 +408,15 @@ nsCacheEntryHashTable::ops =
nsCacheEntryHashTable::nsCacheEntryHashTable()
: initialized(0)
: initialized(PR_FALSE)
{
}
nsCacheEntryHashTable::~nsCacheEntryHashTable()
{
PL_DHashTableFinish(&table);
if (initialized)
PL_DHashTableFinish(&table);
}

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

@ -53,46 +53,43 @@ public:
nsCacheStoragePolicy storagePolicy);
~nsCacheEntry();
nsCacheEntry *
Create(nsCString * key,
PRBool streamBased,
nsCacheStoragePolicy storagePolicy,
nsCacheDevice * cacheDevice);
nsCString * Key(void) { return mKey; }
nsCString * Key() { return mKey; }
PRInt32 FetchCount(void) { return mFetchCount;}
PRInt32 FetchCount() { return mFetchCount;}
void SetFetchCount( PRInt32 count) { mFetchCount = count;}
void IncrementFetchCount(void) { ++mFetchCount; }
void Fetched();
PRUint32 LastFetched(void) { return mLastFetched;}
PRUint32 LastFetched() { return mLastFetched;}
void SetLastFetched( PRUint32 lastFetched) { mLastFetched = lastFetched;}
PRUint32 LastModified(void) { return mLastModified;}
PRUint32 LastModified() { return mLastModified;}
void SetLastModified( PRUint32 lastModified) { mLastModified = lastModified;}
PRUint32 LastValidated(void) { return mLastValidated;}
void SetLastValidated( PRUint32 lastValidated) { mLastValidated = lastValidated;}
PRUint32 ExpirationTime(void) { return mExpirationTime;}
PRUint32 ExpirationTime() { return mExpirationTime;}
void SetExpirationTime( PRUint32 expires) { mExpirationTime = expires;}
PRUint32 DataSize(void) { return mDataSize;}
void SetDataSize( PRUint32 size);
PRUint32 Size() { return mDataSize + mMetaSize; }
PRUint32 MetaDataSize(void) { return mMetaSize;}
PRUint32 Size(void) { return mDataSize + mMetaSize; }
nsCacheDevice * CacheDevice(void) { return mCacheDevice;}
nsCacheDevice * CacheDevice() { return mCacheDevice;}
void SetCacheDevice( nsCacheDevice * device) { mCacheDevice = device;}
nsresult GetSecurityInfo( nsISupports ** result);
nsresult SetSecurityInfo( nsISupports * info);
/**
* Data accessors
*/
nsresult GetData( nsISupports ** result);
nsresult SetData( nsISupports * data);
void SetData( nsISupports * data) { mData = data; }
PRUint32 DataSize() { return mDataSize;}
void SetDataSize( PRUint32 size) { mDataSize = size;}
void TouchData();
/**
* Meta data accessors
*/
nsresult GetMetaDataElement( const nsAReadableCString& key,
nsAReadableCString ** value);
nsresult SetMetaDataElement( const nsAReadableCString& key,
@ -101,6 +98,18 @@ public:
nsresult FlattenMetaData(char ** data, PRUint32 * size);
nsresult UnflattenMetaData(char * data, PRUint32 size);
PRUint32 MetaDataSize() { return mMetaSize;}
void TouchMetaData();
/**
* Security Info accessors
*/
nsresult GetSecurityInfo( nsISupports ** result);
void SetSecurityInfo( nsISupports * info) { mSecurityInfo = info; }
// XXX enumerate MetaData method
@ -187,7 +196,6 @@ private:
void DetachDescriptors(void);
// internal methods
nsresult CommonOpen(nsCacheRequest * request, nsCacheAccessMode *accessGranted);
void MarkDoomed() { mFlags |= eDoomedMask; }
void MarkStreamBased() { mFlags |= eStreamDataMask; }
void MarkInitialized() { mFlags |= eInitializedMask; }
@ -227,7 +235,7 @@ public:
}
virtual ~nsCacheEntryInfo() {}
void DetachEntry(void) { mCacheEntry = nsnull; }
void DetachEntry() { mCacheEntry = nsnull; }
private:
nsCacheEntry * mCacheEntry;

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

@ -146,17 +146,6 @@ nsCacheEntryDescriptor::GetLastModified(PRUint32 *result)
}
NS_IMETHODIMP
nsCacheEntryDescriptor::GetLastValidated(PRUint32 *result)
{
NS_ENSURE_ARG_POINTER(result);
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
*result = mCacheEntry->LastValidated();
return NS_OK;
}
NS_IMETHODIMP
nsCacheEntryDescriptor::GetExpirationTime(PRUint32 *result)
{
@ -174,6 +163,7 @@ nsCacheEntryDescriptor::SetExpirationTime(PRUint32 expirationTime)
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
mCacheEntry->SetExpirationTime(expirationTime);
mCacheEntry->MarkEntryDirty();
return NS_OK;
}
@ -207,6 +197,7 @@ nsCacheEntryDescriptor::RequestDataSizeChange(PRInt32 deltaSize)
// XXX review for signed/unsigned math errors
PRUint32 newDataSize = mCacheEntry->DataSize() + deltaSize;
mCacheEntry->SetDataSize(newDataSize);
mCacheEntry->TouchData();
}
return rv;
}
@ -256,7 +247,9 @@ nsCacheEntryDescriptor::SetCacheElement(nsISupports * cacheElement)
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
if (mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_STREAM;
return mCacheEntry->SetData(cacheElement);
mCacheEntry->SetData(cacheElement);
mCacheEntry->TouchData();
return NS_OK;
}
@ -285,7 +278,7 @@ nsCacheEntryDescriptor::SetStoragePolicy(nsCacheStoragePolicy policy)
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
// XXX validate policy against session?
mCacheEntry->SetStoragePolicy(policy);
mCacheEntry->MarkEntryDirty();
return NS_OK;
}
@ -316,6 +309,7 @@ nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo)
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
mCacheEntry->SetSecurityInfo(securityInfo);
mCacheEntry->MarkEntryDirty();
return NS_OK;
}
@ -394,6 +388,8 @@ nsCacheEntryDescriptor::SetMetaDataElement(const char *key, const char *value)
// XXX allow null value, for clearing key?
nsresult rv = mCacheEntry->SetMetaDataElement(nsLiteralCString(key),
nsLiteralCString(value));
if (NS_SUCCEEDED(rv))
mCacheEntry->TouchMetaData();
return rv;
}

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

@ -44,13 +44,14 @@ nsCacheMetaData::ops =
nsCacheMetaData::nsCacheMetaData()
: initialized(0)
: initialized(PR_FALSE)
{
}
nsCacheMetaData::~nsCacheMetaData()
{
PL_DHashTableFinish(&table);
if (initialized)
PL_DHashTableFinish(&table);
}

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

@ -37,16 +37,129 @@
#include "nsIEventQueue.h"
#include "nsProxiedService.h"
#include "nsIObserverService.h"
#include "nsIPref.h"
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
/******************************************************************************
* nsCachePrefObserver
*****************************************************************************/
#define ENABLE_MEMORY_CACHE_PREF "browser.cache.enable"
#define ENABLE_DISK_CACHE_PREF "browser.cache.disk.enable"
class nsCachePrefObserver : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
nsCachePrefObserver() :
mDiskCacheEnabled(PR_TRUE),
mMemoryCacheEnabled(PR_TRUE)
{
NS_INIT_ISUPPORTS();
}
virtual ~nsCachePrefObserver() {}
nsresult Install();
nsresult Remove();
private:
PRBool mDiskCacheEnabled;
PRBool mMemoryCacheEnabled;
};
NS_IMPL_ISUPPORTS1(nsCachePrefObserver, nsIObserver);
nsresult
nsCachePrefObserver::Install()
{
nsresult rv, rv2;
nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
rv = prefs->AddObserver(ENABLE_MEMORY_CACHE_PREF, this);
if (NS_FAILED(rv)) rv2 = rv;
rv = prefs->AddObserver(ENABLE_DISK_CACHE_PREF, this);
if (NS_FAILED(rv)) rv2 = rv;
rv = prefs->GetBoolPref(ENABLE_DISK_CACHE_PREF, &mDiskCacheEnabled);
if (NS_FAILED(rv)) rv2 = rv;
rv = prefs->GetBoolPref(ENABLE_MEMORY_CACHE_PREF, &mMemoryCacheEnabled);
// if (NS_FAILED(rv)) rv2 = rv;
if (NS_SUCCEEDED(rv)) rv = rv2;
return rv;
}
nsresult
nsCachePrefObserver::Remove()
{
nsresult rv, rv2;
nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
rv = prefs->RemoveObserver(ENABLE_DISK_CACHE_PREF, this);
rv2 = prefs->RemoveObserver(ENABLE_MEMORY_CACHE_PREF, this);
if (NS_SUCCEEDED(rv)) rv = rv2;
return rv;
}
NS_IMETHODIMP
nsCachePrefObserver::Observe(nsISupports * subject,
const PRUnichar * topic,
const PRUnichar * data)
{
nsresult rv;
if (NS_LITERAL_STRING("nsPref:changed").Equals(topic)) {
nsCOMPtr<nsIPref> prefs = do_QueryInterface(subject, &rv);
if (NS_FAILED(rv)) return rv;
// which preference changed?
if (NS_LITERAL_STRING(ENABLE_DISK_CACHE_PREF).Equals(data)) {
rv = prefs->GetBoolPref(ENABLE_DISK_CACHE_PREF, &mDiskCacheEnabled);
} else if (NS_LITERAL_STRING(ENABLE_MEMORY_CACHE_PREF).Equals(data)) {
rv = prefs->GetBoolPref(ENABLE_MEMORY_CACHE_PREF, &mMemoryCacheEnabled);
}
if (NS_FAILED(rv)) return rv;
nsCacheService::GlobalInstance()->SetCacheDevicesEnabled(mDiskCacheEnabled,
mMemoryCacheEnabled);
}
return NS_OK;
}
/******************************************************************************
* nsCacheService
*****************************************************************************/
nsCacheService * nsCacheService::gService = nsnull;
NS_IMPL_THREADSAFE_ISUPPORTS2(nsCacheService, nsICacheService, nsIObserver)
nsCacheService::nsCacheService()
: mCacheServiceLock(nsnull),
mEnableMemoryDevice(PR_TRUE),
mEnableDiskDevice(PR_TRUE),
mMemoryDevice(nsnull),
mDiskDevice(nsnull),
mTotalEntries(0),
@ -95,25 +208,40 @@ nsCacheService::Init()
// initialize hashtable for active cache entries
rv = mActiveEntries.Init();
if (NS_FAILED(rv)) goto error;
// create memory cache
mMemoryDevice = new nsMemoryCacheDevice;
if (!mMemoryDevice) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto error;
{ // scope nsCOMPtr<nsIPref>
nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = prefs->GetBoolPref(ENABLE_DISK_CACHE_PREF, &mEnableDiskDevice);
rv = prefs->GetBoolPref(ENABLE_MEMORY_CACHE_PREF, &mEnableMemoryDevice);
// ignore errors
}
}
if (mEnableMemoryDevice) { // create memory cache
mMemoryDevice = new nsMemoryCacheDevice;
if (!mMemoryDevice) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto error;
}
rv = mMemoryDevice->Init();
if (NS_FAILED(rv)) {
// XXX log error
delete mMemoryDevice;
mMemoryDevice = nsnull;
}
}
rv = mMemoryDevice->Init();
if (NS_FAILED(rv)) goto error;
#if EAGER_DISK_INIT
// create disk cache
mDiskDevice = new nsDiskCacheDevice;
if (!mDiskDevice) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto error;
if (mEnableDiskCache) { // create disk cache
mDiskDevice = new nsDiskCacheDevice;
if (!mDiskDevice) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto error;
}
rv = mDiskDevice->Init();
if (NS_FAILED(rv)) goto error;
}
rv = mDiskDevice->Init();
if (NS_FAILED(rv)) goto error;
#endif
// observer XPCOM shutdown.
@ -194,6 +322,9 @@ nsCacheService::CreateSession(const char * clientID,
{
*result = nsnull;
if (!(mEnableDiskDevice || mEnableMemoryDevice))
return NS_ERROR_NOT_AVAILABLE;
nsCacheSession * session = new nsCacheSession(clientID, storagePolicy, streamBased);
if (!session) return NS_ERROR_OUT_OF_MEMORY;
@ -207,44 +338,89 @@ nsCacheService::CreateSession(const char * clientID,
NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor)
{
nsAutoLock lock(mCacheServiceLock);
if (!(mEnableDiskDevice || mEnableMemoryDevice))
return NS_ERROR_NOT_AVAILABLE;
// XXX record the fact that a visitation is in progress, i.e. keep
// list of visitors in progress.
nsresult rv = mMemoryDevice->Visit(visitor);
if (NS_FAILED(rv)) return rv;
if (!mDiskDevice) {
rv = CreateDiskDevice();
nsresult rv = NS_OK;
if (mEnableMemoryDevice) {
rv = mMemoryDevice->Visit(visitor);
if (NS_FAILED(rv)) return rv;
}
if (mEnableDiskDevice) {
if (!mDiskDevice) {
rv = CreateDiskDevice();
if (NS_FAILED(rv)) return rv;
}
rv = mDiskDevice->Visit(visitor);
if (NS_FAILED(rv)) return rv;
}
rv = mDiskDevice->Visit(visitor);
if (NS_FAILED(rv)) return rv;
// XXX notify any shutdown process that visitation is complete for THIS visitor.
// XXX keep queue of visitors
return NS_OK;
}
NS_IMETHODIMP nsCacheService::EvictEntries(nsCacheStoragePolicy storagePolicy)
{
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
if (storagePolicy == nsICache::STORE_ON_DISK) {
if (mEnableDiskDevice) {
if (!mDiskDevice) {
rv = CreateDiskDevice();
if (NS_FAILED(rv)) return rv;
}
rv = mDiskDevice->EvictEntries(nsnull);
}
}
return rv;
}
/**
* Internal Methods
*/
nsresult
nsCacheService::CreateDiskDevice()
{
nsresult rv = NS_OK;
if (!mDiskDevice) {
// create disk cache lazily
mDiskDevice = new nsDiskCacheDevice;
if (mDiskDevice) {
rv = mDiskDevice->Init();
if (NS_FAILED(rv)) {
delete mDiskDevice;
mDiskDevice = nsnull;
}
} else {
rv = NS_ERROR_OUT_OF_MEMORY;
}
if (!mEnableDiskDevice) return NS_ERROR_NOT_AVAILABLE;
if (mDiskDevice) return NS_OK;
mDiskDevice = new nsDiskCacheDevice;
if (!mDiskDevice) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = mDiskDevice->Init();
if (NS_FAILED(rv)) {
// XXX log error
delete mDiskDevice;
mDiskDevice = nsnull;
}
return rv;
}
nsresult
nsCacheService::CreateMemoryDevice()
{
if (!mEnableMemoryDevice) return NS_ERROR_NOT_AVAILABLE;
if (mMemoryDevice) return NS_OK;
mMemoryDevice = new nsMemoryCacheDevice;
if (!mMemoryDevice) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = mMemoryDevice->Init();
if (NS_FAILED(rv)) {
// XXX log error
delete mMemoryDevice;
mMemoryDevice = nsnull;
}
return rv;
}
@ -434,7 +610,7 @@ nsCacheService::ActivateEntry(nsCacheRequest * request,
if (entry) {
++mCacheHits;
entry->IncrementFetchCount();
entry->Fetched();
} else {
++mCacheMisses;
}
@ -465,6 +641,7 @@ nsCacheService::ActivateEntry(nsCacheRequest * request,
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
entry->Fetched();
++mTotalEntries;
// XXX we could perform an early bind in some cases based on storage policy
@ -494,19 +671,22 @@ nsCacheService::SearchCacheDevices(nsCString * key, nsCacheStoragePolicy policy)
nsCacheEntry * entry = nsnull;
if ((policy == nsICache::STORE_ANYWHERE) || (policy == nsICache::STORE_IN_MEMORY)) {
entry = mMemoryDevice->FindEntry(key);
if (mEnableMemoryDevice)
entry = mMemoryDevice->FindEntry(key);
}
if (!entry &&
((policy == nsICache::STORE_ANYWHERE) || (policy == nsICache::STORE_ON_DISK))) {
if (!mDiskDevice) {
nsresult rv = CreateDiskDevice();
if (NS_FAILED(rv))
return nsnull;
if (mEnableDiskDevice) {
if (!mDiskDevice) {
nsresult rv = CreateDiskDevice();
if (NS_FAILED(rv))
return nsnull;
}
entry = mDiskDevice->FindEntry(key);
}
entry = mDiskDevice->FindEntry(key);
}
return entry;
@ -519,7 +699,7 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry)
nsCacheDevice * device = entry->CacheDevice();
if (device) return device;
if (entry->IsStreamData() && entry->IsAllowedOnDisk()) {
if (entry->IsStreamData() && entry->IsAllowedOnDisk() && mEnableDiskDevice) {
// this is the default
if (!mDiskDevice) {
nsresult rv = CreateDiskDevice();
@ -528,11 +708,13 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry)
}
device = mDiskDevice;
} else {
} else if (mEnableMemoryDevice) {
NS_ASSERTION(entry->IsAllowedInMemory(), "oops.. bad flags");
device = mMemoryDevice;
}
if (device == nsnull) return nsnull;
nsresult rv = device->BindEntry(entry);
if (NS_FAILED(rv)) return nsnull;
@ -601,6 +783,24 @@ nsCacheService::DoomEntry_Locked(nsCacheEntry * entry)
}
void
nsCacheService::SetCacheDevicesEnabled(PRBool enableDisk, PRBool enableMemory)
{
if (this == nsnull) return; // NS_ERROR_NOT_AVAILABLE;
nsAutoLock lock(mCacheServiceLock);
if (enableDisk && !mDiskDevice) {
// disk device requires lazy activation
} else if (!enableDisk && mDiskDevice) {
// XXX deactivate disk
}
if (enableMemory && !mMemoryDevice) {
// XXX enable memory cache device
} else if (!enableMemory && mMemoryDevice) {
// XXX disable memory cache device
}
}
nsresult

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

@ -95,10 +95,9 @@ public:
nsresult DoomEntry_Locked(nsCacheEntry * entry);
/**
* static utility methods
* Methods called by nsCachePrefObserver
*/
static nsresult ClientID(const nsAReadableCString& clientID, char ** result);
static nsresult ClientKey(const nsAReadableCString& clientKey, char ** result);
void SetCacheDevicesEnabled(PRBool disk, PRBool memory);
private:
@ -107,6 +106,7 @@ private:
*/
nsresult CreateDiskDevice();
nsresult CreateMemoryDevice();
nsresult CreateRequest(nsCacheSession * session,
const char * clientKey,
@ -137,7 +137,7 @@ private:
void ClearActiveEntries(void);
static
PLDHashOperator PR_CALLBACK DeactivateAndClearEntry(PLDHashTable * table,
PLDHashOperator PR_CALLBACK DeactivateAndClearEntry(PLDHashTable * table,
PLDHashEntryHdr * hdr,
PRUint32 number,
void * arg);
@ -154,6 +154,9 @@ private:
PRLock* mCacheServiceLock;
PRBool mEnableMemoryDevice;
PRBool mEnableDiskDevice;
nsCacheDevice * mMemoryDevice;
nsCacheDevice * mDiskDevice;

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

@ -94,3 +94,8 @@ NS_IMETHODIMP nsCacheSession::AsyncOpenCacheEntry(const char *key,
if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) rv = NS_OK;
return rv;
}
NS_IMETHODIMP nsCacheSession::EvictEntries()
{
return NS_ERROR_NOT_IMPLEMENTED;
}

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

@ -26,83 +26,115 @@
#ifndef _nsDiskCache_h_
#define _nsDiskCache_h_
enum {
eEvictionRankMask = 0xFF000000;
eLocationSelectorMask = 0x00C00000;
#include "prtypes.h"
#include "prnetdb.h"
#include "nsDebug.h"
eExtraBlocksMask = 0x00300000;
eBlockNumberMask = 0x000FFFFF;
class nsDiskCacheRecord {
enum {
eEvictionRankMask = 0xFF000000,
eLocationSelectorMask = 0x00C00000,
eFileReservedMask = 0x003F0000;
eFileGenerationMask = 0x0000FFFF;
};
eExtraBlocksMask = 0x00300000,
eBlockNumberMask = 0x000FFFFF,
eFileReservedMask = 0x003F0000,
eFileGenerationMask = 0x0000FFFF
};
class DiskCacheRecord {
public:
PRUint32 HashNumber(void) { return mHashNumber; }
void SetHashNumber(PRUint32 hashNumber) { mHashNumber = hashNumber; }
PRUint8 EvictionRank(void)
nsDiskCacheRecord()
: mHashNumber(0), mEvictionRank(0), mLocation(0), mUnused(0)
{
return (PRUint8)(mInfo & eEvictionRankMask) >> 24;
}
PRUint32 HashNumber()
{
return mHashNumber;
}
void SetHashNumber(PRUint32 hashNumber)
{
mHashNumber = hashNumber;
}
void SetEvictionRank(PRUint8 rank)
PRUint32 EvictionRank()
{
mInfo &= ~eEvictionRankMask; // clear eviction rank bits
mInfo |= rank << 24;
return mEvictionRank;
}
PRUint32 LocationSelector(void)
void SetEvictionRank(PRUint32 rank)
{
return (PRUint32)(mInfo & eLocationSelectorMask) >> 22;
mEvictionRank = rank;
}
void SetLocationSelector(PRUint32 selector)
PRUint32 LocationSelector()
{
mInfo &= ~eLocationSelectorMask; // clear location selector bits
mInfo |= (selector & eLocationSelectorMask) << 22;
return (PRUint32)(mLocation & eLocationSelectorMask) >> 22;
}
PRUint32 BlockCount(void)
void SetLocationSelector(PRUint32 selector)
{
return (PRUint32)((mInfo & eExtraBlocksMask) >> 20) + 1;
mLocation &= ~eLocationSelectorMask; // clear location selector bits
mLocation |= (selector & eLocationSelectorMask) << 22;
}
void SetBlockCount(PRUint32 count)
PRUint32 BlockCount()
{
return (PRUint32)((mLocation & eExtraBlocksMask) >> 20) + 1;
}
void SetBlockCount(PRUint32 count)
{
NS_ASSERTION( (count>=1) && (count<=4),"invalid block count");
count = --count;
mInfo &= ~eExtraBlocksMask; // clear extra blocks bits
mInfo |= (count & eExtraBlocksMask) << 20;
mLocation &= ~eExtraBlocksMask; // clear extra blocks bits
mLocation |= (count & eExtraBlocksMask) << 20;
}
PRUint32 BlockNumber(void)
PRUint32 BlockNumber()
{
return mInfo & eBlockNumberMask;
return (mLocation & eBlockNumberMask);
}
void SetBlockNumber(PRUint32 blockNumber)
{
mInfo &= ~eBlockNumberMask; // clear block number bits
mInfo |= blockNumber & eBlockNumberMask;
mLocation &= ~eBlockNumberMask; // clear block number bits
mLocation |= blockNumber & eBlockNumberMask;
}
PRUint16 FileGeneration(void)
PRUint16 FileGeneration()
{
return mInfo & eFileGenerationMask;
return (mLocation & eFileGenerationMask);
}
void SetFileGeneration(PRUint16 generation)
{
mInfo &= ~eFileGenerationMask; // clear file generation bits
mInfo |= generation & eFileGenerationMask;
mLocation &= ~eFileGenerationMask; // clear file generation bits
mLocation |= generation & eFileGenerationMask;
}
void Swap()
{
mHashNumber = ::PR_htonl(mHashNumber);
mEvictionRank = ::PR_htonl(mEvictionRank);
mLocation = ::PR_htonl(mLocation);
mUnused = ::PR_htonl(mUnused);
}
void Unswap()
{
mHashNumber = ::PR_ntohl(mHashNumber);
mEvictionRank = ::PR_ntohl(mEvictionRank);
mLocation = ::PR_ntohl(mLocation);
mUnused = ::PR_ntohl(mUnused);
}
private:
PRUint32 mHashNumber;
PRUint32 mInfo;
PRUint32 mHashNumber;
PRUint32 mEvictionRank;
PRUint32 mLocation;
PRUint32 mUnused;
};

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

@ -10,7 +10,7 @@
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is nsMemoryCacheDevice.cpp, released February 22, 2001.
* The Original Code is nsDiskCacheDevice.cpp, released February 22, 2001.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
@ -24,8 +24,10 @@
#include <limits.h>
#include "nsANSIFileStreams.h"
#include "nsDiskCacheDevice.h"
#include "nsDiskCacheEntry.h"
#include "nsDiskCacheMap.h"
#include "nsCacheService.h"
#include "nsCache.h"
@ -43,8 +45,6 @@
static const char DISK_CACHE_DEVICE_ID[] = { "disk" };
static FILE* openFileStream(nsIFile* file, const char* mode);
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// Using nsIPref will be subsumed with nsIDirectoryService when a selector
@ -75,9 +75,7 @@ NS_IMETHODIMP nsDiskCacheObserver::Observe(nsISupports *aSubject, const PRUnicha
nsresult rv;
// did a preference change?
nsLiteralString aTopicString(aTopic);
if (aTopicString.Equals(NS_LITERAL_STRING("nsPref:changed"))) {
// when bug #71879 gets fixed, this QueryInterface will succeed!
if (NS_LITERAL_STRING("nsPref:changed").Equals(aTopic)) {
nsCOMPtr<nsIPref> prefs = do_QueryInterface(aSubject, &rv);
if (!prefs) {
prefs = do_GetService(NS_PREF_CONTRACTID, &rv);
@ -98,7 +96,7 @@ NS_IMETHODIMP nsDiskCacheObserver::Observe(nsISupports *aSubject, const PRUnicha
if (NS_SUCCEEDED(rv))
mDevice->setCacheCapacity(cacheCapacity);
}
} else if (aTopicString.Equals(NS_LITERAL_STRING("profile-do-change"))) {
} else if (NS_LITERAL_STRING("profile-do-change").Equals(aTopic)) {
// XXX need to regenerate the cache directory. hopefully the
// cache service has already been informed of this change.
nsCOMPtr<nsIFile> profileDir;
@ -283,6 +281,7 @@ NS_IMPL_ISUPPORTS1(nsDiskCacheDeviceInfo, nsICacheDeviceInfo);
/* readonly attribute string description; */
NS_IMETHODIMP nsDiskCacheDeviceInfo::GetDescription(char ** aDescription)
{
NS_ENSURE_ARG_POINTER(aDescription);
char* result = nsCRT::strdup("disk cache device");
if (!result) return NS_ERROR_OUT_OF_MEMORY;
*aDescription = result;
@ -292,6 +291,7 @@ NS_IMETHODIMP nsDiskCacheDeviceInfo::GetDescription(char ** aDescription)
/* readonly attribute string usageReport; */
NS_IMETHODIMP nsDiskCacheDeviceInfo::GetUsageReport(char ** aUsageReport)
{
NS_ENSURE_ARG_POINTER(aUsageReport);
char* result = nsCRT::strdup("disk cache usage report");
if (!result) return NS_ERROR_OUT_OF_MEMORY;
*aUsageReport = result;
@ -301,12 +301,15 @@ NS_IMETHODIMP nsDiskCacheDeviceInfo::GetUsageReport(char ** aUsageReport)
/* readonly attribute unsigned long entryCount; */
NS_IMETHODIMP nsDiskCacheDeviceInfo::GetEntryCount(PRUint32 *aEntryCount)
{
return NS_ERROR_NOT_IMPLEMENTED;
NS_ENSURE_ARG_POINTER(aEntryCount);
*aEntryCount = mDevice->getEntryCount();
return NS_OK;
}
/* readonly attribute unsigned long totalSize; */
NS_IMETHODIMP nsDiskCacheDeviceInfo::GetTotalSize(PRUint32 *aTotalSize)
{
NS_ENSURE_ARG_POINTER(aTotalSize);
*aTotalSize = mDevice->getCacheSize();
return NS_OK;
}
@ -314,6 +317,7 @@ NS_IMETHODIMP nsDiskCacheDeviceInfo::GetTotalSize(PRUint32 *aTotalSize)
/* readonly attribute unsigned long maximumSize; */
NS_IMETHODIMP nsDiskCacheDeviceInfo::GetMaximumSize(PRUint32 *aMaximumSize)
{
NS_ENSURE_ARG_POINTER(aMaximumSize);
*aMaximumSize = mDevice->getCacheCapacity();
return NS_OK;
}
@ -354,6 +358,30 @@ struct MetaDataHeader {
mMetaDataSize(0)
{
}
void Swap()
{
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);
}
void Unswap()
{
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);
}
};
struct MetaDataFile : MetaDataHeader {
@ -386,69 +414,25 @@ struct MetaDataFile : MetaDataHeader {
return entry->FlattenMetaData(&mMetaData, &mMetaDataSize);
}
nsresult Write(nsIOutputStream* output);
nsresult Read(nsIInputStream* input);
nsresult Write(nsIOutputStream* output);
};
#define WRITE_LONG_(item) \
PR_BEGIN_MACRO \
n = PR_htonl(item); \
rv = output->Write((char*)&n, sizeof(n), &count); \
if (NS_FAILED(rv)) return rv; \
PR_END_MACRO
#define READ_LONG_(item) \
PR_BEGIN_MACRO \
rv = input->Read((char*)&n, sizeof(n), &count); \
if (NS_FAILED(rv)) return rv; \
item = PR_ntohl(n); \
PR_END_MACRO
nsresult MetaDataFile::Write(nsIOutputStream* output)
{
nsresult rv;
PRUint32 n, count;
WRITE_LONG_(mHeaderSize);
WRITE_LONG_(mFetchCount);
WRITE_LONG_(mLastFetched);
WRITE_LONG_(mLastModified);
WRITE_LONG_(mExpirationTime);
WRITE_LONG_(mDataSize);
WRITE_LONG_(mKeySize);
WRITE_LONG_(mMetaDataSize);
// 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;
}
nsresult MetaDataFile::Read(nsIInputStream* input)
{
nsresult rv;
PRUint32 n, count;
PRUint32 count;
// read the header size used by this file.
READ_LONG_(mHeaderSize);
// read in the file header.
rv = input->Read((char*)&mHeaderSize, sizeof(MetaDataHeader), &count);
if (NS_FAILED(rv)) return rv;
Unswap();
// make sure it is self-consistent.
if (mHeaderSize != sizeof(MetaDataHeader)) {
NS_ERROR("### CACHE FORMAT CHANGED!!! PLEASE DELETE YOUR CACHE DIRECTORY!!! ###");
NS_ERROR("### CACHE FORMAT CHANGED!!! PLEASE DELETE YOUR NewCache DIRECTORY!!! ###");
return NS_ERROR_ILLEGAL_VALUE;
}
READ_LONG_(mFetchCount);
READ_LONG_(mLastFetched);
READ_LONG_(mLastModified);
READ_LONG_(mExpirationTime);
READ_LONG_(mDataSize);
READ_LONG_(mKeySize);
READ_LONG_(mMetaDataSize);
// read in the key.
delete[] mKey;
@ -470,6 +454,30 @@ nsresult MetaDataFile::Read(nsIInputStream* input)
return NS_OK;
}
nsresult MetaDataFile::Write(nsIOutputStream* output)
{
nsresult rv;
PRUint32 count;
// 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;
}
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
class nsDiskCacheEntryInfo : public nsICacheEntryInfo {
@ -526,11 +534,6 @@ NS_IMETHODIMP nsDiskCacheEntryInfo::GetLastModified(PRUint32 *aLastModified)
return NS_OK;
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetLastValidated(PRUint32 *aLastValidated)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetExpirationTime(PRUint32 *aExpirationTime)
{
*aExpirationTime = mMetaDataFile.mExpirationTime;
@ -551,30 +554,60 @@ NS_IMETHODIMP nsDiskCacheEntryInfo::GetDataSize(PRUint32 *aDataSize)
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
/**
* Helper class for implementing do_QueryElementAt() pattern. Thanks scc!
* Eventually this should become part of nsICollection.idl.
*/
class do_QueryElementAt : public nsCOMPtr_helper {
public:
do_QueryElementAt(nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr = 0)
: mCollection(aCollection),
mIndex(aIndex),
mErrorPtr(aErrorPtr)
{
// nothing else to do here
}
virtual nsresult operator()( const nsIID& aIID, void** aResult) const
{
nsresult status;
if ( mCollection ) {
if ( !NS_SUCCEEDED(status = mCollection->QueryElementAt(mIndex, aIID, aResult)) )
*aResult = 0;
} else
status = NS_ERROR_NULL_POINTER;
if ( mErrorPtr )
*mErrorPtr = status;
return status;
}
private:
nsICollection* mCollection;
PRUint32 mIndex;
nsresult* mErrorPtr;
};
#if 0
inline const nsQueryElementAt
do_QueryElementAt( nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr = 0 )
{
return nsQueryElementAt(aCollection, aIndex, aErrorPtr);
}
#endif
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
static nsCOMPtr<nsIFileTransportService> gFileTransportService;
nsDiskCacheDevice::nsDiskCacheDevice()
: mCacheCapacity(0), mCacheSize(0), mInitialized(PR_FALSE)
: mInitialized(PR_FALSE), mCacheCapacity(0), mCacheMap(nsnull)
{
}
nsDiskCacheDevice::~nsDiskCacheDevice()
{
removeObservers(this);
if (mInitialized) {
#if 1
// XXX implement poor man's eviction strategy right here,
// keep deleting cache entries from oldest to newest, until
// cache usage is brought below limits.
evictDiskCacheEntries();
#endif
// XXX write out persistent information about the cache.
writeCacheInfo();
}
// XXX release the reference to the cached file transport service.
gFileTransportService = nsnull;
Shutdown();
delete mCacheMap;
}
nsresult
@ -593,16 +626,46 @@ nsDiskCacheDevice::Init()
// XXX read in persistent information about the cache. this can fail, if
// no cache directory has ever existed before.
rv = readCacheInfo();
mCacheMap = new nsDiskCacheMap;
if (!mCacheMap) return NS_ERROR_OUT_OF_MEMORY;
rv = readCacheMap();
if (NS_FAILED(rv)) {
nsCOMPtr<nsISupportsArray> entries;
scanDiskCacheEntries(getter_AddRefs(entries));
}
// XXX record that initialization succeeded.
mInitialized = PR_TRUE;
return NS_OK;
}
nsresult
nsDiskCacheDevice::Shutdown()
{
if (mInitialized) {
// XXX implement poor man's eviction strategy right here,
// keep deleting cache entries from oldest to newest, until
// cache usage is brought below limits.
evictDiskCacheEntries();
// XXX write out persistent information about the cache.
writeCacheMap();
// XXX no longer initialized.
mInitialized = PR_FALSE;
}
// XXX disconnect observers.
removeObservers(this);
// XXX release the reference to the cached file transport service.
gFileTransportService = nsnull;
return NS_OK;
}
nsresult
nsDiskCacheDevice::Create(nsCacheDevice **result)
{
@ -634,13 +697,17 @@ nsDiskCacheDevice::FindEntry(nsCString * key)
nsCacheEntry * entry = nsnull;
nsDiskCacheEntry * diskEntry = mBoundEntries.GetEntry(key->get());
if (!diskEntry) {
nsresult rv = readDiskCacheEntry(key->get(), &diskEntry);
if (NS_FAILED(rv)) return nsnull;
entry = diskEntry->getCacheEntry();
rv = mBoundEntries.AddEntry(diskEntry);
if (NS_FAILED(rv)) {
delete entry;
return nsnull;
PLDHashNumber hashNumber = nsDiskCacheEntry::Hash(key->get());
nsDiskCacheRecord* record = mCacheMap->GetRecord(hashNumber);
if (record->HashNumber() == hashNumber) {
nsresult rv = readDiskCacheEntry(key->get(), &diskEntry);
if (NS_FAILED(rv)) return nsnull;
entry = diskEntry->getCacheEntry();
rv = mBoundEntries.AddEntry(diskEntry);
if (NS_FAILED(rv)) {
delete entry;
return nsnull;
}
}
} else {
// XXX need to make sure this is an exact match, not just
@ -707,6 +774,7 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry * newEntry)
// Make sure this entry has its associated nsDiskCacheEntry data attached.
nsDiskCacheEntry* newDiskEntry = ensureDiskCacheEntry(newEntry);
NS_ASSERTION(newDiskEntry, "nsDiskCacheDevice::BindEntry");
if (!newDiskEntry) return NS_ERROR_OUT_OF_MEMORY;
// XXX check for cache collision. if an entry exists on disk that has the same
// hash code as this newly bound entry, AND there is already a bound entry for
@ -736,6 +804,9 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry * newEntry)
OnDataSizeChange(newEntry, dataSize);
// XXX Need to make this entry known to other entries?
// this probably isn't needed while the entry is bound,
// only when the entry is deactivated. this could be
// the reason disk cache performance suffers.
return updateDiskCacheEntry(newDiskEntry);
}
@ -746,9 +817,11 @@ nsDiskCacheDevice::DoomEntry(nsCacheEntry * entry)
// so it can't be seen by FindEntry() ever again.
nsDiskCacheEntry* diskEntry = ensureDiskCacheEntry(entry);
mBoundEntries.RemoveEntry(diskEntry);
// XXX clear this entry out of the cache map.
// keep track of the cache total size.
mCacheSize -= entry->DataSize();
mCacheMap->DataSize() -= entry->DataSize();
}
@ -791,20 +864,20 @@ nsDiskCacheDevice::GetFileForEntry(nsCacheEntry * entry,
nsIFile ** result)
{
nsDiskCacheEntry* diskEntry = ensureDiskCacheEntry(entry);
return getFileForKey(entry->Key()->get(), PR_FALSE,
diskEntry->getGeneration(), result);
if (!diskEntry) return NS_ERROR_OUT_OF_MEMORY;
return getFileForDiskCacheEntry(diskEntry, PR_FALSE, result);
}
/**
* This routine will get called every time an open descriptor.
* This routine will get called every time an open descriptor is written to.
*/
nsresult
nsDiskCacheDevice::OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize)
{
mCacheSize += deltaSize;
PRUint32 newCacheSize = (mCacheMap->DataSize() += deltaSize);
#if 0
if (mCacheSize > mCacheCapacity) {
if (newCacheSize > mCacheCapacity) {
// XXX go toss out some disk cache entries.
evictDiskCacheEntries();
}
@ -816,7 +889,6 @@ nsDiskCacheDevice::OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize)
nsresult
nsDiskCacheDevice::Visit(nsICacheVisitor * visitor)
{
// XXX
nsDiskCacheDeviceInfo* deviceInfo = new nsDiskCacheDeviceInfo(this);
nsCOMPtr<nsICacheDeviceInfo> ref(deviceInfo);
@ -830,6 +902,61 @@ nsDiskCacheDevice::Visit(nsICacheVisitor * visitor)
return NS_OK;
}
nsresult
nsDiskCacheDevice::EvictEntries(const char * clientID)
{
nsCOMPtr<nsISupportsArray> entries;
nsresult rv = scanDiskCacheEntries(getter_AddRefs(entries));
if (NS_FAILED(rv)) return rv;
PRUint32 prefixLength = (clientID ? nsCRT::strlen(clientID) : 0);
PRUint32 newDataSize = mCacheMap->DataSize();
PRUint32 count;
entries->Count(&count);
for (PRUint32 i = 0; i < count; ++i) {
nsCOMPtr<nsICacheEntryInfo> info = do_QueryElementAt(entries, i, &rv);
if (NS_SUCCEEDED(rv)) {
nsDiskCacheEntryInfo* entryInfo = (nsDiskCacheEntryInfo*) info.get();
const char* key = entryInfo->Key();
// if filtering by clientID, make sure key prefix and clientID match.
if (clientID && nsCRT::strncmp(clientID, key, prefixLength) != 0)
continue;
// if the entry is currently in use, then doom it rather than evicting right here.
nsDiskCacheEntry* diskEntry = mBoundEntries.GetEntry(key);
if (diskEntry) {
nsCacheService::GlobalInstance()->DoomEntry_Locked(diskEntry->getCacheEntry());
continue;
}
// delete the metadata file.
nsCOMPtr<nsIFile> metaFile;
rv = getFileForKey(key, PR_TRUE, 0, getter_AddRefs(metaFile));
if (NS_SUCCEEDED(rv)) {
rv = metaFile->Delete(PR_FALSE);
}
// delete the data file
nsCOMPtr<nsIFile> dataFile;
rv = getFileForKey(key, PR_FALSE, 0, getter_AddRefs(dataFile));
if (NS_SUCCEEDED(rv)) {
rv = dataFile->Delete(PR_FALSE);
}
// update the cache size.
PRUint32 dataSize;
info->GetDataSize(&dataSize);
newDataSize -= dataSize;
}
}
mCacheMap->DataSize() = newDataSize;
return NS_OK;
}
void nsDiskCacheDevice::setPrefsObserver(nsIObserver* observer)
{
mPrefsObserver = observer;
@ -858,11 +985,15 @@ PRUint32 nsDiskCacheDevice::getCacheCapacity()
PRUint32 nsDiskCacheDevice::getCacheSize()
{
return mCacheSize;
return mCacheMap->DataSize();
}
nsresult nsDiskCacheDevice::getFileForKey(const char* key, PRBool meta,
PRUint32 generation, nsIFile ** result)
PRUint32 nsDiskCacheDevice::getEntryCount()
{
return mCacheMap->EntryCount();
}
nsresult nsDiskCacheDevice::getFileForHashNumber(PLDHashNumber hashNumber, PRBool meta, PRUint32 generation, nsIFile ** result)
{
if (mCacheDirectory) {
nsCOMPtr<nsIFile> entryFile;
@ -871,32 +1002,24 @@ nsresult nsDiskCacheDevice::getFileForKey(const char* key, PRBool meta,
return rv;
// generate the hash code for this entry, and use that as a file name.
char name[32];
PLDHashNumber hash = ::PL_DHashStringKey(NULL, key);
::sprintf(name, "%08X%c%02X", hash, (meta ? 'm' : 'd'), generation);
::sprintf(name, "%08X%c%02X", hashNumber, (meta ? 'm' : 'd'), generation);
entryFile->Append(name);
NS_ADDREF(*result = entryFile);
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
}
nsresult nsDiskCacheDevice::getFileForKey(const char* key, PRBool meta,
PRUint32 generation, nsIFile ** result)
{
PLDHashNumber hash = nsDiskCacheEntry::Hash(key);
return getFileForHashNumber(hash, meta, generation, result);
}
nsresult nsDiskCacheDevice::getFileForDiskCacheEntry(nsDiskCacheEntry * diskEntry, PRBool meta,
nsIFile ** result)
{
if (mCacheDirectory) {
nsCOMPtr<nsIFile> entryFile;
nsresult rv = mCacheDirectory->Clone(getter_AddRefs(entryFile));
if (NS_FAILED(rv))
return rv;
// generate the hash code for this entry, and use that as a file name.
char name[32];
::sprintf(name, "%08X%c%02X", diskEntry->getHashNumber(),
(meta ? 'm' : 'd'), diskEntry->getGeneration());
entryFile->Append(name);
NS_ADDREF(*result = entryFile);
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
return getFileForHashNumber(diskEntry->getHashNumber(), meta, diskEntry->getGeneration(), result);
}
nsresult nsDiskCacheDevice::getTransportForFile(nsIFile* file, nsCacheAccessMode mode, nsITransport ** result)
@ -916,6 +1039,55 @@ nsresult nsDiskCacheDevice::getTransportForFile(nsIFile* file, nsCacheAccessMode
return gFileTransportService->CreateTransport(file, ioFlags, PR_IRUSR | PR_IWUSR, result);
}
static FILE* openFileStream(nsIFile* file, const char* mode)
{
FILE* stream = nsnull;
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(file);
if (localFile) {
nsresult rv = localFile->OpenANSIFileDesc(mode, &stream);
if (NS_FAILED(rv)) return nsnull;
}
return stream;
}
nsresult nsDiskCacheDevice::openInputStream(nsIFile * file, nsIInputStream ** result)
{
FILE* stream = openFileStream(file, "rb");
if (stream) {
nsCOMPtr<nsIInputStream> input(new nsANSIInputStream(stream));
if (!input) {
::fclose(stream);
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*result = input);
return NS_OK;
} else {
nsCOMPtr<nsITransport> transport;
nsresult rv = getTransportForFile(file, nsICache::ACCESS_READ, getter_AddRefs(transport));
if (NS_FAILED(rv)) return rv;
return transport->OpenInputStream(0, ULONG_MAX, 0, result);
}
}
nsresult nsDiskCacheDevice::openOutputStream(nsIFile * file, nsIOutputStream ** result)
{
FILE* stream = openFileStream(file, "wb");
if (stream) {
nsCOMPtr<nsIOutputStream> output(new nsANSIOutputStream(stream));
if (!output) {
::fclose(stream);
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*result = output);
return NS_OK;
} else {
nsCOMPtr<nsITransport> transport;
nsresult rv = getTransportForFile(file, nsICache::ACCESS_WRITE, getter_AddRefs(transport));
if (NS_FAILED(rv)) return rv;
return transport->OpenOutputStream(0, ULONG_MAX, 0, result);
}
}
inline PRBool isMetaDataFile(const char* name)
{
return (name[8] == 'm');
@ -945,11 +1117,8 @@ nsresult nsDiskCacheDevice::visitEntries(nsICacheVisitor * visitor)
rv = file->GetLeafName(getter_Copies(name));
if (isMetaDataFile(name)) {
// this must be a metadata file.
nsCOMPtr<nsITransport> transport;
rv = getTransportForFile(file, nsICache::ACCESS_READ, getter_AddRefs(transport));
if (NS_FAILED(rv)) continue;
nsCOMPtr<nsIInputStream> input;
rv = transport->OpenInputStream(0, ULONG_MAX, 0, getter_AddRefs(input));
rv = openInputStream(file, getter_AddRefs(input));
if (NS_FAILED(rv)) continue;
// read the metadata file.
@ -989,27 +1158,20 @@ nsresult nsDiskCacheDevice::updateDiskCacheEntries()
nsresult nsDiskCacheDevice::updateDiskCacheEntry(nsDiskCacheEntry* diskEntry)
{
nsresult rv;
nsCacheEntry* entry = diskEntry->getCacheEntry();
if (entry->IsMetaDataDirty() || entry->IsEntryDirty()) {
nsresult rv;
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
nsCOMPtr<nsITransport>& transport = diskEntry->getMetaTransport(nsICache::ACCESS_WRITE);
#else
nsCOMPtr<nsITransport> transport;
#endif
if (!transport) {
nsCOMPtr<nsIFile> file;
rv = getFileForDiskCacheEntry(diskEntry, PR_TRUE,
getter_AddRefs(file));
if (NS_FAILED(rv)) return rv;
rv = getTransportForFile(file, nsICache::ACCESS_WRITE,
getter_AddRefs(transport));
if (NS_FAILED(rv)) return rv;
}
// make sure this disk entry is known to the cache map.
rv = updateCacheMap(diskEntry);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIFile> file;
rv = getFileForDiskCacheEntry(diskEntry, PR_TRUE,
getter_AddRefs(file));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIOutputStream> output;
rv = transport->OpenOutputStream(0, ULONG_MAX, 0, getter_AddRefs(output));
rv = openOutputStream(file, getter_AddRefs(output));
if (NS_FAILED(rv)) return rv;
// write the metadata to the file.
@ -1017,8 +1179,8 @@ nsresult nsDiskCacheDevice::updateDiskCacheEntry(nsDiskCacheEntry* diskEntry)
rv = metaDataFile.Init(entry);
if (NS_FAILED(rv)) return rv;
rv = metaDataFile.Write(output);
rv = output->Close();
output->Close();
if (NS_FAILED(rv)) return rv;
// mark the disk entry as being consistent with meta data file.
entry->MarkMetaDataClean();
@ -1058,26 +1220,10 @@ nsresult nsDiskCacheDevice::readDiskCacheEntry(const char * key, nsDiskCacheEntr
rv = file->Exists(&exists);
if (NS_FAILED(rv) || !exists) return NS_ERROR_NOT_AVAILABLE;
nsCacheEntry* entry;
rv = NS_NewCacheEntry(&entry, key, PR_TRUE, nsICache::STORE_ON_DISK, this);
if (NS_FAILED(rv)) return rv;
nsCacheEntry* entry = nsnull;
do {
nsDiskCacheEntry* diskEntry = ensureDiskCacheEntry(entry);
if (!diskEntry) break;
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
nsCOMPtr<nsITransport>& transport = diskEntry->getMetaTransport(nsICache::ACCESS_READ);
#else
nsCOMPtr<nsITransport> transport;
#endif
if (!transport) {
rv = getTransportForFile(file, nsICache::ACCESS_READ, getter_AddRefs(transport));
if (NS_FAILED(rv)) break;
}
nsCOMPtr<nsIInputStream> input;
rv = transport->OpenInputStream(0, ULONG_MAX, 0, getter_AddRefs(input));
rv = openInputStream(file, getter_AddRefs(input));
if (NS_FAILED(rv)) break;
// read the metadata file.
@ -1089,6 +1235,9 @@ nsresult nsDiskCacheDevice::readDiskCacheEntry(const char * key, nsDiskCacheEntr
// Ensure that the keys match.
if (nsCRT::strcmp(key, metaDataFile.mKey) != 0) break;
rv = NS_NewCacheEntry(&entry, key, PR_TRUE, nsICache::STORE_ON_DISK, this);
if (NS_FAILED(rv)) return rv;
// initialize the entry.
entry->SetFetchCount(metaDataFile.mFetchCount);
entry->SetLastFetched(metaDataFile.mLastFetched);
@ -1103,7 +1252,8 @@ nsresult nsDiskCacheDevice::readDiskCacheEntry(const char * key, nsDiskCacheEntr
}
// celebrate!
*result = diskEntry;
*result = ensureDiskCacheEntry(entry);
if (!*result) break;
return NS_OK;
} while (0);
@ -1134,10 +1284,12 @@ nsresult nsDiskCacheDevice::deleteDiskCacheEntry(nsDiskCacheEntry * diskEntry)
// NS_ASSERTION(NS_SUCCEEDED(rv), "nsDiskCacheDevice::deleteDiskCacheEntry");
}
// remove from cache map.
mCacheMap->DeleteRecord(diskEntry->getHashNumber());
return NS_OK;
}
nsresult nsDiskCacheDevice::scavengeDiskCacheEntries(nsDiskCacheEntry * diskEntry)
{
nsresult rv;
@ -1193,45 +1345,6 @@ nsresult nsDiskCacheDevice::scavengeDiskCacheEntries(nsDiskCacheEntry * diskEntr
return NS_OK;
}
/**
* Helper class for implementing do_QueryElementAt() pattern. Thanks scc!
* Eventually this should become part of nsICollection.idl.
*/
class nsQueryElementAt : public nsCOMPtr_helper {
public:
nsQueryElementAt( nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr )
: mCollection(aCollection),
mIndex(aIndex),
mErrorPtr(aErrorPtr)
{
// nothing else to do here
}
virtual nsresult operator()( const nsIID& aIID, void** aResult) const
{
nsresult status;
if ( mCollection ) {
if ( !NS_SUCCEEDED(status = mCollection->QueryElementAt(mIndex, aIID, aResult)) )
*aResult = 0;
} else
status = NS_ERROR_NULL_POINTER;
if ( mErrorPtr )
*mErrorPtr = status;
return status;
}
private:
nsICollection* mCollection;
PRUint32 mIndex;
nsresult* mErrorPtr;
};
inline const nsQueryElementAt
do_QueryElementAt( nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr = 0 )
{
return nsQueryElementAt(aCollection, aIndex, aErrorPtr);
}
nsresult nsDiskCacheDevice::scanDiskCacheEntries(nsISupportsArray ** result)
{
nsresult rv;
@ -1259,11 +1372,8 @@ nsresult nsDiskCacheDevice::scanDiskCacheEntries(nsISupportsArray ** result)
rv = file->GetLeafName(getter_Copies(name));
if (isMetaDataFile(name)) {
// this must be a metadata file.
nsCOMPtr<nsITransport> transport;
rv = getTransportForFile(file, nsICache::ACCESS_READ, getter_AddRefs(transport));
if (NS_FAILED(rv)) continue;
nsCOMPtr<nsIInputStream> input;
rv = transport->OpenInputStream(0, ULONG_MAX, 0, getter_AddRefs(input));
rv = openInputStream(file, getter_AddRefs(input));
if (NS_FAILED(rv)) continue;
nsDiskCacheEntryInfo* entryInfo = new nsDiskCacheEntryInfo();
@ -1320,7 +1430,8 @@ nsresult nsDiskCacheDevice::scanDiskCacheEntries(nsISupportsArray ** result)
NS_ADDREF(*result = entries);
// we've successfully totaled the cache size.
mCacheSize = newCacheSize;
mCacheMap->DataSize() = newCacheSize;
entries->Count(&mCacheMap->EntryCount());
return NS_OK;
}
@ -1331,7 +1442,7 @@ nsresult nsDiskCacheDevice::evictDiskCacheEntries()
nsresult rv = scanDiskCacheEntries(getter_AddRefs(entries));
if (NS_FAILED(rv)) return rv;
if (mCacheSize < mCacheCapacity) return NS_OK;
if (mCacheMap->DataSize() < mCacheCapacity) return NS_OK;
// these are sorted in oldest to newest order.
PRUint32 count;
@ -1364,8 +1475,7 @@ nsresult nsDiskCacheDevice::evictDiskCacheEntries()
// update the cache size.
PRUint32 dataSize;
info->GetDataSize(&dataSize);
mCacheSize -= dataSize;
if (mCacheSize <= mCacheCapacity)
if ((mCacheMap->DataSize() -= dataSize) <= mCacheCapacity)
break;
}
}
@ -1373,73 +1483,91 @@ nsresult nsDiskCacheDevice::evictDiskCacheEntries()
return NS_OK;
}
static FILE* openFileStream(nsIFile* file, const char* mode)
nsresult nsDiskCacheDevice::readCacheMap()
{
FILE* stream = nsnull;
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(file);
if (localFile) {
nsresult rv = localFile->OpenANSIFileDesc(mode, &stream);
if (NS_FAILED(rv)) return nsnull;
}
return stream;
nsCOMPtr<nsIFile> file;
nsresult rv = mCacheDirectory->Clone(getter_AddRefs(file));
if (NS_FAILED(rv)) return rv;
rv = file->Append("_CACHE_MAP_");
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIInputStream> input;
rv = openInputStream(file, getter_AddRefs(input));
if (NS_FAILED(rv)) return rv;
rv = mCacheMap->Read(input);
input->Close();
return rv;
}
nsresult nsDiskCacheDevice::writeCacheInfo()
nsresult nsDiskCacheDevice::writeCacheMap()
{
nsCOMPtr<nsIFile> infoFile;
nsresult rv = mCacheDirectory->Clone(getter_AddRefs(infoFile));
nsCOMPtr<nsIFile> file;
nsresult rv = mCacheDirectory->Clone(getter_AddRefs(file));
if (NS_FAILED(rv)) return rv;
rv = infoFile->Append("CacheInfo");
rv = file->Append("_CACHE_MAP_");
if (NS_FAILED(rv)) return rv;
PRUint32 cacheSize = PR_htonl(mCacheSize);
nsCOMPtr<nsIOutputStream> output;
rv = openOutputStream(file, getter_AddRefs(output));
if (NS_FAILED(rv)) return rv;
rv = mCacheMap->Write(output);
output->Close();
return rv;
}
FILE* stream = openFileStream(infoFile, "wb");
if (stream) {
fwrite(&cacheSize, sizeof(cacheSize), 1, stream);
fclose(stream);
nsresult nsDiskCacheDevice::updateCacheMap(nsDiskCacheEntry * diskEntry)
{
// get a record from the cache map, and use the fetch time for eviction ranking.
nsDiskCacheRecord* record = mCacheMap->GetRecord(diskEntry->getHashNumber());
if (record->HashNumber() != diskEntry->getHashNumber()) {
if (record->HashNumber() != 0) {
// eviction of eldest entry in this bucket.
evictDiskCacheRecord(record);
}
// newly bound record. fill in the blanks.
record->SetHashNumber(diskEntry->getHashNumber());
record->SetEvictionRank(0);
record->SetFileGeneration(diskEntry->getGeneration());
} else {
nsCOMPtr<nsITransport> transport;
rv = getTransportForFile(infoFile, nsICache::ACCESS_WRITE, getter_AddRefs(transport));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIOutputStream> output;
rv = transport->OpenOutputStream(0, ULONG_MAX, 0, getter_AddRefs(output));
if (NS_FAILED(rv)) return rv;
PRUint32 count = sizeof(cacheSize);
rv = output->Write((char*)&cacheSize, count, &count);
rv = output->Close();
record->SetEvictionRank(record->EvictionRank() + 1);
}
return NS_OK;
}
nsresult nsDiskCacheDevice::readCacheInfo()
/**
* This evicts the disk cache entry that corresponds to the given record.
* If the entry happens to be bound, it must be doomed, otherwise, it can
* be eagerly removed from disk.
*/
nsresult nsDiskCacheDevice::evictDiskCacheRecord(nsDiskCacheRecord * record)
{
nsCOMPtr<nsIFile> infoFile;
nsresult rv = mCacheDirectory->Clone(getter_AddRefs(infoFile));
if (NS_FAILED(rv)) return rv;
nsresult rv;
rv = infoFile->Append("CacheInfo");
if (NS_FAILED(rv)) return rv;
// if the entry is currently in use, then doom it rather than evicting right here.
nsDiskCacheEntry* diskEntry = mBoundEntries.GetEntry(record->HashNumber());
if (diskEntry)
return nsCacheService::GlobalInstance()->DoomEntry_Locked(diskEntry->getCacheEntry());
PRUint32 cacheSize = 0;
// delete the metadata file.
nsCOMPtr<nsIFile> metaFile;
rv = getFileForHashNumber(record->HashNumber(), PR_TRUE,
record->FileGeneration(), getter_AddRefs(metaFile));
if (NS_SUCCEEDED(rv))
rv = metaFile->Delete(PR_FALSE);
FILE* stream = openFileStream(infoFile, "rb");
if (stream) {
fread(&cacheSize, sizeof(mCacheSize), 1, stream);
fclose(stream);
} else {
nsCOMPtr<nsITransport> transport;
rv = getTransportForFile(infoFile, nsICache::ACCESS_READ, getter_AddRefs(transport));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIInputStream> input;
rv = transport->OpenInputStream(0, ULONG_MAX, 0, getter_AddRefs(input));
if (NS_FAILED(rv)) return rv;
PRUint32 count = sizeof(cacheSize);
rv = input->Read((char*)&cacheSize, count, &count);
rv = input->Close();
}
mCacheSize = PR_ntohl(cacheSize);
return NS_OK;
// delete the data file
nsCOMPtr<nsIFile> dataFile;
rv = getFileForHashNumber(record->HashNumber(), PR_FALSE,
record->FileGeneration(), getter_AddRefs(dataFile));
if (NS_SUCCEEDED(rv))
rv = dataFile->Delete(PR_FALSE);
return rv;
}

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

@ -10,7 +10,7 @@
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is nsMemoryCacheDevice.h, released February 20, 2001.
* The Original Code is nsDiskCacheDevice.h, released February 20, 2001.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
@ -18,7 +18,8 @@
* Rights Reserved.
*
* Contributor(s):
* Gordon Sheridan, 20-February-2001
* Gordon Sheridan <gordon@netscape.com>
* Patrick C. Beard <beard@netscape.com>
*/
#ifndef _nsDiskCacheDevice_h_
@ -31,16 +32,22 @@
#include "nsIObserver.h"
class nsDiskCacheEntry;
class nsDiskCacheMap;
class nsDiskCacheRecord;
class nsISupportsArray;
class nsIInputStream;
class nsIOutputStream;
class nsDiskCacheDevice : public nsCacheDevice {
public:
nsDiskCacheDevice();
virtual ~nsDiskCacheDevice();
nsresult Init();
static nsresult Create(nsCacheDevice **result);
static nsresult Create(nsCacheDevice **result);
virtual nsresult Init();
virtual nsresult Shutdown();
virtual const char * GetDeviceID(void);
virtual nsCacheEntry * FindEntry(nsCString * key);
@ -59,6 +66,8 @@ public:
virtual nsresult Visit(nsICacheVisitor * visitor);
virtual nsresult EvictEntries(const char * clientID);
/* private: */
void setPrefsObserver(nsIObserver* observer);
void getPrefsObserver(nsIObserver ** result);
@ -66,10 +75,15 @@ public:
void setCacheCapacity(PRUint32 capacity);
PRUint32 getCacheCapacity();
PRUint32 getCacheSize();
PRUint32 getEntryCount();
nsresult getFileForHashNumber(PLDHashNumber hashNumber, PRBool meta, PRUint32 generation, nsIFile ** result);
nsresult getFileForKey(const char* key, PRBool meta, PRUint32 generation, nsIFile ** result);
nsresult getFileForDiskCacheEntry(nsDiskCacheEntry * diskEntry, PRBool meta, nsIFile ** result);
static nsresult getTransportForFile(nsIFile* file, nsCacheAccessMode mode, nsITransport ** result);
static nsresult openInputStream(nsIFile* file, nsIInputStream ** result);
static nsresult openOutputStream(nsIFile* file, nsIOutputStream ** result);
nsresult visitEntries(nsICacheVisitor * visitory);
@ -84,16 +98,19 @@ public:
nsresult scanDiskCacheEntries(nsISupportsArray ** result);
nsresult evictDiskCacheEntries();
nsresult writeCacheInfo();
nsresult readCacheInfo();
nsresult readCacheMap();
nsresult writeCacheMap();
nsresult updateCacheMap(nsDiskCacheEntry * diskEntry);
nsresult evictDiskCacheRecord(nsDiskCacheRecord * record);
private:
PRBool mInitialized;
nsCOMPtr<nsIObserver> mPrefsObserver;
nsCOMPtr<nsILocalFile> mCacheDirectory;
nsDiskCacheEntryHashTable mBoundEntries;
PRUint32 mCacheCapacity;
PRUint32 mCacheSize;
PRBool mInitialized;
nsDiskCacheMap* mCacheMap;
};
#endif // _nsDiskCacheDevice_h_

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

@ -21,10 +21,21 @@
* Patrick C. Beard <beard@netscape.com>
*/
#include <limits.h>
#include "nsDiskCacheEntry.h"
NS_IMPL_ISUPPORTS0(nsDiskCacheEntry);
PLDHashNumber
nsDiskCacheEntry::Hash(const char* key)
{
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);
}
/******************************************************************************
* nsCacheEntryHashTable
*****************************************************************************/
@ -70,7 +81,7 @@ nsDiskCacheEntryHashTable::Init()
nsDiskCacheEntry *
nsDiskCacheEntryHashTable::GetEntry(const char * key)
{
return GetEntry(::PL_DHashStringKey(NULL, key));
return GetEntry(nsDiskCacheEntry::Hash(key));
}

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

@ -44,7 +44,7 @@ public:
{
NS_INIT_ISUPPORTS();
PR_INIT_CLIST(this);
mHashNumber = ::PL_DHashStringKey(NULL, entry->Key()->get());
mHashNumber = Hash(entry->Key()->get());
}
virtual ~nsDiskCacheEntry()
@ -89,6 +89,8 @@ public:
return mHashNumber;
}
static PLDHashNumber Hash(const char* key);
private:
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
nsCOMPtr<nsITransport> mTransports[3];

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

@ -22,8 +22,9 @@
*/
#include "nsDiskCacheMap.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIFileStreams.h"
#include <string.h>
nsDiskCacheMap::nsDiskCacheMap()
{
@ -35,33 +36,74 @@ nsDiskCacheMap::~nsDiskCacheMap()
nsDiskCacheRecord* nsDiskCacheMap::GetRecord(PRUint32 hashNumber)
{
PRUint32 index = (hashNumber & (kBucketsPerTable - 1));
nsDiskCacheBucket& bucket = mBuckets[index];
nsDiskCacheBucket& bucket = mBuckets[(hashNumber & (kBucketsPerTable - 1))];
nsDiskCacheRecord* oldestRecord = &bucket.mRecords[0];
for (int i = 0; i < kRecordsPerBucket; ++i) {
nsDiskCacheRecord* record = &bucket.mRecords[i];
for (int r = 0; r < kRecordsPerBucket; ++r) {
nsDiskCacheRecord* record = &bucket.mRecords[r];
if (record->HashNumber() == 0 || record->HashNumber() == hashNumber)
return record;
if (record->EvictionRank() > oldestRecord->EvictionRank())
if (record->EvictionRank() < oldestRecord->EvictionRank())
oldestRecord = record;
}
// record not found, so must evict a record.
oldestRecord->SetHashNumber(0);
oldestRecord->SetEvictionRank(0);
// if we don't find an empty record, return the oldest record for eviction.
return oldestRecord;
}
void nsDiskCacheMap::DeleteRecord(PRUint32 hashNumber)
{
nsDiskCacheBucket& bucket = mBuckets[(hashNumber & (kBucketsPerTable - 1))];
for (int r = 0; r < kRecordsPerBucket; ++r) {
nsDiskCacheRecord* record = &bucket.mRecords[r];
if (record->HashNumber() == hashNumber) {
nsDiskCacheRecord* deletedRecord = record;
nsDiskCacheRecord* lastRecord = nsnull;
// XXX use binary search to find the end, much quicker.
// find the last record, to fill in the deleted record.
for (int j = r + 1; j < kRecordsPerBucket; ++j) {
record = &bucket.mRecords[j];
if (record->HashNumber() == 0) {
lastRecord = record - 1;
break;
}
}
// copy the last record, to the newly deleted record.
if (lastRecord && deletedRecord != lastRecord) {
*deletedRecord = *lastRecord;
deletedRecord = lastRecord;
}
// mark record as free.
deletedRecord->SetHashNumber(0);
break;
}
}
}
nsresult nsDiskCacheMap::Read(nsIInputStream* input)
{
// XXX need a header, etc.
nsresult rv;
PRUint32 count;
nsresult rv = input->Read((char*)&mBuckets, sizeof(mBuckets), &count);
// read the header.
rv = input->Read((char*)&mHeader, sizeof(mHeader), &count);
if (NS_FAILED(rv)) return rv;
mHeader.Unswap();
// validate the version.
if (mHeader.mVersion != nsDiskCacheHeader::kCurrentVersion) return NS_ERROR_FAILURE;
// seek to beginning of first bucket.
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(input, &rv);
if (NS_FAILED(rv)) return rv;
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, sizeof(nsDiskCacheBucket));
if (NS_FAILED(rv)) return rv;
// read the buckets.
rv = input->Read((char*)&mBuckets[1], sizeof(mBuckets) - sizeof(nsDiskCacheBucket), &count);
if (NS_FAILED(rv)) return rv;
// unswap all of the active records.
for (int b = 0; b < kBucketsPerTable; ++b) {
for (int b = 1; b < kBucketsPerTable; ++b) {
nsDiskCacheBucket& bucket = mBuckets[b];
for (int r = 0; r < kRecordsPerBucket; ++r) {
nsDiskCacheRecord* record = &bucket.mRecords[r];
@ -76,8 +118,12 @@ nsresult nsDiskCacheMap::Read(nsIInputStream* input)
nsresult nsDiskCacheMap::Write(nsIOutputStream* output)
{
nsresult rv;
PRUint32 count;
int b;
// swap all of the active records.
for (int b = 0; b < kBucketsPerTable; ++b) {
for (b = 1; b < kBucketsPerTable; ++b) {
nsDiskCacheBucket& bucket = mBuckets[b];
for (int r = 0; r < kRecordsPerBucket; ++r) {
nsDiskCacheRecord* record = &bucket.mRecords[r];
@ -87,12 +133,11 @@ nsresult nsDiskCacheMap::Write(nsIOutputStream* output)
}
}
// XXX need a header, etc.
PRUint32 count;
nsresult rv = output->Write((char*)&mBuckets, sizeof(mBuckets), &count);
// write the buckets.
rv = output->Write((char*)&mBuckets, sizeof(mBuckets), &count);
// unswap all of the active records.
for (int b = 0; b < kBucketsPerTable; ++b) {
for (b = 1; b < kBucketsPerTable; ++b) {
nsDiskCacheBucket& bucket = mBuckets[b];
for (int r = 0; r < kRecordsPerBucket; ++r) {
nsDiskCacheRecord* record = &bucket.mRecords[r];
@ -101,6 +146,18 @@ nsresult nsDiskCacheMap::Write(nsIOutputStream* output)
record->Unswap();
}
}
if (NS_FAILED(rv)) return rv;
// seek back to beginning of file.
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(output, &rv);
if (NS_FAILED(rv)) return rv;
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
if (NS_FAILED(rv)) return rv;
// write the header.
mHeader.Swap();
rv = output->Write((char*)&mHeader, sizeof(mHeader), &count);
mHeader.Unswap();
return rv;
}

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

@ -29,26 +29,62 @@
class nsIInputStream;
class nsIOutputStream;
struct nsDiskCacheHeader {
enum { kCurrentVersion = 0x00010000 };
PRUint32 mVersion; // cache version.
PRUint32 mDataSize; // size of cache in bytes.
PRUint32 mEntryCount; // number of entries stored in cache.
// XXX need a bitmap?
nsDiskCacheHeader()
: mVersion(kCurrentVersion), mDataSize(0), mEntryCount(0)
{
}
void Swap()
{
mVersion = ::PR_htonl(mVersion);
mDataSize = ::PR_htonl(mDataSize);
mEntryCount = ::PR_htonl(mEntryCount);
}
void Unswap()
{
mVersion = ::PR_ntohl(mVersion);
mDataSize = ::PR_ntohl(mDataSize);
mEntryCount = ::PR_ntohl(mEntryCount);
}
};
// XXX initial capacity, enough for 8192 distint entries.
const PRUint32 kRecordsPerBucket = 256;
const PRUint32 kBucketsPerTable = (1 << 4); // must be a power of 2!
class nsDiskCacheMap {
public:
nsDiskCacheMap();
~nsDiskCacheMap();
PRUint32& DataSize() { return mHeader.mDataSize; }
PRUint32& EntryCount() { return mHeader.mEntryCount; }
nsDiskCacheRecord* GetRecord(PRUint32 hashNumber);
void DeleteRecord(PRUint32 hashNumber);
nsresult Read(nsIInputStream* input);
nsresult Write(nsIOutputStream* output);
private:
// XXX need a bitmap?
struct nsDiskCacheBucket {
nsDiskCacheRecord mRecords[kRecordsPerBucket];
enum {
kRecordsPerBucket = 256,
kBucketsPerTable = (1 << 5) // must be a power of 2!
};
nsDiskCacheBucket mBuckets[kBucketsPerTable];
private:
struct nsDiskCacheBucket {
nsDiskCacheRecord mRecords[kRecordsPerBucket];
};
nsDiskCacheHeader mHeader;
nsDiskCacheBucket mBuckets[kBucketsPerTable];
};
#endif // _nsDiskCacheMap_h_

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

@ -119,6 +119,11 @@ nsMemoryCacheDevice::Init()
return rv;
}
nsresult
nsMemoryCacheDevice::Shutdown()
{
return NS_OK;
}
const char *
nsMemoryCacheDevice::GetDeviceID()
@ -232,7 +237,8 @@ nsMemoryCacheDevice::GetTransportForEntry( nsCacheEntry * entry,
(void **) transport);
if (NS_FAILED(rv)) return rv;
return entry->SetData(*transport);
entry->SetData(*transport);
return NS_OK;
}
}
@ -344,6 +350,13 @@ nsMemoryCacheDevice::Visit(nsICacheVisitor * visitor)
}
nsresult
nsMemoryCacheDevice::EvictEntries(const char * clientID)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/******************************************************************************
* nsMemoryCacheDeviceInfo - for implementing about:cache
*****************************************************************************/

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

@ -40,14 +40,15 @@ public:
nsMemoryCacheDevice();
virtual ~nsMemoryCacheDevice();
virtual nsresult Init();
virtual nsresult Init();
virtual nsresult Shutdown();
virtual const char * GetDeviceID(void);
virtual const char * GetDeviceID(void);
virtual nsresult BindEntry( nsCacheEntry * entry );
virtual nsCacheEntry * FindEntry( nsCString * key );
virtual void DoomEntry( nsCacheEntry * entry );
virtual nsresult DeactivateEntry( nsCacheEntry * entry );
virtual nsresult BindEntry( nsCacheEntry * entry );
virtual nsCacheEntry * FindEntry( nsCString * key );
virtual void DoomEntry( nsCacheEntry * entry );
virtual nsresult DeactivateEntry( nsCacheEntry * entry );
virtual nsresult GetTransportForEntry( nsCacheEntry * entry,
nsCacheAccessMode mode,
@ -59,6 +60,8 @@ public:
virtual nsresult OnDataSizeChange( nsCacheEntry * entry, PRInt32 deltaSize );
virtual nsresult Visit( nsICacheVisitor * visitor );
virtual nsresult EvictEntries(const char * clientID);
static int PR_CALLBACK MemoryCacheSizeChanged(const char * pref, void * closure);