Backed out changeset 1d9301697aa0 (bug 1887752) for causing failures on browser_all_f...
[gecko.git] / dom / cache / Manager.h
blobb506a793e214fbf6980a5a424da56a9ce8f4f732
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_cache_Manager_h
8 #define mozilla_dom_cache_Manager_h
10 #include "mozilla/RefPtr.h"
11 #include "mozilla/dom/SafeRefPtr.h"
12 #include "mozilla/dom/cache/Types.h"
13 #include "mozilla/dom/quota/Client.h"
14 #include "mozilla/dom/quota/StringifyUtils.h"
15 #include "CacheCommon.h"
16 #include "nsCOMPtr.h"
17 #include "nsISupportsImpl.h"
18 #include "nsString.h"
19 #include "nsTArray.h"
21 class nsIInputStream;
22 class nsIThread;
24 namespace mozilla {
26 class ErrorResult;
28 namespace dom {
30 namespace quota {
32 class DirectoryLock;
34 } // namespace quota
36 namespace cache {
38 class CacheOpArgs;
39 class CacheOpResult;
40 class CacheRequestResponse;
41 class Context;
42 class ManagerId;
43 struct SavedRequest;
44 struct SavedResponse;
45 class StreamList;
47 // The Manager is class is responsible for performing all of the underlying
48 // work for a Cache or CacheStorage operation. The DOM objects and IPC actors
49 // are basically just plumbing to get the request to the right Manager object
50 // running in the parent process.
52 // There should be exactly one Manager object for each origin or app using the
53 // Cache API. This uniqueness is defined by the ManagerId equality operator.
54 // The uniqueness is enforced by the Manager GetOrCreate() factory method.
56 // The life cycle of Manager objects is somewhat complex. While code may
57 // hold a strong reference to the Manager, it will invalidate itself once it
58 // believes it has become completely idle. This is currently determined when
59 // all of the following conditions occur:
61 // 1) There are no more Manager::Listener objects registered with the Manager
62 // by performing a Cache or Storage operation.
63 // 2) There are no more CacheId references noted via Manager::AddRefCacheId().
64 // 3) There are no more BodyId references noted via Manager::AddRefBodyId().
66 // In order to keep your Manager alive you should perform an operation to set
67 // a Listener, call AddRefCacheId(), or call AddRefBodyId().
69 // Even once a Manager becomes invalid, however, it may still continue to
70 // exist. This is allowed so that any in-progress Actions can gracefully
71 // complete.
73 // As an invariant, all Manager objects must cease all IO before shutdown. This
74 // is enforced by the Manager::Factory. If content still holds references to
75 // Cache DOM objects during shutdown, then all operations will begin rejecting.
76 class Manager final : public SafeRefCounted<Manager>, public Stringifyable {
77 using Client = quota::Client;
78 using DirectoryLock = quota::DirectoryLock;
80 public:
81 // Callback interface implemented by clients of Manager, such as CacheParent
82 // and CacheStorageParent. In general, if you call a Manager method you
83 // should expect to receive exactly one On*() callback. For example, if
84 // you call Manager::CacheMatch(), then you should expect to receive
85 // OnCacheMatch() back in response.
87 // Listener objects are set on a per-operation basis. So you pass the
88 // Listener to a call like Manager::CacheMatch(). Once set in this way,
89 // the Manager will continue to reference the Listener until RemoveListener()
90 // is called. This is done to allow the same listener to be used for
91 // multiple operations simultaneously without having to maintain an exact
92 // count of operations-in-flight.
94 // Note, the Manager only holds weak references to Listener objects.
95 // Listeners must call Manager::RemoveListener() before they are destroyed
96 // to clear these weak references.
98 // All public methods should be invoked on the same thread used to create
99 // the Manager.
100 class Listener {
101 public:
102 // convenience routines
103 void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult);
105 void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
106 CacheId aOpenedCacheId);
108 void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
109 const SavedResponse& aSavedResponse,
110 StreamList& aStreamList);
112 void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
113 const nsTArray<SavedResponse>& aSavedResponseList,
114 StreamList& aStreamList);
116 void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
117 const nsTArray<SavedRequest>& aSavedRequestList,
118 StreamList& aStreamList);
120 struct StreamInfo {
121 const nsTArray<SavedResponse>& mSavedResponseList;
122 const nsTArray<SavedRequest>& mSavedRequestList;
123 StreamList& mStreamList;
126 // interface to be implemented
127 virtual void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
128 CacheId aOpenedCacheId,
129 const Maybe<StreamInfo>& aStreamInfo) {}
131 protected:
132 ~Listener() = default;
135 enum State { Open, Closing };
137 static Result<SafeRefPtr<Manager>, nsresult> AcquireCreateIfNonExistent(
138 const SafeRefPtr<ManagerId>& aManagerId);
140 static void InitiateShutdown();
142 static bool IsShutdownAllComplete();
144 static nsCString GetShutdownStatus();
146 // Cancel actions for given DirectoryLock ids.
147 static void Abort(const Client::DirectoryLockIdTable& aDirectoryLockIds);
149 // Cancel all actions.
150 static void AbortAll();
152 // Must be called by Listener objects before they are destroyed.
153 void RemoveListener(Listener* aListener);
155 // Must be called by Context objects before they are destroyed.
156 void RemoveContext(Context& aContext);
158 // Marks the Manager "invalid". Once the Context completes no new operations
159 // will be permitted with this Manager. New actors will get a new Manager.
160 void NoteClosing();
162 State GetState() const;
164 // If an actor represents a long term reference to a cache or body stream,
165 // then they must call AddRefCacheId() or AddRefBodyId(). This will
166 // cause the Manager to keep the backing data store alive for the given
167 // object. The actor must then call ReleaseCacheId() or ReleaseBodyId()
168 // exactly once for every AddRef*() call it made. Any delayed deletion
169 // will then be performed.
170 void AddRefCacheId(CacheId aCacheId);
171 void ReleaseCacheId(CacheId aCacheId);
172 void AddRefBodyId(const nsID& aBodyId);
173 void ReleaseBodyId(const nsID& aBodyId);
175 const ManagerId& GetManagerId() const;
177 Maybe<DirectoryLock&> MaybeDirectoryLockRef() const;
179 // Methods to allow a StreamList to register themselves with the Manager.
180 // StreamList objects must call RemoveStreamList() before they are destroyed.
181 void AddStreamList(StreamList& aStreamList);
182 void RemoveStreamList(StreamList& aStreamList);
184 void ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
185 const CacheOpArgs& aOpArgs);
186 void ExecutePutAll(
187 Listener* aListener, CacheId aCacheId,
188 const nsTArray<CacheRequestResponse>& aPutList,
189 const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
190 const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList);
192 void ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
193 const CacheOpArgs& aOpArgs);
195 void ExecuteOpenStream(Listener* aListener, InputStreamResolver&& aResolver,
196 const nsID& aBodyId);
198 void NoteStreamOpenComplete(const nsID& aBodyId, ErrorResult&& aRv,
199 nsCOMPtr<nsIInputStream>&& aBodyStream);
201 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
202 void RecordMayNotDeleteCSCP(int32_t aCacheStreamControlParentId);
203 void RecordHaveDeletedCSCP(int32_t aCacheStreamControlParentId);
204 #endif
206 private:
207 class Factory;
208 class BaseAction;
209 class DeleteOrphanedCacheAction;
211 class CacheMatchAction;
212 class CacheMatchAllAction;
213 class CachePutAllAction;
214 class CacheDeleteAction;
215 class CacheKeysAction;
217 class StorageMatchAction;
218 class StorageHasAction;
219 class StorageOpenAction;
220 class StorageDeleteAction;
221 class StorageKeysAction;
223 class OpenStreamAction;
225 using ListenerId = uint64_t;
227 void Init(Maybe<Manager&> aOldManager);
228 void Shutdown();
230 void Abort();
232 ListenerId SaveListener(Listener* aListener);
233 Listener* GetListener(ListenerId aListenerId) const;
235 bool SetCacheIdOrphanedIfRefed(CacheId aCacheId);
236 bool SetBodyIdOrphanedIfRefed(const nsID& aBodyId);
237 void NoteOrphanedBodyIdList(const nsTArray<nsID>& aDeletedBodyIdList);
239 void MaybeAllowContextToClose();
241 SafeRefPtr<ManagerId> mManagerId;
242 nsCOMPtr<nsIThread> mIOThread;
244 // Weak reference cleared by RemoveContext() in Context destructor.
245 Context* MOZ_NON_OWNING_REF mContext;
247 // Weak references cleared by RemoveListener() in Listener destructors.
248 struct ListenerEntry {
249 ListenerEntry() : mId(UINT64_MAX), mListener(nullptr) {}
251 ListenerEntry(ListenerId aId, Listener* aListener)
252 : mId(aId), mListener(aListener) {}
254 ListenerId mId;
255 Listener* mListener;
258 class ListenerEntryIdComparator {
259 public:
260 bool Equals(const ListenerEntry& aA, const ListenerId& aB) const {
261 return aA.mId == aB;
265 class ListenerEntryListenerComparator {
266 public:
267 bool Equals(const ListenerEntry& aA, const Listener* aB) const {
268 return aA.mListener == aB;
272 using ListenerList = nsTArray<ListenerEntry>;
273 ListenerList mListeners;
274 static ListenerId sNextListenerId;
276 // Weak references cleared by RemoveStreamList() in StreamList destructors.
277 nsTArray<NotNull<StreamList*>> mStreamLists;
279 bool mShuttingDown;
280 State mState;
282 struct CacheIdRefCounter {
283 CacheId mCacheId;
284 MozRefCountType mCount;
285 bool mOrphaned;
287 nsTArray<CacheIdRefCounter> mCacheIdRefs;
289 struct BodyIdRefCounter {
290 nsID mBodyId;
291 MozRefCountType mCount;
292 bool mOrphaned;
294 nsTArray<BodyIdRefCounter> mBodyIdRefs;
296 struct ConstructorGuard {};
298 void DoStringify(nsACString& aData) override;
300 public:
301 Manager(SafeRefPtr<ManagerId> aManagerId, nsIThread* aIOThread,
302 const ConstructorGuard&);
303 ~Manager();
305 NS_DECL_OWNINGTHREAD
306 MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Manager)
309 } // namespace cache
310 } // namespace dom
311 } // namespace mozilla
313 #endif // mozilla_dom_cache_Manager_h