Bug 1913377 - Comment and assert that `allowedScope` has a very limited set of values...
[gecko.git] / dom / quota / DirectoryLockImpl.h
blob0c295115f41ba87ac0b97a220dcbb619918b80dc
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef DOM_QUOTA_DIRECTORYLOCKIMPL_H_
8 #define DOM_QUOTA_DIRECTORYLOCKIMPL_H_
10 #include "mozilla/MozPromise.h"
11 #include "mozilla/dom/FlippedOnce.h"
12 #include "mozilla/dom/quota/CommonMetadata.h"
13 #include "mozilla/dom/quota/DirectoryLock.h"
14 #include "mozilla/dom/quota/DirectoryLockCategory.h"
15 #include "mozilla/dom/quota/OriginScope.h"
16 #include "mozilla/dom/quota/PersistenceScope.h"
18 namespace mozilla::dom::quota {
20 enum class ShouldUpdateLockIdTableFlag { No, Yes };
22 class DirectoryLockImpl final : public ClientDirectoryLock,
23 public UniversalDirectoryLock {
24 const NotNull<RefPtr<QuotaManager>> mQuotaManager;
26 const PersistenceScope mPersistenceScope;
27 const nsCString mSuffix;
28 const nsCString mGroup;
29 const OriginScope mOriginScope;
30 const nsCString mStorageOrigin;
31 const Nullable<Client::Type> mClientType;
32 MozPromiseHolder<BoolPromise> mAcquirePromiseHolder;
33 std::function<void()> mInvalidateCallback;
35 nsTArray<NotNull<DirectoryLockImpl*>> mBlocking;
36 nsTArray<NotNull<DirectoryLockImpl*>> mBlockedOn;
38 const int64_t mId;
40 const bool mIsPrivate;
42 const bool mExclusive;
44 // Internal quota manager operations use this flag to prevent directory lock
45 // registraction/unregistration from updating origin access time, etc.
46 const bool mInternal;
48 const bool mShouldUpdateLockIdTable;
50 const DirectoryLockCategory mCategory;
52 bool mRegistered;
53 FlippedOnce<true> mPending;
54 FlippedOnce<false> mInvalidated;
55 FlippedOnce<false> mAcquired;
56 FlippedOnce<false> mDropped;
58 public:
59 DirectoryLockImpl(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
60 const PersistenceScope& aPersistenceScope,
61 const nsACString& aSuffix, const nsACString& aGroup,
62 const OriginScope& aOriginScope,
63 const nsACString& aStorageOrigin, bool aIsPrivate,
64 const Nullable<Client::Type>& aClientType, bool aExclusive,
65 bool aInternal,
66 ShouldUpdateLockIdTableFlag aShouldUpdateLockIdTableFlag,
67 DirectoryLockCategory aCategory);
69 static RefPtr<ClientDirectoryLock> Create(
70 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
71 PersistenceType aPersistenceType,
72 const quota::OriginMetadata& aOriginMetadata, Client::Type aClientType,
73 bool aExclusive) {
74 return Create(std::move(aQuotaManager),
75 PersistenceScope::CreateFromValue(aPersistenceType),
76 aOriginMetadata.mSuffix, aOriginMetadata.mGroup,
77 OriginScope::FromOrigin(aOriginMetadata.mOrigin),
78 aOriginMetadata.mStorageOrigin, aOriginMetadata.mIsPrivate,
79 Nullable<Client::Type>(aClientType), aExclusive, false,
80 ShouldUpdateLockIdTableFlag::Yes,
81 DirectoryLockCategory::None);
84 static RefPtr<OriginDirectoryLock> CreateForEviction(
85 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
86 PersistenceType aPersistenceType,
87 const quota::OriginMetadata& aOriginMetadata) {
88 MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_INVALID);
89 MOZ_ASSERT(!aOriginMetadata.mOrigin.IsEmpty());
90 MOZ_ASSERT(!aOriginMetadata.mStorageOrigin.IsEmpty());
92 return Create(std::move(aQuotaManager),
93 PersistenceScope::CreateFromValue(aPersistenceType),
94 aOriginMetadata.mSuffix, aOriginMetadata.mGroup,
95 OriginScope::FromOrigin(aOriginMetadata.mOrigin),
96 aOriginMetadata.mStorageOrigin, aOriginMetadata.mIsPrivate,
97 Nullable<Client::Type>(),
98 /* aExclusive */ true, /* aInternal */ true,
99 ShouldUpdateLockIdTableFlag::No, DirectoryLockCategory::None);
102 static RefPtr<UniversalDirectoryLock> CreateInternal(
103 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
104 const PersistenceScope& aPersistenceScope,
105 const OriginScope& aOriginScope,
106 const Nullable<Client::Type>& aClientType, bool aExclusive,
107 DirectoryLockCategory aCategory) {
108 return Create(std::move(aQuotaManager), aPersistenceScope, ""_ns, ""_ns,
109 aOriginScope, ""_ns, false, aClientType, aExclusive, true,
110 ShouldUpdateLockIdTableFlag::Yes, aCategory);
113 void AssertIsOnOwningThread() const
114 #ifdef DEBUG
116 #else
119 #endif
121 bool IsInternal() const { return mInternal; }
123 void SetRegistered(bool aRegistered) { mRegistered = aRegistered; }
125 bool IsPending() const { return mPending; }
127 // Ideally, we would have just one table (instead of these two:
128 // QuotaManager::mDirectoryLocks and QuotaManager::mDirectoryLockIdTable) for
129 // all registered locks. However, some directory locks need to be accessed off
130 // the PBackground thread, so the access must be protected by the quota mutex.
131 // The problem is that directory locks for eviction must be currently created
132 // while the mutex lock is already acquired. So we decided to have two tables
133 // for now and to not register directory locks for eviction in
134 // QuotaManager::mDirectoryLockIdTable. This can be improved in future after
135 // some refactoring of the mutex locking.
136 bool ShouldUpdateLockIdTable() const { return mShouldUpdateLockIdTable; }
138 bool ShouldUpdateLockTable() {
139 return !mInternal &&
140 mPersistenceScope.GetValue() != PERSISTENCE_TYPE_PERSISTENT;
143 bool Overlaps(const DirectoryLockImpl& aLock) const;
145 // Test whether this DirectoryLock needs to wait for the given lock.
146 bool MustWaitFor(const DirectoryLockImpl& aLock) const;
148 void AddBlockingLock(DirectoryLockImpl& aLock) {
149 AssertIsOnOwningThread();
151 mBlocking.AppendElement(WrapNotNull(&aLock));
154 const nsTArray<NotNull<DirectoryLockImpl*>>& GetBlockedOnLocks() {
155 return mBlockedOn;
158 void AddBlockedOnLock(DirectoryLockImpl& aLock) {
159 AssertIsOnOwningThread();
161 mBlockedOn.AppendElement(WrapNotNull(&aLock));
164 void MaybeUnblock(DirectoryLockImpl& aLock) {
165 AssertIsOnOwningThread();
167 mBlockedOn.RemoveElement(&aLock);
168 if (mBlockedOn.IsEmpty()) {
169 NotifyOpenListener();
173 void NotifyOpenListener();
175 void Invalidate();
177 void Unregister();
179 // DirectoryLock interface
181 NS_INLINE_DECL_REFCOUNTING(DirectoryLockImpl, override)
183 int64_t Id() const override { return mId; }
185 DirectoryLockCategory Category() const override { return mCategory; }
187 bool Acquired() const override { return mAcquired; }
189 bool MustWait() const override;
191 nsTArray<RefPtr<DirectoryLock>> LocksMustWaitFor() const override;
193 bool Dropped() const override { return mDropped; }
195 RefPtr<BoolPromise> Acquire() override;
197 void AcquireImmediately() override;
199 void AssertIsAcquiredExclusively() override
200 #ifdef DEBUG
202 #else
205 #endif
207 RefPtr<BoolPromise> Drop() override;
209 void OnInvalidate(std::function<void()>&& aCallback) override;
211 void Log() const override;
213 // OriginDirectoryLock interface
215 PersistenceType GetPersistenceType() const override {
216 MOZ_DIAGNOSTIC_ASSERT(mPersistenceScope.IsValue());
218 return mPersistenceScope.GetValue();
221 quota::OriginMetadata OriginMetadata() const override {
222 MOZ_DIAGNOSTIC_ASSERT(!mGroup.IsEmpty());
224 return quota::OriginMetadata{
225 mSuffix, mGroup, nsCString(Origin()),
226 mStorageOrigin, mIsPrivate, GetPersistenceType()};
229 const nsACString& Origin() const override {
230 MOZ_DIAGNOSTIC_ASSERT(mOriginScope.IsOrigin());
231 MOZ_DIAGNOSTIC_ASSERT(!mOriginScope.GetOrigin().IsEmpty());
233 return mOriginScope.GetOrigin();
236 // ClientDirectoryLock interface
238 Client::Type ClientType() const override {
239 MOZ_DIAGNOSTIC_ASSERT(!mClientType.IsNull());
240 MOZ_DIAGNOSTIC_ASSERT(mClientType.Value() < Client::TypeMax());
242 return mClientType.Value();
245 // UniversalDirectoryLock interface
247 const PersistenceScope& PersistenceScopeRef() const override {
248 return mPersistenceScope;
251 const OriginScope& GetOriginScope() const override { return mOriginScope; }
253 const Nullable<Client::Type>& NullableClientType() const override {
254 return mClientType;
257 RefPtr<ClientDirectoryLock> SpecializeForClient(
258 PersistenceType aPersistenceType,
259 const quota::OriginMetadata& aOriginMetadata,
260 Client::Type aClientType) const override;
262 private:
263 ~DirectoryLockImpl();
265 static RefPtr<DirectoryLockImpl> Create(
266 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
267 const PersistenceScope& aPersistenceScope, const nsACString& aSuffix,
268 const nsACString& aGroup, const OriginScope& aOriginScope,
269 const nsACString& aStorageOrigin, bool aIsPrivate,
270 const Nullable<Client::Type>& aClientType, bool aExclusive,
271 bool aInternal, ShouldUpdateLockIdTableFlag aShouldUpdateLockIdTableFlag,
272 DirectoryLockCategory aCategory) {
273 MOZ_ASSERT_IF(aOriginScope.IsOrigin(), !aOriginScope.GetOrigin().IsEmpty());
274 MOZ_ASSERT_IF(!aInternal, aPersistenceScope.IsValue());
275 MOZ_ASSERT_IF(!aInternal,
276 aPersistenceScope.GetValue() != PERSISTENCE_TYPE_INVALID);
277 MOZ_ASSERT_IF(!aInternal, !aGroup.IsEmpty());
278 MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin());
279 MOZ_ASSERT_IF(!aInternal, !aStorageOrigin.IsEmpty());
280 MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull());
281 MOZ_ASSERT_IF(!aInternal, aClientType.Value() < Client::TypeMax());
283 return MakeRefPtr<DirectoryLockImpl>(
284 std::move(aQuotaManager), aPersistenceScope, aSuffix, aGroup,
285 aOriginScope, aStorageOrigin, aIsPrivate, aClientType, aExclusive,
286 aInternal, aShouldUpdateLockIdTableFlag, aCategory);
289 void AcquireInternal();
292 } // namespace mozilla::dom::quota
294 #endif // DOM_QUOTA_DIRECTORYLOCKIMPL_H_