gecko-dev/dom/cache/Manager.h

290 строки
11 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/CacheInitData.h"
#include "mozilla/dom/cache/PCacheStreamControlParent.h"
#include "mozilla/dom/cache/Types.h"
#include "nsCOMPtr.h"
#include "nsISupportsImpl.h"
#include "nsString.h"
#include "nsTArray.h"
class nsIInputStream;
class nsIThread;
namespace mozilla {
namespace dom {
namespace cache {
class CacheRequestResponse;
class Context;
class ManagerId;
class PCacheQueryParams;
class PCacheRequest;
class PCacheRequestOrVoid;
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 Manager object can out live the IPC actors in the case where the child
// process is killed; e.g a child process OOM. The Manager object can
// The Manager object can potentially use non-trivial resources. Long lived
// DOM objects and their actors should not maintain a reference to the Manager
// while idle. Transient DOM objects that may keep a reference for their
// lifetimes.
//
// For example, once a CacheStorage DOM object is access it will live until its
// global is released. Therefore, CacheStorage should release its Manager
// reference after operations complete and it becomes idle. Cache objects,
// however, can be GC'd once content are done using them and can therefore keep
// their Manager reference alive. Its expected that more operations are
// performed on a Cache object, so keeping the Manager reference will help
// minimize overhead for each reference.
//
// As an invariant, all Manager objects must cease all IO before shutdown. This
// is enforced by the ShutdownObserver. 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:
virtual void OnCacheMatch(RequestId aRequestId, nsresult aRv,
const SavedResponse* aResponse,
StreamList* aStreamList) { }
virtual void OnCacheMatchAll(RequestId aRequestId, nsresult aRv,
const nsTArray<SavedResponse>& aSavedResponses,
StreamList* aStreamList) { }
virtual void OnCachePutAll(RequestId aRequestId, nsresult aRv) { }
virtual void OnCacheDelete(RequestId aRequestId, nsresult aRv,
bool aSuccess) { }
virtual void OnCacheKeys(RequestId aRequestId, nsresult aRv,
const nsTArray<SavedRequest>& aSavedRequests,
StreamList* aStreamList) { }
virtual void OnStorageMatch(RequestId aRequestId, nsresult aRv,
const SavedResponse* aResponse,
StreamList* aStreamList) { }
virtual void OnStorageHas(RequestId aRequestId, nsresult aRv,
bool aCacheFound) { }
virtual void OnStorageOpen(RequestId aRequestId, nsresult aRv,
CacheId aCacheId) { }
virtual void OnStorageDelete(RequestId aRequestId, nsresult aRv,
bool aCacheDeleted) { }
virtual void OnStorageKeys(RequestId aRequestId, nsresult aRv,
const nsTArray<nsString>& aKeys) { }
protected:
~Listener() { }
};
static nsresult GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut);
static already_AddRefed<Manager> Get(ManagerId* aManagerId);
// Synchronously shutdown from main thread. This spins the event loop.
static void ShutdownAllOnMainThread();
// 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 Invalidate();
bool IsValid() 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);
// TODO: consider moving CacheId up in the argument lists below (bug 1110485)
void CacheMatch(Listener* aListener, RequestId aRequestId, CacheId aCacheId,
const PCacheRequest& aRequest,
const PCacheQueryParams& aParams);
void CacheMatchAll(Listener* aListener, RequestId aRequestId,
CacheId aCacheId, const PCacheRequestOrVoid& aRequestOrVoid,
const PCacheQueryParams& aParams);
void CachePutAll(Listener* aListener, RequestId aRequestId, CacheId aCacheId,
const nsTArray<CacheRequestResponse>& aPutList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList);
void CacheDelete(Listener* aListener, RequestId aRequestId,
CacheId aCacheId, const PCacheRequest& aRequest,
const PCacheQueryParams& aParams);
void CacheKeys(Listener* aListener, RequestId aRequestId,
CacheId aCacheId, const PCacheRequestOrVoid& aRequestOrVoid,
const PCacheQueryParams& aParams);
void StorageMatch(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const PCacheRequest& aRequest,
const PCacheQueryParams& aParams);
void StorageHas(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const nsAString& aKey);
void StorageOpen(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const nsAString& aKey);
void StorageDelete(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const nsAString& aKey);
void StorageKeys(Listener* aListener, RequestId aRequestId,
Namespace aNamespace);
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;
typedef uint64_t ListenerId;
Manager(ManagerId* aManagerId, nsIThread* aIOThread);
~Manager();
void Shutdown();
already_AddRefed<Context> CurrentContext();
ListenerId SaveListener(Listener* aListener);
Listener* GetListener(ListenerId aListenerId) const;
bool SetCacheIdOrphanedIfRefed(CacheId aCacheId);
bool SetBodyIdOrphanedIfRefed(const nsID& aBodyId);
void NoteOrphanedBodyIdList(const nsTArray<nsID>& aDeletedBodyIdList);
nsRefPtr<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;
bool mValid;
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