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"
17 #include "nsISupportsImpl.h"
32 class ClientDirectoryLock
;
40 class CacheRequestResponse
;
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
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 ClientDirectoryLock
= quota::ClientDirectoryLock
;
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
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
);
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
) {}
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.
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
<ClientDirectoryLock
&> 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
);
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
);
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
);
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
) {}
258 class ListenerEntryIdComparator
{
260 bool Equals(const ListenerEntry
& aA
, const ListenerId
& aB
) const {
265 class ListenerEntryListenerComparator
{
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
;
282 struct CacheIdRefCounter
{
284 MozRefCountType mCount
;
287 nsTArray
<CacheIdRefCounter
> mCacheIdRefs
;
289 struct BodyIdRefCounter
{
291 MozRefCountType mCount
;
294 nsTArray
<BodyIdRefCounter
> mBodyIdRefs
;
296 struct ConstructorGuard
{};
298 void DoStringify(nsACString
& aData
) override
;
301 Manager(SafeRefPtr
<ManagerId
> aManagerId
, nsIThread
* aIOThread
,
302 const ConstructorGuard
&);
306 MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Manager
)
311 } // namespace mozilla
313 #endif // mozilla_dom_cache_Manager_h