mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
302 lines
9.4 KiB
C++
302 lines
9.4 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef mozilla_dom_cache_Manager_h
|
|
#define mozilla_dom_cache_Manager_h
|
|
|
|
#include "mozilla/dom/cache/Types.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsISupportsImpl.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "nsString.h"
|
|
#include "nsTArray.h"
|
|
|
|
class nsIInputStream;
|
|
class nsIThread;
|
|
|
|
namespace mozilla {
|
|
|
|
class ErrorResult;
|
|
|
|
namespace dom {
|
|
namespace cache {
|
|
|
|
class CacheOpArgs;
|
|
class CacheOpResult;
|
|
class CacheRequestResponse;
|
|
class Context;
|
|
class ManagerId;
|
|
struct SavedRequest;
|
|
struct SavedResponse;
|
|
class StreamList;
|
|
|
|
// The Manager is class is responsible for performing all of the underlying
|
|
// work for a Cache or CacheStorage operation. The DOM objects and IPC actors
|
|
// are basically just plumbing to get the request to the right Manager object
|
|
// running in the parent process.
|
|
//
|
|
// There should be exactly one Manager object for each origin or app using the
|
|
// Cache API. This uniqueness is defined by the ManagerId equality operator.
|
|
// The uniqueness is enforced by the Manager GetOrCreate() factory method.
|
|
//
|
|
// The life cycle of Manager objects is somewhat complex. While code may
|
|
// hold a strong reference to the Manager, it will invalidate itself once it
|
|
// believes it has become completely idle. This is currently determined when
|
|
// all of the following conditions occur:
|
|
//
|
|
// 1) There are no more Manager::Listener objects registered with the Manager
|
|
// by performing a Cache or Storage operation.
|
|
// 2) There are no more CacheId references noted via Manager::AddRefCacheId().
|
|
// 3) There are no more BodyId references noted via Manager::AddRefBodyId().
|
|
//
|
|
// In order to keep your Manager alive you should perform an operation to set
|
|
// a Listener, call AddRefCacheId(), or call AddRefBodyId().
|
|
//
|
|
// Even once a Manager becomes invalid, however, it may still continue to
|
|
// exist. This is allowed so that any in-progress Actions can gracefully
|
|
// complete.
|
|
//
|
|
// As an invariant, all Manager objects must cease all IO before shutdown. This
|
|
// is enforced by the Manager::Factory. If content still holds references to
|
|
// Cache DOM objects during shutdown, then all operations will begin rejecting.
|
|
class Manager final
|
|
{
|
|
public:
|
|
// Callback interface implemented by clients of Manager, such as CacheParent
|
|
// and CacheStorageParent. In general, if you call a Manager method you
|
|
// should expect to receive exactly one On*() callback. For example, if
|
|
// you call Manager::CacheMatch(), then you should expect to receive
|
|
// OnCacheMatch() back in response.
|
|
//
|
|
// Listener objects are set on a per-operation basis. So you pass the
|
|
// Listener to a call like Manager::CacheMatch(). Once set in this way,
|
|
// the Manager will continue to reference the Listener until RemoveListener()
|
|
// is called. This is done to allow the same listener to be used for
|
|
// multiple operations simultaneously without having to maintain an exact
|
|
// count of operations-in-flight.
|
|
//
|
|
// Note, the Manager only holds weak references to Listener objects.
|
|
// Listeners must call Manager::RemoveListener() before they are destroyed
|
|
// to clear these weak references.
|
|
//
|
|
// All public methods should be invoked on the same thread used to create
|
|
// the Manager.
|
|
class Listener
|
|
{
|
|
public:
|
|
// convenience routines
|
|
void
|
|
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult);
|
|
|
|
void
|
|
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
|
CacheId aOpenedCacheId);
|
|
|
|
void
|
|
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
|
const SavedResponse& aSavedResponse,
|
|
StreamList* aStreamList);
|
|
|
|
void
|
|
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
|
const nsTArray<SavedResponse>& aSavedResponseList,
|
|
StreamList* aStreamList);
|
|
|
|
void
|
|
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
|
const nsTArray<SavedRequest>& aSavedRequestList,
|
|
StreamList* aStreamList);
|
|
|
|
// interface to be implemented
|
|
virtual void
|
|
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
|
CacheId aOpenedCacheId,
|
|
const nsTArray<SavedResponse>& aSavedResponseList,
|
|
const nsTArray<SavedRequest>& aSavedRequestList,
|
|
StreamList* aStreamList) { }
|
|
|
|
protected:
|
|
~Listener() { }
|
|
};
|
|
|
|
enum State
|
|
{
|
|
Open,
|
|
Closing
|
|
};
|
|
|
|
static nsresult GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut);
|
|
static already_AddRefed<Manager> Get(ManagerId* aManagerId);
|
|
|
|
// Synchronously shutdown. This spins the event loop.
|
|
static void ShutdownAll();
|
|
|
|
// Cancel actions for given origin or all actions if passed string is null.
|
|
static void Abort(const nsACString& aOrigin);
|
|
|
|
// Must be called by Listener objects before they are destroyed.
|
|
void RemoveListener(Listener* aListener);
|
|
|
|
// Must be called by Context objects before they are destroyed.
|
|
void RemoveContext(Context* aContext);
|
|
|
|
// Marks the Manager "invalid". Once the Context completes no new operations
|
|
// will be permitted with this Manager. New actors will get a new Manager.
|
|
void NoteClosing();
|
|
|
|
State GetState() const;
|
|
|
|
// If an actor represents a long term reference to a cache or body stream,
|
|
// then they must call AddRefCacheId() or AddRefBodyId(). This will
|
|
// cause the Manager to keep the backing data store alive for the given
|
|
// object. The actor must then call ReleaseCacheId() or ReleaseBodyId()
|
|
// exactly once for every AddRef*() call it made. Any delayed deletion
|
|
// will then be performed.
|
|
void AddRefCacheId(CacheId aCacheId);
|
|
void ReleaseCacheId(CacheId aCacheId);
|
|
void AddRefBodyId(const nsID& aBodyId);
|
|
void ReleaseBodyId(const nsID& aBodyId);
|
|
|
|
already_AddRefed<ManagerId> GetManagerId() const;
|
|
|
|
// Methods to allow a StreamList to register themselves with the Manager.
|
|
// StreamList objects must call RemoveStreamList() before they are destroyed.
|
|
void AddStreamList(StreamList* aStreamList);
|
|
void RemoveStreamList(StreamList* aStreamList);
|
|
|
|
void ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
|
|
const CacheOpArgs& aOpArgs);
|
|
void ExecutePutAll(Listener* aListener, CacheId aCacheId,
|
|
const nsTArray<CacheRequestResponse>& aPutList,
|
|
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
|
|
const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList);
|
|
|
|
void ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
|
|
const CacheOpArgs& aOpArgs);
|
|
|
|
void ExecuteOpenStream(Listener* aListener, InputStreamResolver&& aResolver,
|
|
const nsID& aBodyId);
|
|
|
|
void
|
|
NoteStreamOpenComplete(const nsID& aBodyId, ErrorResult&& aRv,
|
|
nsCOMPtr<nsIInputStream>&& aBodyStream);
|
|
|
|
private:
|
|
class Factory;
|
|
class BaseAction;
|
|
class DeleteOrphanedCacheAction;
|
|
|
|
class CacheMatchAction;
|
|
class CacheMatchAllAction;
|
|
class CachePutAllAction;
|
|
class CacheDeleteAction;
|
|
class CacheKeysAction;
|
|
|
|
class StorageMatchAction;
|
|
class StorageHasAction;
|
|
class StorageOpenAction;
|
|
class StorageDeleteAction;
|
|
class StorageKeysAction;
|
|
|
|
class OpenStreamAction;
|
|
|
|
typedef uint64_t ListenerId;
|
|
|
|
Manager(ManagerId* aManagerId, nsIThread* aIOThread);
|
|
~Manager();
|
|
void Init(Manager* aOldManager);
|
|
void Shutdown();
|
|
|
|
void Abort();
|
|
|
|
ListenerId SaveListener(Listener* aListener);
|
|
Listener* GetListener(ListenerId aListenerId) const;
|
|
|
|
bool SetCacheIdOrphanedIfRefed(CacheId aCacheId);
|
|
bool SetBodyIdOrphanedIfRefed(const nsID& aBodyId);
|
|
void NoteOrphanedBodyIdList(const nsTArray<nsID>& aDeletedBodyIdList);
|
|
|
|
void MaybeAllowContextToClose();
|
|
|
|
RefPtr<ManagerId> mManagerId;
|
|
nsCOMPtr<nsIThread> mIOThread;
|
|
|
|
// Weak reference cleared by RemoveContext() in Context destructor.
|
|
Context* MOZ_NON_OWNING_REF mContext;
|
|
|
|
// Weak references cleared by RemoveListener() in Listener destructors.
|
|
struct ListenerEntry
|
|
{
|
|
ListenerEntry()
|
|
: mId(UINT64_MAX)
|
|
, mListener(nullptr)
|
|
{
|
|
}
|
|
|
|
ListenerEntry(ListenerId aId, Listener* aListener)
|
|
: mId(aId)
|
|
, mListener(aListener)
|
|
{
|
|
}
|
|
|
|
ListenerId mId;
|
|
Listener* mListener;
|
|
};
|
|
|
|
class ListenerEntryIdComparator
|
|
{
|
|
public:
|
|
bool Equals(const ListenerEntry& aA, const ListenerId& aB) const
|
|
{
|
|
return aA.mId == aB;
|
|
}
|
|
};
|
|
|
|
class ListenerEntryListenerComparator
|
|
{
|
|
public:
|
|
bool Equals(const ListenerEntry& aA, const Listener* aB) const
|
|
{
|
|
return aA.mListener == aB;
|
|
}
|
|
};
|
|
|
|
typedef nsTArray<ListenerEntry> ListenerList;
|
|
ListenerList mListeners;
|
|
static ListenerId sNextListenerId;
|
|
|
|
// Weak references cleared by RemoveStreamList() in StreamList destructors.
|
|
nsTArray<StreamList*> mStreamLists;
|
|
|
|
bool mShuttingDown;
|
|
State mState;
|
|
|
|
struct CacheIdRefCounter
|
|
{
|
|
CacheId mCacheId;
|
|
MozRefCountType mCount;
|
|
bool mOrphaned;
|
|
};
|
|
nsTArray<CacheIdRefCounter> mCacheIdRefs;
|
|
|
|
struct BodyIdRefCounter
|
|
{
|
|
nsID mBodyId;
|
|
MozRefCountType mCount;
|
|
bool mOrphaned;
|
|
};
|
|
nsTArray<BodyIdRefCounter> mBodyIdRefs;
|
|
|
|
public:
|
|
NS_INLINE_DECL_REFCOUNTING(cache::Manager)
|
|
};
|
|
|
|
} // namespace cache
|
|
} // namespace dom
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_dom_cache_Manager_h
|