Line data Source code
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/. */
6 :
7 : #ifndef mozilla_dom_cache_Manager_h
8 : #define mozilla_dom_cache_Manager_h
9 :
10 : #include "mozilla/dom/cache/Types.h"
11 : #include "nsCOMPtr.h"
12 : #include "nsISupportsImpl.h"
13 : #include "mozilla/RefPtr.h"
14 : #include "nsString.h"
15 : #include "nsTArray.h"
16 :
17 : class nsIInputStream;
18 : class nsIThread;
19 :
20 : namespace mozilla {
21 :
22 : class ErrorResult;
23 :
24 : namespace dom {
25 : namespace cache {
26 :
27 : class CacheOpArgs;
28 : class CacheOpResult;
29 : class CacheRequestResponse;
30 : class Context;
31 : class ManagerId;
32 : struct SavedRequest;
33 : struct SavedResponse;
34 : class StreamList;
35 :
36 : // The Manager is class is responsible for performing all of the underlying
37 : // work for a Cache or CacheStorage operation. The DOM objects and IPC actors
38 : // are basically just plumbing to get the request to the right Manager object
39 : // running in the parent process.
40 : //
41 : // There should be exactly one Manager object for each origin or app using the
42 : // Cache API. This uniqueness is defined by the ManagerId equality operator.
43 : // The uniqueness is enforced by the Manager GetOrCreate() factory method.
44 : //
45 : // The life cycle of Manager objects is somewhat complex. While code may
46 : // hold a strong reference to the Manager, it will invalidate itself once it
47 : // believes it has become completely idle. This is currently determined when
48 : // all of the following conditions occur:
49 : //
50 : // 1) There are no more Manager::Listener objects registered with the Manager
51 : // by performing a Cache or Storage operation.
52 : // 2) There are no more CacheId references noted via Manager::AddRefCacheId().
53 : // 3) There are no more BodyId references noted via Manager::AddRefBodyId().
54 : //
55 : // In order to keep your Manager alive you should perform an operation to set
56 : // a Listener, call AddRefCacheId(), or call AddRefBodyId().
57 : //
58 : // Even once a Manager becomes invalid, however, it may still continue to
59 : // exist. This is allowed so that any in-progress Actions can gracefully
60 : // complete.
61 : //
62 : // As an invariant, all Manager objects must cease all IO before shutdown. This
63 : // is enforced by the Manager::Factory. If content still holds references to
64 : // Cache DOM objects during shutdown, then all operations will begin rejecting.
65 : class Manager final
66 : {
67 : public:
68 : // Callback interface implemented by clients of Manager, such as CacheParent
69 : // and CacheStorageParent. In general, if you call a Manager method you
70 : // should expect to receive exactly one On*() callback. For example, if
71 : // you call Manager::CacheMatch(), then you should expect to receive
72 : // OnCacheMatch() back in response.
73 : //
74 : // Listener objects are set on a per-operation basis. So you pass the
75 : // Listener to a call like Manager::CacheMatch(). Once set in this way,
76 : // the Manager will continue to reference the Listener until RemoveListener()
77 : // is called. This is done to allow the same listener to be used for
78 : // multiple operations simultaneously without having to maintain an exact
79 : // count of operations-in-flight.
80 : //
81 : // Note, the Manager only holds weak references to Listener objects.
82 : // Listeners must call Manager::RemoveListener() before they are destroyed
83 : // to clear these weak references.
84 : //
85 : // All public methods should be invoked on the same thread used to create
86 : // the Manager.
87 0 : class Listener
88 : {
89 : public:
90 : // convenience routines
91 : void
92 : OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult);
93 :
94 : void
95 : OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
96 : CacheId aOpenedCacheId);
97 :
98 : void
99 : OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
100 : const SavedResponse& aSavedResponse,
101 : StreamList* aStreamList);
102 :
103 : void
104 : OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
105 : const nsTArray<SavedResponse>& aSavedResponseList,
106 : StreamList* aStreamList);
107 :
108 : void
109 : OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
110 : const nsTArray<SavedRequest>& aSavedRequestList,
111 : StreamList* aStreamList);
112 :
113 : // interface to be implemented
114 : virtual void
115 0 : OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
116 : CacheId aOpenedCacheId,
117 : const nsTArray<SavedResponse>& aSavedResponseList,
118 : const nsTArray<SavedRequest>& aSavedRequestList,
119 0 : StreamList* aStreamList) { }
120 :
121 : protected:
122 0 : ~Listener() { }
123 : };
124 :
125 : enum State
126 : {
127 : Open,
128 : Closing
129 : };
130 :
131 : static nsresult GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut);
132 : static already_AddRefed<Manager> Get(ManagerId* aManagerId);
133 :
134 : // Synchronously shutdown. This spins the event loop.
135 : static void ShutdownAll();
136 :
137 : // Cancel actions for given origin or all actions if passed string is null.
138 : static void Abort(const nsACString& aOrigin);
139 :
140 : // Must be called by Listener objects before they are destroyed.
141 : void RemoveListener(Listener* aListener);
142 :
143 : // Must be called by Context objects before they are destroyed.
144 : void RemoveContext(Context* aContext);
145 :
146 : // Marks the Manager "invalid". Once the Context completes no new operations
147 : // will be permitted with this Manager. New actors will get a new Manager.
148 : void NoteClosing();
149 :
150 : State GetState() const;
151 :
152 : // If an actor represents a long term reference to a cache or body stream,
153 : // then they must call AddRefCacheId() or AddRefBodyId(). This will
154 : // cause the Manager to keep the backing data store alive for the given
155 : // object. The actor must then call ReleaseCacheId() or ReleaseBodyId()
156 : // exactly once for every AddRef*() call it made. Any delayed deletion
157 : // will then be performed.
158 : void AddRefCacheId(CacheId aCacheId);
159 : void ReleaseCacheId(CacheId aCacheId);
160 : void AddRefBodyId(const nsID& aBodyId);
161 : void ReleaseBodyId(const nsID& aBodyId);
162 :
163 : already_AddRefed<ManagerId> GetManagerId() const;
164 :
165 : // Methods to allow a StreamList to register themselves with the Manager.
166 : // StreamList objects must call RemoveStreamList() before they are destroyed.
167 : void AddStreamList(StreamList* aStreamList);
168 : void RemoveStreamList(StreamList* aStreamList);
169 :
170 : void ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
171 : const CacheOpArgs& aOpArgs);
172 : void ExecutePutAll(Listener* aListener, CacheId aCacheId,
173 : const nsTArray<CacheRequestResponse>& aPutList,
174 : const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
175 : const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList);
176 :
177 : void ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
178 : const CacheOpArgs& aOpArgs);
179 :
180 : private:
181 : class Factory;
182 : class BaseAction;
183 : class DeleteOrphanedCacheAction;
184 :
185 : class CacheMatchAction;
186 : class CacheMatchAllAction;
187 : class CachePutAllAction;
188 : class CacheDeleteAction;
189 : class CacheKeysAction;
190 :
191 : class StorageMatchAction;
192 : class StorageHasAction;
193 : class StorageOpenAction;
194 : class StorageDeleteAction;
195 : class StorageKeysAction;
196 :
197 : typedef uint64_t ListenerId;
198 :
199 : Manager(ManagerId* aManagerId, nsIThread* aIOThread);
200 : ~Manager();
201 : void Init(Manager* aOldManager);
202 : void Shutdown();
203 :
204 : void Abort();
205 :
206 : ListenerId SaveListener(Listener* aListener);
207 : Listener* GetListener(ListenerId aListenerId) const;
208 :
209 : bool SetCacheIdOrphanedIfRefed(CacheId aCacheId);
210 : bool SetBodyIdOrphanedIfRefed(const nsID& aBodyId);
211 : void NoteOrphanedBodyIdList(const nsTArray<nsID>& aDeletedBodyIdList);
212 :
213 : void MaybeAllowContextToClose();
214 :
215 : RefPtr<ManagerId> mManagerId;
216 : nsCOMPtr<nsIThread> mIOThread;
217 :
218 : // Weak reference cleared by RemoveContext() in Context destructor.
219 : Context* MOZ_NON_OWNING_REF mContext;
220 :
221 : // Weak references cleared by RemoveListener() in Listener destructors.
222 : struct ListenerEntry
223 : {
224 : ListenerEntry()
225 : : mId(UINT64_MAX)
226 : , mListener(nullptr)
227 : {
228 : }
229 :
230 0 : ListenerEntry(ListenerId aId, Listener* aListener)
231 0 : : mId(aId)
232 0 : , mListener(aListener)
233 : {
234 0 : }
235 :
236 : ListenerId mId;
237 : Listener* mListener;
238 : };
239 :
240 : class ListenerEntryIdComparator
241 : {
242 : public:
243 0 : bool Equals(const ListenerEntry& aA, const ListenerId& aB) const
244 : {
245 0 : return aA.mId == aB;
246 : }
247 : };
248 :
249 : class ListenerEntryListenerComparator
250 : {
251 : public:
252 0 : bool Equals(const ListenerEntry& aA, const Listener* aB) const
253 : {
254 0 : return aA.mListener == aB;
255 : }
256 : };
257 :
258 : typedef nsTArray<ListenerEntry> ListenerList;
259 : ListenerList mListeners;
260 : static ListenerId sNextListenerId;
261 :
262 : // Weak references cleared by RemoveStreamList() in StreamList destructors.
263 : nsTArray<StreamList*> mStreamLists;
264 :
265 : bool mShuttingDown;
266 : State mState;
267 :
268 : struct CacheIdRefCounter
269 : {
270 : CacheId mCacheId;
271 : MozRefCountType mCount;
272 : bool mOrphaned;
273 : };
274 : nsTArray<CacheIdRefCounter> mCacheIdRefs;
275 :
276 : struct BodyIdRefCounter
277 : {
278 : nsID mBodyId;
279 : MozRefCountType mCount;
280 : bool mOrphaned;
281 : };
282 : nsTArray<BodyIdRefCounter> mBodyIdRefs;
283 :
284 : public:
285 0 : NS_INLINE_DECL_REFCOUNTING(cache::Manager)
286 : };
287 :
288 : } // namespace cache
289 : } // namespace dom
290 : } // namespace mozilla
291 :
292 : #endif // mozilla_dom_cache_Manager_h
|