From 7f9fc38dbd7879e17819ad4d3c854532a52ddc43 Mon Sep 17 00:00:00 2001 From: "darin%netscape.com" Date: Wed, 7 Aug 2002 01:13:29 +0000 Subject: [PATCH] landing gordon's patch for bug 81724 - disk cache needs stream wrappers (disk cache phase 3) patch=gordon r=dougt sr=darin git-svn-id: svn://10.0.0.236/trunk@126569 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/netwerk/cache/src/Makefile.in | 5 + mozilla/netwerk/cache/src/makefile.win | 1 + mozilla/netwerk/cache/src/nsCache.cpp | 35 +++ mozilla/netwerk/cache/src/nsCache.h | 19 ++ mozilla/netwerk/cache/src/nsCacheEntry.cpp | 3 +- .../cache/src/nsCacheEntryDescriptor.cpp | 87 ++++-- mozilla/netwerk/cache/src/nsCacheService.cpp | 281 ++++++++--------- mozilla/netwerk/cache/src/nsCacheService.h | 44 +-- mozilla/netwerk/cache/src/nsCacheSession.cpp | 26 +- mozilla/netwerk/cache/src/nsDiskCache.h | 3 +- .../netwerk/cache/src/nsDiskCacheBinding.cpp | 5 + .../netwerk/cache/src/nsDiskCacheBinding.h | 23 +- .../cache/src/nsDiskCacheBlockFile.cpp | 9 +- .../netwerk/cache/src/nsDiskCacheDevice.cpp | 222 +++++++++----- mozilla/netwerk/cache/src/nsDiskCacheDevice.h | 9 +- .../netwerk/cache/src/nsDiskCacheEntry.cpp | 9 +- mozilla/netwerk/cache/src/nsDiskCacheMap.cpp | 122 ++++++-- mozilla/netwerk/cache/src/nsDiskCacheMap.h | 28 +- .../netwerk/cache/src/nsDiskCacheStreams.cpp | 289 ++++++++---------- .../netwerk/cache/src/nsDiskCacheStreams.h | 30 +- .../netwerk/cache/src/nsMemoryCacheDevice.cpp | 29 +- .../netwerk/cache/src/nsMemoryCacheDevice.h | 20 +- mozilla/netwerk/macbuild/cache.xml | 30 ++ 23 files changed, 792 insertions(+), 537 deletions(-) diff --git a/mozilla/netwerk/cache/src/Makefile.in b/mozilla/netwerk/cache/src/Makefile.in index 03f68bb2d9d..fbced9f14cf 100644 --- a/mozilla/netwerk/cache/src/Makefile.in +++ b/mozilla/netwerk/cache/src/Makefile.in @@ -54,6 +54,7 @@ CPPSRCS = \ nsDiskCacheDevice.cpp \ nsDiskCacheEntry.cpp \ nsDiskCacheMap.cpp \ + nsDiskCacheStreams.cpp \ nsMemoryCacheDevice.cpp \ $(NULL) @@ -70,6 +71,10 @@ EXTRA_DSO_LDOPTS = $(MOZ_COMPONENT_LIBS) include $(topsrcdir)/config/rules.mk +# For fruncate +ifeq ($(OS_ARCH),Linux) +DEFINES += -D_BSD_SOURCE +endif ifeq ($(OS_ARCH),WINNT) DEFINES += -DWIN32_LEAN_AND_MEAN endif diff --git a/mozilla/netwerk/cache/src/makefile.win b/mozilla/netwerk/cache/src/makefile.win index dd7116ca1bb..586094bfaea 100755 --- a/mozilla/netwerk/cache/src/makefile.win +++ b/mozilla/netwerk/cache/src/makefile.win @@ -51,6 +51,7 @@ CPP_OBJS = \ .\$(OBJDIR)\nsDiskCacheDevice.obj \ .\$(OBJDIR)\nsDiskCacheEntry.obj \ .\$(OBJDIR)\nsDiskCacheMap.obj \ + .\$(OBJDIR)\nsDiskCacheStreams.obj \ .\$(OBJDIR)\nsMemoryCacheDevice.obj \ $(NULL) diff --git a/mozilla/netwerk/cache/src/nsCache.cpp b/mozilla/netwerk/cache/src/nsCache.cpp index 8586b032b06..4cd28bdf0eb 100644 --- a/mozilla/netwerk/cache/src/nsCache.cpp +++ b/mozilla/netwerk/cache/src/nsCache.cpp @@ -118,3 +118,38 @@ ClientKeyFromCacheKey(const nsACString& key, char ** result) } return rv; } + + + +NS_IMPL_THREADSAFE_ISUPPORTS0(nsCacheLock); + + +nsCacheLock::nsCacheLock() + : mLock(nsnull) +{ + NS_INIT_ISUPPORTS(); +} + + +nsCacheLock::~nsCacheLock() +{ + if (!mLock) return; + + PR_DestroyLock(mLock); +} + + +nsCacheLock * +nsCacheLock::Create() +{ + nsCacheLock * cacheLock = new nsCacheLock; + if (!cacheLock) return nsnull; + cacheLock->mLock = PR_NewLock(); + if (!cacheLock->mLock) { + delete cacheLock; + return nsnull; + } + + NS_ADDREF(cacheLock); + return cacheLock; +} diff --git a/mozilla/netwerk/cache/src/nsCache.h b/mozilla/netwerk/cache/src/nsCache.h index fbe7a58d2ca..a357ffebc9d 100644 --- a/mozilla/netwerk/cache/src/nsCache.h +++ b/mozilla/netwerk/cache/src/nsCache.h @@ -30,6 +30,7 @@ #ifndef _nsCache_h_ #define _nsCache_h_ +#include "nsISupports.h" #include "nsAString.h" #include "prtime.h" #include "nsError.h" @@ -60,4 +61,22 @@ extern PRTime PRTimeFromSeconds(PRUint32 seconds); extern nsresult ClientIDFromCacheKey(const nsACString& key, char ** result); extern nsresult ClientKeyFromCacheKey(const nsACString& key, char ** result); + +class nsCacheLock : public nsISupports { +public: + + NS_DECL_ISUPPORTS + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISUPPORTS_IID) + + nsCacheLock(); + virtual ~nsCacheLock(); + + static nsCacheLock * Create(); + PRLock * GetPRLock() { return mLock; } + +private: + PRLock * mLock; +}; + + #endif // _nsCache_h diff --git a/mozilla/netwerk/cache/src/nsCacheEntry.cpp b/mozilla/netwerk/cache/src/nsCacheEntry.cpp index 5e8bd22c8bc..29d60e9df6b 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntry.cpp +++ b/mozilla/netwerk/cache/src/nsCacheEntry.cpp @@ -304,8 +304,9 @@ nsCacheEntry::RemoveRequest(nsCacheRequest * request) PRBool nsCacheEntry::RemoveDescriptor(nsCacheEntryDescriptor * descriptor) { - // XXX if debug: verify this descriptor belongs to this entry + NS_ASSERTION(descriptor->CacheEntry() == this, "### Wrong cache entry!!"); PR_REMOVE_AND_INIT_LINK(descriptor); + descriptor->ClearCacheEntry(); if (!PR_CLIST_IS_EMPTY(&mDescriptorQ)) return PR_TRUE; // stay active if we still have open descriptors diff --git a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp index cefd4d2b433..c79ea38b4b3 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp +++ b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp @@ -29,6 +29,7 @@ #include "nsReadableUtils.h" #include "nsIOutputStream.h" #include "nsCRT.h" +#include "nsAutoLock.h" NS_IMPL_THREADSAFE_ISUPPORTS2(nsCacheEntryDescriptor, nsICacheEntryDescriptor, @@ -41,13 +42,15 @@ nsCacheEntryDescriptor::nsCacheEntryDescriptor(nsCacheEntry * entry, { NS_INIT_ISUPPORTS(); PR_INIT_CLIST(this); + NS_ADDREF(nsCacheService::GlobalInstance()); // ensure it lives for the lifetime of the descriptor } nsCacheEntryDescriptor::~nsCacheEntryDescriptor() { - if (mCacheEntry) - Close(); + Close(); + nsCacheService * service = nsCacheService::GlobalInstance(); + NS_RELEASE(service); } @@ -75,6 +78,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetClientID(char ** result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return ClientIDFromCacheKey(*(mCacheEntry->Key()), result); @@ -85,6 +89,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetDeviceID(char ** result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = nsCRT::strdup(mCacheEntry->GetDeviceID()); @@ -96,6 +101,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetKey(char ** result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return ClientKeyFromCacheKey(*(mCacheEntry->Key()), result); @@ -106,6 +112,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetFetchCount(PRInt32 *result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->FetchCount(); @@ -117,6 +124,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetLastFetched(PRUint32 *result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->LastFetched(); @@ -128,6 +136,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetLastModified(PRUint32 *result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->LastModified(); @@ -139,6 +148,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetExpirationTime(PRUint32 *result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->ExpirationTime(); @@ -149,6 +159,7 @@ nsCacheEntryDescriptor::GetExpirationTime(PRUint32 *result) NS_IMETHODIMP nsCacheEntryDescriptor::SetExpirationTime(PRUint32 expirationTime) { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; mCacheEntry->SetExpirationTime(expirationTime); @@ -160,9 +171,10 @@ nsCacheEntryDescriptor::SetExpirationTime(PRUint32 expirationTime) NS_IMETHODIMP nsCacheEntryDescriptor::IsStreamBased(PRBool *result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - *result = mCacheEntry->IsStreamData(); // XXX which name is better? + *result = mCacheEntry->IsStreamData(); return NS_OK; } @@ -170,6 +182,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::IsStreamBased(PRBool *result) NS_IMETHODIMP nsCacheEntryDescriptor::GetDataSize(PRUint32 *result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->DataSize(); @@ -180,10 +193,11 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetDataSize(PRUint32 *result) nsresult nsCacheEntryDescriptor::RequestDataSizeChange(PRInt32 deltaSize) { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; nsresult rv; - rv = nsCacheService::GlobalInstance()->OnDataSizeChange(mCacheEntry, deltaSize); + rv = nsCacheService::OnDataSizeChange(mCacheEntry, deltaSize); if (NS_SUCCEEDED(rv)) { // XXX review for signed/unsigned math errors PRUint32 newDataSize = mCacheEntry->DataSize() + deltaSize; @@ -197,14 +211,24 @@ nsCacheEntryDescriptor::RequestDataSizeChange(PRInt32 deltaSize) NS_IMETHODIMP nsCacheEntryDescriptor::SetDataSize(PRUint32 dataSize) { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; // XXX review for signed/unsigned math errors PRInt32 deltaSize = dataSize - mCacheEntry->DataSize(); - // this had better be NS_OK, this call instance is advisory - nsresult rv = RequestDataSizeChange(deltaSize); - NS_ASSERTION(NS_SUCCEEDED(rv), "failed SetDataSize() on memory cache object!"); + nsresult rv; + rv = nsCacheService::OnDataSizeChange(mCacheEntry, deltaSize); + // this had better be NS_OK, this call instance is advisory for memory cache objects + if (NS_SUCCEEDED(rv)) { + // XXX review for signed/unsigned math errors + PRUint32 newDataSize = mCacheEntry->DataSize() + deltaSize; + mCacheEntry->SetDataSize(newDataSize); + mCacheEntry->TouchData(); + } else { + NS_WARNING("failed SetDataSize() on memory cache object!"); + } + return rv; } @@ -213,6 +237,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetTransport(nsITransport ** result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM; @@ -225,6 +250,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetCacheElement(nsISupports ** result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_STREAM; @@ -235,10 +261,11 @@ nsCacheEntryDescriptor::GetCacheElement(nsISupports ** result) NS_IMETHODIMP nsCacheEntryDescriptor::SetCacheElement(nsISupports * cacheElement) { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_STREAM; - return nsCacheService::GlobalInstance()->SetCacheElement(mCacheEntry, cacheElement); + return nsCacheService::SetCacheElement(mCacheEntry, cacheElement); } @@ -255,6 +282,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetStoragePolicy(nsCacheStoragePolicy *result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return mCacheEntry->StoragePolicy(); @@ -264,12 +292,12 @@ nsCacheEntryDescriptor::GetStoragePolicy(nsCacheStoragePolicy *result) NS_IMETHODIMP nsCacheEntryDescriptor::SetStoragePolicy(nsCacheStoragePolicy policy) { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; // XXX validate policy against session? PRBool storageEnabled = PR_FALSE; - nsresult rv = nsCacheService::IsStorageEnabledForPolicy(policy, &storageEnabled); - if (NS_FAILED(rv)) return rv; + storageEnabled = nsCacheService::IsStorageEnabledForPolicy_Locked(policy); if (!storageEnabled) return NS_ERROR_FAILURE; mCacheEntry->SetStoragePolicy(policy); @@ -282,9 +310,10 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetFile(nsIFile ** result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - - return nsCacheService::GlobalInstance()->GetFileForEntry(mCacheEntry, result); + + return nsCacheService::GetFileForEntry(mCacheEntry, result); } @@ -292,6 +321,7 @@ NS_IMETHODIMP nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result) { NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return mCacheEntry->GetSecurityInfo(result); @@ -301,6 +331,7 @@ nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result) NS_IMETHODIMP nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo) { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; mCacheEntry->SetSecurityInfo(securityInfo); @@ -312,15 +343,17 @@ nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo) NS_IMETHODIMP nsCacheEntryDescriptor::Doom() { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - return nsCacheService::GlobalInstance()->DoomEntry(mCacheEntry); + return nsCacheService::DoomEntry(mCacheEntry); } NS_IMETHODIMP nsCacheEntryDescriptor::DoomAndFailPendingRequests(nsresult status) { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_IMPLEMENTED; @@ -330,10 +363,10 @@ nsCacheEntryDescriptor::DoomAndFailPendingRequests(nsresult status) NS_IMETHODIMP nsCacheEntryDescriptor::MarkValid() { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - nsresult rv; - rv = nsCacheService::GlobalInstance()->ValidateEntry(mCacheEntry); + nsresult rv = nsCacheService::ValidateEntry(mCacheEntry); return rv; } @@ -341,11 +374,14 @@ nsCacheEntryDescriptor::MarkValid() NS_IMETHODIMP nsCacheEntryDescriptor::Close() { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; +// XXX perhaps closing descriptors should clear/sever transports + // tell nsCacheService we're going away - nsCacheService::GlobalInstance()->CloseDescriptor(this); - mCacheEntry = nsnull; + nsCacheService::CloseDescriptor(this); + NS_ASSERTION(mCacheEntry == nsnull, "mCacheEntry not null"); return NS_OK; } @@ -354,6 +390,7 @@ nsCacheEntryDescriptor::Close() NS_IMETHODIMP nsCacheEntryDescriptor::GetMetaDataElement(const char *key, char ** result) { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (!key | !result) return NS_ERROR_NULL_POINTER; @@ -376,6 +413,7 @@ nsCacheEntryDescriptor::GetMetaDataElement(const char *key, char ** result) NS_IMETHODIMP nsCacheEntryDescriptor::SetMetaDataElement(const char *key, const char *value) { + nsAutoLock lock(nsCacheService::ServiceLock()); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (!key) return NS_ERROR_NULL_POINTER; @@ -392,6 +430,7 @@ nsCacheEntryDescriptor::SetMetaDataElement(const char *key, const char *value) NS_IMETHODIMP nsCacheEntryDescriptor::VisitMetaData(nsICacheMetaDataVisitor * visitor) { + nsAutoLock lock(nsCacheService::ServiceLock()); // XXX check callers, we're calling out of module NS_ENSURE_ARG_POINTER(visitor); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; @@ -403,7 +442,6 @@ nsCacheEntryDescriptor::VisitMetaData(nsICacheMetaDataVisitor * visitor) * nsCacheTransportWrapper ******************************************************************************/ -// XXX NS_IMPL_ISUPPORTS1(nsCacheEntryDescriptor::nsTransportWrapper, nsITransport); NS_IMPL_QUERY_INTERFACE1(nsCacheEntryDescriptor::nsTransportWrapper, nsITransport) @@ -431,6 +469,7 @@ nsTransportWrapper::EnsureTransportWithAccess(nsCacheAccessMode mode) nsresult rv = NS_OK; nsCacheEntryDescriptor * descriptor = GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this); + nsAutoLock lock(nsCacheService::ServiceLock()); if (!descriptor->mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (!descriptor->mAccessGranted & mode) { rv = (mode == nsICache::ACCESS_READ) ? @@ -439,10 +478,9 @@ nsTransportWrapper::EnsureTransportWithAccess(nsCacheAccessMode mode) } if (!mTransport) { - rv = nsCacheService::GlobalInstance()-> - GetTransportForEntry(descriptor->mCacheEntry, - descriptor->mAccessGranted, - getter_AddRefs(mTransport)); + rv = nsCacheService::GetTransportForEntry(descriptor->mCacheEntry, + descriptor->mAccessGranted, + getter_AddRefs(mTransport)); if (NS_FAILED(rv)) return rv; if (mCallbacks) { @@ -531,8 +569,6 @@ nsTransportWrapper::OpenOutputStream(PRUint32 offset, nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_WRITE); if (NS_FAILED(rv)) return rv; - // XXX allow more than one output stream at a time on a descriptor? Why? - // Create the underlying output stream using the wrapped transport. nsCOMPtr output; rv = mTransport->OpenOutputStream(offset, count, flags, getter_AddRefs(output)); @@ -606,6 +642,7 @@ nsOutputStreamWrapper::Init() if (NS_FAILED(rv)) return rv; if (mode == nsICache::ACCESS_WRITE) { + nsAutoLock lock(nsCacheService::ServiceLock()); nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; @@ -658,7 +695,7 @@ nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun reader, nsresult nsCacheEntryDescriptor:: nsOutputStreamWrapper::OnWrite(PRUint32 count) { - // XXX if count > 2^31 error_write_too_big + if (count > 0x7FFFFFFF) return NS_ERROR_UNEXPECTED; return mDescriptor->RequestDataSizeChange((PRInt32)count); } diff --git a/mozilla/netwerk/cache/src/nsCacheService.cpp b/mozilla/netwerk/cache/src/nsCacheService.cpp index a1f13cfed1f..cb23bd097c0 100644 --- a/mozilla/netwerk/cache/src/nsCacheService.cpp +++ b/mozilla/netwerk/cache/src/nsCacheService.cpp @@ -250,7 +250,7 @@ nsCacheProfilePrefObserver::Observe(nsISupports * subject, PRInt32 capacity = 0; rv = prefBranch->GetIntPref(DISK_CACHE_CAPACITY_PREF, &capacity); if (NS_FAILED(rv)) return rv; - mDiskCacheCapacity = (PRUint32) PR_MAX(0, capacity); + mDiskCacheCapacity = PR_MAX(0, capacity); nsCacheService::SetDiskCacheCapacity(mDiskCacheCapacity); #if 0 } else if (!nsCRT::strcmp(DISK_CACHE_DIR_PREF, NS_ConvertUCS2toUTF8(data).get())) { @@ -269,7 +269,7 @@ nsCacheProfilePrefObserver::Observe(nsISupports * subject, PRInt32 capacity = 0; rv = prefBranch->GetIntPref(MEMORY_CACHE_CAPACITY_PREF, &capacity); if (NS_FAILED(rv)) return rv; - mMemoryCacheCapacity = (PRUint32) PR_MAX(0, capacity); + mMemoryCacheCapacity = PR_MAX(0, capacity); nsCacheService::SetMemoryCacheCapacity(mMemoryCacheCapacity); } } @@ -296,7 +296,7 @@ nsCacheProfilePrefObserver::ReadPrefs() rv = prefBranch->GetIntPref(DISK_CACHE_CAPACITY_PREF, &capacity); if (NS_FAILED(rv)) rv2 = rv; - mDiskCacheCapacity = (PRUint32) PR_MAX(0, capacity); + mDiskCacheCapacity = PR_MAX(0, capacity); (void) prefBranch->GetComplexValue(DISK_CACHE_DIR_PREF, // ignore error NS_GET_IID(nsILocalFile), @@ -322,7 +322,7 @@ nsCacheProfilePrefObserver::ReadPrefs() capacity = 0; rv = prefBranch->GetIntPref(MEMORY_CACHE_CAPACITY_PREF, &capacity); - mMemoryCacheCapacity = (PRUint32) PR_MAX(0, capacity); + mMemoryCacheCapacity = PR_MAX(0, capacity); return NS_SUCCEEDED(rv) ? rv2 : rv; } @@ -355,11 +355,11 @@ nsCacheProfilePrefObserver::MemoryCacheEnabled() nsCacheService * nsCacheService::gService = nsnull; -//NS_IMPL_THREADSAFE_ISUPPORTS2(nsCacheService, nsICacheService, nsIObserver) NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheService, nsICacheService); nsCacheService::nsCacheService() : mCacheServiceLock(nsnull), + mInitialized(PR_FALSE), mEnableMemoryDevice(PR_TRUE), mEnableDiskDevice(PR_TRUE), mMemoryDevice(nsnull), @@ -373,20 +373,24 @@ nsCacheService::nsCacheService() mDeactivateFailures(0), mDeactivatedUnboundEntries(0) { - NS_INIT_REFCNT(); + NS_INIT_REFCNT(); - NS_ASSERTION(gService==nsnull, "multiple nsCacheService instances!"); - gService = this; + NS_ASSERTION(gService==nsnull, "multiple nsCacheService instances!"); + gService = this; - // create list of cache devices - PR_INIT_CLIST(&mDoomedEntries); + // create list of cache devices + PR_INIT_CLIST(&mDoomedEntries); + + // allocate service lock + mCacheServiceLock = PR_NewLock(); } nsCacheService::~nsCacheService() { - if (mCacheServiceLock) // Shutdown hasn't been called yet. + if (mInitialized) // Shutdown hasn't been called yet. (void) Shutdown(); + PR_DestroyLock(mCacheServiceLock); gService = nsnull; } @@ -396,19 +400,18 @@ nsCacheService::Init() { nsresult rv; - NS_ASSERTION(mCacheServiceLock== nsnull, "nsCacheService already initialized."); - if (mCacheServiceLock) + NS_ASSERTION(!mInitialized, "nsCacheService already initialized."); + if (mInitialized) return NS_ERROR_ALREADY_INITIALIZED; - CACHE_LOG_INIT(); - - mCacheServiceLock = PR_NewLock(); if (mCacheServiceLock == nsnull) return NS_ERROR_OUT_OF_MEMORY; + CACHE_LOG_INIT(); + // initialize hashtable for active cache entries rv = mActiveEntries.Init(); - if (NS_FAILED(rv)) goto error; + if (NS_FAILED(rv)) return rv; // get references to services we'll be using frequently mEventQService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); @@ -417,6 +420,7 @@ nsCacheService::Init() mProxyObjectManager = do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; + // create profile/preference observer mObserver = new nsCacheProfilePrefObserver(); if (!mObserver) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(mObserver); @@ -425,30 +429,25 @@ nsCacheService::Init() mEnableDiskDevice = mObserver->DiskCacheEnabled(); mEnableMemoryDevice = mObserver->MemoryCacheEnabled(); - rv = CreateMemoryDevice(); - if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_AVAILABLE)) goto error; + if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_AVAILABLE)) + return rv; + mInitialized = PR_TRUE; return NS_OK; - - error: - (void)Shutdown(); - - return rv; } NS_IMETHODIMP nsCacheService::Shutdown() { - NS_ASSERTION(mCacheServiceLock != nsnull, + nsAutoLock lock(mCacheServiceLock); + NS_ASSERTION(mInitialized, "can't shutdown nsCacheService unless it has been initialized."); - if (mCacheServiceLock) { - // XXX this is not sufficient - PRLock * tempLock = mCacheServiceLock; - mCacheServiceLock = nsnull; + if (mInitialized) { + mInitialized = PR_FALSE; #if defined(PR_LOGGING) LogCacheStatistics(); #endif @@ -466,8 +465,6 @@ nsCacheService::Shutdown() delete mDiskDevice; mDiskDevice = nsnull; - - PR_DestroyLock(tempLock); } return NS_OK; } @@ -517,7 +514,8 @@ nsCacheService::CreateSession(const char * clientID, nsresult nsCacheService::EvictEntriesForSession(nsCacheSession * session) { - return EvictEntriesForClient(session->ClientID()->get(), + NS_ASSERTION(gService, "nsCacheService::gService is null."); + return gService->EvictEntriesForClient(session->ClientID()->get(), session->StoragePolicy()); } @@ -567,20 +565,22 @@ nsCacheService::IsStorageEnabledForPolicy(nsCacheStoragePolicy storagePolicy, return NS_OK; } + PRBool nsCacheService::IsStorageEnabledForPolicy_Locked(nsCacheStoragePolicy storagePolicy) { - if (mEnableMemoryDevice && + if (gService->mEnableMemoryDevice && (storagePolicy == nsICache::STORE_ANYWHERE || storagePolicy == nsICache::STORE_IN_MEMORY)) { return PR_TRUE; } - if (mEnableDiskDevice && + if (gService->mEnableDiskDevice && (storagePolicy == nsICache::STORE_ANYWHERE || storagePolicy == nsICache::STORE_ON_DISK || storagePolicy == nsICache::STORE_ON_DISK_AS_FILE)) { return PR_TRUE; } + return PR_FALSE; } @@ -592,8 +592,8 @@ NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor) 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. + // XXX record the fact that a visitation is in progress, + // XXX i.e. keep list of visitors in progress. nsresult rv = NS_OK; if (mEnableMemoryDevice) { @@ -669,7 +669,7 @@ nsCacheService::CreateMemoryDevice() nsresult rv = mMemoryDevice->Init(); if (NS_FAILED(rv)) { - // XXX log error + NS_WARNING("Initialization of Memory Cache failed."); delete mMemoryDevice; mMemoryDevice = nsnull; } @@ -685,7 +685,7 @@ nsCacheService::CreateRequest(nsCacheSession * session, nsICacheListener * listener, nsCacheRequest ** request) { - NS_ASSERTION(request, "CommonOpenCacheEntry: request or entry is null"); + NS_ASSERTION(request, "CreateRequest: request or entry is null"); nsCString * key = new nsCString(*session->ClientID()); if (!key) @@ -802,28 +802,28 @@ nsCacheService::ProcessRequest(nsCacheRequest * request, nsresult nsCacheService::OpenCacheEntry(nsCacheSession * session, - const char * key, - nsCacheAccessMode accessRequested, - PRBool blockingMode, - nsICacheListener * listener, - nsICacheEntryDescriptor ** result) + const char * key, + nsCacheAccessMode accessRequested, + PRBool blockingMode, + nsICacheListener * listener, + nsICacheEntryDescriptor ** result) { - if (this == nsnull) return NS_ERROR_NOT_AVAILABLE; + NS_ASSERTION(gService, "nsCacheService::gService is null."); if (result) *result = nsnull; nsCacheRequest * request = nsnull; - nsAutoLock lock(mCacheServiceLock); - nsresult rv = CreateRequest(session, - key, - accessRequested, - blockingMode, - listener, - &request); + nsAutoLock lock(gService->mCacheServiceLock); + nsresult rv = gService->CreateRequest(session, + key, + accessRequested, + blockingMode, + listener, + &request); if (NS_FAILED(rv)) return rv; - rv = ProcessRequest(request, PR_TRUE, result); + rv = gService->ProcessRequest(request, PR_TRUE, result); // delete requests that have completed if (!(listener && (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION))) @@ -871,7 +871,7 @@ nsCacheService::ActivateEntry(nsCacheRequest * request, request->WillDoomEntriesIfExpired()))) { // this is FORCE-WRITE request or the entry has expired - rv = DoomEntry_Locked(entry); + rv = DoomEntry_Internal(entry); if (NS_FAILED(rv)) { // XXX what to do? Increment FailedDooms counter? } @@ -908,7 +908,6 @@ nsCacheService::ActivateEntry(nsCacheRequest * request, error: *result = nsnull; if (entry) { - // XXX clean up delete entry; } return rv; @@ -957,9 +956,9 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry) } if (mDiskDevice) { - entry->MarkBinding(); // XXX + entry->MarkBinding(); // enter state of binding rv = mDiskDevice->BindEntry(entry); - entry->ClearBinding(); // XXX + entry->ClearBinding(); // exit state of binding if (NS_SUCCEEDED(rv)) device = mDiskDevice; } @@ -967,9 +966,9 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry) // if we can't use mDiskDevice, try mMemoryDevice if (!device && mEnableMemoryDevice && entry->IsAllowedInMemory()) { - entry->MarkBinding(); // XXX + entry->MarkBinding(); // enter state of binding rv = mMemoryDevice->BindEntry(entry); - entry->ClearBinding(); // XXX + entry->ClearBinding(); // exit state of binding if (NS_SUCCEEDED(rv)) device = mMemoryDevice; } @@ -981,37 +980,16 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry) } -nsresult -nsCacheService::ValidateEntry(nsCacheEntry * entry) -{ - if (this == nsnull) return NS_ERROR_NOT_AVAILABLE; - - nsAutoLock lock(mCacheServiceLock); - nsCacheDevice * device = EnsureEntryHasDevice(entry); - if (!device) return NS_ERROR_UNEXPECTED; // XXX need better error here - - entry->MarkValid(); - nsresult rv = ProcessPendingRequests(entry); - NS_ASSERTION(rv == NS_OK, "ProcessPendingRequests failed."); - // XXX what else can be done? - - return rv; -} - - nsresult nsCacheService::DoomEntry(nsCacheEntry * entry) { - if (this == nsnull) return NS_ERROR_NOT_AVAILABLE; - nsAutoLock lock(mCacheServiceLock); - return DoomEntry_Locked(entry); + return gService->DoomEntry_Internal(entry); } nsresult -nsCacheService::DoomEntry_Locked(nsCacheEntry * entry) +nsCacheService::DoomEntry_Internal(nsCacheEntry * entry) { - if (this == nsnull) return NS_ERROR_NOT_AVAILABLE; if (entry->IsDoomed()) return NS_OK; nsresult rv = NS_OK; @@ -1073,7 +1051,7 @@ nsCacheService::ProxyObjectRelease(nsISupports * object, PRThread * thread) PLEvent * event = new PLEvent; if (!event) { - // XXX warning + NS_WARNING("failed to allocate a PLEvent."); return; } PL_InitEvent(event, object, EventHandler, DestroyHandler); @@ -1215,6 +1193,74 @@ nsCacheService::SetCacheDevicesEnabled(PRBool enableDisk, PRBool enableMemory) } #endif + + +/****************************************************************************** + * static methods for nsCacheEntryDescriptor + *****************************************************************************/ +#ifdef XP_MAC +#pragma mark - +#endif + +void +nsCacheService::CloseDescriptor(nsCacheEntryDescriptor * descriptor) +{ + // ask entry to remove descriptor + nsCacheEntry * entry = descriptor->CacheEntry(); + PRBool stillActive = entry->RemoveDescriptor(descriptor); + nsresult rv = NS_OK; + + if (!entry->IsValid()) { + rv = gService->ProcessPendingRequests(entry); + } + + if (!stillActive) { + gService->DeactivateEntry(entry); + } +} + + +nsresult +nsCacheService::GetFileForEntry(nsCacheEntry * entry, + nsIFile ** result) +{ + nsCacheDevice * device = gService->EnsureEntryHasDevice(entry); + if (!device) return NS_ERROR_UNEXPECTED; + + return device->GetFileForEntry(entry, result); +} + + +nsresult +nsCacheService::GetTransportForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + nsITransport ** result) +{ + nsCacheDevice * device = gService->EnsureEntryHasDevice(entry); + if (!device) return NS_ERROR_UNEXPECTED; + + return device->GetTransportForEntry(entry, mode, result); +} + + +nsresult +nsCacheService::OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize) +{ + nsCacheDevice * device = gService->EnsureEntryHasDevice(entry); + if (!device) return NS_ERROR_UNEXPECTED; + + return device->OnDataSizeChange(entry, deltaSize); +} + + +PRLock * +nsCacheService::ServiceLock() +{ + NS_ASSERTION(gService, "nsCacheService::gService is null."); + return gService->mCacheServiceLock; +} + + nsresult nsCacheService::SetCacheElement(nsCacheEntry * entry, nsISupports * element) { @@ -1226,65 +1272,22 @@ nsCacheService::SetCacheElement(nsCacheEntry * entry, nsISupports * element) nsresult -nsCacheService::OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize) +nsCacheService::ValidateEntry(nsCacheEntry * entry) { - if (this == nsnull) return NS_ERROR_NOT_AVAILABLE; - nsAutoLock lock(mCacheServiceLock); + nsCacheDevice * device = gService->EnsureEntryHasDevice(entry); + if (!device) return NS_ERROR_UNEXPECTED; - nsCacheDevice * device = EnsureEntryHasDevice(entry); - if (!device) return NS_ERROR_UNEXPECTED; // XXX need better error here + entry->MarkValid(); + nsresult rv = gService->ProcessPendingRequests(entry); + NS_ASSERTION(rv == NS_OK, "ProcessPendingRequests failed."); + // XXX what else should be done? - return device->OnDataSizeChange(entry, deltaSize); + return rv; } - -nsresult -nsCacheService::GetTransportForEntry(nsCacheEntry * entry, - nsCacheAccessMode mode, - nsITransport ** result) -{ - if (this == nsnull) return NS_ERROR_NOT_AVAILABLE; - nsAutoLock lock(mCacheServiceLock); - - nsCacheDevice * device = EnsureEntryHasDevice(entry); - if (!device) return NS_ERROR_UNEXPECTED; // XXX need better error here - - return device->GetTransportForEntry(entry, mode, result); -} - - -void -nsCacheService::CloseDescriptor(nsCacheEntryDescriptor * descriptor) -{ - NS_ASSERTION(this != nsnull, "CloseDescriptor called with no cache service!"); - if (this == nsnull) return; - nsAutoLock lock(mCacheServiceLock); - - // ask entry to remove descriptor - nsCacheEntry * entry = descriptor->CacheEntry(); - PRBool stillActive = entry->RemoveDescriptor(descriptor); - nsresult rv = NS_OK; - - if (!entry->IsValid()) { - rv = ProcessPendingRequests(entry); - } - - if (!stillActive) { - DeactivateEntry(entry); - } -} - - -nsresult -nsCacheService::GetFileForEntry(nsCacheEntry * entry, - nsIFile ** result) -{ - if (this == nsnull) return NS_ERROR_NOT_AVAILABLE; - nsAutoLock lock(mCacheServiceLock); - nsCacheDevice * device = EnsureEntryHasDevice(entry); - if (!device) return NS_ERROR_UNEXPECTED; // XXX need better error here - return device->GetFileForEntry(entry, result); -} +#ifdef XP_MAC +#pragma mark - +#endif void @@ -1312,9 +1315,9 @@ nsCacheService::DeactivateEntry(nsCacheEntry * entry) return; } } else { - // if mCacheServiceLock == nsnull, + // if mInitialized == PR_FALSE, // then we're shutting down and this state is okay. - NS_ASSERTION(!mCacheServiceLock, "DeactivateEntry: bad cache entry state\n"); + NS_ASSERTION(!mInitialized, "DeactivateEntry: bad cache entry state."); } device = entry->CacheDevice(); @@ -1495,7 +1498,7 @@ nsCacheService::DoomActiveEntries() PRUint32 count = array.Count(); for (PRUint32 i=0; i < count; ++i) - DoomEntry_Locked((nsCacheEntry *) array[i]); + DoomEntry_Internal((nsCacheEntry *) array[i]); } diff --git a/mozilla/netwerk/cache/src/nsCacheService.h b/mozilla/netwerk/cache/src/nsCacheService.h index bba9d0badf1..fab35c5c023 100644 --- a/mozilla/netwerk/cache/src/nsCacheService.h +++ b/mozilla/netwerk/cache/src/nsCacheService.h @@ -65,17 +65,14 @@ public: /** * Methods called by nsCacheSession */ - nsresult OpenCacheEntry(nsCacheSession * session, + static nsresult OpenCacheEntry(nsCacheSession * session, const char * key, nsCacheAccessMode accessRequested, PRBool blockingMode, nsICacheListener * listener, nsICacheEntryDescriptor ** result); - nsresult EvictEntriesForSession(nsCacheSession * session); - - nsresult EvictEntriesForClient(const char * clientID, - nsCacheStoragePolicy storagePolicy); + static nsresult EvictEntriesForSession(nsCacheSession * session); static nsresult IsStorageEnabledForPolicy(nsCacheStoragePolicy storagePolicy, PRBool * result); @@ -83,34 +80,37 @@ public: /** * Methods called by nsCacheEntryDescriptor */ - nsresult SetCacheElement(nsCacheEntry * entry, nsISupports * element); - nsresult OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize); + static void CloseDescriptor(nsCacheEntryDescriptor * descriptor); - nsresult ValidateEntry(nsCacheEntry * entry); + static nsresult GetFileForEntry(nsCacheEntry * entry, + nsIFile ** result); - nsresult GetTransportForEntry(nsCacheEntry * entry, + static nsresult GetTransportForEntry(nsCacheEntry * entry, nsCacheAccessMode mode, nsITransport ** result); - void CloseDescriptor(nsCacheEntryDescriptor * descriptor); + static nsresult OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize); + + static PRLock * ServiceLock(); + + static nsresult SetCacheElement(nsCacheEntry * entry, nsISupports * element); + + static nsresult ValidateEntry(nsCacheEntry * entry); - nsresult GetFileForEntry(nsCacheEntry * entry, - nsIFile ** result); /** * Methods called by any cache classes */ static - nsCacheService * GlobalInstance() { return gService; }; + nsCacheService * GlobalInstance() { return gService; } + + static nsresult DoomEntry(nsCacheEntry * entry); - nsresult DoomEntry(nsCacheEntry * entry); + static void ProxyObjectRelease(nsISupports * object, PRThread * thread); - nsresult DoomEntry_Locked(nsCacheEntry * entry); - - static - void ProxyObjectRelease(nsISupports * object, PRThread * thread); + static PRBool IsStorageEnabledForPolicy_Locked(nsCacheStoragePolicy policy); /** * Methods called by nsCacheProfilePrefObserver @@ -140,6 +140,11 @@ private: nsICacheListener * listener, nsCacheRequest ** request); + nsresult DoomEntry_Internal(nsCacheEntry * entry); + + nsresult EvictEntriesForClient(const char * clientID, + nsCacheStoragePolicy storagePolicy); + nsresult NotifyListener(nsCacheRequest * request, nsICacheEntryDescriptor * descriptor, nsCacheAccessMode accessGranted, @@ -164,7 +169,6 @@ private: void ClearActiveEntries(void); void DoomActiveEntries(void); - PRBool IsStorageEnabledForPolicy_Locked(nsCacheStoragePolicy policy); static PLDHashOperator PR_CALLBACK DeactivateAndClearEntry(PLDHashTable * table, @@ -192,6 +196,8 @@ private: PRLock * mCacheServiceLock; + PRBool mInitialized; + PRBool mEnableMemoryDevice; PRBool mEnableDiskDevice; diff --git a/mozilla/netwerk/cache/src/nsCacheSession.cpp b/mozilla/netwerk/cache/src/nsCacheSession.cpp index 6523c33fcc5..f4fe1c89685 100644 --- a/mozilla/netwerk/cache/src/nsCacheSession.cpp +++ b/mozilla/netwerk/cache/src/nsCacheSession.cpp @@ -74,12 +74,12 @@ nsCacheSession::OpenCacheEntry(const char * key, nsICacheEntryDescriptor ** result) { nsresult rv; - rv = nsCacheService::GlobalInstance()->OpenCacheEntry(this, - key, - accessRequested, - blockingMode, - nsnull, // no listener - result); + rv = nsCacheService::OpenCacheEntry(this, + key, + accessRequested, + blockingMode, + nsnull, // no listener + result); return rv; } @@ -89,12 +89,12 @@ NS_IMETHODIMP nsCacheSession::AsyncOpenCacheEntry(const char *key, nsICacheListener *listener) { nsresult rv; - rv = nsCacheService::GlobalInstance()->OpenCacheEntry(this, - key, - accessRequested, - nsICache::BLOCKING, - listener, - nsnull); // no result + rv = nsCacheService::OpenCacheEntry(this, + key, + accessRequested, + nsICache::BLOCKING, + listener, + nsnull); // no result if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) rv = NS_OK; return rv; @@ -102,7 +102,7 @@ NS_IMETHODIMP nsCacheSession::AsyncOpenCacheEntry(const char *key, NS_IMETHODIMP nsCacheSession::EvictEntries() { - return nsCacheService::GlobalInstance()->EvictEntriesForSession(this); + return nsCacheService::EvictEntriesForSession(this); } diff --git a/mozilla/netwerk/cache/src/nsDiskCache.h b/mozilla/netwerk/cache/src/nsDiskCache.h index 05c0f9ad52e..577097e13ec 100644 --- a/mozilla/netwerk/cache/src/nsDiskCache.h +++ b/mozilla/netwerk/cache/src/nsDiskCache.h @@ -32,12 +32,13 @@ class nsDiskCache { public: enum { - kCurrentVersion = 0x00010003 // XXX whats the format? + kCurrentVersion = 0x00010005 // format = 16 bits major version/16 bits minor version }; enum { kData, kMetaData }; static PLDHashNumber Hash(const char* key); + static nsresult Truncate(PRFileDesc * fd, PRUint32 newEOF); }; #endif // _nsDiskCache_h_ diff --git a/mozilla/netwerk/cache/src/nsDiskCacheBinding.cpp b/mozilla/netwerk/cache/src/nsDiskCacheBinding.cpp index 7dd0c2059b8..495dfb58f75 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheBinding.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheBinding.cpp @@ -124,6 +124,11 @@ nsDiskCacheBinding::~nsDiskCacheBinding() NS_ASSERTION(PR_CLIST_IS_EMPTY(this), "binding deleted while still on list"); if (!PR_CLIST_IS_EMPTY(this)) PR_REMOVE_LINK(this); // XXX why are we still on a list? + + // sever streamIO/binding link + // XXX what's the right way to call a method on the concrete class? + nsDiskCacheStreamIO * streamIO = (nsDiskCacheStreamIO *)mStreamIO.get(); + if (streamIO) streamIO->ClearBinding(); } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheBinding.h b/mozilla/netwerk/cache/src/nsDiskCacheBinding.h index 035111e4e37..c04039651d9 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheBinding.h +++ b/mozilla/netwerk/cache/src/nsDiskCacheBinding.h @@ -32,11 +32,8 @@ #include "nsISupports.h" #include "nsCacheEntry.h" -#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS -#include "nsITransport.h" -#endif - #include "nsDiskCacheMap.h" +#include "nsDiskCacheStreams.h" /****************************************************************************** @@ -55,30 +52,14 @@ public: nsDiskCacheBinding(nsCacheEntry* entry, nsDiskCacheRecord * record); virtual ~nsDiskCacheBinding(); -#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS - /** - * Maps a cache access mode to a cached nsITransport for that access - * mode. We keep these cached to avoid repeated trips to the - * file transport service. - */ - nsCOMPtr& getTransport(nsCacheAccessMode mode) - { - return mTransports[mode - 1]; - } -#endif - // XXX make friends public: nsCacheEntry* mCacheEntry; // back pointer to parent nsCacheEntry nsDiskCacheRecord mRecord; + nsCOMPtr mStreamIO; PRBool mDoomed; // record is not stored in cache map PRUint8 mGeneration; // possibly just reservation - -private: -#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS - nsCOMPtr mTransports[3]; -#endif }; diff --git a/mozilla/netwerk/cache/src/nsDiskCacheBlockFile.cpp b/mozilla/netwerk/cache/src/nsDiskCacheBlockFile.cpp index 1d6514a85b3..53686ed4420 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheBlockFile.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheBlockFile.cpp @@ -22,6 +22,7 @@ */ #include "nsCRT.h" +#include "nsDiskCache.h" #include "nsDiskCacheBlockFile.h" /****************************************************************************** @@ -132,7 +133,13 @@ nsDiskCacheBlockFile::Close() nsresult nsDiskCacheBlockFile::Trim() { - return NS_OK; + PRInt32 estimatedSize = kBitMapBytes; + PRInt32 lastBlock = LastBlock(); + if (lastBlock >= 0) + estimatedSize += (lastBlock + 1) * mBlockSize; + + nsresult rv = nsDiskCache::Truncate(mFD, estimatedSize); + return rv; } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp b/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp index b8254d60eed..8c5c714d584 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp @@ -24,9 +24,32 @@ #include +// include files for ftruncate (or equivalent) +#if defined(XP_UNIX) +#include +#elif defined(XP_MAC) +#include +#elif defined(XP_WIN) +#include +#elif defined(XP_OS2) +#define INCL_DOSERRORS +#include +#else +// XXX add necessary include file for ftruncate (or equivalent) +#endif + +#if defined(XP_MAC) +#include "pprio.h" +#else +#include "private/pprio.h" +#endif + + #include "nsDiskCacheDevice.h" #include "nsDiskCacheEntry.h" #include "nsDiskCacheMap.h" +#include "nsDiskCacheStreams.h" + #include "nsDiskCache.h" #include "nsCacheService.h" @@ -39,6 +62,7 @@ #include "nsReadableUtils.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" +#include "nsAutoLock.h" #include "nsCRT.h" @@ -115,9 +139,9 @@ nsDiskCacheEvictor::VisitRecord(nsDiskCacheRecord * mapRecord) // we are currently using this entry, so all we can do is doom it // since we're enumerating the records, we don't want to call DeleteRecord - // when nsCacheService::GlobalInstance()->DoomEntry_Locked() calls us back. + // when nsCacheService::DoomEntry() calls us back. binding->mDoomed = PR_TRUE; // mark binding record as 'deleted' - nsCacheService::GlobalInstance()->DoomEntry_Locked(binding->mCacheEntry); + nsCacheService::DoomEntry(binding->mCacheEntry); result = kDeleteRecordAndContinue; // this will REALLY delete the record } else { @@ -247,6 +271,43 @@ nsDiskCache::Hash(const char * key) } +nsresult +nsDiskCache::Truncate(PRFileDesc * fd, PRUint32 newEOF) +{ + // use modified SetEOF from nsFileStreams::SetEOF() + +#if defined(XP_UNIX) + if (ftruncate(PR_FileDesc2NativeHandle(fd), newEOF) != 0) { + NS_ERROR("ftruncate failed"); + return NS_ERROR_FAILURE; + } + +#elif defined(XP_MAC) + if (::SetEOF(PR_FileDesc2NativeHandle(fd), newEOF) != 0) { + NS_ERROR("SetEOF failed"); + return NS_ERROR_FAILURE; + } + +#elif defined(XP_WIN) + PRInt32 cnt = PR_Seek(fd, newEOF, PR_SEEK_SET); + if (cnt == -1) return NS_ERROR_FAILURE; + if (!SetEndOfFile((HANDLE) PR_FileDesc2NativeHandle(fd))) { + NS_ERROR("SetEndOfFile failed"); + return NS_ERROR_FAILURE; + } + +#elif defined(XP_OS2) + if (DosSetFileSize((HFILE) PR_FileDesc2NativeHandle(fd), newEOF) != NO_ERROR) { + NS_ERROR("DosSetFileSize failed"); + return NS_ERROR_FAILURE; + } +#else + // add implementations for other platforms here +#endif + return NS_OK; +} + + /****************************************************************************** * nsDiskCacheDevice *****************************************************************************/ @@ -258,7 +319,9 @@ static nsCOMPtr gFileTransportService; #endif nsDiskCacheDevice::nsDiskCacheDevice() - : mInitialized(PR_FALSE), mCacheCapacity(0), mCacheMap(nsnull) + : mDeviceLock(nsnull) + , mCacheCapacity(0) + , mCacheMap(nsnull) { } @@ -277,8 +340,8 @@ nsDiskCacheDevice::Init() { nsresult rv; - NS_ENSURE_TRUE(!mInitialized, NS_ERROR_FAILURE); - + NS_ENSURE_TRUE(!Initialized(), NS_ERROR_FAILURE); + if (!mCacheDirectory) return NS_ERROR_FAILURE; rv = mBindery.Init(); if (NS_FAILED(rv)) return rv; @@ -287,7 +350,7 @@ nsDiskCacheDevice::Init() gFileTransportService = do_GetService("@mozilla.org/network/file-transport-service;1", &rv); if (NS_FAILED(rv)) return rv; - // XXX are we sure we want to do this on startup? + // XXX we should spawn another thread to do this after startup // delete "Cache.Trash" folder nsCOMPtr cacheTrashDir; rv = GetCacheTrashDirectory(getter_AddRefs(cacheTrashDir)); @@ -307,7 +370,13 @@ nsDiskCacheDevice::Init() if (NS_FAILED(rv)) goto error_exit; } - mInitialized = PR_TRUE; // record that initialization succeeded. + mDeviceLock = nsCacheLock::Create(); + if (mDeviceLock == nsnull) { + rv = NS_ERROR_OUT_OF_MEMORY; + goto error_exit; + } + // creation of lock indicates successful initialization + return NS_OK; error_exit: @@ -326,19 +395,22 @@ error_exit: nsresult nsDiskCacheDevice::Shutdown() { - if (mInitialized) { - // check cache limits in case we need to evict. - EvictDiskCacheEntries(); + if (Initialized()) { + { // code block for nsAutoLock + nsAutoLock lock(mDeviceLock->GetPRLock()); + // check cache limits in case we need to evict. + EvictDiskCacheEntries((PRInt32)mCacheCapacity); - // write out persistent information about the cache. - (void) mCacheMap->Close(); - delete mCacheMap; - mCacheMap = nsnull; + // write out persistent information about the cache. + (void) mCacheMap->Close(); + delete mCacheMap; + mCacheMap = nsnull; - mBindery.Reset(); + mBindery.Reset(); + } // no longer initialized. - mInitialized = PR_FALSE; + mDeviceLock = nsnull; } // release the reference to the cached file transport service. @@ -387,6 +459,8 @@ nsDiskCacheDevice::FindEntry(nsCString * key) nsDiskCacheBinding * binding = nsnull; PLDHashNumber hashNumber = nsDiskCache::Hash(key->get()); + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock + #if DEBUG /*because we shouldn't be called for active entries */ binding = mBindery.FindActiveBinding(hashNumber); NS_ASSERTION(!binding, "### FindEntry() called for a bound entry."); @@ -423,6 +497,8 @@ nsDiskCacheDevice::FindEntry(nsCString * key) nsresult nsDiskCacheDevice::DeactivateEntry(nsCacheEntry * entry) { + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock + nsresult rv = NS_OK; nsDiskCacheBinding * binding = GetCacheEntryBinding(entry); NS_ASSERTION(binding, "DeactivateEntry: binding == nsnull"); @@ -466,6 +542,7 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry * entry) { nsresult rv = NS_OK; nsDiskCacheRecord record, oldRecord; + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock // create a new record for this entry record.SetHashNumber(nsDiskCache::Hash(entry->Key()->get())); @@ -485,7 +562,7 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry * entry) if (!oldBinding->mCacheEntry->IsDoomed()) { // we've got a live one! - nsCacheService::GlobalInstance()->DoomEntry_Locked(oldBinding->mCacheEntry); + nsCacheService::DoomEntry(oldBinding->mCacheEntry); // storage will be delete when oldBinding->mCacheEntry is Deactivated } } else { @@ -510,6 +587,7 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry * entry) void nsDiskCacheDevice::DoomEntry(nsCacheEntry * entry) { + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock nsDiskCacheBinding * binding = GetCacheEntryBinding(entry); NS_ASSERTION(binding, "DoomEntry: binding == nsnull"); if (!binding) return; @@ -524,13 +602,14 @@ nsDiskCacheDevice::DoomEntry(nsCacheEntry * entry) nsresult -nsDiskCacheDevice::GetTransportForEntry(nsCacheEntry * entry, - nsCacheAccessMode mode, - nsITransport ** result) +nsDiskCacheDevice::GetTransportForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + nsITransport ** result) { NS_ENSURE_ARG_POINTER(entry); NS_ENSURE_ARG_POINTER(result); + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock nsresult rv; nsDiskCacheBinding * binding = GetCacheEntryBinding(entry); NS_ASSERTION(binding, "GetTransportForEntry: binding == nsnull"); @@ -538,51 +617,14 @@ nsDiskCacheDevice::GetTransportForEntry(nsCacheEntry * entry, NS_ASSERTION(binding->mCacheEntry == entry, "binding & entry don't point to each other"); -#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS - nsCOMPtr& transport = binding->getTransport(mode); - if (transport) { - NS_ADDREF(*result = transport); - return NS_OK; + if (!binding->mStreamIO) { + binding->mStreamIO = new nsDiskCacheStreamIO(binding); + if (!binding->mStreamIO) return NS_ERROR_OUT_OF_MEMORY; } -#endif - - // check/set binding->mRecord for separate file, sync w/mCacheMap - if (binding->mRecord.DataLocationInitialized()) { - NS_ASSERTION(binding->mRecord.DataFile() == 0, "error: cache block file"); // make sure it's a separate file - NS_ASSERTION(binding->mRecord.DataFileGeneration() == binding->mGeneration, "error generations out of sync"); - } else { - binding->mRecord.SetDataFileGeneration(binding->mGeneration); - binding->mRecord.SetDataFileSize(0); // 1k minimum - if (!binding->mDoomed) { - // record stored in cache map, so update it - rv = mCacheMap->UpdateRecord(&binding->mRecord); - if (NS_FAILED(rv)) return rv; - } - } - - // generate the name of the cache entry from the hash code of its key, - // modulo the number of files we're willing to keep cached. - nsCOMPtr file; - rv = mCacheMap->GetFileForDiskCacheRecord(&binding->mRecord, - nsDiskCache::kData, - getter_AddRefs(file)); - if (NS_FAILED(rv)) return rv; - - PRInt32 ioFlags = 0; - switch (mode) { - case nsICache::ACCESS_READ: - ioFlags = PR_RDONLY; - break; - case nsICache::ACCESS_WRITE: - ioFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; - break; - case nsICache::ACCESS_READ_WRITE: - ioFlags = PR_RDWR | PR_CREATE_FILE; - break; - } - - rv = gFileTransportService->CreateTransport(file, ioFlags, PR_IRUSR | PR_IWUSR, PR_FALSE, result); - return rv; + // XXX assumption: CreateTransportFromStreamIO() is light-weight + // PR_FALSE = keep streamIO open for lifetime of transport + rv = gFileTransportService->CreateTransportFromStreamIO(binding->mStreamIO, PR_FALSE, result); + return rv; } @@ -590,14 +632,23 @@ nsresult nsDiskCacheDevice::GetFileForEntry(nsCacheEntry * entry, nsIFile ** result) { + NS_ENSURE_ARG_POINTER(result); + *result = nsnull; + + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock nsresult rv; + nsDiskCacheBinding * binding = GetCacheEntryBinding(entry); - NS_ASSERTION(binding, "GetFileForEntry: binding == nsnull"); - if (!binding) return NS_ERROR_UNEXPECTED; + if (!binding) { + NS_WARNING("GetFileForEntry: binding == nsnull"); + return NS_ERROR_UNEXPECTED; + } // check/set binding->mRecord for separate file, sync w/mCacheMap if (binding->mRecord.DataLocationInitialized()) { - NS_ASSERTION(binding->mRecord.DataFile() == 0, "error: cache block file"); // make sure it's a separate file + if (binding->mRecord.DataFile() != 0) + return NS_ERROR_NOT_AVAILABLE; // data not stored as separate file + NS_ASSERTION(binding->mRecord.DataFileGeneration() == binding->mGeneration, "error generations out of sync"); } else { binding->mRecord.SetDataFileGeneration(binding->mGeneration); @@ -626,6 +677,7 @@ nsDiskCacheDevice::GetFileForEntry(nsCacheEntry * entry, nsresult nsDiskCacheDevice::OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize) { + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock nsDiskCacheBinding * binding = GetCacheEntryBinding(entry); NS_ASSERTION(binding, "OnDataSizeChange: binding == nsnull"); if (!binding) return NS_ERROR_UNEXPECTED; @@ -634,22 +686,20 @@ nsDiskCacheDevice::OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize) PRUint32 newSize = entry->DataSize() + deltaSize; if (newSize > mCacheCapacity) { - nsresult rv = nsCacheService::GlobalInstance()->DoomEntry_Locked(entry); - NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry_Locked() failed."); + nsresult rv = nsCacheService::DoomEntry(entry); + NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry() failed."); return NS_ERROR_ABORT; } - PRUint32 sizeK = ((entry->DataSize() + 0x0399) >> 10); // round up to next 1k - PRUint32 newSizeK = ((newSize + 0x399) >> 10); + PRUint32 sizeK = ((entry->DataSize() + 0x03FF) >> 10); // round up to next 1k + PRUint32 newSizeK = ((newSize + 0x3FF) >> 10); - NS_ASSERTION((sizeK < USHRT_MAX) && (sizeK == binding->mRecord.DataFileSize()), - "data size out of sync"); + NS_ASSERTION(sizeK < USHRT_MAX, "data size out of range"); + NS_ASSERTION(newSizeK < USHRT_MAX, "data size out of range"); - mCacheMap->IncrementTotalSize((newSizeK - sizeK) * 1024); - newSizeK = (newSizeK < USHRT_MAX) ? newSizeK : USHRT_MAX; // record file size ceiling - binding->mRecord.SetDataFileSize(newSizeK); // update binding->mRecord - - EvictDiskCacheEntries(); + // pre-evict entries to make space for new data + PRInt32 targetCapacity = (PRInt32)(mCacheCapacity - ((newSizeK - sizeK) * 1024)); + EvictDiskCacheEntries(targetCapacity); return NS_OK; } @@ -728,6 +778,9 @@ nsDiskCacheDevice::EvictEntries(const char * clientID) { nsDiskCacheEvictor evictor(this, mCacheMap, &mBindery, 0, clientID); nsresult rv = mCacheMap->VisitRecords(&evictor); + + if (clientID == nsnull) // we tried to clear the entire cache + rv = mCacheMap->Trim(); // so trim cache block files (if possible) return rv; } @@ -804,13 +857,13 @@ nsDiskCacheDevice::GetCacheTrashDirectory(nsIFile ** result) nsresult -nsDiskCacheDevice::EvictDiskCacheEntries() +nsDiskCacheDevice::EvictDiskCacheEntries(PRInt32 targetCapacity) { nsresult rv; - if (mCacheMap->TotalSize() < (PRInt32) mCacheCapacity) return NS_OK; + if (mCacheMap->TotalSize() < targetCapacity) return NS_OK; - nsDiskCacheEvictor evictor(this, mCacheMap, &mBindery, mCacheCapacity, nsnull); + nsDiskCacheEvictor evictor(this, mCacheMap, &mBindery, targetCapacity, nsnull); rv = mCacheMap->EvictRecords(&evictor); return rv; @@ -831,7 +884,7 @@ nsDiskCacheDevice::SetCacheParentDirectory(nsILocalFile * parentDir) nsresult rv; PRBool exists; - if (mInitialized) { + if (Initialized()) { NS_ASSERTION(PR_FALSE, "Cannot switch cache directory when initialized"); return; } @@ -896,9 +949,10 @@ void nsDiskCacheDevice::SetCapacity(PRUint32 capacity) { mCacheCapacity = capacity * 1024; - if (mInitialized) { + if (Initialized()) { + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock // start evicting entries if the new size is smaller! - EvictDiskCacheEntries(); + EvictDiskCacheEntries((PRInt32)mCacheCapacity); } } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDevice.h b/mozilla/netwerk/cache/src/nsDiskCacheDevice.h index 0c5994e40cb..9cb6bac0295 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDevice.h +++ b/mozilla/netwerk/cache/src/nsDiskCacheDevice.h @@ -35,6 +35,7 @@ class nsDiskCacheMap; + class nsDiskCacheDevice : public nsCacheDevice { public: nsDiskCacheDevice(); @@ -78,18 +79,22 @@ public: PRUint32 getCacheSize(); PRUint32 getEntryCount(); + nsCacheLock * DeviceLock() { return mDeviceLock; } + PRBool Initialized() { return (mDeviceLock != nsnull); } + nsDiskCacheMap * CacheMap() { return mCacheMap; } + private: /** * Private methods */ nsresult InitializeCacheDirectory(); nsresult GetCacheTrashDirectory(nsIFile ** result); - nsresult EvictDiskCacheEntries(); + nsresult EvictDiskCacheEntries(PRInt32 targetCapacity); /** * Member variables */ - PRBool mInitialized; + nsCOMPtr mDeviceLock; nsCOMPtr mCacheDirectory; nsDiskCacheBindery mBindery; PRUint32 mCacheCapacity; // XXX need soft/hard limits, currentTotal diff --git a/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp b/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp index 69c9b0ad147..c50887ba3e7 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp @@ -103,11 +103,10 @@ CreateDiskCacheEntry(nsDiskCacheBinding * binding) PRUint32 size = sizeof(nsDiskCacheEntry) + keySize + metaSize; // pad size so we can write to block files without overrunning buffer - PRInt32 pad = size; - if (pad < 1024) pad = 1024; - else if (pad < 4096) pad = 4096; - else if (pad < 16384) pad = 16384; - // XXX be more precise + PRInt32 pad; + if (size <= 1024) pad = (((size-1)/ 256) + 1) * 256; + else if (size <= 4096) pad = (((size-1)/1024) + 1) * 1024; + else if (size <= 16384) pad = (((size-1)/4096) + 1) * 4096; nsDiskCacheEntry * diskEntry = (nsDiskCacheEntry *)new char[pad]; if (!diskEntry) return nsnull; diff --git a/mozilla/netwerk/cache/src/nsDiskCacheMap.cpp b/mozilla/netwerk/cache/src/nsDiskCacheMap.cpp index 0435f87ab12..93898e38f1d 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheMap.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheMap.cpp @@ -250,6 +250,18 @@ exit: } +nsresult +nsDiskCacheMap::Trim() +{ + nsresult rv, rv2 = NS_OK; + for (int i=0; i < 3; ++i) { + rv = mBlockFile[i].Trim(); + if (NS_FAILED(rv)) rv2 = rv; // if one or more errors, report at least one + } + return rv2; +} + + nsresult nsDiskCacheMap::FlushHeader() { @@ -529,7 +541,7 @@ nsDiskCacheMap::OpenBlockFiles() rv = GetBlockFileForIndex(i, getter_AddRefs(blockFile)); if (NS_FAILED(rv)) goto error_exit; - PRUint32 blockSize = GetBlockSizeForIndex(i); + PRUint32 blockSize = GetBlockSizeForIndex(i+1); // +1 to match file selectors 1,2,3 rv = mBlockFile[i].Open(blockFile, blockSize); if (NS_FAILED(rv)) goto error_exit; } @@ -576,7 +588,7 @@ nsDiskCacheMap::ReadDiskCacheEntry(nsDiskCacheRecord * record, nsDiskCacheEntry PRInt32 fileSize = PR_Available(fd); if (fileSize < 0) { - // XXX an error occurred. We could call PR_GetError(), but how would that help? + // an error occurred. We could call PR_GetError(), but how would that help? rv = NS_ERROR_UNEXPECTED; goto exit; } @@ -597,7 +609,7 @@ nsDiskCacheMap::ReadDiskCacheEntry(nsDiskCacheRecord * record, nsDiskCacheEntry // entry/metadata stored in cache block file // allocate buffer - PRUint32 blockSize = GetBlockSizeForIndex(metaFile - 1); + PRUint32 blockSize = GetBlockSizeForIndex(metaFile); PRUint32 blockCount = record->MetaBlockCount(); diskEntry = (nsDiskCacheEntry *) new char[blockSize * blockCount]; @@ -628,30 +640,17 @@ nsDiskCacheMap::WriteDiskCacheEntry(nsDiskCacheBinding * binding) nsDiskCacheEntry * diskEntry = CreateDiskCacheEntry(binding); if (!diskEntry) return NS_ERROR_UNEXPECTED; - PRUint32 size = diskEntry->Size(); - PRUint32 fileIndex; - PRUint32 blocks = 0; - - if (size < 1024) { // block size 256 - fileIndex = 1; - blocks = size / 256 + 1; - } else if (size < 4096) { // block size 1024 - fileIndex = 2; - blocks = size / 1024 + 1; - } else if (size < 16384) { // block size 4096 - fileIndex = 3; - blocks = size / 4096 + 1; - } else { // separate file - fileIndex = 0; - } - - PRUint32 metaFile = binding->mRecord.MetaFile(); + PRUint32 size = diskEntry->Size(); + PRUint32 fileIndex = CalculateFileIndex(size); + PRUint32 blockSize = BLOCK_SIZE_FOR_INDEX(fileIndex); + PRUint32 blocks = blockSize ? size / blockSize + 1 : 0; // Deallocate old storage if necessary if (binding->mRecord.MetaLocationInitialized()) { // we have existing storage - if ((metaFile == 0) && (fileIndex == 0)) { // keeping the separate file + if ((binding->mRecord.MetaFile() == 0) && + (fileIndex == 0)) { // keeping the separate file // just decrement total // XXX if bindRecord.MetaFileSize == USHRT_MAX, stat the file to see how big it is DecrementTotalSize(binding->mRecord.MetaFileSize() * 1024); @@ -667,7 +666,7 @@ nsDiskCacheMap::WriteDiskCacheEntry(nsDiskCacheBinding * binding) if (fileIndex == 0) { // Write entry data to separate file - PRUint32 metaFileSizeK = ((size + 0x0399) >> 10); // round up to nearest 1k + PRUint32 metaFileSizeK = ((size + 0x03FF) >> 10); // round up to nearest 1k nsCOMPtr localFile; // XXX handle metaFileSizeK > USHRT_MAX @@ -717,7 +716,7 @@ nsDiskCacheMap::WriteDiskCacheEntry(nsDiskCacheBinding * binding) rv = mBlockFile[fileIndex - 1].WriteBlocks(diskEntry, startBlock, blocks); if (NS_FAILED(rv)) goto exit; - IncrementTotalSize(blocks * GetBlockSizeForIndex(fileIndex - 1)); + IncrementTotalSize(blocks * GetBlockSizeForIndex(fileIndex)); } exit: @@ -726,6 +725,56 @@ exit: } +nsresult +nsDiskCacheMap::ReadDataCacheBlocks(nsDiskCacheBinding * binding, char * buffer, PRUint32 size) +{ + nsresult rv; + PRUint32 fileIndex = binding->mRecord.DataFile(); + PRUint32 blockSize = GetBlockSizeForIndex(fileIndex); + PRUint32 blockCount = binding->mRecord.DataBlockCount(); + PRUint32 minSize = blockSize * blockCount; + + if (size < minSize) { + NS_WARNING("buffer too small"); + return NS_ERROR_UNEXPECTED; + } + + rv = mBlockFile[fileIndex - 1].ReadBlocks(buffer, + binding->mRecord.DataStartBlock(), + blockCount); + return rv; +} + + +nsresult +nsDiskCacheMap::WriteDataCacheBlocks(nsDiskCacheBinding * binding, char * buffer, PRUint32 size) +{ + nsresult rv; + + // determine block file & number of blocks + PRUint32 fileIndex = CalculateFileIndex(size); + PRUint32 blockSize = BLOCK_SIZE_FOR_INDEX(fileIndex); + PRUint32 blockCount = blockSize ? size / blockSize + 1 : 0; + PRInt32 startBlock = 0; + + if (size > 0) { + startBlock = mBlockFile[fileIndex - 1].AllocateBlocks(blockCount); + + rv = mBlockFile[fileIndex - 1].WriteBlocks(buffer, startBlock, blockCount); + if (NS_FAILED(rv)) return rv; + + IncrementTotalSize(blockCount * blockSize); + } + + + // update binding and cache map record + binding->mRecord.SetDataBlocks(fileIndex, startBlock, blockCount); + rv = UpdateRecord(&binding->mRecord); + + return rv; +} + + nsresult nsDiskCacheMap::DoomRecord(nsDiskCacheRecord * record) { @@ -769,8 +818,10 @@ nsDiskCacheMap::DeleteStorage(nsDiskCacheRecord * record, PRBool metaData) PRInt32 blockCount = metaData ? record->MetaBlockCount() : record->DataBlockCount(); rv = mBlockFile[fileIndex - 1].DeallocateBlocks(startBlock, blockCount); - DecrementTotalSize(blockCount * GetBlockSizeForIndex(fileIndex - 1)); + DecrementTotalSize(blockCount * GetBlockSizeForIndex(fileIndex)); } + if (metaData) record->ClearMetaLocation(); + else record->ClearDataLocation(); return rv; } @@ -787,8 +838,8 @@ nsDiskCacheMap::DeleteRecordAndStorage(nsDiskCacheRecord * record) nsresult nsDiskCacheMap::GetFileForDiskCacheRecord(nsDiskCacheRecord * record, - PRBool meta, - nsIFile ** result) + PRBool meta, + nsIFile ** result) { if (!mCacheDirectory) return NS_ERROR_NOT_AVAILABLE; @@ -806,10 +857,11 @@ nsDiskCacheMap::GetFileForDiskCacheRecord(nsDiskCacheRecord * record, return rv; } + nsresult nsDiskCacheMap::GetLocalFileForDiskCacheRecord(nsDiskCacheRecord * record, - PRBool meta, - nsILocalFile ** result) + PRBool meta, + nsILocalFile ** result) { nsCOMPtr file; nsresult rv = GetFileForDiskCacheRecord(record, meta, getter_AddRefs(file)); @@ -844,9 +896,19 @@ nsDiskCacheMap::GetBlockFileForIndex(PRUint32 index, nsILocalFile ** result) } +PRUint32 +nsDiskCacheMap::CalculateFileIndex(PRUint32 size) +{ + if (size <= 1024) return 1; + else if (size <= 4096) return 2; + else if (size <= 16384) return 3; + else return 0; +} + + PRUint32 nsDiskCacheMap::GetBlockSizeForIndex(PRUint32 index) { - return 256 << (2 * (index)); // XXX magic numbers + return BLOCK_SIZE_FOR_INDEX(index); } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheMap.h b/mozilla/netwerk/cache/src/nsDiskCacheMap.h index 519fab18589..dcb7589d14d 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheMap.h +++ b/mozilla/netwerk/cache/src/nsDiskCacheMap.h @@ -67,6 +67,9 @@ struct nsDiskCacheEntry; * *****************************************************************************/ +#define BLOCK_SIZE_FOR_INDEX(index) ((index) ? (256 << (2 * ((index) - 1))) : 0) +#define kSeparateFile 0 + class nsDiskCacheRecord { private: @@ -118,9 +121,7 @@ public: // DataLocation accessors PRBool DataLocationInitialized() { return mDataLocation & eLocationInitializedMask; } - - PRUint32 DataLocation() { return mDataLocation; } - void SetDataLocation( PRUint32 location) { mDataLocation = location; } + void ClearDataLocation() { mDataLocation = 0; } PRUint32 DataFile() const { @@ -159,6 +160,11 @@ public: return (mDataLocation & eBlockNumberMask); } + PRUint32 DataBlockSize() const + { + return BLOCK_SIZE_FOR_INDEX(DataFile()); + } + PRUint32 DataFileSize() const { return (mDataLocation & eFileSizeMask) >> eFileSizeOffset; } void SetDataFileSize(PRUint32 size) { @@ -182,9 +188,9 @@ public: // MetaLocation accessors PRBool MetaLocationInitialized() { return mMetaLocation & eLocationInitializedMask; } + void ClearMetaLocation() { mMetaLocation = 0; } PRUint32 MetaLocation() { return mMetaLocation; } - void SetMetaLocation( PRUint32 location) { mMetaLocation = location; } PRUint32 MetaFile() const { @@ -223,6 +229,11 @@ public: return (mMetaLocation & eBlockNumberMask); } + PRUint32 MetaBlockSize() const + { + return BLOCK_SIZE_FOR_INDEX(MetaFile()); + } + PRUint32 MetaFileSize() const { return (mMetaLocation & eFileSizeMask) >> eFileSizeOffset; } void SetMetaFileSize(PRUint32 size) { @@ -401,6 +412,7 @@ public: */ nsresult Open( nsILocalFile * cacheDirectory); nsresult Close(); + nsresult Trim(); // nsresult Flush(); nsresult FlushHeader(); @@ -436,6 +448,10 @@ public: nsresult WriteDiskCacheEntry( nsDiskCacheBinding * binding); + nsresult ReadDataCacheBlocks(nsDiskCacheBinding * binding, char * buffer, PRUint32 size); + nsresult WriteDataCacheBlocks(nsDiskCacheBinding * binding, char * buffer, PRUint32 size); + nsresult DeleteStorage( nsDiskCacheRecord * record, PRBool metaData); + /** * Statistical Operations */ @@ -466,11 +482,11 @@ private: nsresult OpenBlockFiles(); nsresult CloseBlockFiles(); + PRUint32 CalculateFileIndex(PRUint32 size); + nsresult GetBlockFileForIndex( PRUint32 index, nsILocalFile ** result); PRUint32 GetBlockSizeForIndex( PRUint32 index); - nsresult DeleteStorage( nsDiskCacheRecord * record, PRBool metaData); - nsresult GetBucketForHashNumber( PRUint32 hashNumber, nsDiskCacheBucket ** result) { *result = &mBuckets[GetBucketIndex(hashNumber)]; diff --git a/mozilla/netwerk/cache/src/nsDiskCacheStreams.cpp b/mozilla/netwerk/cache/src/nsDiskCacheStreams.cpp index c867ed43143..f13dffdff79 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheStreams.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheStreams.cpp @@ -22,6 +22,7 @@ */ +#include "nsDiskCache.h" #include "nsDiskCacheDevice.h" #include "nsDiskCacheStreams.h" @@ -30,27 +31,6 @@ #include "nsISeekableStream.h" #include "nsAutoLock.h" -// headers for ftruncate (or equivalent) -#if defined(XP_UNIX) -#include -#elif defined(XP_MAC) -#include -#elif defined(XP_WIN) -#include -#elif defined(XP_OS2) -#define INCL_DOSERRORS -#include -#else -// other platforms: add necessary include file for ftruncate (or equivalent) -#endif - -#if defined(XP_MAC) -#include "pprio.h" -#else -#include "private/pprio.h" -#endif - - // Assumptions: @@ -60,17 +40,13 @@ // - overlapped I/O is NOT supported -// XXX perhaps closing descriptors should clear/sever transports -// XXX why doesn't nsCacheDescriptor::RemoveDescriptor() clear descriptor->mCacheEntry? - - /****************************************************************************** * nsDiskCacheInputStream *****************************************************************************/ #ifdef XP_MAC #pragma mark nsDiskCacheInputStream #endif -class nsDiskCacheInputStream : public PRCList, public nsIInputStream { +class nsDiskCacheInputStream : public nsIInputStream { public: @@ -87,11 +63,12 @@ public: private: friend class nsDiskCacheStreamIO; - nsDiskCacheStreamIO * mStreamIO; // backpointer to parent - PRFileDesc * mFD; - const char * mBuffer; - PRUint32 mStreamEnd; - PRUint32 mPos; // stream position + nsCOMPtr mStreamIO; // backpointer to parent + PRFileDesc * mFD; + const char * mBuffer; + PRUint32 mStreamEnd; + PRUint32 mPos; // stream position + PRBool mClosed; }; @@ -107,27 +84,29 @@ nsDiskCacheInputStream::nsDiskCacheInputStream( nsDiskCacheStreamIO * parent, , mBuffer(buffer) , mStreamEnd(endOfStream) , mPos(0) + , mClosed(PR_FALSE) { NS_INIT_ISUPPORTS(); - PR_INIT_CLIST(this); + mStreamIO->IncrementInputStreamCount(); } nsDiskCacheInputStream::~nsDiskCacheInputStream() { - - Close(); // tell our parent we're going away - NS_ASSERTION(PR_CLIST_IS_EMPTY(this), "nsDiskCacheInputStream destructed while still on list"); + Close(); + mStreamIO->DecrementInputStreamCount(); } NS_IMETHODIMP nsDiskCacheInputStream::Close() { - if (mStreamIO) { - mStreamIO->CloseInputStream(this); - NS_ASSERTION(!mStreamIO, "mStreamIO hasn't been nulled out"); + if (mClosed) return NS_ERROR_NOT_AVAILABLE; + if (mFD) { + (void) PR_Close(mFD); + mFD = nsnull; } + mClosed = PR_TRUE; return NS_OK; } @@ -135,7 +114,7 @@ nsDiskCacheInputStream::Close() NS_IMETHODIMP nsDiskCacheInputStream::Available(PRUint32 * bytesAvailable) { - if (!mStreamIO) return NS_ERROR_NOT_AVAILABLE; + if (mClosed) return NS_ERROR_NOT_AVAILABLE; if (mStreamEnd < mPos) return NS_ERROR_UNEXPECTED; *bytesAvailable = mStreamEnd - mPos; @@ -146,7 +125,7 @@ nsDiskCacheInputStream::Available(PRUint32 * bytesAvailable) NS_IMETHODIMP nsDiskCacheInputStream::Read(char * buffer, PRUint32 count, PRUint32 * bytesRead) { - if (!mStreamIO) return NS_ERROR_NOT_AVAILABLE; + if (mClosed) return NS_ERROR_NOT_AVAILABLE; *bytesRead = 0; if (mPos == mStreamEnd) return NS_OK; @@ -215,7 +194,8 @@ public: private: friend class nsDiskCacheStreamIO; - nsDiskCacheStreamIO * mStreamIO; // backpointer to parent + nsCOMPtr mStreamIO; // backpointer to parent + PRBool mClosed; }; @@ -224,6 +204,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsDiskCacheOutputStream, nsIOutputStream, nsISeeka nsDiskCacheOutputStream::nsDiskCacheOutputStream( nsDiskCacheStreamIO * parent) : mStreamIO(parent) + , mClosed(PR_FALSE) { NS_INIT_ISUPPORTS(); } @@ -238,10 +219,10 @@ nsDiskCacheOutputStream::~nsDiskCacheOutputStream() NS_IMETHODIMP nsDiskCacheOutputStream::Close() { + if (mClosed) return NS_ERROR_NOT_AVAILABLE; // tell parent streamIO we are closing - if (!mStreamIO) return NS_OK; mStreamIO->CloseOutputStream(this); - NS_ASSERTION(!mStreamIO, "mStreamIO hasn't been nulled out"); + mClosed = PR_TRUE; return NS_OK; } @@ -249,6 +230,7 @@ nsDiskCacheOutputStream::Close() NS_IMETHODIMP nsDiskCacheOutputStream::Flush() { + if (mClosed) return NS_ERROR_NOT_AVAILABLE; // yeah, yeah, well get to it...eventually... return NS_OK; } @@ -257,7 +239,7 @@ nsDiskCacheOutputStream::Flush() NS_IMETHODIMP nsDiskCacheOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *bytesWritten) { - if (!mStreamIO) return NS_ERROR_NOT_AVAILABLE; + if (mClosed) return NS_ERROR_NOT_AVAILABLE; return mStreamIO->Write(buf, count, bytesWritten); } @@ -284,7 +266,7 @@ nsDiskCacheOutputStream::WriteSegments( nsReadSegmentFun reader, NS_IMETHODIMP nsDiskCacheOutputStream::Seek(PRInt32 whence, PRInt32 offset) { - if (!mStreamIO) return NS_ERROR_NOT_AVAILABLE; + if (mClosed) return NS_ERROR_NOT_AVAILABLE; return mStreamIO->Seek(whence, offset); } @@ -292,7 +274,7 @@ nsDiskCacheOutputStream::Seek(PRInt32 whence, PRInt32 offset) NS_IMETHODIMP nsDiskCacheOutputStream::Tell(PRUint32 * result) { - if (!mStreamIO) return NS_ERROR_NOT_AVAILABLE; + if (mClosed) return NS_ERROR_NOT_AVAILABLE; return mStreamIO->Tell(result); } @@ -300,7 +282,7 @@ nsDiskCacheOutputStream::Tell(PRUint32 * result) NS_IMETHODIMP nsDiskCacheOutputStream::SetEOF() { - if (!mStreamIO) return NS_ERROR_NOT_AVAILABLE; + if (mClosed) return NS_ERROR_NOT_AVAILABLE; return mStreamIO->SetEOF(); } @@ -332,6 +314,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsDiskCacheStreamIO, nsIStreamIO); nsDiskCacheStreamIO::nsDiskCacheStreamIO(nsDiskCacheBinding * binding) : mBinding(binding) , mOutStream(nsnull) + , mInStreamCount(0) , mFD(nsnull) , mStreamPos(0) , mStreamEnd(0) @@ -344,7 +327,7 @@ nsDiskCacheStreamIO::nsDiskCacheStreamIO(nsDiskCacheBinding * binding) { NS_INIT_ISUPPORTS(); mDevice = (nsDiskCacheDevice *)mBinding->mCacheEntry->CacheDevice(); - PR_INIT_CLIST(&mInStreamQ); + mDeviceLock = mDevice->DeviceLock(); } @@ -361,32 +344,15 @@ nsDiskCacheStreamIO::Open() } -NS_IMETHODIMP nsDiskCacheStreamIO::Close(nsresult status) +NS_IMETHODIMP +nsDiskCacheStreamIO::Close(nsresult status) { - nsAutoLock lock(mDevice->DeviceLock()); // grab device lock - + // this should only be called from our destructor + // no one is interested in us anymore, so we don't need to grab any locks + // assert streams closed - if (mOutStream) { - NS_WARNING("output stream still open"); - (void) mOutStream->Close(); - } - - NS_ASSERTION(PR_CLIST_IS_EMPTY(&mInStreamQ), "input stream still open"); - - // close remaining input streams (if any) - nsDiskCacheInputStream * stream = - (nsDiskCacheInputStream *)PR_LIST_HEAD(&mInStreamQ); - while (stream != &mInStreamQ) { - nsDiskCacheInputStream * nextStream = - (nsDiskCacheInputStream *)PR_NEXT_LINK(stream); - - // can't call (void) stream->Close(), because it will try to reaquire device lock - PR_REMOVE_AND_INIT_LINK(stream); - stream->mStreamIO = nsnull; - - stream = nextStream; - } - + NS_ASSERTION(!mOutStream, "output stream still open"); + NS_ASSERTION(mInStreamCount == 0, "input stream still open"); NS_ASSERTION(!mFD, "file descriptor not closed"); delete [] mBuffer; @@ -400,10 +366,13 @@ nsDiskCacheStreamIO::GetInputStream(nsIInputStream ** inputStream) NS_ENSURE_ARG_POINTER(inputStream); *inputStream = nsnull; - nsAutoLock lock(mDevice->DeviceLock()); // grab device lock + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock + if (!mBinding) return NS_ERROR_NOT_AVAILABLE; - NS_ASSERTION(!mOutStream, "already have an output stream open"); - if (mOutStream) return NS_ERROR_NOT_AVAILABLE; + if (mOutStream) { + NS_WARNING("already have an output stream open"); + return NS_ERROR_NOT_AVAILABLE; + } nsresult rv; PRFileDesc * fd = nsnull; @@ -430,7 +399,6 @@ nsDiskCacheStreamIO::GetInputStream(nsIInputStream ** inputStream) nsDiskCacheInputStream * inStream = new nsDiskCacheInputStream(this, fd, mBuffer, mStreamEnd); if (!inStream) return NS_ERROR_OUT_OF_MEMORY; - PR_APPEND_LINK(inStream, &mInStreamQ); NS_ADDREF(*inputStream = inStream); return NS_OK; } @@ -442,12 +410,12 @@ nsDiskCacheStreamIO::GetOutputStream(nsIOutputStream ** outputStream) NS_ENSURE_ARG_POINTER(outputStream); *outputStream = nsnull; - nsAutoLock lock(mDevice->DeviceLock()); // grab device lock + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock + if (!mBinding) return NS_ERROR_NOT_AVAILABLE; NS_ASSERTION(!mOutStream, "already have an output stream open"); - NS_ASSERTION(PR_CLIST_IS_EMPTY(&mInStreamQ), "we already have input streams open"); - if ((mOutStream) || (!PR_CLIST_IS_EMPTY(&mInStreamQ))) - return NS_ERROR_NOT_AVAILABLE; + NS_ASSERTION(mInStreamCount == 0, "we already have input streams open"); + if (mOutStream || mInStreamCount) return NS_ERROR_NOT_AVAILABLE; // mBuffer lazily allocated, but might exist if a previous stream already created one mBufPos = 0; @@ -496,27 +464,23 @@ nsDiskCacheStreamIO::GetContentLength(PRInt32 *contentLength) } -void -nsDiskCacheStreamIO::CloseInputStream(nsDiskCacheInputStream * inputStream) -{ - nsAutoLock lock(mDevice->DeviceLock()); // grab device lock - PR_REMOVE_AND_INIT_LINK(inputStream); - inputStream->mStreamIO = nsnull; -} - - -void +nsresult nsDiskCacheStreamIO::CloseOutputStream(nsDiskCacheOutputStream * outputStream) { - nsAutoLock lock(mDevice->DeviceLock()); // grab device lock + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock nsresult rv; if (outputStream != mOutStream) { NS_WARNING("mismatched output streams"); - return; + return NS_ERROR_UNEXPECTED; } // output stream is closing + if (!mBinding) { // if we're severed, just clear member variables + mOutStream = nsnull; + outputStream->mStreamIO = nsnull; + return NS_ERROR_NOT_AVAILABLE; + } // write data to cache blocks, or flush mBuffer to file nsDiskCacheMap * cacheMap = mDevice->CacheMap(); // get map reference @@ -530,6 +494,7 @@ nsDiskCacheStreamIO::CloseOutputStream(nsDiskCacheOutputStream * outputStream) // close file descriptor NS_ASSERTION(mFD, "no file descriptor"); (void) PR_Close(mFD); + mFD = nsnull; } else { // store data (if any) in cache block files @@ -538,27 +503,20 @@ nsDiskCacheStreamIO::CloseOutputStream(nsDiskCacheOutputStream * outputStream) nsDiskCacheRecord * record = &mBinding->mRecord; if (record->DataLocationInitialized()) { - rv = cacheMap->DeleteStorage(record, nsDiskCache::kData); if (NS_FAILED(rv)) { - // XXX but perhaps DecrementTotalSize() should not be called ? - // XXX mark DataLocation Uninitialized NS_WARNING("cacheMap->DeleteStorage() failed."); - // XXX doom cache entry - return; + return rv; // XXX doom cache entry } } - // XXX calculate which disk block file to put it in and put it there - // XXX update data location for mBinding - // flush buffer to block files if (mStreamEnd > 0) { nsresult rv = cacheMap->WriteDataCacheBlocks(mBinding, mBuffer, mBufEnd); if (NS_FAILED(rv)) { - NS_WARNING("WriteDatacacheBlocks() failed."); - // XXX doom cache entry - // XXX return ? + NS_WARNING("WriteDataCacheBlocks() failed."); + return rv; // XXX doom cache entry? + } } } @@ -566,19 +524,23 @@ nsDiskCacheStreamIO::CloseOutputStream(nsDiskCacheOutputStream * outputStream) // dealloc mBuffer if it doesn't contain beginning of stream if (mBufOffset != 0) { free(mBuffer); + mBuffer = nsnull; + mBufOffset = 0; + mBufEnd = 0; } + // XXX do we need this here? WriteDataCacheBlocks() calls UpdateRecord() // update cache map if entry isn't doomed if (!mBinding->mDoomed) { rv = cacheMap->UpdateRecord(&mBinding->mRecord); if (NS_FAILED(rv)) { NS_WARNING("cacheMap->UpdateRecord() failed."); - // XXX doom cache entry + return rv; // XXX doom cache entry } } mOutStream = nsnull; - outputStream->mStreamIO = nsnull; + return NS_OK; } @@ -593,9 +555,10 @@ nsDiskCacheStreamIO::Write( const char * buffer, PRUint32 * bytesWritten) { nsresult rv = NS_OK; - nsAutoLock lock(mDevice->DeviceLock()); // grab device lock + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock + if (!mBinding) return NS_ERROR_NOT_AVAILABLE; - if (!PR_CLIST_IS_EMPTY(&mInStreamQ)) { + if (mInStreamCount) { // we have open input streams already // this is an error until we support overlapped I/O NS_WARNING("Attempting to write to cache entry with open input streams.\n"); @@ -607,27 +570,48 @@ nsDiskCacheStreamIO::Write( const char * buffer, // update mStreamPos, mStreamEnd mStreamPos += count; - if (mStreamEnd < mStreamPos) + if (mStreamEnd < mStreamPos) { mStreamEnd = mStreamPos; + NS_ASSERTION(mBinding->mCacheEntry->DataSize() == mStreamEnd, "bad stream"); - return NS_OK; + // if we have a separate file, we need to adjust the disk cache size totals here + if (mFD) { + rv = UpdateFileSize(); + } + } + + return rv; } -// XXX collapse function if only used once -PRBool -nsDiskCacheStreamIO::EnsureLocalFile() +nsresult +nsDiskCacheStreamIO::UpdateFileSize() { - if (mLocalFile) return PR_TRUE; + NS_ASSERTION(mFD, "nsDiskCacheStreamIO::UpdateFileSize should not have been called"); + if (!mFD) return NS_ERROR_UNEXPECTED; - nsresult rv; - nsDiskCacheMap * cacheMap = mDevice->CacheMap(); + nsDiskCacheRecord * record = &mBinding->mRecord; + PRUint32 oldSizeK = record->DataFileSize(); + PRUint32 newSizeK = (mStreamEnd + 0x03FF) >> 10; - rv = cacheMap->GetLocalFileForDiskCacheRecord(&mBinding->mRecord, - nsDiskCache::kData, - getter_AddRefs(mLocalFile)); + if (newSizeK == oldSizeK) return NS_OK; + + record->SetDataFileSize(newSizeK); - return NS_SUCCEEDED(rv) ? PR_TRUE : PR_FALSE; + // update cache size totals + nsDiskCacheMap * cacheMap = mDevice->CacheMap(); + cacheMap->DecrementTotalSize(oldSizeK * 1024); // decrement old size + cacheMap->IncrementTotalSize(newSizeK * 1024); // increment new size + + if (!mBinding->mDoomed) { + nsresult rv = cacheMap->UpdateRecord(&mBinding->mRecord); + if (NS_FAILED(rv)) { + NS_WARNING("cacheMap->UpdateRecord() failed."); + // XXX doom cache entry? + return rv; + } + } + return NS_OK; } @@ -636,10 +620,16 @@ nsDiskCacheStreamIO::OpenCacheFile(PRIntn flags, PRFileDesc ** fd) { NS_ENSURE_ARG_POINTER(fd); - if (!EnsureLocalFile()) return NS_ERROR_UNEXPECTED; + nsresult rv; + nsDiskCacheMap * cacheMap = mDevice->CacheMap(); + + rv = cacheMap->GetLocalFileForDiskCacheRecord(&mBinding->mRecord, + nsDiskCache::kData, + getter_AddRefs(mLocalFile)); + if (NS_FAILED(rv)) return rv; // create PRFileDesc for input stream - nsresult rv = mLocalFile->OpenNSPRFileDesc(flags, 00666, fd); + rv = mLocalFile->OpenNSPRFileDesc(flags, 00666, fd); if (NS_FAILED(rv)) return rv; // unable to open file return NS_OK; @@ -711,7 +701,6 @@ nsDiskCacheStreamIO::FlushBufferToFile(PRBool clearBuffer) nsDiskCacheMap * cacheMap = mDevice->CacheMap(); rv = cacheMap->DeleteStorage(record, nsDiskCache::kData); if (NS_FAILED(rv)) return rv; - // XXX update size totals? } record->SetDataFileGeneration(mBinding->mGeneration); @@ -727,11 +716,6 @@ nsDiskCacheStreamIO::FlushBufferToFile(PRBool clearBuffer) return NS_ERROR_UNEXPECTED; // NS_ErrorAccordingToNSPR() } mBufDirty = PR_FALSE; - - // XXX entry->DataSize() may be larger than amount of data flushed at this point - nsCacheEntry * entry = mBinding->mCacheEntry; - PRUint32 sizeK = ((entry->DataSize() + 0x03FF) >> 10); // round up to next 1k - record->SetDataFileSize(sizeK); // 1k minimum if (clearBuffer) { // reset buffer @@ -789,6 +773,8 @@ nsresult nsDiskCacheStreamIO::Seek(PRInt32 whence, PRInt32 offset) { PRInt32 newPos; + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock + if (!mBinding) return NS_ERROR_NOT_AVAILABLE; if (offset > mStreamEnd) return NS_ERROR_FAILURE; @@ -816,10 +802,12 @@ nsDiskCacheStreamIO::Seek(PRInt32 whence, PRInt32 offset) // seek in mBuffer - // read data into mBuffer if not read yet. mStreamEnd != mBufEnd XXX - if (mStreamEnd != mBufEnd) { + // read data into mBuffer if not read yet. + if (mStreamEnd && !mBufEnd) { nsresult rv = ReadCacheBlocks(); if (NS_FAILED(rv)) return rv; + } else { + // XXX warn if mStreamEnd and mBufEnd aren't coherent } // stream buffer sanity checks @@ -889,6 +877,8 @@ nsDiskCacheStreamIO::SetEOF() { nsresult rv; NS_ASSERTION(mStreamPos <= mStreamEnd, "bad stream"); + nsAutoLock lock(mDeviceLock->GetPRLock()); // grab device lock + if (!mBinding) return NS_ERROR_NOT_AVAILABLE; if (mBinding->mRecord.DataLocationInitialized()) { @@ -908,32 +898,13 @@ nsDiskCacheStreamIO::SetEOF() } } + PRUint32 oldSizeK = (mStreamEnd + 0x03FF) >> 10; + PRUint32 newSizeK = (mStreamPos + 0x03FF) >> 10; + if (mFD) { - // use modified SetEOF from nsFileStreams::SetEOF() -#if defined(XP_UNIX) - if (ftruncate(PR_FileDesc2NativeHandle(mFD), mStreamPos) != 0) { - NS_ERROR("ftruncate failed"); - return NS_ERROR_FAILURE; - } -#elif defined(XP_MAC) - if (::SetEOF(PR_FileDesc2NativeHandle(mFD), mStreamPos) != 0) { - NS_ERROR("SetEOF failed"); - return NS_ERROR_FAILURE; - } -#elif defined(XP_WIN) - if (!SetEndOfFile((HANDLE) PR_FileDesc2NativeHandle(mFD))) { - NS_ERROR("SetEndOfFile failed"); - return NS_ERROR_FAILURE; - } -#elif defined(XP_OS2) - if (DosSetFileSize((HFILE) PR_FileDesc2NativeHandle(mFD), mStreamPos) != NO_ERROR) { - NS_ERROR("DosSetFileSize failed"); - return NS_ERROR_FAILURE; - } -#else - // add implementations for other platforms here -#endif - + rv = nsDiskCache::Truncate(mFD, mStreamPos); + NS_ASSERTION(mBinding->mRecord.DataFileSize() == oldSizeK, "bad disk cache entry size"); + } else { // data stored in buffer. NS_ASSERTION(mStreamEnd < (16 * 1024), "buffer truncation inadequate"); @@ -943,11 +914,15 @@ nsDiskCacheStreamIO::SetEOF() } NS_ASSERTION(mStreamEnd == mBinding->mCacheEntry->DataSize(), "cache entry not updated"); - // XXX we expect nsCacheEntryDescriptor::TransportWrapper::OpenOutputStream() to eventually - // XXX update the cache entry + // we expect nsCacheEntryDescriptor::TransportWrapper::OpenOutputStream() + // to eventually update the cache entry mStreamEnd = mStreamPos; - mBufEnd = mBufPos; + mBufEnd = mBufPos; + + if (mFD) { + UpdateFileSize(); + } return NS_OK; } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheStreams.h b/mozilla/netwerk/cache/src/nsDiskCacheStreams.h index 1f639532a42..1a7f196fb5a 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheStreams.h +++ b/mozilla/netwerk/cache/src/nsDiskCacheStreams.h @@ -27,18 +27,22 @@ #include "nsDiskCacheBinding.h" +#include "nsCache.h" + #include "nsIStreamIO.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" +#include "pratom.h" + class nsDiskCacheInputStream; class nsDiskCacheOutputStream; class nsDiskCacheDevice; class nsDiskCacheStreamIO : public nsIStreamIO { +// we're implementing nsIStreamIO to leverage the AsyncRead on the FileTransport thread -// XXX we're implementing nsIStreamIO to leverage the AsyncRead on the FileTransport thread public: nsDiskCacheStreamIO(nsDiskCacheBinding * binding); @@ -46,11 +50,10 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSISTREAMIO - - // Create(nsDiskCacheBinding ); - +// NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISUPPORTS_IID) + void CloseInputStream(nsDiskCacheInputStream * inputStream); - void CloseOutputStream(nsDiskCacheOutputStream * outputStream); + nsresult CloseOutputStream(nsDiskCacheOutputStream * outputStream); nsresult Write( const char * buffer, PRUint32 count, @@ -60,18 +63,29 @@ public: nsresult Tell(PRUint32 * position); nsresult SetEOF(); - PRBool EnsureLocalFile(); + void ClearBinding() { mBinding = nsnull; } + + void IncrementInputStreamCount() { PR_AtomicIncrement(&mInStreamCount); } + void DecrementInputStreamCount() + { + PR_AtomicDecrement(&mInStreamCount); + NS_ASSERTION(mInStreamCount >= 0, "mInStreamCount has gone negative"); + } + +private: + nsresult OpenCacheFile(PRIntn flags, PRFileDesc ** fd); nsresult ReadCacheBlocks(); nsresult FlushBufferToFile(PRBool clearBuffer); PRUint32 WriteToBuffer(const char * buffer, PRUint32 count); + nsresult UpdateFileSize(); -private: nsDiskCacheBinding * mBinding; nsDiskCacheDevice * mDevice; + nsCOMPtr mDeviceLock; nsDiskCacheOutputStream * mOutStream; - PRCList mInStreamQ; + PRInt32 mInStreamCount; nsCOMPtr mLocalFile; PRFileDesc * mFD; diff --git a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp index 9907c7bfc61..e04d17c381a 100644 --- a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp +++ b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp @@ -71,7 +71,6 @@ nsMemoryCacheDevice::Init() // set some default memory limits, in case prefs aren't available mSoftLimit = mHardLimit * 0.9; - // XXX Register as a memory pressure observer mInitialized = NS_SUCCEEDED(rv); return rv; } @@ -96,7 +95,7 @@ nsMemoryCacheDevice::Shutdown() PR_REMOVE_AND_INIT_LINK(entry); // update statistics - PRUint32 memoryRecovered = entry->Size(); + PRInt32 memoryRecovered = (PRInt32)entry->Size(); mTotalSize -= memoryRecovered; mInactiveSize -= memoryRecovered; --mEntryCount; @@ -253,8 +252,8 @@ nsMemoryCacheDevice::OnDataSizeChange( nsCacheEntry * entry, PRInt32 deltaSize) // we have the right to refuse or pre-evict PRUint32 newSize = entry->DataSize() + deltaSize; if (newSize > mSoftLimit) { - nsresult rv = nsCacheService::GlobalInstance()->DoomEntry_Locked(entry); - NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry_Locked() failed."); + nsresult rv = nsCacheService::DoomEntry(entry); + NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry() failed."); return NS_ERROR_ABORT; } } @@ -275,7 +274,7 @@ nsMemoryCacheDevice::OnDataSizeChange( nsCacheEntry * entry, PRInt32 deltaSize) void -nsMemoryCacheDevice::AdjustMemoryLimits(PRUint32 softLimit, PRUint32 hardLimit) +nsMemoryCacheDevice::AdjustMemoryLimits(PRInt32 softLimit, PRInt32 hardLimit) { mSoftLimit = softLimit; mHardLimit = hardLimit; @@ -293,7 +292,7 @@ nsMemoryCacheDevice::EvictEntry(nsCacheEntry * entry) PR_REMOVE_AND_INIT_LINK(entry); // update statistics - PRUint32 memoryRecovered = entry->Size(); + PRInt32 memoryRecovered = (PRInt32)entry->Size(); mTotalSize -= memoryRecovered; mInactiveSize -= memoryRecovered; --mEntryCount; @@ -330,9 +329,9 @@ nsMemoryCacheDevice::EvictEntriesIfNecessary(void) int -nsMemoryCacheDevice::EvictionList(nsCacheEntry * entry, PRUint32 deltaSize) +nsMemoryCacheDevice::EvictionList(nsCacheEntry * entry, PRInt32 deltaSize) { - PRUint32 size = entry->Size() + deltaSize; + PRInt32 size = deltaSize + (PRInt32)entry->Size(); if ((size > mEvictionThreshold) || (entry->ExpirationTime() != NO_EXPIRATION_TIME)) return mostLikelyToEvict; @@ -393,7 +392,7 @@ nsMemoryCacheDevice::EvictEntries(const char * clientID) continue; if (entry->IsInUse()) { - nsresult rv = nsCacheService::GlobalInstance()->DoomEntry_Locked(entry); + nsresult rv = nsCacheService::DoomEntry(entry); if (NS_FAILED(rv)) return rv; } else { EvictEntry(entry); @@ -405,10 +404,10 @@ nsMemoryCacheDevice::EvictEntries(const char * clientID) void -nsMemoryCacheDevice::SetCapacity(PRUint32 capacity) +nsMemoryCacheDevice::SetCapacity(PRInt32 capacity) { - PRUint32 hardLimit = capacity * 1024; // convert k into bytes - PRUint32 softLimit = hardLimit * 0.9; + PRInt32 hardLimit = capacity * 1024; // convert k into bytes + PRInt32 softLimit = hardLimit * 0.9; AdjustMemoryLimits(softLimit, hardLimit); } @@ -446,7 +445,7 @@ nsMemoryCacheDeviceInfo::GetEntryCount(PRUint32 * result) { NS_ENSURE_ARG_POINTER(result); // XXX compare calculated count vs. mEntryCount - *result = mDevice->mEntryCount; + *result = (PRUint32)mDevice->mEntryCount; return NS_OK; } @@ -455,7 +454,7 @@ NS_IMETHODIMP nsMemoryCacheDeviceInfo::GetTotalSize(PRUint32 * result) { NS_ENSURE_ARG_POINTER(result); - *result = mDevice->mTotalSize; + *result = (PRUint32)mDevice->mTotalSize; return NS_OK; } @@ -464,6 +463,6 @@ NS_IMETHODIMP nsMemoryCacheDeviceInfo::GetMaximumSize(PRUint32 * result) { NS_ENSURE_ARG_POINTER(result); - *result = mDevice->mHardLimit; + *result = (PRUint32)mDevice->mHardLimit; return NS_OK; } diff --git a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h index d6f37056882..94a12a427e1 100644 --- a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h +++ b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h @@ -63,14 +63,14 @@ public: virtual nsresult EvictEntries(const char * clientID); - void SetCapacity(PRUint32 capacity); + void SetCapacity(PRInt32 capacity); private: friend class nsMemoryCacheDeviceInfo; - void AdjustMemoryLimits( PRUint32 softLimit, PRUint32 hardLimit); + void AdjustMemoryLimits( PRInt32 softLimit, PRInt32 hardLimit); void EvictEntry( nsCacheEntry * entry ); void EvictEntriesIfNecessary(); - int EvictionList(nsCacheEntry * entry, PRUint32 deltaSize); + int EvictionList(nsCacheEntry * entry, PRInt32 deltaSize); /* * Data members @@ -81,17 +81,17 @@ private: enum { mostLikelyToEvict = 0, leastLikelyToEvict = 1 }; // constants to differentiate eviction lists PRCList mEvictionList[2]; - PRUint32 mEvictionThreshold; + PRInt32 mEvictionThreshold; - PRUint32 mHardLimit; - PRUint32 mSoftLimit; + PRInt32 mHardLimit; + PRInt32 mSoftLimit; - PRUint32 mTotalSize; - PRUint32 mInactiveSize; + PRInt32 mTotalSize; + PRInt32 mInactiveSize; - PRUint32 mEntryCount; + PRInt32 mEntryCount; - PRUint32 mMaxEntryCount; + PRInt32 mMaxEntryCount; // XXX what other stats do we want to keep? }; diff --git a/mozilla/netwerk/macbuild/cache.xml b/mozilla/netwerk/macbuild/cache.xml index 82d6aeff808..da6bd087ce9 100644 --- a/mozilla/netwerk/macbuild/cache.xml +++ b/mozilla/netwerk/macbuild/cache.xml @@ -1096,6 +1096,13 @@ Text + + Name + nsDiskCacheStreams.cpp + MacOS + Text + + Name nsDiskCacheBlockFile.cpp @@ -1197,6 +1204,11 @@ nsDiskCacheMap.cpp MacOS + + Name + nsDiskCacheStreams.cpp + MacOS + Name nsDiskCacheBlockFile.cpp @@ -2242,6 +2254,13 @@ Text Debug + + Name + nsDiskCacheStreams.cpp + MacOS + Text + Debug + Name nsDiskCacheBlockFile.cpp @@ -2343,6 +2362,11 @@ nsDiskCacheMap.cpp MacOS + + Name + nsDiskCacheStreams.cpp + MacOS + Name nsDiskCacheBlockFile.cpp @@ -2438,6 +2462,12 @@ nsDiskCacheMap.cpp MacOS + + Cache.shlb + Name + nsDiskCacheStreams.cpp + MacOS + Memory Cache