summaryrefslogtreecommitdiffstats
path: root/dom/quota/DirectoryLockImpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/DirectoryLockImpl.h')
-rw-r--r--dom/quota/DirectoryLockImpl.h273
1 files changed, 273 insertions, 0 deletions
diff --git a/dom/quota/DirectoryLockImpl.h b/dom/quota/DirectoryLockImpl.h
new file mode 100644
index 0000000000..818d1c81bd
--- /dev/null
+++ b/dom/quota/DirectoryLockImpl.h
@@ -0,0 +1,273 @@
+/* -*- 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 DOM_QUOTA_DIRECTORYLOCKIMPL_H_
+#define DOM_QUOTA_DIRECTORYLOCKIMPL_H_
+
+#include "mozilla/InitializedOnce.h"
+#include "mozilla/MozPromise.h"
+#include "mozilla/dom/FlippedOnce.h"
+#include "mozilla/dom/quota/CommonMetadata.h"
+#include "mozilla/dom/quota/DirectoryLock.h"
+#include "mozilla/dom/quota/OriginScope.h"
+
+namespace mozilla::dom::quota {
+
+enum class ShouldUpdateLockIdTableFlag { No, Yes };
+
+class DirectoryLockImpl final : public ClientDirectoryLock,
+ public UniversalDirectoryLock {
+ const NotNull<RefPtr<QuotaManager>> mQuotaManager;
+
+ const Nullable<PersistenceType> mPersistenceType;
+ const nsCString mSuffix;
+ const nsCString mGroup;
+ const OriginScope mOriginScope;
+ const Nullable<Client::Type> mClientType;
+ LazyInitializedOnceEarlyDestructible<
+ const NotNull<RefPtr<OpenDirectoryListener>>>
+ mOpenListener;
+ MozPromiseHolder<BoolPromise> mAcquirePromiseHolder;
+
+ nsTArray<NotNull<DirectoryLockImpl*>> mBlocking;
+ nsTArray<NotNull<DirectoryLockImpl*>> mBlockedOn;
+
+ const int64_t mId;
+
+ const bool mExclusive;
+
+ // Internal quota manager operations use this flag to prevent directory lock
+ // registraction/unregistration from updating origin access time, etc.
+ const bool mInternal;
+
+ const bool mShouldUpdateLockIdTable;
+
+ bool mRegistered;
+ FlippedOnce<true> mPending;
+ FlippedOnce<false> mInvalidated;
+
+#ifdef DEBUG
+ FlippedOnce<false> mAcquired;
+#endif
+
+ public:
+ DirectoryLockImpl(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const Nullable<PersistenceType>& aPersistenceType,
+ const nsACString& aSuffix, const nsACString& aGroup,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType, bool aExclusive,
+ bool aInternal,
+ ShouldUpdateLockIdTableFlag aShouldUpdateLockIdTableFlag);
+
+ static RefPtr<ClientDirectoryLock> Create(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ PersistenceType aPersistenceType,
+ const quota::OriginMetadata& aOriginMetadata, Client::Type aClientType,
+ bool aExclusive) {
+ return Create(std::move(aQuotaManager),
+ Nullable<PersistenceType>(aPersistenceType),
+ aOriginMetadata.mSuffix, aOriginMetadata.mGroup,
+ OriginScope::FromOrigin(aOriginMetadata.mOrigin),
+ Nullable<Client::Type>(aClientType), aExclusive, false,
+ ShouldUpdateLockIdTableFlag::Yes);
+ }
+
+ static RefPtr<OriginDirectoryLock> CreateForEviction(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ PersistenceType aPersistenceType,
+ const quota::OriginMetadata& aOriginMetadata) {
+ MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_INVALID);
+ MOZ_ASSERT(!aOriginMetadata.mOrigin.IsEmpty());
+
+ return Create(std::move(aQuotaManager),
+ Nullable<PersistenceType>(aPersistenceType),
+ aOriginMetadata.mSuffix, aOriginMetadata.mGroup,
+ OriginScope::FromOrigin(aOriginMetadata.mOrigin),
+ Nullable<Client::Type>(),
+ /* aExclusive */ true, /* aInternal */ true,
+ ShouldUpdateLockIdTableFlag::No);
+ }
+
+ static RefPtr<UniversalDirectoryLock> CreateInternal(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const Nullable<PersistenceType>& aPersistenceType,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType, bool aExclusive) {
+ return Create(std::move(aQuotaManager), aPersistenceType, ""_ns, ""_ns,
+ aOriginScope, aClientType, aExclusive, true,
+ ShouldUpdateLockIdTableFlag::Yes);
+ }
+
+ void AssertIsOnOwningThread() const
+#ifdef DEBUG
+ ;
+#else
+ {
+ }
+#endif
+
+ bool IsInternal() const { return mInternal; }
+
+ void SetRegistered(bool aRegistered) { mRegistered = aRegistered; }
+
+ bool IsPending() const { return mPending; }
+
+ // Ideally, we would have just one table (instead of these two:
+ // QuotaManager::mDirectoryLocks and QuotaManager::mDirectoryLockIdTable) for
+ // all registered locks. However, some directory locks need to be accessed off
+ // the PBackground thread, so the access must be protected by the quota mutex.
+ // The problem is that directory locks for eviction must be currently created
+ // while the mutex lock is already acquired. So we decided to have two tables
+ // for now and to not register directory locks for eviction in
+ // QuotaManager::mDirectoryLockIdTable. This can be improved in future after
+ // some refactoring of the mutex locking.
+ bool ShouldUpdateLockIdTable() const { return mShouldUpdateLockIdTable; }
+
+ bool ShouldUpdateLockTable() {
+ return !mInternal &&
+ mPersistenceType.Value() != PERSISTENCE_TYPE_PERSISTENT;
+ }
+
+ bool Overlaps(const DirectoryLockImpl& aLock) const;
+
+ // Test whether this DirectoryLock needs to wait for the given lock.
+ bool MustWaitFor(const DirectoryLockImpl& aLock) const;
+
+ void AddBlockingLock(DirectoryLockImpl& aLock) {
+ AssertIsOnOwningThread();
+
+ mBlocking.AppendElement(WrapNotNull(&aLock));
+ }
+
+ const nsTArray<NotNull<DirectoryLockImpl*>>& GetBlockedOnLocks() {
+ return mBlockedOn;
+ }
+
+ void AddBlockedOnLock(DirectoryLockImpl& aLock) {
+ AssertIsOnOwningThread();
+
+ mBlockedOn.AppendElement(WrapNotNull(&aLock));
+ }
+
+ void MaybeUnblock(DirectoryLockImpl& aLock) {
+ AssertIsOnOwningThread();
+
+ mBlockedOn.RemoveElement(&aLock);
+ if (mBlockedOn.IsEmpty()) {
+ NotifyOpenListener();
+ }
+ }
+
+ void NotifyOpenListener();
+
+ void Invalidate() {
+ AssertIsOnOwningThread();
+
+ mInvalidated.EnsureFlipped();
+ }
+
+ // DirectoryLock interface
+
+ NS_INLINE_DECL_REFCOUNTING(DirectoryLockImpl, override)
+
+ int64_t Id() const override { return mId; }
+
+ void Acquire(RefPtr<OpenDirectoryListener> aOpenListener) override;
+
+ RefPtr<BoolPromise> Acquire() override;
+
+ void AcquireImmediately() override;
+
+ void AssertIsAcquiredExclusively() override
+#ifdef DEBUG
+ ;
+#else
+ {
+ }
+#endif
+
+ void Log() const override;
+
+ // OriginDirectoryLock interface
+
+ PersistenceType GetPersistenceType() const override {
+ MOZ_DIAGNOSTIC_ASSERT(!mPersistenceType.IsNull());
+
+ return mPersistenceType.Value();
+ }
+
+ quota::OriginMetadata OriginMetadata() const override {
+ MOZ_DIAGNOSTIC_ASSERT(!mGroup.IsEmpty());
+
+ return quota::OriginMetadata{mSuffix, mGroup, nsCString(Origin()),
+ GetPersistenceType()};
+ }
+
+ const nsACString& Origin() const override {
+ MOZ_DIAGNOSTIC_ASSERT(mOriginScope.IsOrigin());
+ MOZ_DIAGNOSTIC_ASSERT(!mOriginScope.GetOrigin().IsEmpty());
+
+ return mOriginScope.GetOrigin();
+ }
+
+ // ClientDirectoryLock interface
+
+ Client::Type ClientType() const override {
+ MOZ_DIAGNOSTIC_ASSERT(!mClientType.IsNull());
+ MOZ_DIAGNOSTIC_ASSERT(mClientType.Value() < Client::TypeMax());
+
+ return mClientType.Value();
+ }
+
+ // UniversalDirectoryLock interface
+
+ const Nullable<PersistenceType>& NullablePersistenceType() const override {
+ return mPersistenceType;
+ }
+
+ const OriginScope& GetOriginScope() const override { return mOriginScope; }
+
+ const Nullable<Client::Type>& NullableClientType() const override {
+ return mClientType;
+ }
+
+ RefPtr<ClientDirectoryLock> SpecializeForClient(
+ PersistenceType aPersistenceType,
+ const quota::OriginMetadata& aOriginMetadata,
+ Client::Type aClientType) const override;
+
+ private:
+ ~DirectoryLockImpl();
+
+ static RefPtr<DirectoryLockImpl> Create(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const Nullable<PersistenceType>& aPersistenceType,
+ const nsACString& aSuffix, const nsACString& aGroup,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType, bool aExclusive,
+ bool aInternal,
+ ShouldUpdateLockIdTableFlag aShouldUpdateLockIdTableFlag) {
+ MOZ_ASSERT_IF(aOriginScope.IsOrigin(), !aOriginScope.GetOrigin().IsEmpty());
+ MOZ_ASSERT_IF(!aInternal, !aPersistenceType.IsNull());
+ MOZ_ASSERT_IF(!aInternal,
+ aPersistenceType.Value() != PERSISTENCE_TYPE_INVALID);
+ MOZ_ASSERT_IF(!aInternal, !aGroup.IsEmpty());
+ MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin());
+ MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull());
+ MOZ_ASSERT_IF(!aInternal, aClientType.Value() < Client::TypeMax());
+
+ return MakeRefPtr<DirectoryLockImpl>(
+ std::move(aQuotaManager), aPersistenceType, aSuffix, aGroup,
+ aOriginScope, aClientType, aExclusive, aInternal,
+ aShouldUpdateLockIdTableFlag);
+ }
+
+ void AcquireInternal();
+};
+
+} // namespace mozilla::dom::quota
+
+#endif // DOM_QUOTA_DIRECTORYLOCKIMPL_H_