зеркало из https://github.com/mozilla/gecko-dev.git
311 строки
10 KiB
C++
311 строки
10 KiB
C++
/* -*- 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
|