diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/cache/Manager.h | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/cache/Manager.h')
-rw-r--r-- | dom/cache/Manager.h | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/dom/cache/Manager.h b/dom/cache/Manager.h new file mode 100644 index 0000000000..d5ebce6d48 --- /dev/null +++ b/dom/cache/Manager.h @@ -0,0 +1,310 @@ +/* -*- 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/RefPtr.h" +#include "mozilla/dom/SafeRefPtr.h" +#include "mozilla/dom/cache/Types.h" +#include "mozilla/dom/quota/Client.h" +#include "CacheCommon.h" +#include "nsCOMPtr.h" +#include "nsISupportsImpl.h" +#include "nsString.h" +#include "nsTArray.h" + +class nsIInputStream; +class nsIThread; + +namespace mozilla { + +class ErrorResult; + +namespace dom { + +namespace quota { + +class DirectoryLock; + +} // namespace quota + +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 SafeRefCounted<Manager> { + using Client = quota::Client; + using DirectoryLock = quota::DirectoryLock; + + 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); + + struct StreamInfo { + const nsTArray<SavedResponse>& mSavedResponseList; + const nsTArray<SavedRequest>& mSavedRequestList; + StreamList& mStreamList; + }; + + // interface to be implemented + virtual void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult, + CacheId aOpenedCacheId, + const Maybe<StreamInfo>& aStreamInfo) {} + + protected: + ~Listener() = default; + }; + + enum State { Open, Closing }; + + static Result<SafeRefPtr<Manager>, nsresult> AcquireCreateIfNonExistent( + const SafeRefPtr<ManagerId>& aManagerId); + + static void InitiateShutdown(); + + static bool IsShutdownAllComplete(); + + static nsCString GetShutdownStatus(); + + // Cancel actions for given DirectoryLock ids. + static void Abort(const Client::DirectoryLockIdTable& aDirectoryLockIds); + + // Cancel all actions. + static void AbortAll(); + + // 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); + + const ManagerId& GetManagerId() const; + + Maybe<DirectoryLock&> MaybeDirectoryLockRef() 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); + + void ExecuteOpenStream(Listener* aListener, InputStreamResolver&& aResolver, + const nsID& aBodyId); + + void NoteStreamOpenComplete(const nsID& aBodyId, ErrorResult&& aRv, + nsCOMPtr<nsIInputStream>&& aBodyStream); + +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + void RecordMayNotDeleteCSCP(int32_t aCacheStreamControlParentId); + void RecordHaveDeletedCSCP(int32_t aCacheStreamControlParentId); +#endif + + 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; + + class OpenStreamAction; + + using ListenerId = uint64_t; + + void Init(Maybe<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(); + + SafeRefPtr<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; + } + }; + + using ListenerList = nsTArray<ListenerEntry>; + ListenerList mListeners; + static ListenerId sNextListenerId; + + // Weak references cleared by RemoveStreamList() in StreamList destructors. + nsTArray<NotNull<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; + + struct ConstructorGuard {}; + + public: + Manager(SafeRefPtr<ManagerId> aManagerId, nsIThread* aIOThread, + const ConstructorGuard&); + ~Manager(); + + NS_DECL_OWNINGTHREAD + MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Manager) +}; + +} // namespace cache +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_cache_Manager_h |