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
;
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.
48 const bool mShouldUpdateLockIdTable
;
50 const DirectoryLockCategory mCategory
;
53 FlippedOnce
<true> mPending
;
54 FlippedOnce
<false> mInvalidated
;
55 FlippedOnce
<false> mAcquired
;
56 FlippedOnce
<false> mDropped
;
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
,
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
,
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
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() {
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() {
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();
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
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
{
257 RefPtr
<ClientDirectoryLock
> SpecializeForClient(
258 PersistenceType aPersistenceType
,
259 const quota::OriginMetadata
& aOriginMetadata
,
260 Client::Type aClientType
) const override
;
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_