diff --git a/mozilla/content/base/src/Makefile.in b/mozilla/content/base/src/Makefile.in index 96189689c82..2df925d4d3a 100644 --- a/mozilla/content/base/src/Makefile.in +++ b/mozilla/content/base/src/Makefile.in @@ -59,6 +59,7 @@ REQUIRES = xpcom \ js \ webshell \ necko \ + nkcache \ mimetype \ caps \ lwbrk \ diff --git a/mozilla/content/base/src/nsContentSink.cpp b/mozilla/content/base/src/nsContentSink.cpp index b37de9812d0..51c0d8ccfa8 100644 --- a/mozilla/content/base/src/nsContentSink.cpp +++ b/mozilla/content/base/src/nsContentSink.cpp @@ -68,6 +68,10 @@ #include "nsIPrincipal.h" #include "nsIScriptGlobalObject.h" #include "nsNetCID.h" +#include "nsICache.h" +#include "nsICacheService.h" +#include "nsICacheSession.h" +#include "nsIOfflineCacheSession.h" #include "nsICookieService.h" #include "nsIPrompt.h" #include "nsServiceManagerUtils.h" @@ -673,7 +677,9 @@ nsContentSink::ProcessLink(nsIContent* aElement, // fetch href into the offline cache if relation is "offline-resource" if (linkTypes.IndexOf(NS_LITERAL_STRING("offline-resource")) != -1) { - PrefetchHref(aHref, PR_TRUE, PR_TRUE); + AddOfflineResource(aHref); + if (mSaveOfflineResources) + PrefetchHref(aHref, PR_TRUE, PR_TRUE); } // is it a stylesheet link? @@ -809,6 +815,115 @@ nsContentSink::PrefetchHref(const nsAString &aHref, } } +nsresult +nsContentSink::GetOfflineCacheSession(nsIOfflineCacheSession **aSession) +{ + if (!mOfflineCacheSession) { + nsresult rv; + nsCOMPtr serv = + do_GetService(NS_CACHESERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr session; + rv = serv->CreateSession("HTTP-offline", + nsICache::STORE_OFFLINE, + nsICache::STREAM_BASED, + getter_AddRefs(session)); + NS_ENSURE_SUCCESS(rv, rv); + + mOfflineCacheSession = + do_QueryInterface(session, &rv); + NS_ENSURE_SUCCESS(rv, rv); + } + + NS_ADDREF(*aSession = mOfflineCacheSession); + + return NS_OK; +} + +nsresult +nsContentSink::AddOfflineResource(const nsAString &aHref) +{ + PRBool match; + nsresult rv; + + nsCAutoString ownerHost; + rv = mDocumentURI->GetHostPort(ownerHost); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString ownerSpec; + rv = mDocumentURI->GetSpec(ownerSpec); + NS_ENSURE_SUCCESS(rv, rv); + + if (!mHaveOfflineResources) { + mHaveOfflineResources = PR_TRUE; + mSaveOfflineResources = PR_FALSE; + + // only let http and https urls add offline resources + nsresult rv = mDocumentURI->SchemeIs("http", &match); + NS_ENSURE_SUCCESS(rv, rv); + + if (!match) { + rv = mDocumentURI->SchemeIs("https", &match); + NS_ENSURE_SUCCESS(rv, rv); + if (!match) + return NS_OK; + } + + nsCOMPtr session; + rv = GetOfflineCacheSession(getter_AddRefs(session)); + NS_ENSURE_SUCCESS(rv, rv); + + // we're going to replace the list, clear it out + rv = session->SetOwnedKeys(ownerHost, ownerSpec, 0, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + + mSaveOfflineResources = PR_TRUE; + } + + if (!mSaveOfflineResources) return NS_OK; + + const nsACString &charset = mDocument->GetDocumentCharacterSet(); + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), aHref, + charset.IsEmpty() ? nsnull : PromiseFlatCString(charset).get(), + mDocumentBaseURI); + NS_ENSURE_SUCCESS(rv, rv); + + // only http and https urls can be marked as offline resources + rv = uri->SchemeIs("http", &match); + NS_ENSURE_SUCCESS(rv, rv); + + if (!match) { + rv = uri->SchemeIs("https", &match); + NS_ENSURE_SUCCESS(rv, rv); + if (!match) + return NS_OK; + } + + nsCAutoString spec; + rv = uri->GetSpec(spec); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr offlineCacheSession; + rv = GetOfflineCacheSession(getter_AddRefs(offlineCacheSession)); + NS_ENSURE_SUCCESS(rv, rv); + + // url fragments aren't used in cache keys + nsCAutoString::const_iterator specStart, specEnd; + spec.BeginReading(specStart); + spec.EndReading(specEnd); + if (FindCharInReadable('#', specStart, specEnd)) { + spec.BeginReading(specEnd); + offlineCacheSession->AddOwnedKey(ownerHost, ownerSpec, + Substring(specEnd, specStart)); + } else { + offlineCacheSession->AddOwnedKey(ownerHost, ownerSpec, spec); + } + + return NS_OK; +} + void nsContentSink::ScrollToRef() { diff --git a/mozilla/content/base/src/nsContentSink.h b/mozilla/content/base/src/nsContentSink.h index 2a57b49c584..2fb2afb65dc 100644 --- a/mozilla/content/base/src/nsContentSink.h +++ b/mozilla/content/base/src/nsContentSink.h @@ -75,6 +75,7 @@ class nsIContent; class nsIViewManager; class nsNodeInfoManager; class nsScriptLoader; +class nsIOfflineCacheSession; #ifdef NS_DEBUG @@ -167,6 +168,8 @@ protected: const nsSubstring& aMedia); void PrefetchHref(const nsAString &aHref, PRBool aExplicit, PRBool aOffline); + nsresult GetOfflineCacheSession(nsIOfflineCacheSession **aSession); + nsresult AddOfflineResource(const nsAString &aHref); void ScrollToRef(); nsresult RefreshIfEnabled(nsIViewManager* vm); @@ -252,6 +255,9 @@ protected: // Do we notify based on time? PRPackedBool mNotifyOnTimer; + // For saving links + nsCOMPtr mOfflineCacheSession; + // Have we already called BeginUpdate for this set of content changes? PRUint8 mBeganUpdate : 1; PRUint8 mLayoutStarted : 1; @@ -264,7 +270,11 @@ protected: PRUint8 mChangeScrollPosWhenScrollingToRef : 1; // If true, we deferred starting layout until sheets load PRUint8 mDeferredLayoutStart : 1; - + // true if an nodes have been encountered. + PRUint8 mHaveOfflineResources : 1; + // true if offline-resource links should be saved to the offline cache + PRUint8 mSaveOfflineResources : 1; + // -- Can interrupt parsing members -- PRUint32 mDelayTimerStart; diff --git a/mozilla/content/html/document/src/nsHTMLContentSink.cpp b/mozilla/content/html/document/src/nsHTMLContentSink.cpp index d97e2bb6f6b..39ecd6206e4 100644 --- a/mozilla/content/html/document/src/nsHTMLContentSink.cpp +++ b/mozilla/content/html/document/src/nsHTMLContentSink.cpp @@ -3012,7 +3012,9 @@ HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode) nsAutoString hrefVal; element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal); if (!hrefVal.IsEmpty()) { - PrefetchHref(hrefVal, PR_TRUE, PR_TRUE); + AddOfflineResource(hrefVal); + if (mSaveOfflineResources) + PrefetchHref(hrefVal, PR_TRUE, PR_TRUE); } } } diff --git a/mozilla/modules/libpref/src/init/all.js b/mozilla/modules/libpref/src/init/all.js index 34ebbe06224..a596f087e89 100644 --- a/mozilla/modules/libpref/src/init/all.js +++ b/mozilla/modules/libpref/src/init/all.js @@ -70,7 +70,7 @@ pref("browser.cache.check_doc_frequency", 3); pref("browser.cache.offline.enable", true); // offline cache capacity in kilobytes -pref("browser.cache.offline.capacity", 51200); +pref("browser.cache.offline.capacity", 10240); // Fastback caching - if this pref is negative, then we calculate the number // of content viewers to cache based on the amount of available memory. diff --git a/mozilla/netwerk/build.mk b/mozilla/netwerk/build.mk index af827dd77dc..71274ab3a87 100644 --- a/mozilla/netwerk/build.mk +++ b/mozilla/netwerk/build.mk @@ -58,6 +58,11 @@ endif # tier "necko" - the networking library and its dependencies # +# the offline cache uses mozStorage +ifdef MOZ_STORAGE +tier_necko_dirs += storage/public +endif + # these are only in the necko tier because libpref needs it ifneq (1_,$(MOZ_NO_XPCOM_OBSOLETE)_$(MOZ_XPINSTALL)) diff --git a/mozilla/netwerk/cache/public/Makefile.in b/mozilla/netwerk/cache/public/Makefile.in index 40b70c38e5d..8460f3763db 100644 --- a/mozilla/netwerk/cache/public/Makefile.in +++ b/mozilla/netwerk/cache/public/Makefile.in @@ -53,7 +53,8 @@ XPIDLSRCS = \ nsICacheService.idl \ nsICacheSession.idl \ nsICacheVisitor.idl \ - $(NULL) + nsIOfflineCacheSession.idl \ + $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/mozilla/netwerk/cache/public/nsIOfflineCacheSession.idl b/mozilla/netwerk/cache/public/nsIOfflineCacheSession.idl new file mode 100644 index 00000000000..b1f83f3e7d6 --- /dev/null +++ b/mozilla/netwerk/cache/public/nsIOfflineCacheSession.idl @@ -0,0 +1,160 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is nsIOfflineCacheSession.idl. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dave Camp + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" +#include "nsICache.idl" + +[scriptable, uuid(e9581d9f-3c0c-4722-8d2b-3d18f8d41299)] +interface nsIOfflineCacheSession : nsISupports +{ + /** + * The offline cache is meant to reliably store resources for + * offline use. The expected semantics are: + * + * a) Once populated, the cache will not evict an application resource + * unless explicitly asked. + * + * b) Resources no longer in use by the application should be evicted. + * + * c) If the cache fills up, new entries should be rejected rather + * than throwing out old ones. + * + * The offline cache uses domains to concretely represent an + * application. It maintains a list of resources to be pinned for + * each domain. This list is separate from actual cache + * population - the caller is still responsible for placing items + * in the cache, and ownership can be declared without a + * corresponding entry. + * + * A key can optionally be associated with a specific URI within + * the domain. + */ + + /** + * Sets the resources owned by a given domain/URI pair. + * + * Setting a list will remove any resources previously owned by this + * domain/URI pair. + * + * A key can be added while there is no associated entry. When + * an entry is created with this key, it will be owned by the + * domain/URI pair. + * + * @param ownerDomain The domain that owns the resources. + * @param ownerURI The specific URI that owns the resources. This can + * be empty if no URI specifically owns the resources. + * @param count The number of keys in keys. + * @param keys The keys that the domain/URI pair own. This can be empty + * to clear ownership for the domain/URI pair. + */ + void setOwnedKeys(in ACString ownerDomain, + in ACString ownerURI, + in unsigned long count, + [array, size_is(count)]in string keys); + + /** + * Gets the list of resources owned by a given domain/URI pair. + * + * @param ownerDomain The domain that owns the resources. + * @param ownerURI The specific URI that owns the resources. This can + * be empty if no URI specifically owns the resources. + * @param count The number of keys in keys. + * @param keys The keys that the domain/URI pair own. + */ + void getOwnedKeys(in ACString ownerDomain, + in ACString ownerURI, + out unsigned long count, + [array, size_is(count)]out string keys); + + /** + * Adds an owned key to a domain/URI pair. + * + * A key can be added while there is no associated entry. When + * an entry is created with this key, it will be owned by the + * domain/URI pair. + * + * @param ownerDomain The domain that owns the resources. + * @param ownerURI The specific URI that owns the resources. This can + * be empty if no URI specifically owns the resources. + * @param key The key to add. + */ + void addOwnedKey(in ACString ownerDomain, + in ACString ownerURI, + in ACString key); + + /** + * Removes an owned key from a domain/URI pair. + * + * If the key does not exist, an NS_ERROR_NOT_AVAILABLE exception + * will be thrown. + * + * @param ownerDomain The domain that owns the resources. + * @param ownerURI The specific URI that owns the resources. This can + * be empty if no URI specifically owns the resources. + * @param key The key to remove. + */ + void removeOwnedKey(in ACString ownerDomain, + in ACString ownerURI, + in ACString key); + + /** + * Checks whether a key is owned by a given domain/URI pair. + * + * @param ownerDomain The domain that owns the resources. + * @param ownerURI The specific URI that owns the resources. This can + * be empty if no URI specifically owns the resources. + * @param key The key to check + */ + boolean keyIsOwned(in ACString ownerDomain, + in ACString ownerURI, + in ACString key); + + /** + * Remove all keys owned by a domain, including keys owned by + * a specific URI. + * + * @param domain The domain for which keys should be removed. + */ + void clearKeysOwnedByDomain(in ACString ownerDomain); + + /** + * Evict all entries that are not owned by a domain. + */ + void evictUnownedEntries(); +}; diff --git a/mozilla/netwerk/cache/src/Makefile.in b/mozilla/netwerk/cache/src/Makefile.in index ee0d800330a..db6cb59ccdc 100644 --- a/mozilla/netwerk/cache/src/Makefile.in +++ b/mozilla/netwerk/cache/src/Makefile.in @@ -69,13 +69,6 @@ CPPSRCS = \ $(NULL) ifdef NECKO_DISK_CACHE -ifdef NECKO_DISK_CACHE_SQL -DEFINES += -DNECKO_DISK_CACHE_SQL -REQUIRES += storage -CPPSRCS += \ - nsDiskCacheDeviceSQL.cpp \ - $(NULL) -else CPPSRCS += \ nsDiskCacheBinding.cpp \ nsDiskCacheBlockFile.cpp \ @@ -86,6 +79,14 @@ CPPSRCS += \ nsDeleteDir.cpp \ $(NULL) endif + +ifdef MOZ_STORAGE +CPPSRCS += \ + nsDiskCacheDeviceSQL.cpp \ + $(NULL) + +REQUIRES += storage +DEFINES += -DNECKO_OFFLINE_CACHE endif LOCAL_INCLUDES=-I$(srcdir)/../../base/src diff --git a/mozilla/netwerk/cache/src/nsCacheEntry.cpp b/mozilla/netwerk/cache/src/nsCacheEntry.cpp index 1dbf2339ab9..ce73f4f66e7 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntry.cpp +++ b/mozilla/netwerk/cache/src/nsCacheEntry.cpp @@ -307,8 +307,8 @@ nsCacheEntryInfo::GetDeviceID(char ** deviceID) { NS_ENSURE_ARG_POINTER(deviceID); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - - *deviceID = nsCRT::strdup(mCacheEntry->GetDeviceID()); + + *deviceID = NS_strdup(mCacheEntry->GetDeviceID()); return *deviceID ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } diff --git a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp index a951bd60f41..571a22e3530 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp +++ b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp @@ -95,7 +95,7 @@ nsCacheEntryDescriptor::GetDeviceID(char ** result) nsCacheServiceAutoLock lock; if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - *result = nsCRT::strdup(mCacheEntry->GetDeviceID()); + *result = NS_strdup(mCacheEntry->GetDeviceID()); return *result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } @@ -438,7 +438,7 @@ nsCacheEntryDescriptor::GetMetaDataElement(const char *key, char **result) value = mCacheEntry->GetMetaDataElement(key); if (!value) return NS_ERROR_NOT_AVAILABLE; - *result = PL_strdup(value); + *result = NS_strdup(value); if (!*result) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; diff --git a/mozilla/netwerk/cache/src/nsCacheService.cpp b/mozilla/netwerk/cache/src/nsCacheService.cpp index 8e52d1c1701..a21ce7cc835 100644 --- a/mozilla/netwerk/cache/src/nsCacheService.cpp +++ b/mozilla/netwerk/cache/src/nsCacheService.cpp @@ -48,11 +48,10 @@ #include "nsCacheDevice.h" #include "nsMemoryCacheDevice.h" #include "nsICacheVisitor.h" - -#ifdef NECKO_DISK_CACHE_SQL -#include "nsDiskCacheDeviceSQL.h" -#else #include "nsDiskCacheDevice.h" + +#ifdef NECKO_OFFLINE_CACHE +#include "nsDiskCacheDeviceSQL.h" #endif #include "nsIObserverService.h" @@ -86,7 +85,7 @@ #define OFFLINE_CACHE_ENABLE_PREF "browser.cache.offline.enable" #define OFFLINE_CACHE_DIR_PREF "browser.cache.offline.parent_directory" #define OFFLINE_CACHE_CAPACITY_PREF "browser.cache.offline.capacity" -#define OFFLINE_CACHE_CAPACITY 51200 +#define OFFLINE_CACHE_CAPACITY 512000 #define MEMORY_CACHE_ENABLE_PREF "browser.cache.memory.enable" #define MEMORY_CACHE_CAPACITY_PREF "browser.cache.memory.capacity" @@ -662,14 +661,16 @@ nsCacheService::Shutdown() #ifdef NECKO_DISK_CACHE delete mDiskDevice; mDiskDevice = nsnull; +#endif // !NECKO_DISK_CACHE +#ifdef NECKO_OFFLINE_CACHE delete mOfflineDevice; mOfflineDevice = nsnull; +#endif // !NECKO_OFFLINE_CACHE -#if defined(PR_LOGGING) +#if defined(NECKO_DISK_CACHE) && defined(PR_LOGGING) LogCacheStatistics(); #endif -#endif // !NECKO_DISK_CACHE } } @@ -765,7 +766,9 @@ nsCacheService::EvictEntriesForClient(const char * clientID, if (NS_FAILED(rv)) return rv; } } +#endif // ! NECKO_DISK_CACHE +#ifdef NECKO_OFFLINE_CACHE if (storagePolicy == nsICache::STORE_ANYWHERE || storagePolicy == nsICache::STORE_OFFLINE) { if (mEnableOfflineDevice) { @@ -777,7 +780,7 @@ nsCacheService::EvictEntriesForClient(const char * clientID, if (NS_FAILED(rv)) return rv; } } -#endif // ! NECKO_DISK_CACHE +#endif // ! NECKO_OFFLINE_CACHE if (storagePolicy == nsICache::STORE_ANYWHERE || storagePolicy == nsICache::STORE_IN_MEMORY) { @@ -827,6 +830,162 @@ nsCacheService::IsStorageEnabledForPolicy_Locked(nsCacheStoragePolicy storagePo return PR_FALSE; } +nsresult +nsCacheService::SetOfflineOwnedKeys(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerURI, + PRUint32 count, + const char ** keys) +{ +#ifdef NECKO_OFFLINE_CACHE + if (session->StoragePolicy() != nsICache::STORE_OFFLINE) + return NS_ERROR_NOT_AVAILABLE; + + if (!gService->mOfflineDevice) { + nsresult rv = gService->CreateOfflineDevice(); + if (NS_FAILED(rv)) return rv; + } + + return gService->mOfflineDevice->SetOwnedKeys(session->ClientID()->get(), + ownerDomain, + ownerURI, + count, + keys); +#else // !NECKO_OFFLINE_CACHE + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +nsresult nsCacheService::GetOfflineOwnedKeys(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerURI, + PRUint32 * count, + char *** keys) +{ +#ifdef NECKO_OFFLINE_CACHE + if (session->StoragePolicy() != nsICache::STORE_OFFLINE) + return NS_ERROR_NOT_AVAILABLE; + + if (!gService->mOfflineDevice) { + nsresult rv = gService->CreateOfflineDevice(); + if (NS_FAILED(rv)) return rv; + } + + return gService->mOfflineDevice->GetOwnedKeys(session->ClientID()->get(), + ownerDomain, + ownerURI, + count, + keys); +#else // !NECKO_OFFLINE_CACHE + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +nsresult nsCacheService::AddOfflineOwnedKey(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key) +{ +#ifdef NECKO_OFFLINE_CACHE + if (session->StoragePolicy() != nsICache::STORE_OFFLINE) + return NS_ERROR_NOT_AVAILABLE; + + if (!gService->mOfflineDevice) { + nsresult rv = gService->CreateOfflineDevice(); + if (NS_FAILED(rv)) return rv; + } + + return gService->mOfflineDevice->AddOwnedKey(session->ClientID()->get(), + ownerDomain, + ownerURI, + key); +#else // !NECKO_OFFLINE_CACHE + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +nsresult nsCacheService::RemoveOfflineOwnedKey(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key) +{ +#ifdef NECKO_OFFLINE_CACHE + if (session->StoragePolicy() != nsICache::STORE_OFFLINE) + return NS_ERROR_NOT_AVAILABLE; + + if (!gService->mOfflineDevice) { + nsresult rv = gService->CreateOfflineDevice(); + if (NS_FAILED(rv)) return rv; + } + + return gService->mOfflineDevice->RemoveOwnedKey(session->ClientID()->get(), + ownerDomain, + ownerURI, + key); +#else // !NECKO_OFFLINE_CACHE + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +nsresult nsCacheService::OfflineKeyIsOwned(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key, + PRBool *isOwned) +{ +#ifdef NECKO_OFFLINE_CACHE + if (session->StoragePolicy() != nsICache::STORE_OFFLINE) + return NS_ERROR_NOT_AVAILABLE; + + if (!gService->mOfflineDevice) { + nsresult rv = gService->CreateOfflineDevice(); + if (NS_FAILED(rv)) return rv; + } + + return gService->mOfflineDevice->KeyIsOwned(session->ClientID()->get(), + ownerDomain, + ownerURI, + key, + isOwned); +#else // !NECKO_OFFLINE_CACHE + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +nsresult nsCacheService::ClearOfflineKeysOwnedByDomain(nsCacheSession * session, + const nsACString & domain) +{ +#ifdef NECKO_OFFLINE_CACHE + if (session->StoragePolicy() != nsICache::STORE_OFFLINE) + return NS_ERROR_NOT_AVAILABLE; + if (!gService->mOfflineDevice) { + nsresult rv = gService->CreateOfflineDevice(); + if (NS_FAILED(rv)) return rv; + } + + return gService->mOfflineDevice->ClearKeysOwnedByDomain(session->ClientID()->get(), + domain); +#else // !NECKO_OFFLINE_CACHE + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +nsresult nsCacheService::EvictUnownedOfflineEntries(nsCacheSession * session) +{ +#ifdef NECKO_OFFLINE_CACHE + if (session->StoragePolicy() != nsICache::STORE_OFFLINE) + return NS_ERROR_NOT_AVAILABLE; + + if (!gService->mOfflineDevice) { + nsresult rv = gService->CreateOfflineDevice(); + if (NS_FAILED(rv)) return rv; + } + + return gService->mOfflineDevice->EvictUnownedEntries(session->ClientID()->get()); +#else // !NECKO_OFFLINE_CACHE + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor) { @@ -856,7 +1015,9 @@ NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor) rv = mDiskDevice->Visit(visitor); if (NS_FAILED(rv)) return rv; } +#endif // !NECKO_DISK_CACHE +#ifdef NECKO_OFFLINE_CACHE if (mEnableOfflineDevice) { if (!mOfflineDevice) { rv = CreateOfflineDevice(); @@ -865,7 +1026,7 @@ NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor) rv = mOfflineDevice->Visit(visitor); if (NS_FAILED(rv)) return rv; } -#endif // !NECKO_DISK_CACHE +#endif // !NECKO_OFFLINE_CACHE // XXX notify any shutdown process that visitation is complete for THIS visitor. // XXX keep queue of visitors @@ -919,19 +1080,18 @@ nsCacheService::CreateDiskDevice() nsresult nsCacheService::CreateOfflineDevice() { -#ifdef NECKO_DISK_CACHE +#ifdef NECKO_OFFLINE_CACHE CACHE_LOG_ALWAYS(("Creating offline device")); - // XXX: want a sql-based device if (!mEnableOfflineDevice) return NS_ERROR_NOT_AVAILABLE; if (mOfflineDevice) return NS_OK; - mOfflineDevice = new nsDiskCacheDevice; + mOfflineDevice = new nsOfflineCacheDevice; if (!mOfflineDevice) return NS_ERROR_OUT_OF_MEMORY; // set the preferences - mOfflineDevice->SetCacheParentDirectoryAndName(mObserver->OfflineCacheParentDirectory(), - NS_LITERAL_CSTRING("OfflineCache")); + mOfflineDevice->SetCacheParentDirectory( + mObserver->OfflineCacheParentDirectory()); mOfflineDevice->SetCapacity(mObserver->OfflineCacheCapacity()); nsresult rv = mOfflineDevice->Init(); @@ -1282,7 +1442,7 @@ nsCacheService::SearchCacheDevices(nsCString * key, nsCacheStoragePolicy policy, (policy == nsICache::STORE_ANYWHERE && gIOService->IsOffline()))) { -#ifdef NECKO_DISK_CACHE +#ifdef NECKO_OFFLINE_CACHE if (mEnableOfflineDevice) { if (!mOfflineDevice) { nsresult rv = CreateOfflineDevice(); @@ -1292,7 +1452,7 @@ nsCacheService::SearchCacheDevices(nsCString * key, nsCacheStoragePolicy policy, entry = mOfflineDevice->FindEntry(key, collision); } -#endif +#endif // !NECKO_OFFLINE_CACHE } return entry; @@ -1336,7 +1496,7 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry) } } -#ifdef NECKO_DISK_CACHE +#ifdef NECKO_OFFLINE_CACHE if (!device && entry->IsStreamData() && entry->IsAllowedOffline() && mEnableOfflineDevice) { if (!mOfflineDevice) { @@ -1351,7 +1511,7 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry) device = mOfflineDevice; } } -#endif // ! NECKO_DISK_CACHE +#endif // ! NECKO_OFFLINE_CACHE if (device) entry->SetCacheDevice(device); @@ -1416,7 +1576,9 @@ nsCacheService::OnProfileShutdown(PRBool cleanse) gService->mDiskDevice->Shutdown(); gService->mEnableDiskDevice = PR_FALSE; } +#endif // !NECKO_DISK_CACHE +#ifdef NECKO_OFFLINE_CACHE if (gService->mOfflineDevice && gService->mEnableOfflineDevice) { if (cleanse) gService->mOfflineDevice->EvictEntries(nsnull); @@ -1424,7 +1586,7 @@ nsCacheService::OnProfileShutdown(PRBool cleanse) gService->mOfflineDevice->Shutdown(); gService->mEnableOfflineDevice = PR_FALSE; } -#endif // !NECKO_DISK_CACHE +#endif // !NECKO_OFFLINE_CACHE if (gService->mMemoryDevice) { // clear memory cache @@ -1458,7 +1620,9 @@ nsCacheService::OnProfileChanged() // XXX delete mDiskDevice? } } +#endif // !NECKO_DISK_CACHE +#ifdef NECKO_OFFLINE_CACHE if (gService->mOfflineDevice) { gService->mOfflineDevice->SetCacheParentDirectory(gService->mObserver->OfflineCacheParentDirectory()); gService->mOfflineDevice->SetCapacity(gService->mObserver->OfflineCacheCapacity()); @@ -1471,7 +1635,7 @@ nsCacheService::OnProfileChanged() // XXX delete mOfflineDevice? } } -#endif // !NECKO_DISK_CACHE +#endif // !NECKO_OFFLINE_CACHE // If memoryDevice exists, reset its size to the new profile if (gService->mMemoryDevice) { @@ -1525,11 +1689,11 @@ nsCacheService::SetOfflineCacheCapacity(PRInt32 capacity) if (!gService) return; nsCacheServiceAutoLock lock; -#ifdef NECKO_DISK_CACHE +#ifdef NECKO_OFFLINE_CACHE if (gService->mOfflineDevice) { gService->mOfflineDevice->SetCapacity(capacity); } -#endif // !NECKO_DISK_CACHE +#endif // !NECKO_OFFLINE_CACHE gService->mEnableOfflineDevice = gService->mObserver->OfflineCacheEnabled(); } diff --git a/mozilla/netwerk/cache/src/nsCacheService.h b/mozilla/netwerk/cache/src/nsCacheService.h index c23ec906a44..d676b335f2c 100644 --- a/mozilla/netwerk/cache/src/nsCacheService.h +++ b/mozilla/netwerk/cache/src/nsCacheService.h @@ -60,6 +60,7 @@ class nsCacheRequest; class nsCacheProfilePrefObserver; class nsDiskCacheDevice; class nsMemoryCacheDevice; +class nsOfflineCacheDevice; class nsCacheServiceAutoLock; @@ -96,6 +97,40 @@ public: static nsresult IsStorageEnabledForPolicy(nsCacheStoragePolicy storagePolicy, PRBool * result); + + static nsresult SetOfflineOwnedKeys(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerUri, + PRUint32 count, + const char ** keys); + + static nsresult GetOfflineOwnedKeys(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerURI, + PRUint32 * count, + char *** keys); + + static nsresult AddOfflineOwnedKey(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key); + + static nsresult RemoveOfflineOwnedKey(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key); + + static nsresult OfflineKeyIsOwned(nsCacheSession * session, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key, + PRBool * isOwned); + + static nsresult ClearOfflineKeysOwnedByDomain(nsCacheSession * session, + const nsACString & domain); + + static nsresult EvictUnownedOfflineEntries(nsCacheSession * session); + /** * Methods called by nsCacheEntryDescriptor */ @@ -248,7 +283,7 @@ private: nsMemoryCacheDevice * mMemoryDevice; nsDiskCacheDevice * mDiskDevice; - nsDiskCacheDevice * mOfflineDevice; + nsOfflineCacheDevice * mOfflineDevice; nsCacheEntryHashTable mActiveEntries; PRCList mDoomedEntries; diff --git a/mozilla/netwerk/cache/src/nsCacheSession.cpp b/mozilla/netwerk/cache/src/nsCacheSession.cpp index a8452f9524e..ed02bb34dac 100644 --- a/mozilla/netwerk/cache/src/nsCacheSession.cpp +++ b/mozilla/netwerk/cache/src/nsCacheSession.cpp @@ -42,9 +42,17 @@ #include "nsCacheSession.h" #include "nsCacheService.h" +#include "nsCRT.h" +NS_IMPL_ADDREF(nsCacheSession) +NS_IMPL_RELEASE(nsCacheSession) -NS_IMPL_ISUPPORTS1(nsCacheSession, nsICacheSession) +NS_INTERFACE_MAP_BEGIN(nsCacheSession) + NS_INTERFACE_MAP_ENTRY(nsICacheSession) + NS_INTERFACE_MAP_ENTRY_CONDITIONAL( + nsIOfflineCacheSession, (StoragePolicy() == nsICache::STORE_OFFLINE)) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICacheSession) +NS_INTERFACE_MAP_END nsCacheSession::nsCacheSession(const char * clientID, nsCacheStoragePolicy storagePolicy, @@ -128,3 +136,51 @@ NS_IMETHODIMP nsCacheSession::IsStorageEnabled(PRBool *result) return nsCacheService::IsStorageEnabledForPolicy(StoragePolicy(), result); } +NS_IMETHODIMP nsCacheSession::SetOwnedKeys(const nsACString & domain, + const nsACString & uri, + PRUint32 count, + const char ** keys) +{ + return nsCacheService::SetOfflineOwnedKeys(this, domain, uri, count, keys); +} + +NS_IMETHODIMP nsCacheSession::GetOwnedKeys(const nsACString & domain, + const nsACString & uri, + PRUint32 * count, + char *** keys) +{ + return nsCacheService::GetOfflineOwnedKeys(this, domain, uri, count, keys); +} + +NS_IMETHODIMP nsCacheSession::AddOwnedKey(const nsACString & domain, + const nsACString & uri, + const nsACString & key) +{ + return nsCacheService::AddOfflineOwnedKey(this, domain, uri, key); +} + +NS_IMETHODIMP nsCacheSession::RemoveOwnedKey(const nsACString & domain, + const nsACString & uri, + const nsACString & key) +{ + return nsCacheService::RemoveOfflineOwnedKey(this, domain, uri, key); +} + +NS_IMETHODIMP nsCacheSession::KeyIsOwned(const nsACString & domain, + const nsACString & uri, + const nsACString & key, + PRBool * isOwned) +{ + return nsCacheService::OfflineKeyIsOwned(this, domain, uri, key, isOwned); +} + +NS_IMETHODIMP nsCacheSession::ClearKeysOwnedByDomain(const nsACString & domain) +{ + return nsCacheService::ClearOfflineKeysOwnedByDomain(this, domain); +} + +NS_IMETHODIMP nsCacheSession::EvictUnownedEntries() +{ + return nsCacheService::EvictUnownedOfflineEntries(this); +} + diff --git a/mozilla/netwerk/cache/src/nsCacheSession.h b/mozilla/netwerk/cache/src/nsCacheSession.h index ec88251114e..b8c7f70b3eb 100644 --- a/mozilla/netwerk/cache/src/nsCacheSession.h +++ b/mozilla/netwerk/cache/src/nsCacheSession.h @@ -46,13 +46,16 @@ #include "nspr.h" #include "nsError.h" #include "nsICacheSession.h" +#include "nsIOfflineCacheSession.h" #include "nsString.h" class nsCacheSession : public nsICacheSession + , public nsIOfflineCacheSession { public: NS_DECL_ISUPPORTS NS_DECL_NSICACHESESSION + NS_DECL_NSIOFFLINECACHESESSION nsCacheSession(const char * clientID, nsCacheStoragePolicy storagePolicy, PRBool streamBased); virtual ~nsCacheSession(); diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp b/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp index 6649fc0a9f1..7d2490bb095 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp @@ -180,7 +180,7 @@ NS_IMPL_ISUPPORTS1(nsDiskCacheDeviceInfo, nsICacheDeviceInfo) NS_IMETHODIMP nsDiskCacheDeviceInfo::GetDescription(char ** aDescription) { NS_ENSURE_ARG_POINTER(aDescription); - *aDescription = nsCRT::strdup("Disk cache device"); + *aDescription = NS_strdup("Disk cache device"); return *aDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } @@ -929,43 +929,6 @@ nsDiskCacheDevice::SetCacheParentDirectory(nsILocalFile * parentDir) mCacheDirectory = do_QueryInterface(directory); } -// XXX: This is here to support the offline cache, and can be removed -// XXX: once it has its own cache implementation -void -nsDiskCacheDevice::SetCacheParentDirectoryAndName(nsILocalFile * parentDir, - const nsACString & str) -{ - nsresult rv; - PRBool exists; - - if (Initialized()) { - NS_ASSERTION(PR_FALSE, "Cannot switch cache directory when initialized"); - return; - } - - if (!parentDir) { - mCacheDirectory = nsnull; - return; - } - - // ensure parent directory exists - rv = parentDir->Exists(&exists); - if (NS_SUCCEEDED(rv) && !exists) - rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0700); - if (NS_FAILED(rv)) return; - - // ensure cache directory exists - nsCOMPtr directory; - - rv = parentDir->Clone(getter_AddRefs(directory)); - if (NS_FAILED(rv)) return; - rv = directory->AppendNative(str); - if (NS_FAILED(rv)) return; - - mCacheDirectory = do_QueryInterface(directory); -} - - void nsDiskCacheDevice::getCacheDirectory(nsILocalFile ** result) diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDevice.h b/mozilla/netwerk/cache/src/nsDiskCacheDevice.h index 20d04d3a9be..be64a6e46fb 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDevice.h +++ b/mozilla/netwerk/cache/src/nsDiskCacheDevice.h @@ -93,11 +93,6 @@ public: void SetCacheParentDirectory(nsILocalFile * parentDir); void SetCapacity(PRUint32 capacity); - // XXX: This is here to support the offline cache, and can be removed - // XXX: once it has its own cache implementation - void SetCacheParentDirectoryAndName(nsILocalFile * parentDir, - const nsACString & str); - /* private: */ void getCacheDirectory(nsILocalFile ** result); diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDeviceSQL.cpp b/mozilla/netwerk/cache/src/nsDiskCacheDeviceSQL.cpp index c30208a193f..9cf4e19bf2b 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDeviceSQL.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheDeviceSQL.cpp @@ -20,6 +20,7 @@ * * Contributor(s): * Darin Fisher + * Dave Camp * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -35,25 +36,10 @@ * * ***** END LICENSE BLOCK ***** */ -// include files for ftruncate (or equivalent) -#if defined(XP_UNIX) || defined(XP_BEOS) -#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 - -#include "private/pprio.h" - -#include "prlong.h" - #include "nsCache.h" #include "nsDiskCache.h" #include "nsDiskCacheDeviceSQL.h" +#include "nsCacheService.h" #include "nsNetUtil.h" #include "nsAutoPtr.h" @@ -63,12 +49,13 @@ #include "mozIStorageService.h" #include "mozIStorageStatement.h" -#include "mozStorageCID.h" +#include "mozIStorageFunction.h" +#include "mozStorageHelper.h" #include "nsICacheVisitor.h" #include "nsISeekableStream.h" -static const char DISK_CACHE_DEVICE_ID[] = { "disk" }; +static const char OFFLINE_CACHE_DEVICE_ID[] = { "offline" }; #define LOG(args) CACHE_LOG_DEBUG(args) @@ -120,17 +107,37 @@ class AutoResetStatement mozIStorageStatement *mStatement; }; -/****************************************************************************** - * nsDiskCache - *****************************************************************************/ +class EvictionObserver +{ + public: + EvictionObserver(mozIStorageConnection *db) + : mDB(db) + { + mDB->ExecuteSimpleSQL( + NS_LITERAL_CSTRING("CREATE TEMP TRIGGER cache_on_delete AFTER DELETE" + " ON moz_cache FOR EACH ROW BEGIN SELECT" + " cache_eviction_observer(" + " OLD.clientID, OLD.key, OLD.generation);" + " END;")); + } + + ~EvictionObserver() + { + mDB->ExecuteSimpleSQL( + NS_LITERAL_CSTRING("DROP TRIGGER cache_on_delete;")); + } + + private: + mozIStorageConnection *mDB; +}; #define DCACHE_HASH_MAX LL_MAXINT #define DCACHE_HASH_BITS 64 /** - * nsDiskCache::Hash(const char * key) + * nsOfflineCache::Hash(const char * key) * - * This algorithm of this method implies nsDiskCacheRecords will be stored + * This algorithm of this method implies nsOfflineCacheRecords will be stored * in a certain order on disk. If the algorithm changes, existing cache * map files may become invalid, and therefore the kCurrentVersion needs * to be revised. @@ -144,67 +151,121 @@ DCacheHash(const char * key) return (h == 0 ? DCACHE_HASH_MAX : h); } +/****************************************************************************** + * nsOfflineCacheEvictionFunction + */ -nsresult -nsDiskCache::Truncate(PRFileDesc * fd, PRUint32 newEOF) +class nsOfflineCacheEvictionFunction : public mozIStorageFunction { +public: + NS_DECL_ISUPPORTS + NS_DECL_MOZISTORAGEFUNCTION + + nsOfflineCacheEvictionFunction(nsOfflineCacheDevice *device) + : mDevice(device) + {} + +private: + nsOfflineCacheDevice *mDevice; + +}; + +NS_IMPL_ISUPPORTS1(nsOfflineCacheEvictionFunction, mozIStorageFunction) + +// helper function for directly exposing the same data file binding +// path algorithm used in nsOfflineCacheBinding::Create +static nsresult +GetCacheDataFile(nsIFile *cacheDir, const char *cid, const char *key, + int generation, nsCOMPtr &file) { - // use modified SetEOF from nsFileStreams::SetEOF() + cacheDir->Clone(getter_AddRefs(file)); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; -#if defined(XP_UNIX) || defined(XP_BEOS) - if (ftruncate(PR_FileDesc2NativeHandle(fd), newEOF) != 0) { - NS_ERROR("ftruncate failed"); - return NS_ERROR_FAILURE; + nsCAutoString fullKey; + fullKey.Append(cid); + fullKey.Append(':'); + fullKey.Append(key); + + PRUint64 hash = DCacheHash(fullKey.get()); + + PRUint32 dir1 = (PRUint32) (hash & 0x0F); + PRUint32 dir2 = (PRUint32)((hash & 0xF0) >> 4); + + hash >>= 8; + + file->AppendNative(nsPrintfCString("%X", dir1)); + file->AppendNative(nsPrintfCString("%X", dir2)); + + char leaf[64]; + PR_snprintf(leaf, sizeof(leaf), "%014llX-%X", hash, generation); + return file->AppendNative(nsDependentCString(leaf)); +} + +NS_IMETHODIMP +nsOfflineCacheEvictionFunction::OnFunctionCall(mozIStorageValueArray *values) +{ + LOG(("nsOfflineCacheDevice::EvictionObserver\n")); + + PRUint32 numEntries; + nsresult rv = values->GetNumEntries(&numEntries); + NS_ENSURE_SUCCESS(rv, rv); + NS_ASSERTION(numEntries == 3, "unexpected number of arguments"); + + PRUint32 valueLen; + const char *cid = values->AsSharedUTF8String(0, &valueLen); + const char *key = values->AsSharedUTF8String(1, &valueLen); + int generation = values->AsInt32(2); + + nsCOMPtr file; + rv = GetCacheDataFile(mDevice->CacheDirectory(), cid, key, + generation, file); + if (NS_FAILED(rv)) + { + LOG(("GetCacheDataFile [cid=%s key=%s generation=%d] failed [rv=%x]!\n", + cid, key, generation, rv)); + return rv; } -#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 +#if defined(PR_LOGGING) + nsCAutoString path; + file->GetNativePath(path); + LOG((" removing %s\n", path.get())); #endif + + file->Remove(PR_FALSE); + return NS_OK; } - /****************************************************************************** - * nsDiskCacheDeviceInfo + * nsOfflineCacheDeviceInfo */ -class nsDiskCacheDeviceInfo : public nsICacheDeviceInfo +class nsOfflineCacheDeviceInfo : public nsICacheDeviceInfo { public: NS_DECL_ISUPPORTS NS_DECL_NSICACHEDEVICEINFO - nsDiskCacheDeviceInfo(nsDiskCacheDevice* device) + nsOfflineCacheDeviceInfo(nsOfflineCacheDevice* device) : mDevice(device) {} - + private: - nsDiskCacheDevice* mDevice; + nsOfflineCacheDevice* mDevice; }; -NS_IMPL_ISUPPORTS1(nsDiskCacheDeviceInfo, nsICacheDeviceInfo) +NS_IMPL_ISUPPORTS1(nsOfflineCacheDeviceInfo, nsICacheDeviceInfo) NS_IMETHODIMP -nsDiskCacheDeviceInfo::GetDescription(char **aDescription) +nsOfflineCacheDeviceInfo::GetDescription(char **aDescription) { - *aDescription = nsCRT::strdup("Disk cache device"); + *aDescription = NS_strdup("Offline cache device"); return *aDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP -nsDiskCacheDeviceInfo::GetUsageReport(char ** usageReport) +nsOfflineCacheDeviceInfo::GetUsageReport(char ** usageReport) { nsCAutoString buffer; buffer.AppendLiteral("\n\nCache Directory:\n "); @@ -229,47 +290,48 @@ nsDiskCacheDeviceInfo::GetUsageReport(char ** usageReport) } NS_IMETHODIMP -nsDiskCacheDeviceInfo::GetEntryCount(PRUint32 *aEntryCount) +nsOfflineCacheDeviceInfo::GetEntryCount(PRUint32 *aEntryCount) { *aEntryCount = mDevice->EntryCount(); return NS_OK; } NS_IMETHODIMP -nsDiskCacheDeviceInfo::GetTotalSize(PRUint32 *aTotalSize) +nsOfflineCacheDeviceInfo::GetTotalSize(PRUint32 *aTotalSize) { *aTotalSize = mDevice->CacheSize(); return NS_OK; } NS_IMETHODIMP -nsDiskCacheDeviceInfo::GetMaximumSize(PRUint32 *aMaximumSize) +nsOfflineCacheDeviceInfo::GetMaximumSize(PRUint32 *aMaximumSize) { *aMaximumSize = mDevice->CacheCapacity(); return NS_OK; } - /****************************************************************************** - * nsDiskCacheBinding + * nsOfflineCacheBinding */ -class nsDiskCacheBinding : public nsISupports +class nsOfflineCacheBinding : public nsISupports { public: NS_DECL_ISUPPORTS - static nsDiskCacheBinding * + static nsOfflineCacheBinding * Create(nsIFile *cacheDir, const char *key, int generation); nsCOMPtr mDataFile; int mGeneration; }; -NS_IMPL_THREADSAFE_ISUPPORTS0(nsDiskCacheBinding) +NS_IMPL_THREADSAFE_ISUPPORTS0(nsOfflineCacheBinding) -nsDiskCacheBinding * -nsDiskCacheBinding::Create(nsIFile *cacheDir, const char *key, int generation) +nsOfflineCacheBinding * +nsOfflineCacheBinding::Create(nsIFile *cacheDir, + const char *key, + int generation) { nsCOMPtr file; cacheDir->Clone(getter_AddRefs(file)); @@ -320,7 +382,7 @@ nsDiskCacheBinding::Create(nsIFile *cacheDir, const char *key, int generation) return nsnull; } - nsDiskCacheBinding *binding = new nsDiskCacheBinding; + nsOfflineCacheBinding *binding = new nsOfflineCacheBinding; if (!binding) return nsnull; @@ -329,42 +391,11 @@ nsDiskCacheBinding::Create(nsIFile *cacheDir, const char *key, int generation) return binding; } -// helper function for directly exposing the same data file binding -// path algorithm used in nsDiskCacheBinding::Create -static nsresult -GetCacheDataFile(nsIFile *cacheDir, const char *cid, const char *key, - int generation, nsCOMPtr &file) -{ - cacheDir->Clone(getter_AddRefs(file)); - if (!file) - return NS_ERROR_OUT_OF_MEMORY; - - nsCAutoString fullKey; - fullKey.Append(cid); - fullKey.Append(':'); - fullKey.Append(key); - - PRUint64 hash = DCacheHash(fullKey.get()); - - PRUint32 dir1 = (PRUint32) (hash & 0x0F); - PRUint32 dir2 = (PRUint32)((hash & 0xF0) >> 4); - - hash >>= 8; - - file->AppendNative(nsPrintfCString("%X", dir1)); - file->AppendNative(nsPrintfCString("%X", dir2)); - - char leaf[64]; - PR_snprintf(leaf, sizeof(leaf), "%014llX-%X", hash, generation); - return file->AppendNative(nsDependentCString(leaf)); -} - - /****************************************************************************** - * nsDiskCacheRecord + * nsOfflineCacheRecord */ -struct nsDiskCacheRecord +struct nsOfflineCacheRecord { const char *clientID; const char *key; @@ -380,9 +411,9 @@ struct nsDiskCacheRecord }; static nsCacheEntry * -CreateCacheEntry(nsDiskCacheDevice *device, +CreateCacheEntry(nsOfflineCacheDevice *device, const nsCString *fullKey, - const nsDiskCacheRecord &rec) + const nsOfflineCacheRecord &rec) { if (rec.flags != 0) { @@ -394,7 +425,7 @@ CreateCacheEntry(nsDiskCacheDevice *device, nsresult rv = nsCacheEntry::Create(fullKey->get(), // XXX enable sharing nsICache::STREAM_BASED, - nsICache::STORE_ON_DISK, + nsICache::STORE_OFFLINE, device, &entry); if (NS_FAILED(rv)) return nsnull; @@ -408,10 +439,10 @@ CreateCacheEntry(nsDiskCacheDevice *device, entry->UnflattenMetaData((const char *) rec.metaData, rec.metaDataLen); // create a binding object for this entry - nsDiskCacheBinding *binding = - nsDiskCacheBinding::Create(device->CacheDirectory(), - fullKey->get(), - rec.generation); + nsOfflineCacheBinding *binding = + nsOfflineCacheBinding::Create(device->CacheDirectory(), + fullKey->get(), + rec.generation); if (!binding) { delete entry; @@ -424,77 +455,78 @@ CreateCacheEntry(nsDiskCacheDevice *device, /****************************************************************************** - * nsDiskCacheEntryInfo + * nsOfflineCacheEntryInfo */ -class nsDiskCacheEntryInfo : public nsICacheEntryInfo +class nsOfflineCacheEntryInfo : public nsICacheEntryInfo { public: NS_DECL_ISUPPORTS NS_DECL_NSICACHEENTRYINFO - nsDiskCacheRecord *mRec; + nsOfflineCacheRecord *mRec; }; -NS_IMPL_ISUPPORTS1(nsDiskCacheEntryInfo, nsICacheEntryInfo) +NS_IMPL_ISUPPORTS1(nsOfflineCacheEntryInfo, nsICacheEntryInfo) NS_IMETHODIMP -nsDiskCacheEntryInfo::GetClientID(char **result) +nsOfflineCacheEntryInfo::GetClientID(char **result) { - *result = nsCRT::strdup(mRec->clientID); + *result = NS_strdup(mRec->clientID); return *result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP -nsDiskCacheEntryInfo::GetDeviceID(char ** deviceID) +nsOfflineCacheEntryInfo::GetDeviceID(char ** deviceID) { - *deviceID = nsCRT::strdup(DISK_CACHE_DEVICE_ID); + *deviceID = NS_strdup(OFFLINE_CACHE_DEVICE_ID); return *deviceID ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP -nsDiskCacheEntryInfo::GetKey(nsACString &clientKey) +nsOfflineCacheEntryInfo::GetKey(nsACString &clientKey) { clientKey.Assign(mRec->key); return NS_OK; } NS_IMETHODIMP -nsDiskCacheEntryInfo::GetFetchCount(PRInt32 *aFetchCount) +nsOfflineCacheEntryInfo::GetFetchCount(PRInt32 *aFetchCount) { *aFetchCount = mRec->fetchCount; return NS_OK; } NS_IMETHODIMP -nsDiskCacheEntryInfo::GetLastFetched(PRUint32 *aLastFetched) +nsOfflineCacheEntryInfo::GetLastFetched(PRUint32 *aLastFetched) { *aLastFetched = SecondsFromPRTime(mRec->lastFetched); return NS_OK; } NS_IMETHODIMP -nsDiskCacheEntryInfo::GetLastModified(PRUint32 *aLastModified) +nsOfflineCacheEntryInfo::GetLastModified(PRUint32 *aLastModified) { *aLastModified = SecondsFromPRTime(mRec->lastModified); return NS_OK; } NS_IMETHODIMP -nsDiskCacheEntryInfo::GetExpirationTime(PRUint32 *aExpirationTime) +nsOfflineCacheEntryInfo::GetExpirationTime(PRUint32 *aExpirationTime) { *aExpirationTime = SecondsFromPRTime(mRec->expirationTime); return NS_OK; } NS_IMETHODIMP -nsDiskCacheEntryInfo::IsStreamBased(PRBool *aStreamBased) +nsOfflineCacheEntryInfo::IsStreamBased(PRBool *aStreamBased) { *aStreamBased = PR_TRUE; return NS_OK; } -NS_IMETHODIMP nsDiskCacheEntryInfo::GetDataSize(PRUint32 *aDataSize) +NS_IMETHODIMP +nsOfflineCacheEntryInfo::GetDataSize(PRUint32 *aDataSize) { *aDataSize = mRec->dataSize; return NS_OK; @@ -502,23 +534,23 @@ NS_IMETHODIMP nsDiskCacheEntryInfo::GetDataSize(PRUint32 *aDataSize) /****************************************************************************** - * nsDiskCacheDevice + * nsOfflineCacheDevice */ -nsDiskCacheDevice::nsDiskCacheDevice() +nsOfflineCacheDevice::nsOfflineCacheDevice() : mDB(nsnull) , mCacheCapacity(0) , mDeltaCounter(0) { } -nsDiskCacheDevice::~nsDiskCacheDevice() +nsOfflineCacheDevice::~nsOfflineCacheDevice() { Shutdown(); } PRUint32 -nsDiskCacheDevice::CacheSize() +nsOfflineCacheDevice::CacheSize() { AutoResetStatement statement(mStatement_CacheSize); @@ -530,7 +562,7 @@ nsDiskCacheDevice::CacheSize() } PRUint32 -nsDiskCacheDevice::EntryCount() +nsOfflineCacheDevice::EntryCount() { AutoResetStatement statement(mStatement_EntryCount); @@ -542,7 +574,7 @@ nsDiskCacheDevice::EntryCount() } nsresult -nsDiskCacheDevice::UpdateEntry(nsCacheEntry *entry) +nsOfflineCacheDevice::UpdateEntry(nsCacheEntry *entry) { // Decompose the key into "ClientID" and "Key" nsCAutoString keyBuf; @@ -557,7 +589,7 @@ nsDiskCacheDevice::UpdateEntry(nsCacheEntry *entry) char *md = metaDataBuf.BeginWriting(); entry->FlattenMetaData(md, mdSize); - nsDiskCacheRecord rec; + nsOfflineCacheRecord rec; rec.metaData = (const PRUint8 *) md; rec.metaDataLen = mdSize; rec.flags = 0; // mark entry as inactive @@ -570,15 +602,15 @@ nsDiskCacheDevice::UpdateEntry(nsCacheEntry *entry) AutoResetStatement statement(mStatement_UpdateEntry); nsresult rv; - rv = statement->BindDataParameter(0, rec.metaData, rec.metaDataLen); + rv = statement->BindBlobParameter(0, rec.metaData, rec.metaDataLen); rv |= statement->BindInt32Parameter(1, rec.flags); rv |= statement->BindInt32Parameter(2, rec.dataSize); rv |= statement->BindInt32Parameter(3, rec.fetchCount); rv |= statement->BindInt64Parameter(4, rec.lastFetched); rv |= statement->BindInt64Parameter(5, rec.lastModified); rv |= statement->BindInt64Parameter(6, rec.expirationTime); - rv |= statement->BindCStringParameter(7, cid); - rv |= statement->BindCStringParameter(8, key); + rv |= statement->BindUTF8StringParameter(7, nsDependentCString(cid)); + rv |= statement->BindUTF8StringParameter(8, nsDependentCString(key)); NS_ENSURE_SUCCESS(rv, rv); PRBool hasRows; @@ -590,7 +622,7 @@ nsDiskCacheDevice::UpdateEntry(nsCacheEntry *entry) } nsresult -nsDiskCacheDevice::UpdateEntrySize(nsCacheEntry *entry, PRUint32 newSize) +nsOfflineCacheDevice::UpdateEntrySize(nsCacheEntry *entry, PRUint32 newSize) { // Decompose the key into "ClientID" and "Key" nsCAutoString keyBuf; @@ -602,8 +634,8 @@ nsDiskCacheDevice::UpdateEntrySize(nsCacheEntry *entry, PRUint32 newSize) nsresult rv; rv = statement->BindInt32Parameter(0, newSize); - rv |= statement->BindCStringParameter(1, cid); - rv |= statement->BindCStringParameter(2, key); + rv |= statement->BindUTF8StringParameter(1, nsDependentCString(cid)); + rv |= statement->BindUTF8StringParameter(2, nsDependentCString(key)); NS_ENSURE_SUCCESS(rv, rv); PRBool hasRows; @@ -615,7 +647,7 @@ nsDiskCacheDevice::UpdateEntrySize(nsCacheEntry *entry, PRUint32 newSize) } nsresult -nsDiskCacheDevice::DeleteEntry(nsCacheEntry *entry, PRBool deleteData) +nsOfflineCacheDevice::DeleteEntry(nsCacheEntry *entry, PRBool deleteData) { if (deleteData) { @@ -633,8 +665,8 @@ nsDiskCacheDevice::DeleteEntry(nsCacheEntry *entry, PRBool deleteData) AutoResetStatement statement(mStatement_DeleteEntry); nsresult rv; - rv = statement->BindCStringParameter(0, cid); - rv |= statement->BindCStringParameter(1, key); + rv = statement->BindUTF8StringParameter(0, nsDependentCString(cid)); + rv |= statement->BindUTF8StringParameter(1, nsDependentCString(key)); NS_ENSURE_SUCCESS(rv, rv); PRBool hasRows; @@ -646,86 +678,20 @@ nsDiskCacheDevice::DeleteEntry(nsCacheEntry *entry, PRBool deleteData) } nsresult -nsDiskCacheDevice::DeleteData(nsCacheEntry *entry) +nsOfflineCacheDevice::DeleteData(nsCacheEntry *entry) { - nsDiskCacheBinding *binding = (nsDiskCacheBinding *) entry->Data(); + nsOfflineCacheBinding *binding = (nsOfflineCacheBinding *) entry->Data(); NS_ENSURE_STATE(binding); return binding->mDataFile->Remove(PR_FALSE); } -nsresult -nsDiskCacheDevice::EnableEvictionObserver() -{ -#if 0 - // use CreateTrigger .. maybe do this only once, and have a member - // variable to control whether or not it is active. - - int res = - sqlite3_exec(mDB, "CREATE TEMP TRIGGER cache_on_delete AFTER DELETE" - " ON moz_cache FOR EACH ROW BEGIN SELECT" - " cache_eviction_observer(" - " OLD.clientID, OLD.key, OLD.generation);" - " END;", NULL, NULL, NULL); - NS_ENSURE_SQLITE_RESULT(res, NS_ERROR_UNEXPECTED); -#endif - - return NS_OK; -} - -nsresult -nsDiskCacheDevice::DisableEvictionObserver() -{ -#if 0 - int res = sqlite3_exec(mDB, "DROP TRIGGER cache_on_delete;", - NULL, NULL, NULL); - NS_ENSURE_SQLITE_RESULT(res, NS_ERROR_UNEXPECTED); -#endif - - return NS_OK; -} - -#if 0 -/* static */ void -nsDiskCacheDevice::EvictionObserver(sqlite3_context *ctx, int narg, - sqlite3_value **values) -{ - LOG(("nsDiskCacheDevice::EvictionObserver\n")); - - nsDiskCacheDevice *device = (nsDiskCacheDevice *) sqlite3_user_data(ctx); - - NS_ASSERTION(narg == 3, "unexpected number of arguments"); - const char *cid = (const char *) sqlite3_value_text(values[0]); - const char *key = (const char *) sqlite3_value_text(values[1]); - int generation = sqlite3_value_int(values[2]); - - nsCOMPtr file; - nsresult rv = GetCacheDataFile(device->CacheDirectory(), cid, key, - generation, file); - if (NS_FAILED(rv)) - { - LOG(("GetCacheDataFile [cid=%s key=%s generation=%d] failed [rv=%x]!\n", - cid, key, generation, rv)); - return; - } - -#if defined(PR_LOGGING) - nsCAutoString path; - file->GetNativePath(path); - LOG((" removing %s\n", path.get())); -#endif - - file->Remove(PR_FALSE); -} -#endif - - /** * nsCacheDevice implementation */ nsresult -nsDiskCacheDevice::Init() +nsOfflineCacheDevice::Init() { NS_ENSURE_TRUE(!mDB, NS_ERROR_ALREADY_INITIALIZED); @@ -740,11 +706,11 @@ nsDiskCacheDevice::Init() nsCOMPtr indexFile; rv = mCacheDirectory->Clone(getter_AddRefs(indexFile)); NS_ENSURE_SUCCESS(rv, rv); - rv = indexFile->AppendNative(NS_LITERAL_CSTRING("index.db")); + rv = indexFile->AppendNative(NS_LITERAL_CSTRING("index.sqlite")); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr ss = - do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv); + do_GetService("@mozilla.org/storage/service;1", &rv); NS_ENSURE_SUCCESS(rv, rv); rv = ss->OpenDatabase(indexFile, getter_AddRefs(mDB)); @@ -777,33 +743,48 @@ nsDiskCacheDevice::Init() ");\n")); // maybe the table already exists, so don't bother checking for errors. + // build the ownership table + mDB->ExecuteSimpleSQL( + NS_LITERAL_CSTRING("CREATE TABLE moz_cache_owners (\n" + " ClientID TEXT,\n" + " Domain TEXT,\n" + " URI TEXT,\n" + " Key TEXT\n" + ");\n")); + // maybe the table already exists, so don't bother checking for errors. + mDB->ExecuteSimpleSQL( NS_LITERAL_CSTRING("CREATE UNIQUE INDEX moz_cache_index" " ON moz_cache (ClientID, Key);")); // maybe the index already exists, so don't bother checking for errors. -#if 0 - // create cache_eviction_observer - res = sqlite3_create_function(mDB, "cache_eviction_observer", - 3, SQLITE_UTF8, this, - nsDiskCacheDevice::EvictionObserver, - NULL, NULL); - if (res != SQLITE_OK) - LOG(("sqlite3_create_function failed [res=%d]\n", res)); -#endif + nsCOMPtr evictionFunction = + new nsOfflineCacheEvictionFunction(this); + if (!evictionFunction) return NS_ERROR_OUT_OF_MEMORY; + + rv = mDB->CreateFunction("cache_eviction_observer", 3, evictionFunction); + NS_ENSURE_SUCCESS(rv, rv); // create all (most) of our statements up front struct { nsCOMPtr &statement; const char *sql; } prepared[] = { - { mStatement_CacheSize, "SELECT Sum(DataSize) from moz_cache;" }, - { mStatement_EntryCount, "SELECT count(*) from moz_cache;" }, - { mStatement_UpdateEntry, "UPDATE moz_cache SET MetaData = ?, Flags = ?, DataSize = ?, FetchCount = ?, LastFetched = ?, LastModified = ?, ExpirationTime = ? WHERE ClientID = ? AND Key = ?;" }, - { mStatement_UpdateEntrySize, "UPDATE moz_cache SET DataSize = ? WHERE ClientID = ? AND Key = ?;" }, - { mStatement_DeleteEntry, "DELETE FROM moz_cache WHERE ClientID = ? AND Key = ?;" }, - { mStatement_FindEntry, "SELECT MetaData, Generation, Flags, DataSize, FetchCount, LastFetched, LastModified, ExpirationTime FROM moz_cache WHERE ClientID = ? AND Key = ?;" }, - { mStatement_BindEntry, "INSERT INTO moz_cache VALUES(?,?,?,?,?,?,?,?,?,?);" } + { mStatement_CacheSize, "SELECT Sum(DataSize) from moz_cache;" }, + { mStatement_EntryCount, "SELECT count(*) from moz_cache;" }, + { mStatement_UpdateEntry, "UPDATE moz_cache SET MetaData = ?, Flags = ?, DataSize = ?, FetchCount = ?, LastFetched = ?, LastModified = ?, ExpirationTime = ? WHERE ClientID = ? AND Key = ?;" }, + { mStatement_UpdateEntrySize, "UPDATE moz_cache SET DataSize = ? WHERE ClientID = ? AND Key = ?;" }, + { mStatement_UpdateEntryFlags, "UPDATE moz_cache SET Flags = ? WHERE ClientID = ? AND Key = ?;" }, + { mStatement_DeleteEntry, "DELETE FROM moz_cache WHERE ClientID = ? AND Key = ?;" }, + { mStatement_FindEntry, "SELECT MetaData, Generation, Flags, DataSize, FetchCount, LastFetched, LastModified, ExpirationTime FROM moz_cache WHERE ClientID = ? AND Key = ?;" }, + { mStatement_BindEntry, "INSERT INTO moz_cache (ClientID, Key, MetaData, Generation, Flags, DataSize, FetchCount, LastFetched, LastModified, ExpirationTime) VALUES(?,?,?,?,?,?,?,?,?,?);" }, + { mStatement_ClearOwnership, "DELETE FROM moz_cache_owners WHERE ClientId = ? AND Domain = ? AND URI = ?;" }, + { mStatement_RemoveOwnership, "DELETE FROM moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ? AND Key = ?;" }, + { mStatement_ClearDomain, "DELETE FROM moz_cache_owners WHERE ClientID = ? AND Domain = ?;" }, + { mStatement_AddOwnership, "INSERT INTO moz_cache_owners (ClientID, Domain, URI, Key) VALUES (?, ?, ?, ?);" }, + { mStatement_CheckOwnership, "SELECT Key From moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ? AND Key = ?;" }, + { mStatement_ListOwned, "SELECT Key FROM moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ?;" }, + { mStatement_DeleteUnowned, "DELETE FROM moz_cache WHERE rowid IN (SELECT moz_cache.rowid FROM moz_cache LEFT OUTER JOIN moz_cache_owners ON (moz_cache.ClientID = moz_cache_owners.ClientID AND moz_cache.Key = moz_cache_owners.Key) WHERE moz_cache.ClientID = ? AND moz_cache_owners.Domain ISNULL);" }, }; for (PRUint32 i=0; iExecuteSimpleSQL( + NS_LITERAL_CSTRING("UPDATE moz_cache" + " SET Flags=(Flags & ~1)" + " WHERE (Flags & 1);")); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; } nsresult -nsDiskCacheDevice::Shutdown() +nsOfflineCacheDevice::Shutdown() { NS_ENSURE_TRUE(mDB, NS_ERROR_NOT_INITIALIZED); -#if 0 - int res; - - // delete cache_eviction_observer - res = sqlite3_create_function(mDB, "cache_eviction_observer", 3, SQLITE_UTF8, - NULL, NULL, NULL, NULL); - if (res != SQLITE_OK) - LOG(("sqlite3_create_function failed [res=%d]\n", res)); - - res = sqlite3_close(mDB); - NS_ENSURE_SQLITE_RESULT(res, NS_ERROR_UNEXPECTED); - - mDB = nsnull; -#endif - mDB = 0; return NS_OK; } const char * -nsDiskCacheDevice::GetDeviceID() +nsOfflineCacheDevice::GetDeviceID() { - return DISK_CACHE_DEVICE_ID; + return OFFLINE_CACHE_DEVICE_ID; } nsCacheEntry * -nsDiskCacheDevice::FindEntry(nsCString *fullKey, PRBool *collision) +nsOfflineCacheDevice::FindEntry(nsCString *fullKey, PRBool *collision) { - LOG(("nsDiskCacheDevice::FindEntry [key=%s]\n", fullKey->get())); + LOG(("nsOfflineCacheDevice::FindEntry [key=%s]\n", fullKey->get())); // SELECT * FROM moz_cache WHERE key = ? @@ -861,8 +834,8 @@ nsDiskCacheDevice::FindEntry(nsCString *fullKey, PRBool *collision) AutoResetStatement statement(mStatement_FindEntry); nsresult rv; - rv = statement->BindCStringParameter(0, cid); - rv |= statement->BindCStringParameter(1, key); + rv = statement->BindUTF8StringParameter(0, nsDependentCString(cid)); + rv |= statement->BindUTF8StringParameter(1, nsDependentCString(key)); NS_ENSURE_SUCCESS(rv, nsnull); PRBool hasRows; @@ -870,8 +843,9 @@ nsDiskCacheDevice::FindEntry(nsCString *fullKey, PRBool *collision) if (NS_FAILED(rv) || !hasRows) return nsnull; // entry not found - nsDiskCacheRecord rec; - statement->AsSharedBlob(0, (const void **) &rec.metaData, &rec.metaDataLen); + nsOfflineCacheRecord rec; + statement->GetSharedBlob(0, &rec.metaDataLen, + (const PRUint8 **) &rec.metaData); rec.generation = statement->AsInt32(1); rec.flags = statement->AsInt32(2); rec.dataSize = statement->AsInt32(3); @@ -890,16 +864,53 @@ nsDiskCacheDevice::FindEntry(nsCString *fullKey, PRBool *collision) rec.lastModified, rec.expirationTime)); - return CreateCacheEntry(this, fullKey, rec); + nsCacheEntry *entry = CreateCacheEntry(this, fullKey, rec); - // XXX we should verify that the corresponding data file exists, - // and if not, then we should delete this row and return null. + if (entry) + { + // make sure that the data file exists + nsOfflineCacheBinding *binding = (nsOfflineCacheBinding*)entry->Data(); + PRBool isFile; + rv = binding->mDataFile->IsFile(&isFile); + if (NS_FAILED(rv) || !isFile) + { + DeleteEntry(entry, PR_FALSE); + delete entry; + return nsnull; + } + + statement->Reset(); + + // mark as active + AutoResetStatement updateStatement(mStatement_UpdateEntryFlags); + rec.flags |= 0x1; + rv |= updateStatement->BindInt32Parameter(0, rec.flags); + rv |= updateStatement->BindUTF8StringParameter(1, nsDependentCString(cid)); + rv |= updateStatement->BindUTF8StringParameter(2, nsDependentCString(key)); + if (NS_FAILED(rv)) + { + delete entry; + return nsnull; + } + + rv = updateStatement->ExecuteStep(&hasRows); + if (NS_FAILED(rv)) + { + delete entry; + return nsnull; + } + + NS_ASSERTION(!hasRows, "UPDATE should not result in output"); + } + + return entry; } nsresult -nsDiskCacheDevice::DeactivateEntry(nsCacheEntry *entry) +nsOfflineCacheDevice::DeactivateEntry(nsCacheEntry *entry) { - LOG(("nsDiskCacheDevice::DeactivateEntry [key=%s]\n", entry->Key()->get())); + LOG(("nsOfflineCacheDevice::DeactivateEntry [key=%s]\n", + entry->Key()->get())); // This method is called to inform us that the nsCacheEntry object is going // away. We should persist anything that needs to be persisted, or if the @@ -925,13 +936,14 @@ nsDiskCacheDevice::DeactivateEntry(nsCacheEntry *entry) } delete entry; + return NS_OK; } nsresult -nsDiskCacheDevice::BindEntry(nsCacheEntry *entry) +nsOfflineCacheDevice::BindEntry(nsCacheEntry *entry) { - LOG(("nsDiskCacheDevice::BindEntry [key=%s]\n", entry->Key()->get())); + LOG(("nsOfflineCacheDevice::BindEntry [key=%s]\n", entry->Key()->get())); NS_ENSURE_STATE(!entry->Data()); @@ -952,12 +964,12 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry *entry) return NS_ERROR_UNEXPECTED; // create binding, pick best generation number - nsRefPtr binding = - nsDiskCacheBinding::Create(mCacheDirectory, entry->Key()->get(), -1); + nsRefPtr binding = + nsOfflineCacheBinding::Create(mCacheDirectory, entry->Key()->get(), -1); if (!binding) return NS_ERROR_OUT_OF_MEMORY; - nsDiskCacheRecord rec; + nsOfflineCacheRecord rec; rec.clientID = cid; rec.key = key; rec.metaData = NULL; // don't write any metadata now. @@ -973,9 +985,9 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry *entry) AutoResetStatement statement(mStatement_BindEntry); nsresult rv; - rv = statement->BindCStringParameter(0, rec.clientID); - rv |= statement->BindCStringParameter(1, rec.key); - rv |= statement->BindDataParameter(2, rec.metaData, rec.metaDataLen); + rv = statement->BindUTF8StringParameter(0, nsDependentCString(rec.clientID)); + rv |= statement->BindUTF8StringParameter(1, nsDependentCString(rec.key)); + rv |= statement->BindBlobParameter(2, rec.metaData, rec.metaDataLen); rv |= statement->BindInt32Parameter(3, rec.generation); rv |= statement->BindInt32Parameter(4, rec.flags); rv |= statement->BindInt32Parameter(5, rec.dataSize); @@ -996,9 +1008,9 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry *entry) } void -nsDiskCacheDevice::DoomEntry(nsCacheEntry *entry) +nsOfflineCacheDevice::DoomEntry(nsCacheEntry *entry) { - LOG(("nsDiskCacheDevice::DoomEntry [key=%s]\n", entry->Key()->get())); + LOG(("nsOfflineCacheDevice::DoomEntry [key=%s]\n", entry->Key()->get())); // This method is called to inform us that we should mark the entry to be // deleted when it is no longer in use. @@ -1010,12 +1022,13 @@ nsDiskCacheDevice::DoomEntry(nsCacheEntry *entry) } nsresult -nsDiskCacheDevice::OpenInputStreamForEntry(nsCacheEntry *entry, - nsCacheAccessMode mode, - PRUint32 offset, - nsIInputStream **result) +nsOfflineCacheDevice::OpenInputStreamForEntry(nsCacheEntry *entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIInputStream **result) { - LOG(("nsDiskCacheDevice::OpenInputStreamForEntry [key=%s]\n", entry->Key()->get())); + LOG(("nsOfflineCacheDevice::OpenInputStreamForEntry [key=%s]\n", + entry->Key()->get())); *result = nsnull; @@ -1024,7 +1037,7 @@ nsDiskCacheDevice::OpenInputStreamForEntry(nsCacheEntry *entry, // return an input stream to the entry's data file. the stream // may be read on a background thread. - nsDiskCacheBinding *binding = (nsDiskCacheBinding *) entry->Data(); + nsOfflineCacheBinding *binding = (nsOfflineCacheBinding *) entry->Data(); NS_ENSURE_STATE(binding); nsCOMPtr in; @@ -1046,12 +1059,13 @@ nsDiskCacheDevice::OpenInputStreamForEntry(nsCacheEntry *entry, } nsresult -nsDiskCacheDevice::OpenOutputStreamForEntry(nsCacheEntry *entry, - nsCacheAccessMode mode, - PRUint32 offset, - nsIOutputStream **result) +nsOfflineCacheDevice::OpenOutputStreamForEntry(nsCacheEntry *entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIOutputStream **result) { - LOG(("nsDiskCacheDevice::OpenOutputStreamForEntry [key=%s]\n", entry->Key()->get())); + LOG(("nsOfflineCacheDevice::OpenOutputStreamForEntry [key=%s]\n", + entry->Key()->get())); *result = nsnull; @@ -1060,7 +1074,7 @@ nsDiskCacheDevice::OpenOutputStreamForEntry(nsCacheEntry *entry, // return an output stream to the entry's data file. we can assume // that the output stream will only be used on the main thread. - nsDiskCacheBinding *binding = (nsDiskCacheBinding *) entry->Data(); + nsOfflineCacheBinding *binding = (nsOfflineCacheBinding *) entry->Data(); NS_ENSURE_STATE(binding); nsCOMPtr out; @@ -1089,11 +1103,12 @@ nsDiskCacheDevice::OpenOutputStreamForEntry(nsCacheEntry *entry, } nsresult -nsDiskCacheDevice::GetFileForEntry(nsCacheEntry *entry, nsIFile **result) +nsOfflineCacheDevice::GetFileForEntry(nsCacheEntry *entry, nsIFile **result) { - LOG(("nsDiskCacheDevice::GetFileForEntry [key=%s]\n", entry->Key()->get())); + LOG(("nsOfflineCacheDevice::GetFileForEntry [key=%s]\n", + entry->Key()->get())); - nsDiskCacheBinding *binding = (nsDiskCacheBinding *) entry->Data(); + nsOfflineCacheBinding *binding = (nsOfflineCacheBinding *) entry->Data(); NS_ENSURE_STATE(binding); NS_IF_ADDREF(*result = binding->mDataFile); @@ -1101,35 +1116,33 @@ nsDiskCacheDevice::GetFileForEntry(nsCacheEntry *entry, nsIFile **result) } nsresult -nsDiskCacheDevice::OnDataSizeChange(nsCacheEntry *entry, PRInt32 deltaSize) +nsOfflineCacheDevice::OnDataSizeChange(nsCacheEntry *entry, PRInt32 deltaSize) { - LOG(("nsDiskCacheDevice::OnDataSizeChange [key=%s delta=%d]\n", + LOG(("nsOfflineCacheDevice::OnDataSizeChange [key=%s delta=%d]\n", entry->Key()->get(), deltaSize)); - // called to notify us of an impending change in the total size of the - // specified entry. we may wish to trigger an eviction cycle at this point. + const PRInt32 DELTA_THRESHOLD = 1<<14; // 16k + + // called to notify us of an impending change in the total size of the + // specified entry. - // update the DataSize attribute for this entry - /* PRUint32 oldSize = entry->DataSize(); NS_ASSERTION(deltaSize >= 0 || PRInt32(oldSize) + deltaSize >= 0, "oops"); PRUint32 newSize = PRInt32(oldSize) + deltaSize; UpdateEntrySize(entry, newSize); - */ - - const PRInt32 DELTA_THRESHOLD = 1<<14; // 16k mDeltaCounter += deltaSize; // this may go negative - // run eviction cycle if (mDeltaCounter >= DELTA_THRESHOLD) { - PRUint32 targetCap, delta = mDeltaCounter; - if (delta <= mCacheCapacity) - targetCap = mCacheCapacity - delta; - else - targetCap = 0; - EvictDiskCacheEntries(targetCap); + if (CacheSize() > mCacheCapacity) { + // the entry will overrun the cache capacity, doom the entry + // and abort + nsresult rv = nsCacheService::DoomEntry(entry); + NS_ASSERTION(NS_SUCCEEDED(rv), "DoomEntry() failed."); + return NS_ERROR_ABORT; + } + mDeltaCounter = 0; // reset counter } @@ -1137,17 +1150,17 @@ nsDiskCacheDevice::OnDataSizeChange(nsCacheEntry *entry, PRInt32 deltaSize) } nsresult -nsDiskCacheDevice::Visit(nsICacheVisitor *visitor) +nsOfflineCacheDevice::Visit(nsICacheVisitor *visitor) { NS_ENSURE_TRUE(Initialized(), NS_ERROR_NOT_INITIALIZED); - // called to enumerate the disk cache. + // called to enumerate the offline cache. nsCOMPtr deviceInfo = - new nsDiskCacheDeviceInfo(this); + new nsOfflineCacheDeviceInfo(this); PRBool keepGoing; - nsresult rv = visitor->VisitDevice(DISK_CACHE_DEVICE_ID, deviceInfo, + nsresult rv = visitor->VisitDevice(OFFLINE_CACHE_DEVICE_ID, deviceInfo, &keepGoing); if (NS_FAILED(rv)) return rv; @@ -1157,8 +1170,8 @@ nsDiskCacheDevice::Visit(nsICacheVisitor *visitor) // SELECT * from moz_cache; - nsDiskCacheRecord rec; - nsRefPtr info = new nsDiskCacheEntryInfo; + nsOfflineCacheRecord rec; + nsRefPtr info = new nsOfflineCacheEntryInfo; if (!info) return NS_ERROR_OUT_OF_MEMORY; info->mRec = &rec; @@ -1177,9 +1190,10 @@ nsDiskCacheDevice::Visit(nsICacheVisitor *visitor) if (NS_FAILED(rv) || !hasRows) break; - rec.clientID = statement->AsSharedCString(0, NULL); - rec.key = statement->AsSharedCString(1, NULL); - statement->AsSharedBlob(2, (const void **) &rec.metaData, &rec.metaDataLen); + statement->GetSharedUTF8String(0, NULL, &rec.clientID); + statement->GetSharedUTF8String(1, NULL, &rec.key); + statement->GetSharedBlob(2, &rec.metaDataLen, + (const PRUint8 **) &rec.metaData); rec.generation = statement->AsInt32(3); rec.flags = statement->AsInt32(4); rec.dataSize = statement->AsInt32(5); @@ -1189,7 +1203,7 @@ nsDiskCacheDevice::Visit(nsICacheVisitor *visitor) rec.expirationTime = statement->AsInt64(9); PRBool keepGoing; - rv = visitor->VisitEntry(DISK_CACHE_DEVICE_ID, info, &keepGoing); + rv = visitor->VisitEntry(OFFLINE_CACHE_DEVICE_ID, info, &keepGoing); if (NS_FAILED(rv) || !keepGoing) break; } @@ -1199,20 +1213,17 @@ nsDiskCacheDevice::Visit(nsICacheVisitor *visitor) } nsresult -nsDiskCacheDevice::EvictEntries(const char *clientID) +nsOfflineCacheDevice::EvictEntries(const char *clientID) { - LOG(("nsDiskCacheDevice::EvictEntries [cid=%s]\n", clientID ? clientID : "")); + LOG(("nsOfflineCacheDevice::EvictEntries [cid=%s]\n", + clientID ? clientID : "")); // called to evict all entries matching the given clientID. // need trigger to fire user defined function after a row is deleted // so we can delete the corresponding data file. + EvictionObserver evictionObserver(mDB); - nsresult rv = EnableEvictionObserver(); - NS_ENSURE_SUCCESS(rv, rv); - - // hook up our eviction observer - const char *deleteCmd; if (clientID) { @@ -1227,69 +1238,199 @@ nsDiskCacheDevice::EvictEntries(const char *clientID) deleteCmd = "DELETE FROM moz_cache WHERE Flags = 0;"; } - rv = mDB->ExecuteSimpleSQL(nsDependentCString(deleteCmd)); + nsresult rv = mDB->ExecuteSimpleSQL(nsDependentCString(deleteCmd)); if (clientID) PR_smprintf_free((char *) deleteCmd); NS_ENSURE_SUCCESS(rv, rv); - DisableEvictionObserver(); - return NS_OK; } nsresult -nsDiskCacheDevice::EvictDiskCacheEntries(PRUint32 desiredCapacity) +nsOfflineCacheDevice::SetOwnedKeys(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerURI, + PRUint32 count, + const char ** keys) { - LOG(("nsDiskCacheDevice::EvictDiskCacheEntries [goal=%u delta=%d]\n", - desiredCapacity, mCacheCapacity - desiredCapacity)); + LOG(("nsOfflineCacheDevice::SetOwnedKeys [cid=%s]\n", clientID)); + mozStorageTransaction transaction(mDB, PR_FALSE); - // need trigger to fire user defined function after a row is deleted - // so we can delete the corresponding data file. + nsDependentCString clientIDStr(clientID); - // BEGIN - // while ("SELECT Sum(DataSize) FROM moz_cache;" > desiredCapacity) - // DELETE FROM moz_cache WHERE Min(LastFetched); - // END - - nsresult rv = EnableEvictionObserver(); + AutoResetStatement clearStatement(mStatement_ClearOwnership); + nsresult rv = clearStatement->BindUTF8StringParameter( + 0, clientIDStr); + rv |= clearStatement->BindUTF8StringParameter(1, ownerDomain); + rv |= clearStatement->BindUTF8StringParameter(2, ownerURI); NS_ENSURE_SUCCESS(rv, rv); - PRUint32 lastCacheSize = PR_UINT32_MAX, cacheSize; - for (;;) + rv = clearStatement->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + for (PRUint32 i = 0; i < count; i++) { - cacheSize = CacheSize(); - if (cacheSize <= desiredCapacity) - break; - if (cacheSize == lastCacheSize) - { - LOG(("unable to reduce cache size to target capacity!\n")); - break; - } + AutoResetStatement insertStatement(mStatement_AddOwnership); + rv = insertStatement->BindUTF8StringParameter(0, clientIDStr); + rv |= insertStatement->BindUTF8StringParameter(1, ownerDomain); + rv |= insertStatement->BindUTF8StringParameter(2, ownerURI); + rv |= insertStatement->BindUTF8StringParameter(3, nsDependentCString(keys[i])); + NS_ENSURE_SUCCESS(rv, rv); - rv = mDB->ExecuteSimpleSQL( - NS_LITERAL_CSTRING("DELETE FROM moz_cache WHERE LastFetched IN (" - " SELECT Min(LastFetched) FROM moz_cache" - " WHERE Flags=0);")); - if (NS_FAILED(rv)) - { - LOG(("failure while deleting Min(LastFetched)\n")); - break; - } - - lastCacheSize = cacheSize; + rv = insertStatement->Execute(); + NS_ENSURE_SUCCESS(rv, rv); } - DisableEvictionObserver(); + return transaction.Commit(); +} + +nsresult +nsOfflineCacheDevice::GetOwnedKeys(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerURI, + PRUint32 * count, + char *** keys) +{ + LOG(("nsOfflineCacheDevice::GetOwnedKeys [cid=%s]\n", clientID)); + + AutoResetStatement statement(mStatement_ListOwned); + nsresult rv = statement->BindUTF8StringParameter( + 0, nsDependentCString(clientID)); + rv |= statement->BindUTF8StringParameter(1, ownerDomain); + rv |= statement->BindUTF8StringParameter(2, ownerURI); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool hasRows; + rv = statement->ExecuteStep(&hasRows); + NS_ENSURE_SUCCESS(rv, rv); + + nsTArray keyArray; + while (hasRows) + { + PRUint32 length; + keyArray.AppendElement( + nsDependentCString(statement->AsSharedUTF8String(0, &length))); + + rv = statement->ExecuteStep(&hasRows); + NS_ENSURE_SUCCESS(rv, rv); + } + + *count = keyArray.Length(); + char **ret = NS_STATIC_CAST(char **, NS_Alloc(*count * sizeof(char*))); + if (!ret) return NS_ERROR_OUT_OF_MEMORY; + + for (PRUint32 i = 0; i < *count; i++) { + ret[i] = NS_strdup(keyArray[i].get()); + if (!ret[i]) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret); + return NS_ERROR_OUT_OF_MEMORY; + } + } + + *keys = ret; + return NS_OK; } +nsresult +nsOfflineCacheDevice::AddOwnedKey(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key) +{ + LOG(("nsOfflineCacheDevice::AddOwnedKey [cid=%s]\n", clientID)); + + PRBool isOwned; + nsresult rv = KeyIsOwned(clientID, ownerDomain, ownerURI, key, &isOwned); + NS_ENSURE_SUCCESS(rv, rv); + if (isOwned) return NS_OK; + + AutoResetStatement statement(mStatement_AddOwnership); + rv = statement->BindUTF8StringParameter(0, nsDependentCString(clientID)); + rv |= statement->BindUTF8StringParameter(1, ownerDomain); + rv |= statement->BindUTF8StringParameter(2, ownerURI); + rv |= statement->BindUTF8StringParameter(3, key); + NS_ENSURE_SUCCESS(rv, rv); + + return statement->Execute(); +} + +nsresult +nsOfflineCacheDevice::RemoveOwnedKey(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key) +{ + LOG(("nsOfflineCacheDevice::RemoveOwnedKey [cid=%s]\n", clientID)); + + PRBool isOwned; + nsresult rv = KeyIsOwned(clientID, ownerDomain, ownerURI, key, &isOwned); + NS_ENSURE_SUCCESS(rv, rv); + if (!isOwned) return NS_ERROR_NOT_AVAILABLE; + + AutoResetStatement statement(mStatement_RemoveOwnership); + rv = statement->BindUTF8StringParameter(0, nsDependentCString(clientID)); + rv |= statement->BindUTF8StringParameter(1, ownerDomain); + rv |= statement->BindUTF8StringParameter(2, ownerURI); + rv |= statement->BindUTF8StringParameter(3, key); + NS_ENSURE_SUCCESS(rv, rv); + + return statement->Execute(); +} + +nsresult +nsOfflineCacheDevice::KeyIsOwned(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key, + PRBool * isOwned) +{ + AutoResetStatement statement(mStatement_CheckOwnership); + nsresult rv = statement->BindUTF8StringParameter( + 0, nsDependentCString(clientID)); + rv |= statement->BindUTF8StringParameter(1, ownerDomain); + rv |= statement->BindUTF8StringParameter(2, ownerURI); + rv |= statement->BindUTF8StringParameter(3, key); + NS_ENSURE_SUCCESS(rv, rv); + + return statement->ExecuteStep(isOwned); +} + +nsresult +nsOfflineCacheDevice::ClearKeysOwnedByDomain(const char *clientID, + const nsACString &domain) +{ + LOG(("nsOfflineCacheDevice::ClearKeysOwnedByDomain [cid=%s]\n", clientID)); + + AutoResetStatement statement(mStatement_ClearDomain); + nsresult rv = statement->BindUTF8StringParameter( + 0, nsDependentCString(clientID)); + rv |= statement->BindUTF8StringParameter(1, domain); + NS_ENSURE_SUCCESS(rv, rv); + + return statement->Execute(); +} + +nsresult +nsOfflineCacheDevice::EvictUnownedEntries(const char *clientID) +{ + LOG(("nsOfflineCacheDevice::EvictUnownedEntries [cid=%s]\n", clientID)); + EvictionObserver evictionObserver(mDB); + + AutoResetStatement statement(mStatement_DeleteUnowned); + nsresult rv = statement->BindUTF8StringParameter( + 0, nsDependentCString(clientID)); + NS_ENSURE_SUCCESS(rv, rv); + + return statement->Execute(); +} /** * Preference accessors */ void -nsDiskCacheDevice::SetCacheParentDirectory(nsILocalFile *parentDir) +nsOfflineCacheDevice::SetCacheParentDirectory(nsILocalFile *parentDir) { if (Initialized()) { @@ -1316,7 +1457,7 @@ nsDiskCacheDevice::SetCacheParentDirectory(nsILocalFile *parentDir) rv = parentDir->Clone(getter_AddRefs(dir)); if (NS_FAILED(rv)) return; - rv = dir->AppendNative(NS_LITERAL_CSTRING("cache_sql")); + rv = dir->AppendNative(NS_LITERAL_CSTRING("OfflineCache")); if (NS_FAILED(rv)) return; @@ -1324,9 +1465,7 @@ nsDiskCacheDevice::SetCacheParentDirectory(nsILocalFile *parentDir) } void -nsDiskCacheDevice::SetCapacity(PRUint32 capacity) +nsOfflineCacheDevice::SetCapacity(PRUint32 capacity) { mCacheCapacity = capacity * 1024; - if (Initialized()) - EvictDiskCacheEntries(mCacheCapacity); } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDeviceSQL.h b/mozilla/netwerk/cache/src/nsDiskCacheDeviceSQL.h index 7cc74a6b852..23ff60d3ea7 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDeviceSQL.h +++ b/mozilla/netwerk/cache/src/nsDiskCacheDeviceSQL.h @@ -35,25 +35,26 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsDiskCacheDeviceSQL_h__ -#define nsDiskCacheDeviceSQL_h__ +#ifndef nsOfflineCacheDevice_h__ +#define nsOfflineCacheDevice_h__ #include "nsCacheDevice.h" #include "nsILocalFile.h" #include "nsIObserver.h" #include "mozIStorageConnection.h" #include "nsCOMPtr.h" +#include "nsVoidArray.h" -class nsDiskCacheDevice : public nsCacheDevice +class nsOfflineCacheDevice : public nsCacheDevice { public: - nsDiskCacheDevice(); + nsOfflineCacheDevice(); /** * nsCacheDevice methods */ - - virtual ~nsDiskCacheDevice(); + + virtual ~nsOfflineCacheDevice(); virtual nsresult Init(); virtual nsresult Shutdown(); @@ -84,6 +85,36 @@ public: virtual nsresult EvictEntries(const char * clientID); + /* Entry ownership */ + nsresult SetOwnedKeys(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerUrl, + PRUint32 count, + const char ** keys); + nsresult GetOwnedKeys(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerUrl, + PRUint32 * count, + char *** keys); + nsresult AddOwnedKey(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key); + nsresult RemoveOwnedKey(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key); + nsresult KeyIsOwned(const char * clientID, + const nsACString & ownerDomain, + const nsACString & ownerURI, + const nsACString & key, + PRBool * isOwned); + + nsresult ClearKeysOwnedByDomain(const char *clientID, + const nsACString &ownerDomain); + nsresult EvictUnownedEntries(const char *clientID); + + /** * Preference accessors */ @@ -96,10 +127,8 @@ public: PRUint32 CacheSize(); PRUint32 EntryCount(); - -private: +private: PRBool Initialized() { return mDB != nsnull; } - nsresult EvictDiskCacheEntries(PRUint32 targetCapacity); nsresult UpdateEntry(nsCacheEntry *entry); nsresult UpdateEntrySize(nsCacheEntry *entry, PRUint32 newSize); nsresult DeleteEntry(nsCacheEntry *entry, PRBool deleteData); @@ -107,23 +136,26 @@ private: nsresult EnableEvictionObserver(); nsresult DisableEvictionObserver(); -#if 0 - // sqlite function for observing DELETE events - static void EvictionObserver(struct sqlite3_context *, int, struct Mem **); -#endif - nsCOMPtr mDB; nsCOMPtr mStatement_CacheSize; nsCOMPtr mStatement_EntryCount; nsCOMPtr mStatement_UpdateEntry; nsCOMPtr mStatement_UpdateEntrySize; + nsCOMPtr mStatement_UpdateEntryFlags; nsCOMPtr mStatement_DeleteEntry; nsCOMPtr mStatement_FindEntry; nsCOMPtr mStatement_BindEntry; + nsCOMPtr mStatement_ClearOwnership; + nsCOMPtr mStatement_RemoveOwnership; + nsCOMPtr mStatement_ClearDomain; + nsCOMPtr mStatement_AddOwnership; + nsCOMPtr mStatement_CheckOwnership; + nsCOMPtr mStatement_DeleteUnowned; + nsCOMPtr mStatement_ListOwned; nsCOMPtr mCacheDirectory; - PRUint32 mCacheCapacity; // XXX need soft/hard limits, currentTotal + PRUint32 mCacheCapacity; PRInt32 mDeltaCounter; }; -#endif // nsDiskCacheDeviceSQL_h__ +#endif // nsOfflineCacheDevice_h__ diff --git a/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp b/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp index 6acd06ccadc..109a0231353 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheEntry.cpp @@ -143,7 +143,7 @@ extern const char DISK_CACHE_DEVICE_ID[]; NS_IMETHODIMP nsDiskCacheEntryInfo::GetDeviceID(char ** deviceID) { NS_ENSURE_ARG_POINTER(deviceID); - *deviceID = nsCRT::strdup(mDeviceID); + *deviceID = NS_strdup(mDeviceID); return *deviceID ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } diff --git a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp index 0f1802a431c..8b50523529c 100644 --- a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp +++ b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp @@ -521,7 +521,7 @@ NS_IMETHODIMP nsMemoryCacheDeviceInfo::GetDescription(char ** result) { NS_ENSURE_ARG_POINTER(result); - *result = nsCRT::strdup("Memory cache device"); + *result = NS_strdup("Memory cache device"); if (!*result) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } diff --git a/mozilla/uriloader/prefetch/nsPrefetchService.cpp b/mozilla/uriloader/prefetch/nsPrefetchService.cpp index 6e23e6f62b8..fc4b242a201 100644 --- a/mozilla/uriloader/prefetch/nsPrefetchService.cpp +++ b/mozilla/uriloader/prefetch/nsPrefetchService.cpp @@ -36,6 +36,9 @@ * ***** END LICENSE BLOCK ***** */ #include "nsPrefetchService.h" +#include "nsICacheSession.h" +#include "nsIOfflineCacheSession.h" +#include "nsICacheService.h" #include "nsIServiceManager.h" #include "nsICategoryManager.h" #include "nsIObserverService.h" @@ -72,9 +75,6 @@ static PRLogModuleInfo *gPrefetchLog; #define LOG(args) PR_LOG(gPrefetchLog, 4, args) #define LOG_ENABLED() PR_LOG_TEST(gPrefetchLog, 4) -static NS_DEFINE_IID(kDocLoaderServiceCID, NS_DOCUMENTLOADER_SERVICE_CID); -static NS_DEFINE_IID(kPrefServiceCID, NS_PREFSERVICE_CID); - #define PREFETCH_PREF "network.prefetch-next" //----------------------------------------------------------------------------- @@ -285,6 +285,7 @@ nsPrefetchService::nsPrefetchService() , mQueueTail(nsnull) , mStopCount(0) , mDisabled(PR_TRUE) + , mFetchedOffline(PR_FALSE) { } @@ -306,7 +307,7 @@ nsPrefetchService::Init() nsresult rv; // read prefs and hook up pref observer - nsCOMPtr prefs(do_GetService(kPrefServiceCID, &rv)); + nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) { PRBool enabled; rv = prefs->GetBoolPref(PREFETCH_PREF, &enabled); @@ -345,6 +346,19 @@ nsPrefetchService::ProcessNextURI() PRBool offline; rv = DequeueURI(getter_AddRefs(uri), getter_AddRefs(referrer), &offline); + if (rv == NS_ERROR_NOT_AVAILABLE && mFetchedOffline) { + // done loading stuff, go ahead and evict unowned entries from + // the offline cache + mFetchedOffline = PR_FALSE; + + nsCOMPtr session; + rv = GetOfflineCacheSession(getter_AddRefs(session)); + if (NS_FAILED(rv)) break; + + session->EvictUnownedEntries(); + break; + } + if (NS_FAILED(rv)) break; #if defined(PR_LOGGING) @@ -385,6 +399,8 @@ nsPrefetchService::ProcessNextURI() continue; } } + + mFetchedOffline = PR_TRUE; } rv = mCurrentChannel->AsyncOpen(listener, nsnull); @@ -400,7 +416,8 @@ void nsPrefetchService::AddProgressListener() { // Register as an observer for the document loader - nsCOMPtr progress(do_GetService(kDocLoaderServiceCID)); + nsCOMPtr progress = + do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID); if (progress) progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT); } @@ -409,7 +426,8 @@ void nsPrefetchService::RemoveProgressListener() { // Register as an observer for the document loader - nsCOMPtr progress(do_GetService(kDocLoaderServiceCID)); + nsCOMPtr progress = + do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID); if (progress) progress->RemoveProgressListener(this); } @@ -480,6 +498,31 @@ nsPrefetchService::EmptyQueue(PRBool includeOffline) } } +nsresult +nsPrefetchService::GetOfflineCacheSession(nsIOfflineCacheSession **aSession) +{ + if (!mOfflineCacheSession) { + nsresult rv; + nsCOMPtr serv = + do_GetService(NS_CACHESERVICE_CONTRACTID, + &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr session; + rv = serv->CreateSession("HTTP-offline", + nsICache::STORE_OFFLINE, + nsICache::STREAM_BASED, + getter_AddRefs(session)); + NS_ENSURE_SUCCESS(rv, rv); + + mOfflineCacheSession = do_QueryInterface(session, &rv); + NS_ENSURE_SUCCESS(rv, rv); + } + + NS_ADDREF(*aSession = mOfflineCacheSession); + return NS_OK; +} + void nsPrefetchService::StartPrefetching() { diff --git a/mozilla/uriloader/prefetch/nsPrefetchService.h b/mozilla/uriloader/prefetch/nsPrefetchService.h index a4c543d9e54..d3169ddb08d 100644 --- a/mozilla/uriloader/prefetch/nsPrefetchService.h +++ b/mozilla/uriloader/prefetch/nsPrefetchService.h @@ -47,12 +47,14 @@ #include "nsIStreamListener.h" #include "nsIChannel.h" #include "nsIURI.h" +#include "nsIDOMDocument.h" #include "nsWeakReference.h" #include "nsCOMPtr.h" class nsPrefetchService; class nsPrefetchListener; class nsPrefetchNode; +class nsIOfflineCacheSession; //----------------------------------------------------------------------------- // nsPrefetchService @@ -88,14 +90,21 @@ private: nsresult EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI, PRBool aOffline); nsresult DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI, PRBool *aOffline); void EmptyQueue(PRBool includeOffline); + nsresult SaveOfflineList(nsIURI *aDocumentUri, + nsIDOMDocument *aDoc); + nsresult GetOfflineCacheSession(nsIOfflineCacheSession **aSession); + void StartPrefetching(); void StopPrefetching(); - nsPrefetchNode *mQueueHead; - nsPrefetchNode *mQueueTail; - nsCOMPtr mCurrentChannel; - PRInt32 mStopCount; - PRBool mDisabled; + nsCOMPtr mOfflineCacheSession; + nsPrefetchNode *mQueueHead; + nsPrefetchNode *mQueueTail; + nsCOMPtr mCurrentChannel; + PRInt32 mStopCount; + PRBool mDisabled; + PRBool mFetchedOffline; + }; //-----------------------------------------------------------------------------