summaryrefslogtreecommitdiffstats
path: root/dom/cache/Manager.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/cache/Manager.h')
-rw-r--r--dom/cache/Manager.h292
1 files changed, 292 insertions, 0 deletions
diff --git a/dom/cache/Manager.h b/dom/cache/Manager.h
new file mode 100644
index 000000000..20392dad8
--- /dev/null
+++ b/dom/cache/Manager.h
@@ -0,0 +1,292 @@
+/* -*- 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);
+
+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 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