update the offline cache atomically. b=389223, r=biesi, sr=jst

This commit is contained in:
dcamp@mozilla.com 2007-07-24 23:31:27 -07:00
Родитель ea1f2f7e17
Коммит 53f92f7497
14 изменённых файлов: 460 добавлений и 134 удалений

Просмотреть файл

@ -47,6 +47,7 @@
#include "nsNetCID.h" #include "nsNetCID.h"
#include "nsICacheService.h" #include "nsICacheService.h"
#include "nsICacheSession.h" #include "nsICacheSession.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
@ -154,7 +155,6 @@ NS_INTERFACE_MAP_BEGIN(nsDOMOfflineLoadStatusList)
NS_INTERFACE_MAP_ENTRY(nsIDOMLoadStatusList) NS_INTERFACE_MAP_ENTRY(nsIDOMLoadStatusList)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsIOfflineCacheUpdateObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(LoadStatusList) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(LoadStatusList)
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
@ -199,7 +199,7 @@ nsDOMOfflineLoadStatusList::Init()
rv = cacheUpdateService->GetUpdate(i, getter_AddRefs(cacheUpdate)); rv = cacheUpdateService->GetUpdate(i, getter_AddRefs(cacheUpdate));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = WatchUpdate(cacheUpdate); UpdateAdded(cacheUpdate);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
@ -210,6 +210,8 @@ nsDOMOfflineLoadStatusList::Init()
rv = observerServ->AddObserver(this, "offline-cache-update-added", PR_TRUE); rv = observerServ->AddObserver(this, "offline-cache-update-added", PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = observerServ->AddObserver(this, "offline-cache-update-completed", PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
} }
@ -231,7 +233,7 @@ nsDOMOfflineLoadStatusList::FindWrapper(nsIDOMLoadStatus *aStatus,
} }
nsresult nsresult
nsDOMOfflineLoadStatusList::WatchUpdate(nsIOfflineCacheUpdate *aUpdate) nsDOMOfflineLoadStatusList::UpdateAdded(nsIOfflineCacheUpdate *aUpdate)
{ {
nsCAutoString owner; nsCAutoString owner;
nsresult rv = aUpdate->GetUpdateDomain(owner); nsresult rv = aUpdate->GetUpdateDomain(owner);
@ -256,19 +258,50 @@ nsDOMOfflineLoadStatusList::WatchUpdate(nsIOfflineCacheUpdate *aUpdate)
mItems.AppendObject(wrapper); mItems.AppendObject(wrapper);
rv = SendLoadEvent(NS_LITERAL_STRING(LOADREQUESTED_STR), SendLoadEvent(NS_LITERAL_STRING(LOADREQUESTED_STR),
mLoadRequestedEventListeners, mLoadRequestedEventListeners,
wrapper); wrapper);
NS_ENSURE_SUCCESS(rv, rv);
} }
NS_ENSURE_SUCCESS(rv, rv);
rv = aUpdate->AddObserver(this, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsDOMOfflineLoadStatusList::UpdateCompleted(nsIOfflineCacheUpdate *aUpdate)
{
nsCAutoString owner;
nsresult rv = aUpdate->GetUpdateDomain(owner);
NS_ENSURE_SUCCESS(rv, rv);
if (owner != mHostPort) {
// This update doesn't belong to us
return NS_OK;
}
PRUint32 numItems;
rv = aUpdate->GetCount(&numItems);
NS_ENSURE_SUCCESS(rv, rv);
for (PRUint32 i = 0; i < numItems; i++) {
nsCOMPtr<nsIDOMLoadStatus> status;
rv = aUpdate->Item(i, getter_AddRefs(status));
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 index;
nsCOMPtr<nsIDOMLoadStatus> wrapper = FindWrapper(status, &index);
if (wrapper) {
mItems.RemoveObjectAt(index);
nsresult rv = SendLoadEvent(NS_LITERAL_STRING(LOADCOMPLETED_STR),
mLoadCompletedEventListeners,
wrapper);
NS_ENSURE_SUCCESS(rv, rv);
}
}
return NS_OK;
}
// //
// nsDOMOfflineLoadStatusList::nsIDOMLoadStatusList // nsDOMOfflineLoadStatusList::nsIDOMLoadStatusList
// //
@ -468,29 +501,13 @@ nsDOMOfflineLoadStatusList::Observe(nsISupports *aSubject,
if (!strcmp(aTopic, "offline-cache-update-added")) { if (!strcmp(aTopic, "offline-cache-update-added")) {
nsCOMPtr<nsIOfflineCacheUpdate> update = do_QueryInterface(aSubject); nsCOMPtr<nsIOfflineCacheUpdate> update = do_QueryInterface(aSubject);
if (update) { if (update) {
rv = WatchUpdate(update); UpdateAdded(update);
NS_ENSURE_SUCCESS(rv, rv);
} }
} else if (!strcmp(aTopic, "offline-cache-update-completed")) {
nsCOMPtr<nsIOfflineCacheUpdate> update = do_QueryInterface(aSubject);
if (update) {
UpdateCompleted(update);
} }
return NS_OK;
}
//
// nsDOMLoadStatusList::nsIOfflineCacheUpdateObserver
//
NS_IMETHODIMP
nsDOMOfflineLoadStatusList::ItemCompleted(nsIDOMLoadStatus *aItem)
{
PRUint32 index;
nsCOMPtr<nsIDOMLoadStatus> wrapper = FindWrapper(aItem, &index);
if (wrapper) {
mItems.RemoveObjectAt(index);
nsresult rv = SendLoadEvent(NS_LITERAL_STRING(LOADCOMPLETED_STR),
mLoadCompletedEventListeners,
wrapper);
NS_ENSURE_SUCCESS(rv, rv);
} }
return NS_OK; return NS_OK;

Просмотреть файл

@ -59,7 +59,6 @@ class nsDOMOfflineLoadStatus;
class nsDOMOfflineLoadStatusList : public nsIDOMLoadStatusList, class nsDOMOfflineLoadStatusList : public nsIDOMLoadStatusList,
public nsIDOMEventTarget, public nsIDOMEventTarget,
public nsIObserver, public nsIObserver,
public nsIOfflineCacheUpdateObserver,
public nsSupportsWeakReference public nsSupportsWeakReference
{ {
public: public:
@ -67,7 +66,6 @@ public:
NS_DECL_NSIDOMLOADSTATUSLIST NS_DECL_NSIDOMLOADSTATUSLIST
NS_DECL_NSIDOMEVENTTARGET NS_DECL_NSIDOMEVENTTARGET
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
NS_DECL_NSIOFFLINECACHEUPDATEOBSERVER
nsDOMOfflineLoadStatusList(nsIURI *aURI); nsDOMOfflineLoadStatusList(nsIURI *aURI);
virtual ~nsDOMOfflineLoadStatusList(); virtual ~nsDOMOfflineLoadStatusList();
@ -75,7 +73,8 @@ public:
nsresult Init(); nsresult Init();
private : private :
nsresult WatchUpdate (nsIOfflineCacheUpdate *aUpdate); nsresult UpdateAdded (nsIOfflineCacheUpdate *aUpdate);
nsresult UpdateCompleted (nsIOfflineCacheUpdate *aUpdate);
nsIDOMLoadStatus *FindWrapper (nsIDOMLoadStatus *aStatus, nsIDOMLoadStatus *FindWrapper (nsIDOMLoadStatus *aStatus,
PRUint32 *aIndex); PRUint32 *aIndex);
void NotifyEventListeners(const nsCOMArray<nsIDOMEventListener>& aListeners, void NotifyEventListeners(const nsCOMArray<nsIDOMEventListener>& aListeners,
@ -95,6 +94,7 @@ private :
nsCOMArray<nsIDOMEventListener> mLoadRequestedEventListeners; nsCOMArray<nsIDOMEventListener> mLoadRequestedEventListeners;
nsCOMArray<nsIDOMEventListener> mLoadCompletedEventListeners; nsCOMArray<nsIDOMEventListener> mLoadCompletedEventListeners;
nsCOMArray<nsIDOMEventListener> mUpdateCompletedEventListeners;
}; };
class nsDOMLoadStatusEvent : public nsDOMEvent, class nsDOMLoadStatusEvent : public nsDOMEvent,

Просмотреть файл

@ -50,7 +50,7 @@ interface nsIFile;
* 3) Support for uniquely identifying cached data in cases when the URL * 3) Support for uniquely identifying cached data in cases when the URL
* is insufficient (e.g., HTTP form submission). * is insufficient (e.g., HTTP form submission).
*/ */
[scriptable, uuid(afafb719-bdf5-49c8-a4a9-db39ec331c9b)] [scriptable, uuid(09556ba7-b13d-47d2-b154-fe690b063899)]
interface nsICachingChannel : nsISupports interface nsICachingChannel : nsISupports
{ {
/** /**
@ -105,6 +105,12 @@ interface nsICachingChannel : nsISupports
*/ */
attribute boolean cacheForOfflineUse; attribute boolean cacheForOfflineUse;
/**
* The session into which to cache offline data. If not specified,
* data will be placed in "HTTP-offline"
*/
attribute ACString offlineCacheClientID;
/** /**
* Get the "file" where the cached data can be found. This is valid for * Get the "file" where the cached data can be found. This is valid for
* as long as a reference to the cache token is held. This may return * as long as a reference to the cache token is held. This may return

11
netwerk/cache/public/nsICacheService.idl поставляемый
Просмотреть файл

@ -48,7 +48,7 @@ interface nsICacheListener;
interface nsICacheSession; interface nsICacheSession;
interface nsICacheVisitor; interface nsICacheVisitor;
[scriptable, uuid(de114eb4-29fc-4959-b2f7-2d03eb9bc771)] [scriptable, uuid(98dd0187-aad4-4cab-82c5-1adddef3629d)]
interface nsICacheService : nsISupports interface nsICacheService : nsISupports
{ {
/** /**
@ -84,6 +84,15 @@ interface nsICacheService : nsISupports
* Evicts all entries in all devices implied by the storage policy. * Evicts all entries in all devices implied by the storage policy.
*/ */
void evictEntries(in nsCacheStoragePolicy storagePolicy); void evictEntries(in nsCacheStoragePolicy storagePolicy);
/**
* Return a unique, temporary cache client ID.
*
* This is used by the offline cache. The offline cache lets clients
* accumulate entries in a temporary client and merge them in as a group
* using nsIOfflineCacheSession.mergeTemporaryClient().
*/
ACString createTemporaryClientID(in nsCacheStoragePolicy storagePolicy);
}; };
%{C++ %{C++

Просмотреть файл

@ -40,9 +40,6 @@
#include "nsISupports.idl" #include "nsISupports.idl"
#include "nsICache.idl" #include "nsICache.idl"
[scriptable, uuid(0058c32b-0d93-4cf8-a561-e6f749c8a7b1)]
interface nsIOfflineCacheSession : nsISupports
{
/** /**
* The offline cache is meant to reliably store resources for * The offline cache is meant to reliably store resources for
* offline use. The expected semantics are: * offline use. The expected semantics are:
@ -66,11 +63,16 @@ interface nsIOfflineCacheSession : nsISupports
* the domain. * the domain.
*/ */
[scriptable, uuid(de7875e5-a7e2-4d8d-ad01-807ef55ef8c0)]
interface nsIOfflineCacheSession : nsISupports
{
/** /**
* Gets the list of owner domains in the cache. * Gets the list of owner domains in the cache.
* *
* @param count The number of domains returned * @param count
* @param uris The domains that own resources in the cache * The number of domains returned
* @param uris
* The domains that own resources in the cache
*/ */
void getOwnerDomains(out unsigned long count, void getOwnerDomains(out unsigned long count,
[array, size_is(count)]out string domains); [array, size_is(count)]out string domains);
@ -78,9 +80,12 @@ interface nsIOfflineCacheSession : nsISupports
/** /**
* Gets the list of owner URIs associated with a domain. * Gets the list of owner URIs associated with a domain.
* *
* @param ownerDomain The domain to query * @param ownerDomain
* @param count The number of uris returned * The domain to query
* @param uris The uris in this domain that own resources * @param count
* The number of uris returned
* @param uris
* The uris in this domain that own resources
*/ */
void getOwnerURIs(in ACString ownerDomain, void getOwnerURIs(in ACString ownerDomain,
out unsigned long count, out unsigned long count,
@ -96,12 +101,16 @@ interface nsIOfflineCacheSession : nsISupports
* an entry is created with this key, it will be owned by the * an entry is created with this key, it will be owned by the
* domain/URI pair. * domain/URI pair.
* *
* @param ownerDomain The domain that owns the resources. * @param ownerDomain
* @param ownerURI The specific URI that owns the resources. This can * The domain that owns the resources.
* be empty if no URI specifically owns the resources. * @param ownerURI
* @param count The number of keys in keys. * The specific URI that owns the resources. This can be empty if
* @param keys The keys that the domain/URI pair own. This can be empty * no URI specifically owns the resources.
* to clear ownership for the domain/URI pair. * @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, void setOwnedKeys(in ACString ownerDomain,
in ACString ownerURI, in ACString ownerURI,
@ -111,11 +120,15 @@ interface nsIOfflineCacheSession : nsISupports
/** /**
* Gets the list of resources owned by a given domain/URI pair. * Gets the list of resources owned by a given domain/URI pair.
* *
* @param ownerDomain The domain that owns the resources. * @param ownerDomain
* @param ownerURI The specific URI that owns the resources. This can * The domain that owns the resources.
* be empty if no URI specifically owns the resources. * @param ownerURI
* @param count The number of keys in keys. * The specific URI that owns the resources. This can be empty
* @param keys The keys that the domain/URI pair own. * 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, void getOwnedKeys(in ACString ownerDomain,
in ACString ownerURI, in ACString ownerURI,
@ -129,10 +142,13 @@ interface nsIOfflineCacheSession : nsISupports
* an entry is created with this key, it will be owned by the * an entry is created with this key, it will be owned by the
* domain/URI pair. * domain/URI pair.
* *
* @param ownerDomain The domain that owns the resources. * @param ownerDomain
* @param ownerURI The specific URI that owns the resources. This can * The domain that owns the resources.
* be empty if no URI specifically owns the resources. * @param ownerURI
* @param key The key to add. * 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, void addOwnedKey(in ACString ownerDomain,
in ACString ownerURI, in ACString ownerURI,
@ -144,9 +160,11 @@ interface nsIOfflineCacheSession : nsISupports
* If the key does not exist, an NS_ERROR_NOT_AVAILABLE exception * If the key does not exist, an NS_ERROR_NOT_AVAILABLE exception
* will be thrown. * will be thrown.
* *
* @param ownerDomain The domain that owns the resources. * @param ownerDomain
* @param ownerURI The specific URI that owns the resources. This can * The domain that owns the resources.
* be empty if no URI specifically 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. * @param key The key to remove.
*/ */
void removeOwnedKey(in ACString ownerDomain, void removeOwnedKey(in ACString ownerDomain,
@ -156,9 +174,11 @@ interface nsIOfflineCacheSession : nsISupports
/** /**
* Checks whether a key is owned by a given domain/URI pair. * Checks whether a key is owned by a given domain/URI pair.
* *
* @param ownerDomain The domain that owns the resources. * @param ownerDomain
* @param ownerURI The specific URI that owns the resources. This can * The domain that owns the resources.
* be empty if no URI specifically 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 * @param key The key to check
*/ */
boolean keyIsOwned(in ACString ownerDomain, boolean keyIsOwned(in ACString ownerDomain,
@ -177,4 +197,17 @@ interface nsIOfflineCacheSession : nsISupports
* Evict all entries that are not owned by a domain. * Evict all entries that are not owned by a domain.
*/ */
void evictUnownedEntries(); void evictUnownedEntries();
/**
* Merge the items from a temporary clientID in to this client. This lets
* offline cache updates accumulate in a temporary client and be moved
* in all at once.
*
* Entries in the temporary client will replace any entries in this client
* with the same cache key.
*
* Ownership lists for a given domain/URI pair from the temporary client
* will replace ownership lists for the same domain/URI pair.
*/
void mergeTemporaryClientID(in ACString temporaryClientID);
}; };

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

@ -1030,6 +1030,25 @@ nsresult nsCacheService::EvictUnownedOfflineEntries(nsCacheSession * session)
#endif #endif
} }
nsresult nsCacheService::MergeTemporaryClientID(nsCacheSession * session,
const nsACString & clientID)
{
#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->MergeTemporaryClientID
(session->ClientID()->get(), PromiseFlatCString(clientID).get());
#else // !NECKO_OFFLINE_CACHE
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor) NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor)
{ {
NS_ENSURE_ARG_POINTER(visitor); NS_ENSURE_ARG_POINTER(visitor);
@ -1083,6 +1102,24 @@ NS_IMETHODIMP nsCacheService::EvictEntries(nsCacheStoragePolicy storagePolicy)
return EvictEntriesForClient(nsnull, storagePolicy); return EvictEntriesForClient(nsnull, storagePolicy);
} }
NS_IMETHODIMP nsCacheService::CreateTemporaryClientID(nsCacheStoragePolicy storagePolicy,
nsACString &clientID)
{
#ifdef NECKO_OFFLINE_CACHE
// Only the offline cache device supports temporary clients
if (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->CreateTemporaryClientID(clientID);
#else // !NECKO_OFFLINE_CACHE
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
/** /**
* Internal Methods * Internal Methods

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

@ -139,6 +139,9 @@ public:
static nsresult EvictUnownedOfflineEntries(nsCacheSession * session); static nsresult EvictUnownedOfflineEntries(nsCacheSession * session);
static nsresult MergeTemporaryClientID(nsCacheSession * session,
const nsACString & fromClientID);
/** /**
* Methods called by nsCacheEntryDescriptor * Methods called by nsCacheEntryDescriptor
*/ */

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

@ -197,3 +197,7 @@ NS_IMETHODIMP nsCacheSession::EvictUnownedEntries()
return nsCacheService::EvictUnownedOfflineEntries(this); return nsCacheService::EvictUnownedOfflineEntries(this);
} }
NS_IMETHODIMP nsCacheSession::MergeTemporaryClientID(const nsACString& fromClientID)
{
return nsCacheService::MergeTemporaryClientID(this, fromClientID);
}

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

@ -60,6 +60,7 @@ static const char OFFLINE_CACHE_DEVICE_ID[] = { "offline" };
#define LOG(args) CACHE_LOG_DEBUG(args) #define LOG(args) CACHE_LOG_DEBUG(args)
static PRUint32 gNextTemporaryClientID = 0;
/***************************************************************************** /*****************************************************************************
* helpers * helpers
@ -118,7 +119,7 @@ class EvictionObserver
NS_LITERAL_CSTRING("CREATE TEMP TRIGGER cache_on_delete AFTER DELETE" NS_LITERAL_CSTRING("CREATE TEMP TRIGGER cache_on_delete AFTER DELETE"
" ON moz_cache FOR EACH ROW BEGIN SELECT" " ON moz_cache FOR EACH ROW BEGIN SELECT"
" cache_eviction_observer(" " cache_eviction_observer("
" OLD.clientID, OLD.key, OLD.generation);" " OLD.key, OLD.generation);"
" END;")); " END;"));
} }
@ -175,19 +176,14 @@ NS_IMPL_ISUPPORTS1(nsOfflineCacheEvictionFunction, mozIStorageFunction)
// helper function for directly exposing the same data file binding // helper function for directly exposing the same data file binding
// path algorithm used in nsOfflineCacheBinding::Create // path algorithm used in nsOfflineCacheBinding::Create
static nsresult static nsresult
GetCacheDataFile(nsIFile *cacheDir, const char *cid, const char *key, GetCacheDataFile(nsIFile *cacheDir, const char *key,
int generation, nsCOMPtr<nsIFile> &file) int generation, nsCOMPtr<nsIFile> &file)
{ {
cacheDir->Clone(getter_AddRefs(file)); cacheDir->Clone(getter_AddRefs(file));
if (!file) if (!file)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
nsCAutoString fullKey; PRUint64 hash = DCacheHash(key);
fullKey.Append(cid);
fullKey.Append(':');
fullKey.Append(key);
PRUint64 hash = DCacheHash(fullKey.get());
PRUint32 dir1 = (PRUint32) (hash & 0x0F); PRUint32 dir1 = (PRUint32) (hash & 0x0F);
PRUint32 dir2 = (PRUint32)((hash & 0xF0) >> 4); PRUint32 dir2 = (PRUint32)((hash & 0xF0) >> 4);
@ -212,20 +208,19 @@ nsOfflineCacheEvictionFunction::OnFunctionCall(mozIStorageValueArray *values, ns
PRUint32 numEntries; PRUint32 numEntries;
nsresult rv = values->GetNumEntries(&numEntries); nsresult rv = values->GetNumEntries(&numEntries);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(numEntries == 3, "unexpected number of arguments"); NS_ASSERTION(numEntries == 2, "unexpected number of arguments");
PRUint32 valueLen; PRUint32 valueLen;
const char *cid = values->AsSharedUTF8String(0, &valueLen); const char *key = values->AsSharedUTF8String(0, &valueLen);
const char *key = values->AsSharedUTF8String(1, &valueLen); int generation = values->AsInt32(1);
int generation = values->AsInt32(2);
nsCOMPtr<nsIFile> file; nsCOMPtr<nsIFile> file;
rv = GetCacheDataFile(mDevice->CacheDirectory(), cid, key, rv = GetCacheDataFile(mDevice->CacheDirectory(), key,
generation, file); generation, file);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
{ {
LOG(("GetCacheDataFile [cid=%s key=%s generation=%d] failed [rv=%x]!\n", LOG(("GetCacheDataFile [key=%s generation=%d] failed [rv=%x]!\n",
cid, key, generation, rv)); key, generation, rv));
return rv; return rv;
} }
@ -323,7 +318,7 @@ public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
static nsOfflineCacheBinding * static nsOfflineCacheBinding *
Create(nsIFile *cacheDir, const char *key, int generation); Create(nsIFile *cacheDir, const nsCString *key, int generation);
nsCOMPtr<nsIFile> mDataFile; nsCOMPtr<nsIFile> mDataFile;
int mGeneration; int mGeneration;
@ -333,7 +328,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS0(nsOfflineCacheBinding)
nsOfflineCacheBinding * nsOfflineCacheBinding *
nsOfflineCacheBinding::Create(nsIFile *cacheDir, nsOfflineCacheBinding::Create(nsIFile *cacheDir,
const char *key, const nsCString *fullKey,
int generation) int generation)
{ {
nsCOMPtr<nsIFile> file; nsCOMPtr<nsIFile> file;
@ -341,6 +336,11 @@ nsOfflineCacheBinding::Create(nsIFile *cacheDir,
if (!file) if (!file)
return nsnull; return nsnull;
nsCAutoString keyBuf;
const char *cid, *key;
if (!DecomposeCacheEntryKey(fullKey, &cid, &key, keyBuf))
return nsnull;
PRUint64 hash = DCacheHash(key); PRUint64 hash = DCacheHash(key);
PRUint32 dir1 = (PRUint32) (hash & 0x0F); PRUint32 dir1 = (PRUint32) (hash & 0x0F);
@ -444,7 +444,7 @@ CreateCacheEntry(nsOfflineCacheDevice *device,
// create a binding object for this entry // create a binding object for this entry
nsOfflineCacheBinding *binding = nsOfflineCacheBinding *binding =
nsOfflineCacheBinding::Create(device->CacheDirectory(), nsOfflineCacheBinding::Create(device->CacheDirectory(),
fullKey->get(), fullKey,
rec.generation); rec.generation);
if (!binding) if (!binding)
{ {
@ -765,7 +765,7 @@ nsOfflineCacheDevice::Init()
new nsOfflineCacheEvictionFunction(this); new nsOfflineCacheEvictionFunction(this);
if (!evictionFunction) return NS_ERROR_OUT_OF_MEMORY; if (!evictionFunction) return NS_ERROR_OUT_OF_MEMORY;
rv = mDB->CreateFunction(NS_LITERAL_CSTRING("cache_eviction_observer"), 3, evictionFunction); rv = mDB->CreateFunction(NS_LITERAL_CSTRING("cache_eviction_observer"), 2, evictionFunction);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// create all (most) of our statements up front // create all (most) of our statements up front
@ -789,9 +789,11 @@ nsOfflineCacheDevice::Init()
StatementSql ( mStatement_AddOwnership, "INSERT INTO moz_cache_owners (ClientID, Domain, URI, Key) VALUES (?, ?, ?, ?);" ), StatementSql ( mStatement_AddOwnership, "INSERT INTO moz_cache_owners (ClientID, Domain, URI, Key) VALUES (?, ?, ?, ?);" ),
StatementSql ( mStatement_CheckOwnership, "SELECT Key From moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ? AND Key = ?;" ), StatementSql ( mStatement_CheckOwnership, "SELECT Key From moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ? AND Key = ?;" ),
StatementSql ( mStatement_ListOwned, "SELECT Key FROM moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ?;" ), StatementSql ( mStatement_ListOwned, "SELECT Key FROM moz_cache_owners WHERE ClientID = ? AND Domain = ? AND URI = ?;" ),
StatementSql ( mStatement_ListOwners, "SELECT DISTINCT Domain, URI FROM moz_cache_owners WHERE ClientID = ?;"),
StatementSql ( mStatement_ListOwnerDomains, "SELECT DISTINCT Domain FROM moz_cache_owners WHERE ClientID = ?;"), StatementSql ( mStatement_ListOwnerDomains, "SELECT DISTINCT Domain FROM moz_cache_owners WHERE ClientID = ?;"),
StatementSql ( mStatement_ListOwnerURIs, "SELECT DISTINCT URI FROM moz_cache_owners WHERE ClientID = ? AND Domain = ?;"), StatementSql ( mStatement_ListOwnerURIs, "SELECT DISTINCT URI FROM moz_cache_owners WHERE ClientID = ? AND Domain = ?;"),
StatementSql ( 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);" ) StatementSql ( 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);" ),
StatementSql ( mStatement_SwapClientID, "UPDATE OR REPLACE moz_cache SET ClientID = ? WHERE ClientID = ?;")
}; };
for (PRUint32 i=0; i<NS_ARRAY_LENGTH(prepared); ++i) for (PRUint32 i=0; i<NS_ARRAY_LENGTH(prepared); ++i)
{ {
@ -807,6 +809,14 @@ nsOfflineCacheDevice::Init()
" WHERE (Flags & 1);")); " WHERE (Flags & 1);"));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Clear up dangling temporary sessions
EvictionObserver evictionObserver(mDB);
rv = mDB->ExecuteSimpleSQL(
NS_LITERAL_CSTRING("DELETE FROM moz_cache"
" WHERE (ClientID GLOB \"TempClient*\")"));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
} }
@ -972,7 +982,7 @@ nsOfflineCacheDevice::BindEntry(nsCacheEntry *entry)
// create binding, pick best generation number // create binding, pick best generation number
nsRefPtr<nsOfflineCacheBinding> binding = nsRefPtr<nsOfflineCacheBinding> binding =
nsOfflineCacheBinding::Create(mCacheDirectory, entry->Key()->get(), -1); nsOfflineCacheBinding::Create(mCacheDirectory, entry->Key(), -1);
if (!binding) if (!binding)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
@ -1474,6 +1484,84 @@ nsOfflineCacheDevice::EvictUnownedEntries(const char *clientID)
return statement->Execute(); return statement->Execute();
} }
nsresult
nsOfflineCacheDevice::CreateTemporaryClientID(nsACString &clientID)
{
nsCAutoString str;
str.AssignLiteral("TempClient");
str.AppendInt(gNextTemporaryClientID++);
clientID.Assign(str);
return NS_OK;
}
nsresult
nsOfflineCacheDevice::MergeTemporaryClientID(const char *clientID,
const char *fromClientID)
{
LOG(("nsOfflineCacheDevice::MergeTemporaryClientID [cid=%s, from=%s]\n",
clientID, fromClientID));
mozStorageTransaction transaction(mDB, PR_FALSE);
// Move over ownerships
AutoResetStatement listOwnersStatement(mStatement_ListOwners);
nsresult rv = listOwnersStatement->BindUTF8StringParameter(
0, nsDependentCString(fromClientID));
NS_ENSURE_SUCCESS(rv, rv);
// List all the owners in the new session
nsTArray<nsCString> domainArray;
nsTArray<nsCString> uriArray;
PRBool hasRows;
rv = listOwnersStatement->ExecuteStep(&hasRows);
NS_ENSURE_SUCCESS(rv, rv);
while (hasRows)
{
PRUint32 length;
domainArray.AppendElement(
nsDependentCString(listOwnersStatement->AsSharedUTF8String(0, &length)));
uriArray.AppendElement(
nsDependentCString(listOwnersStatement->AsSharedUTF8String(1, &length)));
rv = listOwnersStatement->ExecuteStep(&hasRows);
NS_ENSURE_SUCCESS(rv, rv);
}
// Now move over each ownership set
for (PRUint32 i = 0; i < domainArray.Length(); i++) {
PRUint32 count;
char **keys;
rv = GetOwnedKeys(fromClientID, domainArray[i], uriArray[i],
&count, &keys);
NS_ENSURE_SUCCESS(rv, rv);
rv = SetOwnedKeys(clientID, domainArray[i], uriArray[i],
count, const_cast<const char **>(keys));
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, keys);
NS_ENSURE_SUCCESS(rv, rv);
// Now clear out the temporary session's copy
rv = SetOwnedKeys(fromClientID, domainArray[i], uriArray[i], 0, 0);
NS_ENSURE_SUCCESS(rv, rv);
}
EvictionObserver evictionObserver(mDB);
AutoResetStatement swapStatement(mStatement_SwapClientID);
rv = swapStatement->BindUTF8StringParameter(
0, nsDependentCString(clientID));
rv |= swapStatement->BindUTF8StringParameter(
1, nsDependentCString(fromClientID));
NS_ENSURE_SUCCESS(rv, rv);
rv = swapStatement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
return transaction.Commit();
}
/** /**
* Preference accessors * Preference accessors
*/ */

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

@ -121,6 +121,10 @@ public:
const nsACString &ownerDomain); const nsACString &ownerDomain);
nsresult EvictUnownedEntries(const char *clientID); nsresult EvictUnownedEntries(const char *clientID);
nsresult CreateTemporaryClientID(nsACString &clientID);
nsresult MergeTemporaryClientID(const char *clientID,
const char *fromClientID);
/** /**
* Preference accessors * Preference accessors
@ -163,8 +167,10 @@ private:
nsCOMPtr<mozIStorageStatement> mStatement_CheckOwnership; nsCOMPtr<mozIStorageStatement> mStatement_CheckOwnership;
nsCOMPtr<mozIStorageStatement> mStatement_DeleteUnowned; nsCOMPtr<mozIStorageStatement> mStatement_DeleteUnowned;
nsCOMPtr<mozIStorageStatement> mStatement_ListOwned; nsCOMPtr<mozIStorageStatement> mStatement_ListOwned;
nsCOMPtr<mozIStorageStatement> mStatement_ListOwners;
nsCOMPtr<mozIStorageStatement> mStatement_ListOwnerDomains; nsCOMPtr<mozIStorageStatement> mStatement_ListOwnerDomains;
nsCOMPtr<mozIStorageStatement> mStatement_ListOwnerURIs; nsCOMPtr<mozIStorageStatement> mStatement_ListOwnerURIs;
nsCOMPtr<mozIStorageStatement> mStatement_SwapClientID;
nsCOMPtr<nsILocalFile> mCacheDirectory; nsCOMPtr<nsILocalFile> mCacheDirectory;
PRUint32 mCacheCapacity; PRUint32 mCacheCapacity;

Просмотреть файл

@ -75,6 +75,7 @@
#include "nsStreamUtils.h" #include "nsStreamUtils.h"
#include "nsIOService.h" #include "nsIOService.h"
#include "nsAuthInformationHolder.h" #include "nsAuthInformationHolder.h"
#include "nsICacheService.h"
// True if the local cache should be bypassed when processing a request. // True if the local cache should be bypassed when processing a request.
#define BYPASS_LOCAL_CACHE(loadFlags) \ #define BYPASS_LOCAL_CACHE(loadFlags) \
@ -1405,8 +1406,19 @@ nsHttpChannel::OpenOfflineCacheEntryForWriting()
GenerateCacheKey(cacheKey); GenerateCacheKey(cacheKey);
nsCOMPtr<nsICacheSession> session; nsCOMPtr<nsICacheSession> session;
if (!mOfflineCacheClientID.IsEmpty()) {
nsCOMPtr<nsICacheService> serv =
do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
rv = serv->CreateSession(mOfflineCacheClientID.get(),
nsICache::STORE_OFFLINE,
nsICache::STREAM_BASED,
getter_AddRefs(session));
} else {
rv = gHttpHandler->GetCacheSession(nsICache::STORE_OFFLINE, rv = gHttpHandler->GetCacheSession(nsICache::STORE_OFFLINE,
getter_AddRefs(session)); getter_AddRefs(session));
}
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
rv = session->OpenCacheEntry(cacheKey, nsICache::ACCESS_READ_WRITE, rv = session->OpenCacheEntry(cacheKey, nsICache::ACCESS_READ_WRITE,
@ -4550,6 +4562,22 @@ nsHttpChannel::SetCacheForOfflineUse(PRBool value)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsHttpChannel::GetOfflineCacheClientID(nsACString &value)
{
value = mOfflineCacheClientID;
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::SetOfflineCacheClientID(const nsACString &value)
{
mOfflineCacheClientID = value;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsHttpChannel::GetCacheFile(nsIFile **cacheFile) nsHttpChannel::GetCacheFile(nsIFile **cacheFile)
{ {

Просмотреть файл

@ -254,6 +254,7 @@ private:
nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry; nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry;
nsCacheAccessMode mOfflineCacheAccess; nsCacheAccessMode mOfflineCacheAccess;
nsCString mOfflineCacheClientID;
// auth specific data // auth specific data
nsISupports *mProxyAuthContinuationState; nsISupports *mProxyAuthContinuationState;

Просмотреть файл

@ -52,6 +52,7 @@
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsServiceManagerUtils.h" #include "nsServiceManagerUtils.h"
#include "nsStreamUtils.h" #include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "prlog.h" #include "prlog.h"
static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nsnull; static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nsnull;
@ -85,10 +86,11 @@ private:
// nsOfflineCacheUpdateItem::nsISupports // nsOfflineCacheUpdateItem::nsISupports
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS5(nsOfflineCacheUpdateItem, NS_IMPL_ISUPPORTS6(nsOfflineCacheUpdateItem,
nsIDOMLoadStatus, nsIDOMLoadStatus,
nsIRequestObserver, nsIRequestObserver,
nsIStreamListener, nsIStreamListener,
nsIRunnable,
nsIInterfaceRequestor, nsIInterfaceRequestor,
nsIChannelEventSink) nsIChannelEventSink)
@ -99,9 +101,11 @@ NS_IMPL_ISUPPORTS5(nsOfflineCacheUpdateItem,
nsOfflineCacheUpdateItem::nsOfflineCacheUpdateItem(nsOfflineCacheUpdate *aUpdate, nsOfflineCacheUpdateItem::nsOfflineCacheUpdateItem(nsOfflineCacheUpdate *aUpdate,
nsIURI *aURI, nsIURI *aURI,
nsIURI *aReferrerURI, nsIURI *aReferrerURI,
nsIDOMNode *aSource) nsIDOMNode *aSource,
const nsACString &aClientID)
: mURI(aURI) : mURI(aURI)
, mReferrerURI(aReferrerURI) , mReferrerURI(aReferrerURI)
, mClientID(aClientID)
, mUpdate(aUpdate) , mUpdate(aUpdate)
, mChannel(nsnull) , mChannel(nsnull)
, mState(nsIDOMLoadStatus::UNINITIALIZED) , mState(nsIDOMLoadStatus::UNINITIALIZED)
@ -139,6 +143,11 @@ nsOfflineCacheUpdateItem::OpenChannel()
if (cachingChannel) { if (cachingChannel) {
rv = cachingChannel->SetCacheForOfflineUse(PR_TRUE); rv = cachingChannel->SetCacheForOfflineUse(PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!mClientID.IsEmpty()) {
rv = cachingChannel->SetOfflineCacheClientID(mClientID);
NS_ENSURE_SUCCESS(rv, rv);
}
} }
rv = mChannel->AsyncOpen(this, nsnull); rv = mChannel->AsyncOpen(this, nsnull);
@ -206,6 +215,20 @@ nsOfflineCacheUpdateItem::OnStopRequest(nsIRequest *aRequest,
mChannel->GetContentLength(&mBytesRead); mChannel->GetContentLength(&mBytesRead);
} }
// We need to notify the update that the load is complete, but we
// want to give the channel a chance to close the cache entries.
NS_DispatchToCurrentThread(this);
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsOfflineCacheUpdateItem::nsIRunnable
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsOfflineCacheUpdateItem::Run()
{
mUpdate->LoadCompleted(); mUpdate->LoadCompleted();
return NS_OK; return NS_OK;
@ -245,8 +268,15 @@ nsOfflineCacheUpdateItem::OnChannelRedirect(nsIChannel *aOldChannel,
do_QueryInterface(aOldChannel); do_QueryInterface(aOldChannel);
nsCOMPtr<nsICachingChannel> newCachingChannel = nsCOMPtr<nsICachingChannel> newCachingChannel =
do_QueryInterface(aOldChannel); do_QueryInterface(aOldChannel);
if (newCachingChannel) if (newCachingChannel) {
newCachingChannel->SetCacheForOfflineUse(PR_TRUE); rv = newCachingChannel->SetCacheForOfflineUse(PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
if (!mClientID.IsEmpty()) {
rv = newCachingChannel->SetOfflineCacheClientID(mClientID);
NS_ENSURE_SUCCESS(rv, rv);
}
}
PRBool match; PRBool match;
rv = newURI->SchemeIs("http", &match); rv = newURI->SchemeIs("http", &match);
@ -370,6 +400,8 @@ nsOfflineCacheUpdate::nsOfflineCacheUpdate()
: mState(STATE_UNINITIALIZED) : mState(STATE_UNINITIALIZED)
, mAddedItems(PR_FALSE) , mAddedItems(PR_FALSE)
, mPartialUpdate(PR_FALSE) , mPartialUpdate(PR_FALSE)
, mSucceeded(PR_TRUE)
, mCurrentItem(-1)
{ {
} }
@ -409,8 +441,26 @@ nsOfflineCacheUpdate::Init(PRBool aPartialUpdate,
getter_AddRefs(session)); getter_AddRefs(session));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
mMainCacheSession = do_QueryInterface(session, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Partial updates don't use temporary cache sessions
if (aPartialUpdate) {
mCacheSession = mMainCacheSession;
} else {
rv = cacheService->CreateTemporaryClientID(nsICache::STORE_OFFLINE,
mClientID);
NS_ENSURE_SUCCESS(rv, rv);
rv = cacheService->CreateSession(mClientID.get(),
nsICache::STORE_OFFLINE,
nsICache::STREAM_BASED,
getter_AddRefs(session));
NS_ENSURE_SUCCESS(rv, rv);
mCacheSession = do_QueryInterface(session, &rv); mCacheSession = do_QueryInterface(session, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
}
mState = STATE_INITIALIZED; mState = STATE_INITIALIZED;
@ -424,10 +474,23 @@ nsOfflineCacheUpdate::LoadCompleted()
LOG(("nsOfflineCacheUpdate::LoadCompleted [%p]", this)); LOG(("nsOfflineCacheUpdate::LoadCompleted [%p]", this));
NS_ASSERTION(mItems.Length() >= 1, "Unknown load completed"); nsRefPtr<nsOfflineCacheUpdateItem> item = mItems[mCurrentItem];
mCurrentItem++;
nsRefPtr<nsOfflineCacheUpdateItem> item = mItems[0]; PRUint16 status;
mItems.RemoveElementAt(0); rv = item->GetStatus(&status);
// Check for failures. Only connection or server errors (5XX) will cause
// the update to fail.
if (NS_FAILED(rv) || status == 0 || status >= 500) {
// Only fail updates from this domain. Outside-of-domain updates
// are not guaranteeed to be updated.
nsCAutoString domain;
item->mURI->GetHostPort(domain);
if (domain == mUpdateDomain) {
mSucceeded = PR_FALSE;
}
}
rv = NotifyCompleted(item); rv = NotifyCompleted(item);
if (NS_FAILED(rv)) return; if (NS_FAILED(rv)) return;
@ -449,6 +512,7 @@ nsOfflineCacheUpdate::Begin()
mState = STATE_RUNNING; mState = STATE_RUNNING;
mCurrentItem = 0;
ProcessNextURI(); ProcessNextURI();
return NS_OK; return NS_OK;
@ -460,10 +524,12 @@ nsOfflineCacheUpdate::Cancel()
LOG(("nsOfflineCacheUpdate::Cancel [%p]", this)); LOG(("nsOfflineCacheUpdate::Cancel [%p]", this));
mState = STATE_CANCELLED; mState = STATE_CANCELLED;
mSucceeded = PR_FALSE;
if (mItems.Length() > 0) { if (mCurrentItem >= 0 &&
// First load might be running mCurrentItem < static_cast<PRInt32>(mItems.Length())) {
mItems[0]->Cancel(); // Load might be running
mItems[mCurrentItem]->Cancel();
} }
return NS_OK; return NS_OK;
@ -478,7 +544,7 @@ nsOfflineCacheUpdate::AddOwnedItems(const nsACString &aOwnerURI)
{ {
PRUint32 count; PRUint32 count;
char **keys; char **keys;
nsresult rv = mCacheSession->GetOwnedKeys(mUpdateDomain, aOwnerURI, nsresult rv = mMainCacheSession->GetOwnedKeys(mUpdateDomain, aOwnerURI,
&count, &keys); &count, &keys);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -488,7 +554,8 @@ nsOfflineCacheUpdate::AddOwnedItems(const nsACString &aOwnerURI)
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), keys[i]))) { if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), keys[i]))) {
nsRefPtr<nsOfflineCacheUpdateItem> item = nsRefPtr<nsOfflineCacheUpdateItem> item =
new nsOfflineCacheUpdateItem(this, uri, mReferrerURI, nsnull); new nsOfflineCacheUpdateItem(this, uri, mReferrerURI,
nsnull, mClientID);
if (!item) return NS_ERROR_OUT_OF_MEMORY; if (!item) return NS_ERROR_OUT_OF_MEMORY;
mItems.AppendElement(item); mItems.AppendElement(item);
@ -504,7 +571,7 @@ nsOfflineCacheUpdate::AddDomainItems()
{ {
PRUint32 count; PRUint32 count;
char **uris; char **uris;
nsresult rv = mCacheSession->GetOwnerURIs(mUpdateDomain, &count, &uris); nsresult rv = mMainCacheSession->GetOwnerURIs(mUpdateDomain, &count, &uris);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
AutoFreeArray autoFree(count, uris); AutoFreeArray autoFree(count, uris);
@ -525,22 +592,23 @@ nsOfflineCacheUpdate::AddDomainItems()
nsresult nsresult
nsOfflineCacheUpdate::ProcessNextURI() nsOfflineCacheUpdate::ProcessNextURI()
{ {
LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p, numItems=%d]", LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p, current=%d, numItems=%d]",
this, mItems.Length())); this, mCurrentItem, mItems.Length()));
if (mState == STATE_CANCELLED || mItems.Length() == 0) { if (mState == STATE_CANCELLED ||
mCurrentItem >= static_cast<PRInt32>(mItems.Length())) {
return Finish(); return Finish();
} }
#if defined(PR_LOGGING) #if defined(PR_LOGGING)
if (LOG_ENABLED()) { if (LOG_ENABLED()) {
nsCAutoString spec; nsCAutoString spec;
mItems[0]->mURI->GetSpec(spec); mItems[mCurrentItem]->mURI->GetSpec(spec);
LOG(("%p: Opening channel for %s", this, spec.get())); LOG(("%p: Opening channel for %s", this, spec.get()));
} }
#endif #endif
nsresult rv = mItems[0]->OpenChannel(); nsresult rv = mItems[mCurrentItem]->OpenChannel();
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
LoadCompleted(); LoadCompleted();
return rv; return rv;
@ -584,6 +652,21 @@ nsOfflineCacheUpdate::Finish()
nsOfflineCacheUpdateService *service = nsOfflineCacheUpdateService *service =
nsOfflineCacheUpdateService::GetInstance(); nsOfflineCacheUpdateService::GetInstance();
if (!mPartialUpdate) {
if (mSucceeded) {
nsresult rv = mMainCacheSession->MergeTemporaryClientID(mClientID);
if (NS_FAILED(rv))
mSucceeded = PR_FALSE;
}
if (!mSucceeded) {
// Update was not merged, mark all the loads as failures
for (PRUint32 i = 0; i < mItems.Length(); i++) {
mItems[i]->Cancel();
}
}
}
if (!service) if (!service)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -652,7 +735,8 @@ nsOfflineCacheUpdate::AddURI(nsIURI *aURI, nsIDOMNode *aSource)
} }
nsRefPtr<nsOfflineCacheUpdateItem> item = nsRefPtr<nsOfflineCacheUpdateItem> item =
new nsOfflineCacheUpdateItem(this, aURI, mReferrerURI, aSource); new nsOfflineCacheUpdateItem(this, aURI, mReferrerURI,
aSource, mClientID);
if (!item) return NS_ERROR_OUT_OF_MEMORY; if (!item) return NS_ERROR_OUT_OF_MEMORY;
mItems.AppendElement(item); mItems.AppendElement(item);

Просмотреть файл

@ -55,6 +55,7 @@
#include "nsIOfflineCacheSession.h" #include "nsIOfflineCacheSession.h"
#include "nsIPrefetchService.h" #include "nsIPrefetchService.h"
#include "nsIRequestObserver.h" #include "nsIRequestObserver.h"
#include "nsIRunnable.h"
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
#include "nsIURI.h" #include "nsIURI.h"
#include "nsIWebProgressListener.h" #include "nsIWebProgressListener.h"
@ -67,6 +68,7 @@ class nsOfflineCacheUpdate;
class nsOfflineCacheUpdateItem : public nsIDOMLoadStatus class nsOfflineCacheUpdateItem : public nsIDOMLoadStatus
, public nsIStreamListener , public nsIStreamListener
, public nsIRunnable
, public nsIInterfaceRequestor , public nsIInterfaceRequestor
, public nsIChannelEventSink , public nsIChannelEventSink
{ {
@ -75,18 +77,21 @@ public:
NS_DECL_NSIDOMLOADSTATUS NS_DECL_NSIDOMLOADSTATUS
NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIRUNNABLE
NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSICHANNELEVENTSINK
nsOfflineCacheUpdateItem(nsOfflineCacheUpdate *aUpdate, nsOfflineCacheUpdateItem(nsOfflineCacheUpdate *aUpdate,
nsIURI *aURI, nsIURI *aURI,
nsIURI *aReferrerURI, nsIURI *aReferrerURI,
nsIDOMNode *aSource); nsIDOMNode *aSource,
const nsACString &aClientID);
~nsOfflineCacheUpdateItem(); ~nsOfflineCacheUpdateItem();
nsCOMPtr<nsIURI> mURI; nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrerURI; nsCOMPtr<nsIURI> mReferrerURI;
nsCOMPtr<nsIWeakReference> mSource; nsCOMPtr<nsIWeakReference> mSource;
nsCString mClientID;
nsresult OpenChannel(); nsresult OpenChannel();
nsresult Cancel(); nsresult Cancel();
@ -131,14 +136,19 @@ private:
PRBool mAddedItems; PRBool mAddedItems;
PRBool mPartialUpdate; PRBool mPartialUpdate;
PRBool mSucceeded;
nsCString mUpdateDomain; nsCString mUpdateDomain;
nsCString mOwnerURI; nsCString mOwnerURI;
nsCOMPtr<nsIURI> mReferrerURI; nsCOMPtr<nsIURI> mReferrerURI;
nsCString mClientID;
nsCOMPtr<nsIOfflineCacheSession> mCacheSession; nsCOMPtr<nsIOfflineCacheSession> mCacheSession;
nsCOMPtr<nsIOfflineCacheSession> mMainCacheSession;
nsCOMPtr<nsIObserverService> mObserverService; nsCOMPtr<nsIObserverService> mObserverService;
/* Items being updated */ /* Items being updated */
PRInt32 mCurrentItem;
nsTArray<nsRefPtr<nsOfflineCacheUpdateItem> > mItems; nsTArray<nsRefPtr<nsOfflineCacheUpdateItem> > mItems;
/* Clients watching this update for changes */ /* Clients watching this update for changes */