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