--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -54,16 +54,17 @@ REQUIRES = xpcom \
layout \
widget \
view \
locale \
htmlparser \
js \
webshell \
necko \
+ nkcache \
mimetype \
caps \
lwbrk \
uconv \
docshell \
pref \
xpconnect \
unicharutil \
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -63,16 +63,20 @@
#include "nsIViewManager.h"
#include "nsIContentViewer.h"
#include "nsIAtom.h"
#include "nsGkAtoms.h"
#include "nsIDOMWindowInternal.h"
#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"
#include "nsContentUtils.h"
#include "nsParserUtils.h"
#include "nsCRT.h"
#include "nsEscape.h"
#include "nsWeakReference.h"
@@ -668,17 +672,19 @@ nsContentSink::ProcessLink(nsIContent* a
PRBool hasPrefetch = (linkTypes.IndexOf(NS_LITERAL_STRING("prefetch")) != -1);
// prefetch href if relation is "next" or "prefetch"
if (hasPrefetch || linkTypes.IndexOf(NS_LITERAL_STRING("next")) != -1) {
PrefetchHref(aHref, hasPrefetch, PR_FALSE);
}
// 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?
if (linkTypes.IndexOf(NS_LITERAL_STRING("stylesheet")) == -1) {
return NS_OK;
}
PRBool isAlternate = linkTypes.IndexOf(NS_LITERAL_STRING("alternate")) != -1;
@@ -804,16 +810,125 @@ nsContentSink::PrefetchHref(const nsAStr
if (aOffline)
prefetchService->PrefetchURIForOfflineUse(uri, mDocumentURI, aExplicit);
else
prefetchService->PrefetchURI(uri, mDocumentURI, aExplicit);
}
}
}
+nsresult
+nsContentSink::GetOfflineCacheSession(nsIOfflineCacheSession **aSession)
+{
+ if (!mOfflineCacheSession) {
+ nsresult rv;
+ nsCOMPtr<nsICacheService> serv =
+ do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsICacheSession> 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<nsIOfflineCacheSession> 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<nsIURI> 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<nsIOfflineCacheSession> 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()
{
if (mRef.IsEmpty()) {
return;
}
PRBool didScroll = PR_FALSE;
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -70,16 +70,17 @@ class nsIDocShell;
class nsICSSLoader;
class nsIParser;
class nsIAtom;
class nsIChannel;
class nsIContent;
class nsIViewManager;
class nsNodeInfoManager;
class nsScriptLoader;
+class nsIOfflineCacheSession;
#ifdef NS_DEBUG
extern PRLogModuleInfo* gContentSinkLogModuleInfo;
#define SINK_TRACE_CALLS 0x1
#define SINK_TRACE_REFLOW 0x2
#define SINK_ALWAYS_REFLOW 0x4
@@ -162,16 +163,18 @@ protected:
virtual nsresult ProcessStyleLink(nsIContent* aElement,
const nsSubstring& aHref,
PRBool aAlternate,
const nsSubstring& aTitle,
const nsSubstring& aType,
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);
// Start layout. If aIgnorePendingSheets is true, this will happen even if
// we still have stylesheet loads pending. Otherwise, we'll wait until the
// stylesheets are all done loading.
void StartLayout(PRBool aIgnorePendingSheets);
@@ -247,29 +250,36 @@ protected:
// frequency parser interrupt mode without falling through to the
// logic which decides whether to switch to the high frequency
// parser interrupt mode.
PRUint8 mDeflectedCount;
// Do we notify based on time?
PRPackedBool mNotifyOnTimer;
+ // For saving <link rel="offline-resource"> links
+ nsCOMPtr<nsIOfflineCacheSession> mOfflineCacheSession;
+
// Have we already called BeginUpdate for this set of content changes?
PRUint8 mBeganUpdate : 1;
PRUint8 mLayoutStarted : 1;
PRUint8 mScrolledToRefAlready : 1;
PRUint8 mCanInterruptParser : 1;
PRUint8 mDynamicLowerValue : 1;
PRUint8 mParsing : 1;
PRUint8 mDroppedTimer : 1;
PRUint8 mInTitle : 1;
PRUint8 mChangeScrollPosWhenScrollingToRef : 1;
// If true, we deferred starting layout until sheets load
PRUint8 mDeferredLayoutStart : 1;
-
+ // true if an <link rel="offline-resource"> 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;
// Interrupt parsing during token procesing after # of microseconds
PRInt32 mMaxTokenProcessingTime;
// Switch between intervals when time is exceeded
PRInt32 mDynamicIntervalSwitchThreshold;
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -3007,17 +3007,19 @@ HTMLContentSink::ProcessLINKTag(const ns
if (!hrefVal.IsEmpty()) {
PrefetchHref(hrefVal, hasPrefetch, PR_FALSE);
}
}
if (linkTypes.IndexOf(NS_LITERAL_STRING("offline-resource")) != -1) {
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);
}
}
}
}
}
return result;
}
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -65,17 +65,17 @@ pref("browser.cache.memory.enable",
//pref("browser.cache.memory.capacity", -1);
// -1 = determine dynamically, 0 = none, n = memory capacity in kilobytes
pref("browser.cache.disk_cache_ssl", false);
// 0 = once-per-session, 1 = each-time, 2 = never, 3 = when-appropriate/automatically
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.
pref("browser.sessionhistory.max_total_viewers", -1);
pref("browser.display.use_document_fonts", 1); // 0 = never, 1 = quick, 2 = always
pref("browser.display.use_document_colors", true);
pref("browser.display.use_system_colors", false);
--- a/netwerk/build.mk
+++ b/netwerk/build.mk
@@ -53,16 +53,21 @@ TIERS += zlib \
ifndef MOZ_NATIVE_ZLIB
tier_zlib_dirs += modules/zlib
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))
tier_necko_dirs += modules/libreg
endif
ifndef MOZ_NO_XPCOM_OBSOLETE
tier_necko_dirs += xpcom/obsolete
--- a/netwerk/cache/public/Makefile.in
+++ b/netwerk/cache/public/Makefile.in
@@ -48,13 +48,14 @@ include $(DEPTH)/config/autoconf.mk
XPIDLSRCS = \
nsICache.idl \
nsICacheEntryDescriptor.idl \
nsICacheListener.idl \
nsICacheService.idl \
nsICacheSession.idl \
nsICacheVisitor.idl \
- $(NULL)
+ nsIOfflineCacheSession.idl \
+ $(NULL)
include $(topsrcdir)/config/rules.mk
DEFINES += -DIMPL_NS_NET
new file mode 100644
--- /dev/null
+++ b/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 <dcamp@mozilla.com>
+ *
+ * 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();
+};
--- a/netwerk/cache/src/Makefile.in
+++ b/netwerk/cache/src/Makefile.in
@@ -64,33 +64,34 @@ CPPSRCS = \
nsCacheEntryDescriptor.cpp \
nsCacheMetaData.cpp \
nsCacheService.cpp \
nsCacheSession.cpp \
nsMemoryCacheDevice.cpp \
$(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 \
nsDiskCacheDevice.cpp \
nsDiskCacheEntry.cpp \
nsDiskCacheMap.cpp \
nsDiskCacheStreams.cpp \
nsDeleteDir.cpp \
$(NULL)
endif
+
+ifdef MOZ_STORAGE
+CPPSRCS += \
+ nsDiskCacheDeviceSQL.cpp \
+ $(NULL)
+
+REQUIRES += storage
+DEFINES += -DNECKO_OFFLINE_CACHE
endif
LOCAL_INCLUDES=-I$(srcdir)/../../base/src
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk
--- a/netwerk/cache/src/nsCacheEntry.cpp
+++ b/netwerk/cache/src/nsCacheEntry.cpp
@@ -302,18 +302,18 @@ nsCacheEntryInfo::GetClientID(char ** cl
}
NS_IMETHODIMP
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;
}
NS_IMETHODIMP
nsCacheEntryInfo::GetKey(nsACString &key)
{
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
--- a/netwerk/cache/src/nsCacheEntryDescriptor.cpp
+++ b/netwerk/cache/src/nsCacheEntryDescriptor.cpp
@@ -90,17 +90,17 @@ nsCacheEntryDescriptor::GetClientID(char
NS_IMETHODIMP
nsCacheEntryDescriptor::GetDeviceID(char ** result)
{
NS_ENSURE_ARG_POINTER(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;
}
NS_IMETHODIMP
nsCacheEntryDescriptor::GetKey(nsACString &result)
{
nsCacheServiceAutoLock lock;
@@ -433,17 +433,17 @@ nsCacheEntryDescriptor::GetMetaDataEleme
nsCacheServiceAutoLock lock;
NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_AVAILABLE);
const char *value;
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;
}
NS_IMETHODIMP
nsCacheEntryDescriptor::SetMetaDataElement(const char *key, const char *value)
--- a/netwerk/cache/src/nsCacheService.cpp
+++ b/netwerk/cache/src/nsCacheService.cpp
@@ -43,21 +43,20 @@
#include "nsCache.h"
#include "nsCacheService.h"
#include "nsCacheRequest.h"
#include "nsCacheEntry.h"
#include "nsCacheEntryDescriptor.h"
#include "nsCacheDevice.h"
#include "nsMemoryCacheDevice.h"
#include "nsICacheVisitor.h"
+#include "nsDiskCacheDevice.h"
-#ifdef NECKO_DISK_CACHE_SQL
+#ifdef NECKO_OFFLINE_CACHE
#include "nsDiskCacheDeviceSQL.h"
-#else
-#include "nsDiskCacheDevice.h"
#endif
#include "nsIObserverService.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIPrefBranch2.h"
#include "nsILocalFile.h"
#include "nsIOService.h"
@@ -81,17 +80,17 @@
#define DISK_CACHE_DIR_PREF "browser.cache.disk.parent_directory"
#define DISK_CACHE_CAPACITY_PREF "browser.cache.disk.capacity"
#define DISK_CACHE_MAX_ENTRY_SIZE_PREF "browser.cache.disk.max_entry_size"
#define DISK_CACHE_CAPACITY 51200
#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"
#define MEMORY_CACHE_MAX_ENTRY_SIZE_PREF "browser.cache.memory.max_entry_size"
class nsCacheProfilePrefObserver : public nsIObserver
{
@@ -657,24 +656,26 @@ nsCacheService::Shutdown()
// deallocate memory and disk caches
delete mMemoryDevice;
mMemoryDevice = nsnull;
#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
}
}
NS_METHOD
nsCacheService::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
{
nsresult rv;
@@ -760,29 +761,31 @@ nsCacheService::EvictEntriesForClient(co
if (!mDiskDevice) {
rv = CreateDiskDevice();
if (NS_FAILED(rv)) return rv;
}
rv = mDiskDevice->EvictEntries(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) {
if (!mOfflineDevice) {
rv = CreateOfflineDevice();
if (NS_FAILED(rv)) return rv;
}
rv = mOfflineDevice->EvictEntries(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) {
// If there is no memory device, there is no need to evict it...
if (mMemoryDevice) {
rv = mMemoryDevice->EvictEntries(clientID);
if (NS_FAILED(rv)) return rv;
@@ -822,16 +825,172 @@ nsCacheService::IsStorageEnabledForPolic
if (gService->mEnableOfflineDevice &&
storagePolicy == nsICache::STORE_OFFLINE) {
return PR_TRUE;
}
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)
{
NS_ENSURE_ARG_POINTER(visitor);
nsCacheServiceAutoLock lock;
if (!(mEnableDiskDevice || mEnableMemoryDevice))
@@ -851,26 +1010,28 @@ NS_IMETHODIMP nsCacheService::VisitEntri
if (mEnableDiskDevice) {
if (!mDiskDevice) {
rv = CreateDiskDevice();
if (NS_FAILED(rv)) return rv;
}
rv = mDiskDevice->Visit(visitor);
if (NS_FAILED(rv)) return rv;
}
+#endif // !NECKO_DISK_CACHE
+#ifdef NECKO_OFFLINE_CACHE
if (mEnableOfflineDevice) {
if (!mOfflineDevice) {
rv = CreateOfflineDevice();
if (NS_FAILED(rv)) return rv;
}
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
return NS_OK;
}
@@ -914,29 +1075,28 @@ nsCacheService::CreateDiskDevice()
NS_NOTREACHED("nsCacheService::CreateDiskDevice");
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
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();
if (NS_FAILED(rv)) {
CACHE_LOG_DEBUG(("mOfflineDevice->Init() failed (0x%.8x)\n", rv));
CACHE_LOG_DEBUG((" - disabling offline cache for this session.\n"));
mEnableOfflineDevice = PR_FALSE;
@@ -1277,27 +1437,27 @@ nsCacheService::SearchCacheDevices(nsCSt
}
#endif // !NECKO_DISK_CACHE
}
if (!entry && (policy == nsICache::STORE_OFFLINE ||
(policy == nsICache::STORE_ANYWHERE &&
gIOService->IsOffline()))) {
-#ifdef NECKO_DISK_CACHE
+#ifdef NECKO_OFFLINE_CACHE
if (mEnableOfflineDevice) {
if (!mOfflineDevice) {
nsresult rv = CreateOfflineDevice();
if (NS_FAILED(rv))
return nsnull;
}
entry = mOfflineDevice->FindEntry(key, collision);
}
-#endif
+#endif // !NECKO_OFFLINE_CACHE
}
return entry;
}
nsCacheDevice *
nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry)
@@ -1331,32 +1491,32 @@ nsCacheService::EnsureEntryHasDevice(nsC
entry->MarkBinding(); // enter state of binding
nsresult rv = mMemoryDevice->BindEntry(entry);
entry->ClearBinding(); // exit state of binding
if (NS_SUCCEEDED(rv))
device = mMemoryDevice;
}
}
-#ifdef NECKO_DISK_CACHE
+#ifdef NECKO_OFFLINE_CACHE
if (!device && entry->IsStreamData() &&
entry->IsAllowedOffline() && mEnableOfflineDevice) {
if (!mOfflineDevice) {
(void)CreateOfflineDevice(); // ignore the error (check for mOfflineDevice instead)
}
if (mOfflineDevice) {
entry->MarkBinding();
nsresult rv = mOfflineDevice->BindEntry(entry);
entry->ClearBinding();
if (NS_SUCCEEDED(rv))
device = mOfflineDevice;
}
}
-#endif // ! NECKO_DISK_CACHE
+#endif // ! NECKO_OFFLINE_CACHE
if (device)
entry->SetCacheDevice(device);
return device;
}
nsresult
@@ -1411,25 +1571,27 @@ nsCacheService::OnProfileShutdown(PRBool
#ifdef NECKO_DISK_CACHE
if (gService->mDiskDevice && gService->mEnableDiskDevice) {
if (cleanse)
gService->mDiskDevice->EvictEntries(nsnull);
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);
gService->mOfflineDevice->Shutdown();
gService->mEnableOfflineDevice = PR_FALSE;
}
-#endif // !NECKO_DISK_CACHE
+#endif // !NECKO_OFFLINE_CACHE
if (gService->mMemoryDevice) {
// clear memory cache
gService->mMemoryDevice->EvictEntries(nsnull);
}
}
@@ -1453,30 +1615,32 @@ nsCacheService::OnProfileChanged()
// XXX initialization of mDiskDevice could be made lazily, if mEnableDiskDevice is false
nsresult rv = gService->mDiskDevice->Init();
if (NS_FAILED(rv)) {
NS_ERROR("nsCacheService::OnProfileChanged: Re-initializing disk device failed");
gService->mEnableDiskDevice = PR_FALSE;
// 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());
// XXX initialization of mOfflineDevice could be made lazily, if mEnableOfflineDevice is false
nsresult rv = gService->mOfflineDevice->Init();
if (NS_FAILED(rv)) {
NS_ERROR("nsCacheService::OnProfileChanged: Re-initializing offline device failed");
gService->mEnableOfflineDevice = PR_FALSE;
// XXX delete mOfflineDevice?
}
}
-#endif // !NECKO_DISK_CACHE
+#endif // !NECKO_OFFLINE_CACHE
// If memoryDevice exists, reset its size to the new profile
if (gService->mMemoryDevice) {
if (gService->mEnableMemoryDevice) {
// make sure that capacity is reset to the right value
gService->mMemoryDevice->SetCapacity(gService->mObserver->MemoryCacheCapacity());
} else {
// tell memory device to evict everything
@@ -1520,21 +1684,21 @@ nsCacheService::SetOfflineCacheEnabled(P
}
void
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();
}
void
nsCacheService::SetMemoryCache()
{
--- a/netwerk/cache/src/nsCacheService.h
+++ b/netwerk/cache/src/nsCacheService.h
@@ -55,16 +55,17 @@
#include "nsString.h"
#include "nsProxiedService.h"
#include "nsTArray.h"
class nsCacheRequest;
class nsCacheProfilePrefObserver;
class nsDiskCacheDevice;
class nsMemoryCacheDevice;
+class nsOfflineCacheDevice;
class nsCacheServiceAutoLock;
/******************************************************************************
* nsCacheService
******************************************************************************/
class nsCacheService : public nsICacheService
@@ -91,16 +92,50 @@ public:
nsICacheListener * listener,
nsICacheEntryDescriptor ** result);
static nsresult EvictEntriesForSession(nsCacheSession * session);
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
*/
static void CloseDescriptor(nsCacheEntryDescriptor * descriptor);
static nsresult GetFileForEntry(nsCacheEntry * entry,
nsIFile ** result);
@@ -243,17 +278,17 @@ private:
PRBool mInitialized;
PRBool mEnableMemoryDevice;
PRBool mEnableDiskDevice;
PRBool mEnableOfflineDevice;
nsMemoryCacheDevice * mMemoryDevice;
nsDiskCacheDevice * mDiskDevice;
- nsDiskCacheDevice * mOfflineDevice;
+ nsOfflineCacheDevice * mOfflineDevice;
nsCacheEntryHashTable mActiveEntries;
PRCList mDoomedEntries;
// stats
PRUint32 mTotalEntries;
PRUint32 mCacheHits;
--- a/netwerk/cache/src/nsCacheSession.cpp
+++ b/netwerk/cache/src/nsCacheSession.cpp
@@ -37,19 +37,27 @@
* 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 "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,
PRBool streamBased)
: mClientID(clientID),
mInfo(0)
{
SetStoragePolicy(storagePolicy);
@@ -123,8 +131,56 @@ NS_IMETHODIMP nsCacheSession::EvictEntri
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);
+}
+
--- a/netwerk/cache/src/nsCacheSession.h
+++ b/netwerk/cache/src/nsCacheSession.h
@@ -41,23 +41,26 @@
* ***** END LICENSE BLOCK ***** */
#ifndef _nsCacheSession_h_
#define _nsCacheSession_h_
#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();
nsCString * ClientID() { return &mClientID; }
enum SessionInfo {
eStoragePolicyMask = 0x000000FF,
--- a/netwerk/cache/src/nsDiskCacheDevice.cpp
+++ b/netwerk/cache/src/nsDiskCacheDevice.cpp
@@ -175,17 +175,17 @@ private:
};
NS_IMPL_ISUPPORTS1(nsDiskCacheDeviceInfo, nsICacheDeviceInfo)
/* readonly attribute string description; */
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;
}
/* readonly attribute string usageReport; */
NS_IMETHODIMP nsDiskCacheDeviceInfo::GetUsageReport(char ** usageReport)
{
NS_ENSURE_ARG_POINTER(usageReport);
nsCString buffer;
@@ -924,53 +924,16 @@ nsDiskCacheDevice::SetCacheParentDirecto
rv = parentDir->Clone(getter_AddRefs(directory));
if (NS_FAILED(rv)) return;
rv = directory->AppendNative(NS_LITERAL_CSTRING("Cache"));
if (NS_FAILED(rv)) return;
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<nsIFile> 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)
{
*result = mCacheDirectory;
NS_IF_ADDREF(*result);
}
--- a/netwerk/cache/src/nsDiskCacheDevice.h
+++ b/netwerk/cache/src/nsDiskCacheDevice.h
@@ -88,21 +88,16 @@ public:
virtual nsresult EvictEntries(const char * clientID);
/**
* Preference accessors
*/
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);
PRUint32 getCacheCapacity();
PRUint32 getCacheSize();
PRUint32 getEntryCount();
nsDiskCacheMap * CacheMap() { return &mCacheMap; }
--- a/netwerk/cache/src/nsDiskCacheDeviceSQL.cpp
+++ b/netwerk/cache/src/nsDiskCacheDeviceSQL.cpp
@@ -15,65 +15,52 @@
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by IBM Corporation are Copyright (C) 2004
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
+ * Dave Camp <dcamp@mozilla.com>
*
* 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 files for ftruncate (or equivalent)
-#if defined(XP_UNIX) || defined(XP_BEOS)
-#include <unistd.h>
-#elif defined(XP_WIN)
-#include <windows.h>
-#elif defined(XP_OS2)
-#define INCL_DOSERRORS
-#include <os2.h>
-#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"
#include "nsString.h"
#include "nsPrintfCString.h"
#include "nsCRT.h"
#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)
/*****************************************************************************
* helpers
*/
@@ -115,101 +102,175 @@ class AutoResetStatement
AutoResetStatement(mozIStorageStatement *s)
: mStatement(s) {}
~AutoResetStatement() { mStatement->Reset(); }
mozIStorageStatement *operator->() { return mStatement; }
private:
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.
*/
static PRUint64
DCacheHash(const char * key)
{
PRUint64 h = 0;
for (const PRUint8* s = (PRUint8*) key; *s != '\0'; ++s)
h = (h >> (DCACHE_HASH_BITS - 4)) ^ (h << 4) ^ *s;
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<nsIFile> &file)
{
- // use modified SetEOF from nsFileStreams::SetEOF()
+ 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));
+}
-#if defined(XP_UNIX) || defined(XP_BEOS)
- if (ftruncate(PR_FileDesc2NativeHandle(fd), newEOF) != 0) {
- NS_ERROR("ftruncate failed");
- return NS_ERROR_FAILURE;
+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<nsIFile> 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;
- }
+#if defined(PR_LOGGING)
+ nsCAutoString path;
+ file->GetNativePath(path);
+ LOG((" removing %s\n", path.get()));
+#endif
-#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
+ 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<tr>\n<td><b>Cache Directory:</b></td>\n<td><tt> ");
nsILocalFile *cacheDir = mDevice->CacheDirectory();
if (!cacheDir)
return NS_OK;
@@ -224,57 +285,58 @@ nsDiskCacheDeviceInfo::GetUsageReport(ch
*usageReport = ToNewCString(buffer);
if (!*usageReport)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
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<nsIFile> 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<nsIFile> file;
cacheDir->Clone(getter_AddRefs(file));
if (!file)
return nsnull;
PRUint64 hash = DCacheHash(key);
@@ -315,312 +377,282 @@ nsDiskCacheBinding::Create(nsIFile *cach
else
{
PR_snprintf(leaf, sizeof(leaf), "%014llX-%X", hash, generation);
rv = file->AppendNative(nsDependentCString(leaf));
if (NS_FAILED(rv))
return nsnull;
}
- nsDiskCacheBinding *binding = new nsDiskCacheBinding;
+ nsOfflineCacheBinding *binding = new nsOfflineCacheBinding;
if (!binding)
return nsnull;
binding->mDataFile.swap(file);
binding->mGeneration = 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<nsIFile> &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;
const PRUint8 *metaData;
PRUint32 metaDataLen;
PRInt32 generation;
PRInt32 flags;
PRInt32 dataSize;
PRInt32 fetchCount;
PRInt64 lastFetched;
PRInt64 lastModified;
PRInt64 expirationTime;
};
static nsCacheEntry *
-CreateCacheEntry(nsDiskCacheDevice *device,
+CreateCacheEntry(nsOfflineCacheDevice *device,
const nsCString *fullKey,
- const nsDiskCacheRecord &rec)
+ const nsOfflineCacheRecord &rec)
{
if (rec.flags != 0)
{
LOG(("refusing to load busy entry\n"));
return nsnull;
}
nsCacheEntry *entry;
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;
entry->SetFetchCount((PRUint32) rec.fetchCount);
entry->SetLastFetched(SecondsFromPRTime(rec.lastFetched));
entry->SetLastModified(SecondsFromPRTime(rec.lastModified));
entry->SetExpirationTime(SecondsFromPRTime(rec.expirationTime));
entry->SetDataSize((PRUint32) rec.dataSize);
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;
return nsnull;
}
entry->SetData(binding);
return entry;
}
/******************************************************************************
- * 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;
}
/******************************************************************************
- * 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);
PRBool hasRows;
nsresult rv = statement->ExecuteStep(&hasRows);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasRows, 0);
return (PRUint32) statement->AsInt32(0);
}
PRUint32
-nsDiskCacheDevice::EntryCount()
+nsOfflineCacheDevice::EntryCount()
{
AutoResetStatement statement(mStatement_EntryCount);
PRBool hasRows;
nsresult rv = statement->ExecuteStep(&hasRows);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasRows, 0);
return (PRUint32) statement->AsInt32(0);
}
nsresult
-nsDiskCacheDevice::UpdateEntry(nsCacheEntry *entry)
+nsOfflineCacheDevice::UpdateEntry(nsCacheEntry *entry)
{
// Decompose the key into "ClientID" and "Key"
nsCAutoString keyBuf;
const char *cid, *key;
if (!DecomposeCacheEntryKey(entry->Key(), &cid, &key, keyBuf))
return NS_ERROR_UNEXPECTED;
nsCString metaDataBuf;
PRUint32 mdSize = entry->MetaDataSize();
if (!EnsureStringLength(metaDataBuf, mdSize))
return NS_ERROR_OUT_OF_MEMORY;
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
rec.dataSize = entry->DataSize();
rec.fetchCount = entry->FetchCount();
rec.lastFetched = PRTimeFromSeconds(entry->LastFetched());
rec.lastModified = PRTimeFromSeconds(entry->LastModified());
rec.expirationTime = PRTimeFromSeconds(entry->ExpirationTime());
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;
rv = statement->ExecuteStep(&hasRows);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(!hasRows, "UPDATE should not result in output");
return rv;
}
nsresult
-nsDiskCacheDevice::UpdateEntrySize(nsCacheEntry *entry, PRUint32 newSize)
+nsOfflineCacheDevice::UpdateEntrySize(nsCacheEntry *entry, PRUint32 newSize)
{
// Decompose the key into "ClientID" and "Key"
nsCAutoString keyBuf;
const char *cid, *key;
if (!DecomposeCacheEntryKey(entry->Key(), &cid, &key, keyBuf))
return NS_ERROR_UNEXPECTED;
AutoResetStatement statement(mStatement_UpdateEntrySize);
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;
rv = statement->ExecuteStep(&hasRows);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(!hasRows, "UPDATE should not result in output");
return rv;
}
nsresult
-nsDiskCacheDevice::DeleteEntry(nsCacheEntry *entry, PRBool deleteData)
+nsOfflineCacheDevice::DeleteEntry(nsCacheEntry *entry, PRBool deleteData)
{
if (deleteData)
{
nsresult rv = DeleteData(entry);
if (NS_FAILED(rv))
return rv;
}
@@ -628,128 +660,62 @@ nsDiskCacheDevice::DeleteEntry(nsCacheEn
nsCAutoString keyBuf;
const char *cid, *key;
if (!DecomposeCacheEntryKey(entry->Key(), &cid, &key, keyBuf))
return NS_ERROR_UNEXPECTED;
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;
rv = statement->ExecuteStep(&hasRows);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(!hasRows, "DELETE should not result in output");
return rv;
}
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<nsIFile> 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);
// SetCacheParentDirectory must have been called
NS_ENSURE_TRUE(mCacheDirectory, NS_ERROR_UNEXPECTED);
// make sure the cache directory exists
nsresult rv = EnsureDir(mCacheDirectory);
NS_ENSURE_SUCCESS(rv, rv);
// build path to index file
nsCOMPtr<nsIFile> 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<mozIStorageService> 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));
NS_ENSURE_SUCCESS(rv, rv);
mDB->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA synchronous = OFF;"));
// XXX ... other initialization steps
@@ -772,111 +738,119 @@ nsDiskCacheDevice::Init()
" DataSize INTEGER,\n"
" FetchCount INTEGER,\n"
" LastFetched INTEGER,\n"
" LastModified INTEGER,\n"
" ExpirationTime INTEGER\n"
");\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<mozIStorageFunction> 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<mozIStorageStatement> &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; i<NS_ARRAY_LENGTH(prepared); ++i)
{
rv |= mDB->CreateStatement(nsDependentCString(prepared[i].sql),
getter_AddRefs(prepared[i].statement));
}
NS_ENSURE_SUCCESS(rv, rv);
+ // Clear up any dangling active flags
+ rv = mDB->ExecuteSimpleSQL(
+ 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 = ?
// Decompose the key into "ClientID" and "Key"
nsCAutoString keyBuf;
const char *cid, *key;
if (!DecomposeCacheEntryKey(fullKey, &cid, &key, keyBuf))
return nsnull;
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;
rv = statement->ExecuteStep(&hasRows);
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);
rec.fetchCount = statement->AsInt32(4);
rec.lastFetched = statement->AsInt64(5);
rec.lastModified = statement->AsInt64(6);
rec.expirationTime = statement->AsInt64(7);
@@ -885,26 +859,63 @@ nsDiskCacheDevice::FindEntry(nsCString *
rec.generation,
rec.flags,
rec.dataSize,
rec.fetchCount,
rec.lastFetched,
rec.lastModified,
rec.expirationTime));
- return CreateCacheEntry(this, fullKey, rec);
+ nsCacheEntry *entry = CreateCacheEntry(this, fullKey, rec);
+
+ 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();
- // XXX we should verify that the corresponding data file exists,
- // and if not, then we should delete this row and return null.
+ // 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
// entry is doomed, we can go ahead and clear its storage.
if (entry->IsDoomed())
{
// remove corresponding row and file if they exist
@@ -920,23 +931,24 @@ nsDiskCacheDevice::DeactivateEntry(nsCac
// XXX Assumption: the row already exists because it was either created
// with a call to BindEntry or it was there when we called FindEntry.
UpdateEntry(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());
// This method is called to inform us that we have a new entry. The entry
// may collide with an existing entry in our DB, but if that happens we can
// assume that the entry is not being used.
// INSERT the database row
@@ -947,40 +959,40 @@ nsDiskCacheDevice::BindEntry(nsCacheEntr
// Decompose the key into "ClientID" and "Key"
nsCAutoString keyBuf;
const char *cid, *key;
if (!DecomposeCacheEntryKey(entry->Key(), &cid, &key, keyBuf))
return NS_ERROR_UNEXPECTED;
// create binding, pick best generation number
- nsRefPtr<nsDiskCacheBinding> binding =
- nsDiskCacheBinding::Create(mCacheDirectory, entry->Key()->get(), -1);
+ nsRefPtr<nsOfflineCacheBinding> 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.
rec.metaDataLen = 0;
rec.generation = binding->mGeneration;
rec.flags = 0x1; // mark entry as active, we'll reset this in DeactivateEntry
rec.dataSize = 0;
rec.fetchCount = entry->FetchCount();
rec.lastFetched = PRTimeFromSeconds(entry->LastFetched());
rec.lastModified = PRTimeFromSeconds(entry->LastModified());
rec.expirationTime = PRTimeFromSeconds(entry->ExpirationTime());
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);
rv |= statement->BindInt32Parameter(6, rec.fetchCount);
rv |= statement->BindInt64Parameter(7, rec.lastFetched);
rv |= statement->BindInt64Parameter(8, rec.lastModified);
rv |= statement->BindInt64Parameter(9, rec.expirationTime);
NS_ENSURE_SUCCESS(rv, rv);
@@ -991,45 +1003,46 @@ nsDiskCacheDevice::BindEntry(nsCacheEntr
NS_ASSERTION(!hasRows, "INSERT should not result in output");
entry->SetData(binding);
return NS_OK;
}
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.
// We can go ahead and delete the corresponding row in our table,
// but we must not delete the file on disk until we are deactivated.
DeleteEntry(entry, PR_FALSE);
}
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;
NS_ENSURE_TRUE(offset < entry->DataSize(), NS_ERROR_INVALID_ARG);
// 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<nsIInputStream> in;
NS_NewLocalFileInputStream(getter_AddRefs(in), binding->mDataFile, PR_RDONLY);
if (!in)
return NS_ERROR_UNEXPECTED;
// respect |offset| param
@@ -1041,31 +1054,32 @@ nsDiskCacheDevice::OpenInputStreamForEnt
seekable->Seek(nsISeekableStream::NS_SEEK_SET, offset);
}
in.swap(*result);
return NS_OK;
}
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;
NS_ENSURE_TRUE(offset <= entry->DataSize(), NS_ERROR_INVALID_ARG);
// 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<nsIOutputStream> out;
NS_NewLocalFileOutputStream(getter_AddRefs(out), binding->mDataFile,
PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
00600);
if (!out)
return NS_ERROR_UNEXPECTED;
@@ -1084,86 +1098,85 @@ nsDiskCacheDevice::OpenOutputStreamForEn
if (!bufferedOut)
return NS_ERROR_UNEXPECTED;
bufferedOut.swap(*result);
return NS_OK;
}
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);
return NS_OK;
}
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
- // update the DataSize attribute for this entry
- /*
+ // called to notify us of an impending change in the total size of the
+ // specified 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
}
return NS_OK;
}
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<nsICacheDeviceInfo> 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;
if (!keepGoing)
return NS_OK;
// SELECT * from moz_cache;
- nsDiskCacheRecord rec;
- nsRefPtr<nsDiskCacheEntryInfo> info = new nsDiskCacheEntryInfo;
+ nsOfflineCacheRecord rec;
+ nsRefPtr<nsOfflineCacheEntryInfo> info = new nsOfflineCacheEntryInfo;
if (!info)
return NS_ERROR_OUT_OF_MEMORY;
info->mRec = &rec;
// XXX may want to list columns explicitly
nsCOMPtr<mozIStorageStatement> statement;
rv = mDB->CreateStatement(
NS_LITERAL_CSTRING("SELECT * FROM moz_cache;"),
@@ -1172,129 +1185,257 @@ nsDiskCacheDevice::Visit(nsICacheVisitor
PRBool hasRows;
for (;;)
{
rv = statement->ExecuteStep(&hasRows);
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);
rec.fetchCount = statement->AsInt32(6);
rec.lastFetched = statement->AsInt64(7);
rec.lastModified = statement->AsInt64(8);
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;
}
info->mRec = nsnull;
return NS_OK;
}
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)
{
deleteCmd =
PR_smprintf("DELETE FROM moz_cache WHERE ClientID=%q AND Flags=0;",
clientID);
if (!deleteCmd)
return NS_ERROR_OUT_OF_MEMORY;
}
else
{
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
+ 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);
- nsresult rv = EnableEvictionObserver();
+ rv = clearStatement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
- PRUint32 lastCacheSize = PR_UINT32_MAX, cacheSize;
- for (;;)
+ 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<nsCString> 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())
{
NS_ERROR("cannot switch cache directory once initialized");
return;
}
if (!parentDir)
@@ -1311,22 +1452,20 @@ nsDiskCacheDevice::SetCacheParentDirecto
return;
}
// cache dir may not exist, but that's ok
nsCOMPtr<nsIFile> dir;
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;
mCacheDirectory = do_QueryInterface(dir);
}
void
-nsDiskCacheDevice::SetCapacity(PRUint32 capacity)
+nsOfflineCacheDevice::SetCapacity(PRUint32 capacity)
{
mCacheCapacity = capacity * 1024;
- if (Initialized())
- EvictDiskCacheEntries(mCacheCapacity);
}
--- a/netwerk/cache/src/nsDiskCacheDeviceSQL.h
+++ b/netwerk/cache/src/nsDiskCacheDeviceSQL.h
@@ -30,35 +30,36 @@
* 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 ***** */
-#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();
virtual const char * GetDeviceID(void);
virtual nsCacheEntry * FindEntry(nsCString * key, PRBool *collision);
virtual nsresult DeactivateEntry(nsCacheEntry * entry);
virtual nsresult BindEntry(nsCacheEntry * entry);
@@ -79,51 +80,82 @@ public:
virtual nsresult OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize);
virtual nsresult Visit(nsICacheVisitor * visitor);
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
*/
void SetCacheParentDirectory(nsILocalFile * parentDir);
void SetCapacity(PRUint32 capacity);
nsILocalFile * CacheDirectory() { return mCacheDirectory; }
PRUint32 CacheCapacity() { return mCacheCapacity; }
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);
nsresult DeleteData(nsCacheEntry *entry);
nsresult EnableEvictionObserver();
nsresult DisableEvictionObserver();
-#if 0
- // sqlite function for observing DELETE events
- static void EvictionObserver(struct sqlite3_context *, int, struct Mem **);
-#endif
-
nsCOMPtr<mozIStorageConnection> mDB;
nsCOMPtr<mozIStorageStatement> mStatement_CacheSize;
nsCOMPtr<mozIStorageStatement> mStatement_EntryCount;
nsCOMPtr<mozIStorageStatement> mStatement_UpdateEntry;
nsCOMPtr<mozIStorageStatement> mStatement_UpdateEntrySize;
+ nsCOMPtr<mozIStorageStatement> mStatement_UpdateEntryFlags;
nsCOMPtr<mozIStorageStatement> mStatement_DeleteEntry;
nsCOMPtr<mozIStorageStatement> mStatement_FindEntry;
nsCOMPtr<mozIStorageStatement> mStatement_BindEntry;
+ nsCOMPtr<mozIStorageStatement> mStatement_ClearOwnership;
+ nsCOMPtr<mozIStorageStatement> mStatement_RemoveOwnership;
+ nsCOMPtr<mozIStorageStatement> mStatement_ClearDomain;
+ nsCOMPtr<mozIStorageStatement> mStatement_AddOwnership;
+ nsCOMPtr<mozIStorageStatement> mStatement_CheckOwnership;
+ nsCOMPtr<mozIStorageStatement> mStatement_DeleteUnowned;
+ nsCOMPtr<mozIStorageStatement> mStatement_ListOwned;
nsCOMPtr<nsILocalFile> mCacheDirectory;
- PRUint32 mCacheCapacity; // XXX need soft/hard limits, currentTotal
+ PRUint32 mCacheCapacity;
PRInt32 mDeltaCounter;
};
-#endif // nsDiskCacheDeviceSQL_h__
+#endif // nsOfflineCacheDevice_h__
--- a/netwerk/cache/src/nsDiskCacheEntry.cpp
+++ b/netwerk/cache/src/nsDiskCacheEntry.cpp
@@ -138,17 +138,17 @@ NS_IMETHODIMP nsDiskCacheEntryInfo::GetC
NS_ENSURE_ARG_POINTER(clientID);
return ClientIDFromCacheKey(nsDependentCString(mDiskEntry->Key()), clientID);
}
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;
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetKey(nsACString &clientKey)
{
return ClientKeyFromCacheKey(nsDependentCString(mDiskEntry->Key()), clientKey);
}
--- a/netwerk/cache/src/nsMemoryCacheDevice.cpp
+++ b/netwerk/cache/src/nsMemoryCacheDevice.cpp
@@ -516,17 +516,17 @@ nsMemoryCacheDevice::CheckEntryCount()
NS_IMPL_ISUPPORTS1(nsMemoryCacheDeviceInfo, nsICacheDeviceInfo)
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;
}
NS_IMETHODIMP
nsMemoryCacheDeviceInfo::GetUsageReport(char ** result)
{
--- a/uriloader/prefetch/nsPrefetchService.cpp
+++ b/uriloader/prefetch/nsPrefetchService.cpp
@@ -31,16 +31,19 @@
* 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 "nsPrefetchService.h"
+#include "nsICacheSession.h"
+#include "nsIOfflineCacheSession.h"
+#include "nsICacheService.h"
#include "nsIServiceManager.h"
#include "nsICategoryManager.h"
#include "nsIObserverService.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch2.h"
#include "nsIDocCharset.h"
#include "nsIWebProgress.h"
#include "nsCURILoader.h"
@@ -67,19 +70,16 @@
// this enables PR_LOG_ALWAYS level information and places all output in
// the file http.log
//
static PRLogModuleInfo *gPrefetchLog;
#endif
#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"
//-----------------------------------------------------------------------------
// helpers
//-----------------------------------------------------------------------------
static inline PRUint32
PRTimeToSeconds(PRTime t_usec)
@@ -280,16 +280,17 @@ nsPrefetchListener::OnChannelRedirect(ns
// nsPrefetchService <public>
//-----------------------------------------------------------------------------
nsPrefetchService::nsPrefetchService()
: mQueueHead(nsnull)
, mQueueTail(nsnull)
, mStopCount(0)
, mDisabled(PR_TRUE)
+ , mFetchedOffline(PR_FALSE)
{
}
nsPrefetchService::~nsPrefetchService()
{
// cannot reach destructor if prefetch in progress (listener owns reference
// to this service)
EmptyQueue(PR_TRUE);
@@ -301,17 +302,17 @@ nsPrefetchService::Init()
#if defined(PR_LOGGING)
if (!gPrefetchLog)
gPrefetchLog = PR_NewLogModule("nsPrefetch");
#endif
nsresult rv;
// read prefs and hook up pref observer
- nsCOMPtr<nsIPrefBranch2> prefs(do_GetService(kPrefServiceCID, &rv));
+ nsCOMPtr<nsIPrefBranch2> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv)) {
PRBool enabled;
rv = prefs->GetBoolPref(PREFETCH_PREF, &enabled);
if (NS_SUCCEEDED(rv) && enabled)
mDisabled = PR_FALSE;
prefs->AddObserver(PREFETCH_PREF, this, PR_TRUE);
}
@@ -340,16 +341,29 @@ nsPrefetchService::ProcessNextURI()
nsRefPtr<nsPrefetchListener> listener(new nsPrefetchListener(this));
if (!listener) return;
do {
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<nsIOfflineCacheSession> session;
+ rv = GetOfflineCacheSession(getter_AddRefs(session));
+ if (NS_FAILED(rv)) break;
+
+ session->EvictUnownedEntries();
+ break;
+ }
+
if (NS_FAILED(rv)) break;
#if defined(PR_LOGGING)
if (LOG_ENABLED()) {
nsCAutoString spec;
uri->GetSpec(spec);
LOG(("ProcessNextURI [%s]\n", spec.get()));
}
@@ -380,41 +394,45 @@ nsPrefetchService::ProcessNextURI()
if (offline) {
nsCOMPtr<nsICachingChannel> cachingChannel =
do_QueryInterface(mCurrentChannel);
if (cachingChannel) {
if (NS_FAILED(cachingChannel->SetCacheForOfflineUse(PR_TRUE))) {
continue;
}
}
+
+ mFetchedOffline = PR_TRUE;
}
rv = mCurrentChannel->AsyncOpen(listener, nsnull);
}
while (NS_FAILED(rv));
}
//-----------------------------------------------------------------------------
// nsPrefetchService <private>
//-----------------------------------------------------------------------------
void
nsPrefetchService::AddProgressListener()
{
// Register as an observer for the document loader
- nsCOMPtr<nsIWebProgress> progress(do_GetService(kDocLoaderServiceCID));
+ nsCOMPtr<nsIWebProgress> progress =
+ do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
if (progress)
progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
}
void
nsPrefetchService::RemoveProgressListener()
{
// Register as an observer for the document loader
- nsCOMPtr<nsIWebProgress> progress(do_GetService(kDocLoaderServiceCID));
+ nsCOMPtr<nsIWebProgress> progress =
+ do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
if (progress)
progress->RemoveProgressListener(this);
}
nsresult
nsPrefetchService::EnqueueURI(nsIURI *aURI,
nsIURI *aReferrerURI,
PRBool aOffline)
@@ -475,16 +493,41 @@ nsPrefetchService::EmptyQueue(PRBool inc
}
else
prev = node;
node = next;
}
}
+nsresult
+nsPrefetchService::GetOfflineCacheSession(nsIOfflineCacheSession **aSession)
+{
+ if (!mOfflineCacheSession) {
+ nsresult rv;
+ nsCOMPtr<nsICacheService> serv =
+ do_GetService(NS_CACHESERVICE_CONTRACTID,
+ &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsICacheSession> 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()
{
//
// at initialization time we might miss the first DOCUMENT START
// notification, so we have to be careful to avoid letting our
// stop count go negative.
//
--- a/uriloader/prefetch/nsPrefetchService.h
+++ b/uriloader/prefetch/nsPrefetchService.h
@@ -42,22 +42,24 @@
#include "nsIGenericFactory.h"
#include "nsIObserver.h"
#include "nsIInterfaceRequestor.h"
#include "nsIChannelEventSink.h"
#include "nsIWebProgressListener.h"
#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
//-----------------------------------------------------------------------------
class nsPrefetchService : public nsIPrefetchService
, public nsIWebProgressListener
, public nsIObserver
@@ -83,24 +85,31 @@ private:
PRBool aExplicit,
PRBool aOffline);
void AddProgressListener();
void RemoveProgressListener();
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<nsIChannel> mCurrentChannel;
- PRInt32 mStopCount;
- PRBool mDisabled;
+ nsCOMPtr<nsIOfflineCacheSession> mOfflineCacheSession;
+ nsPrefetchNode *mQueueHead;
+ nsPrefetchNode *mQueueTail;
+ nsCOMPtr<nsIChannel> mCurrentChannel;
+ PRInt32 mStopCount;
+ PRBool mDisabled;
+ PRBool mFetchedOffline;
+
};
//-----------------------------------------------------------------------------
// nsPrefetchListener
//-----------------------------------------------------------------------------
class nsPrefetchListener : public nsIStreamListener
, public nsIInterfaceRequestor