From 473ba08356fcbbb0beaf4be0842ecdff3f8815f2 Mon Sep 17 00:00:00 2001 From: "gordon%netscape.com" Date: Thu, 29 Mar 2001 05:54:58 +0000 Subject: [PATCH] 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. git-svn-id: svn://10.0.0.236/trunk@90752 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/netwerk/cache/src/Makefile.in | 2 + mozilla/netwerk/cache/src/makefile.win | 2 + .../netwerk/cache/src/nsANSIFileStreams.cpp | 69 +- mozilla/netwerk/cache/src/nsANSIFileStreams.h | 12 +- mozilla/netwerk/cache/src/nsCacheDevice.h | 9 +- mozilla/netwerk/cache/src/nsCacheEntry.cpp | 116 ++-- mozilla/netwerk/cache/src/nsCacheEntry.h | 60 +- .../cache/src/nsCacheEntryDescriptor.cpp | 22 +- mozilla/netwerk/cache/src/nsCacheMetaData.cpp | 5 +- mozilla/netwerk/cache/src/nsCacheService.cpp | 296 ++++++-- mozilla/netwerk/cache/src/nsCacheService.h | 11 +- mozilla/netwerk/cache/src/nsCacheSession.cpp | 5 + mozilla/netwerk/cache/src/nsDiskCache.h | 106 ++- .../netwerk/cache/src/nsDiskCacheDevice.cpp | 640 +++++++++++------- mozilla/netwerk/cache/src/nsDiskCacheDevice.h | 33 +- .../netwerk/cache/src/nsDiskCacheEntry.cpp | 13 +- mozilla/netwerk/cache/src/nsDiskCacheEntry.h | 4 +- mozilla/netwerk/cache/src/nsDiskCacheMap.cpp | 95 ++- mozilla/netwerk/cache/src/nsDiskCacheMap.h | 52 +- .../netwerk/cache/src/nsMemoryCacheDevice.cpp | 15 +- .../netwerk/cache/src/nsMemoryCacheDevice.h | 15 +- 21 files changed, 1062 insertions(+), 520 deletions(-) diff --git a/mozilla/netwerk/cache/src/Makefile.in b/mozilla/netwerk/cache/src/Makefile.in index 28dee11ffab..63eaa4f2dea 100644 --- a/mozilla/netwerk/cache/src/Makefile.in +++ b/mozilla/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) diff --git a/mozilla/netwerk/cache/src/makefile.win b/mozilla/netwerk/cache/src/makefile.win index b27bb415b6e..503fba6f40c 100755 --- a/mozilla/netwerk/cache/src/makefile.win +++ b/mozilla/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) diff --git a/mozilla/netwerk/cache/src/nsANSIFileStreams.cpp b/mozilla/netwerk/cache/src/nsANSIFileStreams.cpp index e5494a7465b..c68c1313c37 100644 --- a/mozilla/netwerk/cache/src/nsANSIFileStreams.cpp +++ b/mozilla/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; +} diff --git a/mozilla/netwerk/cache/src/nsANSIFileStreams.h b/mozilla/netwerk/cache/src/nsANSIFileStreams.h index 9c6721cdc93..27069011df1 100644 --- a/mozilla/netwerk/cache/src/nsANSIFileStreams.h +++ b/mozilla/netwerk/cache/src/nsANSIFileStreams.h @@ -26,24 +26,26 @@ #include -#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(); diff --git a/mozilla/netwerk/cache/src/nsCacheDevice.h b/mozilla/netwerk/cache/src/nsCacheDevice.h index a54ce558f45..ab6ea981663 100644 --- a/mozilla/netwerk/cache/src/nsCacheDevice.h +++ b/mozilla/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_ diff --git a/mozilla/netwerk/cache/src/nsCacheEntry.cpp b/mozilla/netwerk/cache/src/nsCacheEntry.cpp index 961bd89654e..1010e0d2929 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntry.cpp +++ b/mozilla/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); } diff --git a/mozilla/netwerk/cache/src/nsCacheEntry.h b/mozilla/netwerk/cache/src/nsCacheEntry.h index 23fd703432d..831538ffc59 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntry.h +++ b/mozilla/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; diff --git a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp index 3e45dbc0ad0..74d15e919fd 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp +++ b/mozilla/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; } diff --git a/mozilla/netwerk/cache/src/nsCacheMetaData.cpp b/mozilla/netwerk/cache/src/nsCacheMetaData.cpp index 0ef00e499ec..a11cd183c88 100644 --- a/mozilla/netwerk/cache/src/nsCacheMetaData.cpp +++ b/mozilla/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); } diff --git a/mozilla/netwerk/cache/src/nsCacheService.cpp b/mozilla/netwerk/cache/src/nsCacheService.cpp index 8e0b9362d20..a1ed7c02ae0 100644 --- a/mozilla/netwerk/cache/src/nsCacheService.cpp +++ b/mozilla/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 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 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 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 + nsCOMPtr 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 diff --git a/mozilla/netwerk/cache/src/nsCacheService.h b/mozilla/netwerk/cache/src/nsCacheService.h index 7917bcf03fa..98d736632b2 100644 --- a/mozilla/netwerk/cache/src/nsCacheService.h +++ b/mozilla/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; diff --git a/mozilla/netwerk/cache/src/nsCacheSession.cpp b/mozilla/netwerk/cache/src/nsCacheSession.cpp index 599d16ae05b..4c1f8507fcb 100644 --- a/mozilla/netwerk/cache/src/nsCacheSession.cpp +++ b/mozilla/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; +} diff --git a/mozilla/netwerk/cache/src/nsDiskCache.h b/mozilla/netwerk/cache/src/nsDiskCache.h index 072c848a358..0b4f7a0c2f0 100644 --- a/mozilla/netwerk/cache/src/nsDiskCache.h +++ b/mozilla/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; }; diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp b/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp index 076c5630bf2..28f6905761c 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp +++ b/mozilla/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 +#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 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 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 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 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 ref(deviceInfo); @@ -830,6 +902,61 @@ nsDiskCacheDevice::Visit(nsICacheVisitor * visitor) return NS_OK; } +nsresult +nsDiskCacheDevice::EvictEntries(const char * clientID) +{ + nsCOMPtr 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 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 metaFile; + rv = getFileForKey(key, PR_TRUE, 0, getter_AddRefs(metaFile)); + if (NS_SUCCEEDED(rv)) { + rv = metaFile->Delete(PR_FALSE); + } + + // delete the data file + nsCOMPtr 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 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 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 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 input(new nsANSIInputStream(stream)); + if (!input) { + ::fclose(stream); + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ADDREF(*result = input); + return NS_OK; + } else { + nsCOMPtr 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 output(new nsANSIOutputStream(stream)); + if (!output) { + ::fclose(stream); + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ADDREF(*result = output); + return NS_OK; + } else { + nsCOMPtr 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 transport; - rv = getTransportForFile(file, nsICache::ACCESS_READ, getter_AddRefs(transport)); - if (NS_FAILED(rv)) continue; nsCOMPtr 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& transport = diskEntry->getMetaTransport(nsICache::ACCESS_WRITE); -#else - nsCOMPtr transport; -#endif - if (!transport) { - nsCOMPtr 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 file; + rv = getFileForDiskCacheEntry(diskEntry, PR_TRUE, + getter_AddRefs(file)); + if (NS_FAILED(rv)) return rv; nsCOMPtr 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& transport = diskEntry->getMetaTransport(nsICache::ACCESS_READ); -#else - nsCOMPtr transport; -#endif - if (!transport) { - rv = getTransportForFile(file, nsICache::ACCESS_READ, getter_AddRefs(transport)); - if (NS_FAILED(rv)) break; - } - nsCOMPtr 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 transport; - rv = getTransportForFile(file, nsICache::ACCESS_READ, getter_AddRefs(transport)); - if (NS_FAILED(rv)) continue; nsCOMPtr 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 localFile = do_QueryInterface(file); - if (localFile) { - nsresult rv = localFile->OpenANSIFileDesc(mode, &stream); - if (NS_FAILED(rv)) return nsnull; - } - return stream; + nsCOMPtr 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 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 infoFile; - nsresult rv = mCacheDirectory->Clone(getter_AddRefs(infoFile)); + nsCOMPtr 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 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 transport; - rv = getTransportForFile(infoFile, nsICache::ACCESS_WRITE, getter_AddRefs(transport)); - if (NS_FAILED(rv)) return rv; - nsCOMPtr 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 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 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 transport; - rv = getTransportForFile(infoFile, nsICache::ACCESS_READ, getter_AddRefs(transport)); - if (NS_FAILED(rv)) return rv; - nsCOMPtr 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 dataFile; + rv = getFileForHashNumber(record->HashNumber(), PR_FALSE, + record->FileGeneration(), getter_AddRefs(dataFile)); + if (NS_SUCCEEDED(rv)) + rv = dataFile->Delete(PR_FALSE); + + return rv; } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDevice.h b/mozilla/netwerk/cache/src/nsDiskCacheDevice.h index 6bc76de6117..170d33f27ad 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDevice.h +++ b/mozilla/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 + * Patrick C. Beard */ #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 mPrefsObserver; nsCOMPtr mCacheDirectory; nsDiskCacheEntryHashTable mBoundEntries; PRUint32 mCacheCapacity; - PRUint32 mCacheSize; - PRBool mInitialized; + nsDiskCacheMap* mCacheMap; }; #endif // _nsDiskCacheDevice_h_ diff --git a/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp b/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp index 22f92286154..0d2d56050c5 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp @@ -21,10 +21,21 @@ * Patrick C. Beard */ +#include + #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)); } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheEntry.h b/mozilla/netwerk/cache/src/nsDiskCacheEntry.h index 663e689c8c7..b9d98329430 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheEntry.h +++ b/mozilla/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 mTransports[3]; diff --git a/mozilla/netwerk/cache/src/nsDiskCacheMap.cpp b/mozilla/netwerk/cache/src/nsDiskCacheMap.cpp index 7b4c4eaea2b..49b8e91686a 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheMap.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheMap.cpp @@ -22,8 +22,9 @@ */ #include "nsDiskCacheMap.h" -#include "nsIInputStream.h" -#include "nsIOutputStream.h" +#include "nsIFileStreams.h" + +#include 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 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 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; } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheMap.h b/mozilla/netwerk/cache/src/nsDiskCacheMap.h index 74e36d336b9..60b6bdffe8e 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheMap.h +++ b/mozilla/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_ diff --git a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp index d7a8130adef..f3a1833bd8c 100644 --- a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp +++ b/mozilla/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 *****************************************************************************/ diff --git a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h index 15f496bc286..2aee1dd1751 100644 --- a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h +++ b/mozilla/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);