Bug 1689293 - Introduce DirectoryLock::Acquire; r=sg

Quota clients instead of doing:
RefPtr<DirectoryLock> pendingDirectoryLock = qm->OpenDirectory(..., listener);

now do:
RefPtr<DirectoryLock> directoryLock = qm->CreateDirectoryLock(...);
directoryLock->Acquire(listener);

Differential Revision: https://phabricator.services.mozilla.com/D103279
This commit is contained in:
Jan Varga 2021-02-02 08:20:18 +00:00
Родитель bb69a13c52
Коммит a8d359bfc5
6 изменённых файлов: 194 добавлений и 143 удалений

16
dom/cache/Context.cpp поставляемый
Просмотреть файл

@ -230,14 +230,16 @@ void Context::QuotaInitRunnable::OpenDirectory() {
mState == STATE_OPEN_DIRECTORY); mState == STATE_OPEN_DIRECTORY);
MOZ_DIAGNOSTIC_ASSERT(QuotaManager::Get()); MOZ_DIAGNOSTIC_ASSERT(QuotaManager::Get());
// QuotaManager::OpenDirectory() will hold a reference to us as RefPtr<DirectoryLock> directoryLock =
// a listener. We will then get DirectoryLockAcquired() on the owning QuotaManager::Get()->CreateDirectoryLock(
// thread when it is safe to access our storage directory. PERSISTENCE_TYPE_DEFAULT, mQuotaInfo, quota::Client::DOMCACHE,
/* aExclusive */ false);
// DirectoryLock::Acquire() will hold a reference to us as a listener. We will
// then get DirectoryLockAcquired() on the owning thread when it is safe to
// access our storage directory.
mState = STATE_WAIT_FOR_DIRECTORY_LOCK; mState = STATE_WAIT_FOR_DIRECTORY_LOCK;
RefPtr<DirectoryLock> pendingDirectoryLock = directoryLock->Acquire(this);
QuotaManager::Get()->OpenDirectory(PERSISTENCE_TYPE_DEFAULT, mQuotaInfo,
quota::Client::DOMCACHE,
/* aExclusive */ false, this);
} }
void Context::QuotaInitRunnable::DirectoryLockAcquired(DirectoryLock* aLock) { void Context::QuotaInitRunnable::DirectoryLockAcquired(DirectoryLock* aLock) {

Просмотреть файл

@ -13214,11 +13214,12 @@ void DeleteFilesRunnable::Open() {
return; return;
} }
mState = State_DirectoryOpenPending; RefPtr<DirectoryLock> directoryLock = quotaManager->CreateDirectoryLock(
RefPtr<DirectoryLock> pendingDirectoryLock = quotaManager->OpenDirectory(
mFileManager->Type(), mFileManager->GroupAndOrigin(), quota::Client::IDB, mFileManager->Type(), mFileManager->GroupAndOrigin(), quota::Client::IDB,
/* aExclusive */ false, this); /* aExclusive */ false);
mState = State_DirectoryOpenPending;
directoryLock->Acquire(this);
} }
void DeleteFilesRunnable::DoDatabaseWork() { void DeleteFilesRunnable::DoDatabaseWork() {
@ -13413,12 +13414,14 @@ nsresult Maintenance::OpenDirectory() {
// Get a shared lock for <profile>/storage/*/*/idb // Get a shared lock for <profile>/storage/*/*/idb
mState = State::DirectoryOpenPending; RefPtr<DirectoryLock> directoryLock =
RefPtr<DirectoryLock> pendingDirectoryLock = QuotaManager::Get()->CreateDirectoryLockInternal(
QuotaManager::Get()->OpenDirectoryInternal(
Nullable<PersistenceType>(), OriginScope::FromNull(), Nullable<PersistenceType>(), OriginScope::FromNull(),
Nullable<Client::Type>(Client::IDB), Nullable<Client::Type>(Client::IDB),
/* aExclusive */ false, this); /* aExclusive */ false);
mState = State::DirectoryOpenPending;
directoryLock->Acquire(this);
return NS_OK; return NS_OK;
} }
@ -15714,11 +15717,13 @@ nsresult FactoryOp::OpenDirectory() {
IDB_TRY_RETURN(MOZ_TO_RESULT_INVOKE_TYPED(nsString, dbFile, GetPath)); IDB_TRY_RETURN(MOZ_TO_RESULT_INVOKE_TYPED(nsString, dbFile, GetPath));
}())); }()));
RefPtr<DirectoryLock> directoryLock = quotaManager->CreateDirectoryLock(
persistenceType, mQuotaInfo, Client::IDB,
/* aExclusive */ false);
mState = State::DirectoryOpenPending; mState = State::DirectoryOpenPending;
RefPtr<DirectoryLock> pendingDirectoryLock = directoryLock->Acquire(this);
quotaManager->OpenDirectory(persistenceType, mQuotaInfo, Client::IDB,
/* aExclusive */ false, this);
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -6685,10 +6685,18 @@ nsresult PrepareDatastoreOp::OpenDirectory() {
MOZ_ASSERT(MayProceed()); MOZ_ASSERT(MayProceed());
MOZ_ASSERT(QuotaManager::Get()); MOZ_ASSERT(QuotaManager::Get());
mNestedState = NestedState::DirectoryOpenPending; mPendingDirectoryLock = QuotaManager::Get()->CreateDirectoryLock(
mPendingDirectoryLock = QuotaManager::Get()->OpenDirectory(
PERSISTENCE_TYPE_DEFAULT, mQuotaInfo, mozilla::dom::quota::Client::LS, PERSISTENCE_TYPE_DEFAULT, mQuotaInfo, mozilla::dom::quota::Client::LS,
/* aExclusive */ false, this); /* aExclusive */ false);
mNestedState = NestedState::DirectoryOpenPending;
{
// Pin the directory lock, because Acquire might clear mPendingDirectoryLock
// during the Acquire call.
RefPtr pinnedDirectoryLock = mPendingDirectoryLock;
pinnedDirectoryLock->Acquire(this);
}
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -666,8 +666,7 @@ class DirectoryLockImpl final : public DirectoryLock {
const nsACString& aGroup, const OriginScope& aOriginScope, const nsACString& aGroup, const OriginScope& aOriginScope,
const Nullable<Client::Type>& aClientType, bool aExclusive, const Nullable<Client::Type>& aClientType, bool aExclusive,
bool aInternal, bool aInternal,
ShouldUpdateLockIdTableFlag aShouldUpdateLockIdTableFlag, ShouldUpdateLockIdTableFlag aShouldUpdateLockIdTableFlag);
RefPtr<OpenDirectoryListener> aOpenListener);
void AssertIsOnOwningThread() const void AssertIsOnOwningThread() const
#ifdef DEBUG #ifdef DEBUG
@ -777,6 +776,10 @@ class DirectoryLockImpl final : public DirectoryLock {
return mClientType.Value(); return mClientType.Value();
} }
void Acquire(RefPtr<OpenDirectoryListener> aOpenListener);
void Acquire();
already_AddRefed<DirectoryLock> Specialize( already_AddRefed<DirectoryLock> Specialize(
PersistenceType aPersistenceType, PersistenceType aPersistenceType,
const quota::GroupAndOrigin& aGroupAndOrigin, const quota::GroupAndOrigin& aGroupAndOrigin,
@ -788,13 +791,19 @@ class DirectoryLockImpl final : public DirectoryLock {
~DirectoryLockImpl(); ~DirectoryLockImpl();
}; };
const DirectoryLockImpl* GetDirectoryLockImpl( const DirectoryLockImpl* AsDirectoryLockImpl(
const DirectoryLock* aDirectoryLock) { const DirectoryLock* aDirectoryLock) {
MOZ_ASSERT(aDirectoryLock); MOZ_ASSERT(aDirectoryLock);
return static_cast<const DirectoryLockImpl*>(aDirectoryLock); return static_cast<const DirectoryLockImpl*>(aDirectoryLock);
} }
DirectoryLockImpl* AsDirectoryLockImpl(DirectoryLock* aDirectoryLock) {
MOZ_ASSERT(aDirectoryLock);
return static_cast<DirectoryLockImpl*>(aDirectoryLock);
}
class QuotaManager::Observer final : public nsIObserver { class QuotaManager::Observer final : public nsIObserver {
static Observer* sInstance; static Observer* sInstance;
@ -2695,41 +2704,44 @@ bool RecvShutdownQuotaManager() {
* Directory lock * Directory lock
******************************************************************************/ ******************************************************************************/
int64_t DirectoryLock::Id() const { return GetDirectoryLockImpl(this)->Id(); } int64_t DirectoryLock::Id() const { return AsDirectoryLockImpl(this)->Id(); }
PersistenceType DirectoryLock::GetPersistenceType() const { PersistenceType DirectoryLock::GetPersistenceType() const {
return GetDirectoryLockImpl(this)->GetPersistenceType(); return AsDirectoryLockImpl(this)->GetPersistenceType();
} }
quota::GroupAndOrigin DirectoryLock::GroupAndOrigin() const { quota::GroupAndOrigin DirectoryLock::GroupAndOrigin() const {
return GetDirectoryLockImpl(this)->GroupAndOrigin(); return AsDirectoryLockImpl(this)->GroupAndOrigin();
} }
const nsACString& DirectoryLock::Origin() const { const nsACString& DirectoryLock::Origin() const {
return GetDirectoryLockImpl(this)->Origin(); return AsDirectoryLockImpl(this)->Origin();
} }
Client::Type DirectoryLock::ClientType() const { Client::Type DirectoryLock::ClientType() const {
return GetDirectoryLockImpl(this)->ClientType(); return AsDirectoryLockImpl(this)->ClientType();
}
void DirectoryLock::Acquire(RefPtr<OpenDirectoryListener> aOpenListener) {
AsDirectoryLockImpl(this)->Acquire(std::move(aOpenListener));
} }
already_AddRefed<DirectoryLock> DirectoryLock::Specialize( already_AddRefed<DirectoryLock> DirectoryLock::Specialize(
PersistenceType aPersistenceType, PersistenceType aPersistenceType,
const quota::GroupAndOrigin& aGroupAndOrigin, const quota::GroupAndOrigin& aGroupAndOrigin,
Client::Type aClientType) const { Client::Type aClientType) const {
return GetDirectoryLockImpl(this)->Specialize(aPersistenceType, return AsDirectoryLockImpl(this)->Specialize(aPersistenceType,
aGroupAndOrigin, aClientType); aGroupAndOrigin, aClientType);
} }
void DirectoryLock::Log() const { GetDirectoryLockImpl(this)->Log(); } void DirectoryLock::Log() const { AsDirectoryLockImpl(this)->Log(); }
DirectoryLockImpl::DirectoryLockImpl( DirectoryLockImpl::DirectoryLockImpl(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const int64_t aId, MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const int64_t aId,
const Nullable<PersistenceType>& aPersistenceType, const nsACString& aGroup, const Nullable<PersistenceType>& aPersistenceType, const nsACString& aGroup,
const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType, const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType,
const bool aExclusive, const bool aInternal, const bool aExclusive, const bool aInternal,
const ShouldUpdateLockIdTableFlag aShouldUpdateLockIdTableFlag, const ShouldUpdateLockIdTableFlag aShouldUpdateLockIdTableFlag)
RefPtr<OpenDirectoryListener> aOpenListener)
: mQuotaManager(std::move(aQuotaManager)), : mQuotaManager(std::move(aQuotaManager)),
mPersistenceType(aPersistenceType), mPersistenceType(aPersistenceType),
mGroup(aGroup), mGroup(aGroup),
@ -2750,11 +2762,6 @@ DirectoryLockImpl::DirectoryLockImpl(
MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin()); MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin());
MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull()); MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull());
MOZ_ASSERT_IF(!aInternal, aClientType.Value() < Client::TypeMax()); MOZ_ASSERT_IF(!aInternal, aClientType.Value() < Client::TypeMax());
MOZ_ASSERT_IF(!aInternal, aOpenListener);
if (aOpenListener) {
mOpenListener.init(WrapNotNullUnchecked(std::move(aOpenListener)));
}
} }
DirectoryLockImpl::~DirectoryLockImpl() { DirectoryLockImpl::~DirectoryLockImpl() {
@ -2835,6 +2842,78 @@ void DirectoryLockImpl::NotifyOpenListener() {
mPending.Flip(); mPending.Flip();
} }
void DirectoryLockImpl::Acquire(RefPtr<OpenDirectoryListener> aOpenListener) {
AssertIsOnOwningThread();
MOZ_ASSERT(aOpenListener);
mOpenListener.init(WrapNotNullUnchecked(std::move(aOpenListener)));
mQuotaManager->AddPendingDirectoryLock(*this);
// See if this lock needs to wait.
bool blocked = false;
// XXX It is probably unnecessary to iterate this in reverse order.
for (DirectoryLockImpl* const existingLock :
Reversed(mQuotaManager->mDirectoryLocks)) {
if (MustWaitFor(*existingLock)) {
existingLock->AddBlockingLock(*this);
AddBlockedOnLock(*existingLock);
blocked = true;
}
}
mQuotaManager->RegisterDirectoryLock(*this);
// Otherwise, notify the open listener immediately.
if (!blocked) {
NotifyOpenListener();
return;
}
if (!mExclusive || !mInternal) {
return;
}
// All the locks that block this new exclusive internal lock need to be
// invalidated. We also need to notify clients to abort operations for them.
QuotaManager::DirectoryLockIdTableArray lockIds;
lockIds.SetLength(Client::TypeMax());
const auto& blockedOnLocks = GetBlockedOnLocks();
MOZ_ASSERT(!blockedOnLocks.IsEmpty());
for (DirectoryLockImpl* blockedOnLock : blockedOnLocks) {
if (!blockedOnLock->IsInternal()) {
blockedOnLock->Invalidate();
// Clients don't have to handle pending locks. Invalidation is sufficient
// in that case (once a lock is ready and the listener needs to be
// notified, we will call DirectoryLockFailed instead of
// DirectoryLockAcquired which should release any remaining references to
// the lock).
if (!blockedOnLock->IsPending()) {
lockIds[blockedOnLock->ClientType()].Put(blockedOnLock->Id());
}
}
}
mQuotaManager->AbortOperationsForLocks(lockIds);
}
void DirectoryLockImpl::Acquire() {
AssertIsOnOwningThread();
#ifdef DEBUG
for (const DirectoryLockImpl* const existingLock :
mQuotaManager->mDirectoryLocks) {
MOZ_ASSERT(!MustWaitFor(*existingLock));
}
#endif
mQuotaManager->RegisterDirectoryLock(*this);
}
already_AddRefed<DirectoryLock> DirectoryLockImpl::Specialize( already_AddRefed<DirectoryLock> DirectoryLockImpl::Specialize(
PersistenceType aPersistenceType, PersistenceType aPersistenceType,
const quota::GroupAndOrigin& aGroupAndOrigin, const quota::GroupAndOrigin& aGroupAndOrigin,
@ -2856,16 +2935,14 @@ already_AddRefed<DirectoryLock> DirectoryLockImpl::Specialize(
Nullable<PersistenceType>(aPersistenceType), aGroupAndOrigin.mGroup, Nullable<PersistenceType>(aPersistenceType), aGroupAndOrigin.mGroup,
OriginScope::FromOrigin(aGroupAndOrigin.mOrigin), OriginScope::FromOrigin(aGroupAndOrigin.mOrigin),
Nullable<Client::Type>(aClientType), Nullable<Client::Type>(aClientType),
/* aExclusive */ false, mInternal, ShouldUpdateLockIdTableFlag::Yes, /* aExclusive */ false, mInternal, ShouldUpdateLockIdTableFlag::Yes);
/* aOpenListener */ nullptr);
if (NS_WARN_IF(!Overlaps(*lock))) { if (NS_WARN_IF(!Overlaps(*lock))) {
return nullptr; return nullptr;
} }
#ifdef DEBUG #ifdef DEBUG
for (uint32_t index = mQuotaManager->mDirectoryLocks.Length(); index > 0; for (DirectoryLockImpl* const existingLock :
index--) { Reversed(mQuotaManager->mDirectoryLocks)) {
DirectoryLockImpl* existingLock = mQuotaManager->mDirectoryLocks[index - 1];
if (existingLock != this && !existingLock->MustWaitFor(*this)) { if (existingLock != this && !existingLock->MustWaitFor(*this)) {
MOZ_ASSERT(!existingLock->MustWaitFor(*lock)); MOZ_ASSERT(!existingLock->MustWaitFor(*lock));
} }
@ -3585,9 +3662,7 @@ bool QuotaManager::IsDotFile(const nsAString& aFileName) {
auto QuotaManager::CreateDirectoryLock( auto QuotaManager::CreateDirectoryLock(
const Nullable<PersistenceType>& aPersistenceType, const nsACString& aGroup, const Nullable<PersistenceType>& aPersistenceType, const nsACString& aGroup,
const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType, const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType,
bool aExclusive, bool aInternal, bool aExclusive, bool aInternal) -> already_AddRefed<DirectoryLockImpl> {
RefPtr<OpenDirectoryListener> aOpenListener, bool& aBlockedOut)
-> already_AddRefed<DirectoryLockImpl> {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
MOZ_ASSERT_IF(aOriginScope.IsOrigin(), !aOriginScope.GetOrigin().IsEmpty()); MOZ_ASSERT_IF(aOriginScope.IsOrigin(), !aOriginScope.GetOrigin().IsEmpty());
MOZ_ASSERT_IF(!aInternal, !aPersistenceType.IsNull()); MOZ_ASSERT_IF(!aInternal, !aPersistenceType.IsNull());
@ -3597,35 +3672,12 @@ auto QuotaManager::CreateDirectoryLock(
MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin()); MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin());
MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull()); MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull());
MOZ_ASSERT_IF(!aInternal, aClientType.Value() < Client::TypeMax()); MOZ_ASSERT_IF(!aInternal, aClientType.Value() < Client::TypeMax());
MOZ_ASSERT_IF(!aInternal, aOpenListener);
RefPtr<DirectoryLockImpl> lock = new DirectoryLockImpl( RefPtr<DirectoryLockImpl> lock = new DirectoryLockImpl(
WrapNotNullUnchecked(this), GenerateDirectoryLockId(), aPersistenceType, WrapNotNullUnchecked(this), GenerateDirectoryLockId(), aPersistenceType,
aGroup, aOriginScope, aClientType, aExclusive, aInternal, aGroup, aOriginScope, aClientType, aExclusive, aInternal,
ShouldUpdateLockIdTableFlag::Yes, std::move(aOpenListener)); ShouldUpdateLockIdTableFlag::Yes);
mPendingDirectoryLocks.AppendElement(lock);
// See if this lock needs to wait.
bool blocked = false;
// XXX It is probably unnecessary to iterate this in reverse order.
for (DirectoryLockImpl* const existingLock : Reversed(mDirectoryLocks)) {
if (lock->MustWaitFor(*existingLock)) {
existingLock->AddBlockingLock(*lock);
lock->AddBlockedOnLock(*existingLock);
blocked = true;
}
}
RegisterDirectoryLock(*lock);
// Otherwise, notify the open listener immediately.
if (!blocked) {
lock->NotifyOpenListener();
}
aBlockedOut = blocked;
return lock.forget(); return lock.forget();
} }
@ -3642,15 +3694,7 @@ auto QuotaManager::CreateDirectoryLockForEviction(
OriginScope::FromOrigin(aGroupAndOrigin.mOrigin), OriginScope::FromOrigin(aGroupAndOrigin.mOrigin),
Nullable<Client::Type>(), Nullable<Client::Type>(),
/* aExclusive */ true, /* aInternal */ true, /* aExclusive */ true, /* aInternal */ true,
ShouldUpdateLockIdTableFlag::No, nullptr); ShouldUpdateLockIdTableFlag::No);
#ifdef DEBUG
for (const DirectoryLockImpl* const existingLock : mDirectoryLocks) {
MOZ_ASSERT(!lock->MustWaitFor(*existingLock));
}
#endif
RegisterDirectoryLock(*lock);
return lock.forget(); return lock.forget();
} }
@ -3724,6 +3768,12 @@ void QuotaManager::UnregisterDirectoryLock(DirectoryLockImpl& aLock) {
aLock.SetRegistered(false); aLock.SetRegistered(false);
} }
void QuotaManager::AddPendingDirectoryLock(DirectoryLockImpl& aLock) {
AssertIsOnOwningThread();
mPendingDirectoryLocks.AppendElement(&aLock);
}
void QuotaManager::RemovePendingDirectoryLock(DirectoryLockImpl& aLock) { void QuotaManager::RemovePendingDirectoryLock(DirectoryLockImpl& aLock) {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
@ -3845,6 +3895,9 @@ uint64_t QuotaManager::CollectOriginsForEviction(
RefPtr<DirectoryLockImpl> lock = CreateDirectoryLockForEviction( RefPtr<DirectoryLockImpl> lock = CreateDirectoryLockForEviction(
originInfo->mGroupInfo->mPersistenceType, originInfo->mGroupInfo->mPersistenceType,
GroupAndOrigin{originInfo->mGroupInfo->mGroup, originInfo->mOrigin}); GroupAndOrigin{originInfo->mGroupInfo->mGroup, originInfo->mOrigin});
lock->Acquire();
aLocks.AppendElement(lock.forget()); aLocks.AppendElement(lock.forget());
} }
@ -4805,6 +4858,15 @@ void QuotaManager::PersistOrigin(const GroupAndOrigin& aGroupAndOrigin) {
} }
} }
void QuotaManager::AbortOperationsForLocks(
const DirectoryLockIdTableArray& aLockIds) {
for (Client::Type type : AllClientTypes()) {
if (aLockIds[type].Filled()) {
(*mClients)[type]->AbortOperationsForLocks(aLockIds[type]);
}
}
}
void QuotaManager::AbortOperationsForProcess(ContentParentId aContentParentId) { void QuotaManager::AbortOperationsForProcess(ContentParentId aContentParentId) {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
@ -6312,69 +6374,32 @@ nsresult QuotaManager::EnsureStorageIsInitialized() {
return NS_OK; return NS_OK;
} }
already_AddRefed<DirectoryLock> QuotaManager::OpenDirectory( already_AddRefed<DirectoryLock> QuotaManager::CreateDirectoryLock(
PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin, PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin,
Client::Type aClientType, bool aExclusive, Client::Type aClientType, bool aExclusive) {
RefPtr<OpenDirectoryListener> aOpenListener) {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
bool blocked;
RefPtr<DirectoryLockImpl> lock = CreateDirectoryLock( RefPtr<DirectoryLockImpl> lock = CreateDirectoryLock(
Nullable<PersistenceType>(aPersistenceType), aGroupAndOrigin.mGroup, Nullable<PersistenceType>(aPersistenceType), aGroupAndOrigin.mGroup,
OriginScope::FromOrigin(aGroupAndOrigin.mOrigin), OriginScope::FromOrigin(aGroupAndOrigin.mOrigin),
Nullable<Client::Type>(aClientType), aExclusive, false, Nullable<Client::Type>(aClientType), aExclusive, false);
std::move(aOpenListener), blocked);
MOZ_ASSERT(lock); MOZ_ASSERT(lock);
return blocked ? lock.forget() : nullptr; return lock.forget();
} }
already_AddRefed<DirectoryLock> QuotaManager::OpenDirectoryInternal( already_AddRefed<DirectoryLock> QuotaManager::CreateDirectoryLockInternal(
const Nullable<PersistenceType>& aPersistenceType, const Nullable<PersistenceType>& aPersistenceType,
const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType, const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType,
bool aExclusive, OpenDirectoryListener* aOpenListener) { bool aExclusive) {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
bool blocked; RefPtr<DirectoryLockImpl> lock = CreateDirectoryLock(
RefPtr<DirectoryLockImpl> lock = aPersistenceType, ""_ns, aOriginScope,
CreateDirectoryLock(aPersistenceType, ""_ns, aOriginScope, Nullable<Client::Type>(aClientType), aExclusive, true);
Nullable<Client::Type>(aClientType), aExclusive, true,
aOpenListener, blocked);
MOZ_ASSERT(lock); MOZ_ASSERT(lock);
if (!aExclusive) { return lock.forget();
return blocked ? lock.forget() : nullptr;
}
// All the locks that block this new exclusive lock need to be invalidated.
// We also need to notify clients to abort operations for them.
AutoTArray<Client::DirectoryLockIdTable, Client::TYPE_MAX> lockIds;
lockIds.SetLength(Client::TypeMax());
const auto& blockedOnLocks = lock->GetBlockedOnLocks();
for (DirectoryLockImpl* blockedOnLock : blockedOnLocks) {
if (!blockedOnLock->IsInternal()) {
blockedOnLock->Invalidate();
// Clients don't have to handle pending locks. Invalidation is sufficient
// in that case (once a lock is ready and the listener needs to be
// notified, we will call DirectoryLockFailed instead of
// DirectoryLockAcquired which should release any remaining references to
// the lock).
if (!blockedOnLock->IsPending()) {
lockIds[blockedOnLock->ClientType()].Put(blockedOnLock->Id());
}
}
}
for (Client::Type type : AllClientTypes()) {
if (lockIds[type].Filled()) {
(*mClients)[type]->AbortOperationsForLocks(lockIds[type]);
}
}
return blocked ? lock.forget() : nullptr;
} }
Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult> Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
@ -7807,9 +7832,11 @@ void NormalOriginOperationBase::Open() {
AdvanceState(); AdvanceState();
if (mNeedsDirectoryLocking) { if (mNeedsDirectoryLocking) {
RefPtr<DirectoryLock> pendingDirectoryLock = RefPtr<DirectoryLock> directoryLock =
QuotaManager::Get()->OpenDirectoryInternal( QuotaManager::Get()->CreateDirectoryLockInternal(
mPersistenceType, mOriginScope, mClientType, mExclusive, this); mPersistenceType, mOriginScope, mClientType, mExclusive);
directoryLock->Acquire(this);
} else { } else {
QM_TRY(DirectoryOpen(), QM_VOID, [this](const nsresult rv) { Finish(rv); }); QM_TRY(DirectoryOpen(), QM_VOID, [this](const nsresult rv) { Finish(rv); });
} }

Просмотреть файл

@ -73,6 +73,8 @@ class NS_NO_VTABLE RefCountedObject {
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
}; };
class OpenDirectoryListener;
class DirectoryLock : public RefCountedObject { class DirectoryLock : public RefCountedObject {
friend class DirectoryLockImpl; friend class DirectoryLockImpl;
@ -88,6 +90,8 @@ class DirectoryLock : public RefCountedObject {
Client::Type ClientType() const; Client::Type ClientType() const;
void Acquire(RefPtr<OpenDirectoryListener> aOpenListener);
already_AddRefed<DirectoryLock> Specialize( already_AddRefed<DirectoryLock> Specialize(
PersistenceType aPersistenceType, PersistenceType aPersistenceType,
const quota::GroupAndOrigin& aGroupAndOrigin, const quota::GroupAndOrigin& aGroupAndOrigin,
@ -259,6 +263,10 @@ class QuotaManager final : public BackgroundThreadObject {
void PersistOrigin(const GroupAndOrigin& aGroupAndOrigin); void PersistOrigin(const GroupAndOrigin& aGroupAndOrigin);
using DirectoryLockIdTableArray =
AutoTArray<Client::DirectoryLockIdTable, Client::TYPE_MAX>;
void AbortOperationsForLocks(const DirectoryLockIdTableArray& aLockIds);
// Called when a process is being shot down. Aborts any running operations // Called when a process is being shot down. Aborts any running operations
// for the given process. // for the given process.
void AbortOperationsForProcess(ContentParentId aContentParentId); void AbortOperationsForProcess(ContentParentId aContentParentId);
@ -305,17 +313,15 @@ class QuotaManager final : public BackgroundThreadObject {
// Unlocking is simply done by dropping all references to the lock object. // Unlocking is simply done by dropping all references to the lock object.
// In other words, protection which the lock represents dies with the lock // In other words, protection which the lock represents dies with the lock
// object itself. // object itself.
already_AddRefed<DirectoryLock> OpenDirectory( already_AddRefed<DirectoryLock> CreateDirectoryLock(
PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin, PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin,
Client::Type aClientType, bool aExclusive, Client::Type aClientType, bool aExclusive);
RefPtr<OpenDirectoryListener> aOpenListener);
// XXX RemoveMe once bug 1170279 gets fixed. // XXX RemoveMe once bug 1170279 gets fixed.
already_AddRefed<DirectoryLock> OpenDirectoryInternal( already_AddRefed<DirectoryLock> CreateDirectoryLockInternal(
const Nullable<PersistenceType>& aPersistenceType, const Nullable<PersistenceType>& aPersistenceType,
const OriginScope& aOriginScope, const OriginScope& aOriginScope,
const Nullable<Client::Type>& aClientType, bool aExclusive, const Nullable<Client::Type>& aClientType, bool aExclusive);
OpenDirectoryListener* aOpenListener);
// Collect inactive and the least recently used origins. // Collect inactive and the least recently used origins.
uint64_t CollectOriginsForEviction( uint64_t CollectOriginsForEviction(
@ -484,8 +490,7 @@ class QuotaManager final : public BackgroundThreadObject {
const Nullable<PersistenceType>& aPersistenceType, const Nullable<PersistenceType>& aPersistenceType,
const nsACString& aGroup, const OriginScope& aOriginScope, const nsACString& aGroup, const OriginScope& aOriginScope,
const Nullable<Client::Type>& aClientType, bool aExclusive, const Nullable<Client::Type>& aClientType, bool aExclusive,
bool aInternal, RefPtr<OpenDirectoryListener> aOpenListener, bool aInternal);
bool& aBlockedOut);
already_AddRefed<DirectoryLockImpl> CreateDirectoryLockForEviction( already_AddRefed<DirectoryLockImpl> CreateDirectoryLockForEviction(
PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin); PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin);
@ -494,6 +499,8 @@ class QuotaManager final : public BackgroundThreadObject {
void UnregisterDirectoryLock(DirectoryLockImpl& aLock); void UnregisterDirectoryLock(DirectoryLockImpl& aLock);
void AddPendingDirectoryLock(DirectoryLockImpl& aLock);
void RemovePendingDirectoryLock(DirectoryLockImpl& aLock); void RemovePendingDirectoryLock(DirectoryLockImpl& aLock);
uint64_t LockedCollectOriginsForEviction( uint64_t LockedCollectOriginsForEviction(

Просмотреть файл

@ -1178,12 +1178,14 @@ nsresult OpenOp::OpenDirectory() {
MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread()); MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
MOZ_ASSERT(QuotaManager::Get()); MOZ_ASSERT(QuotaManager::Get());
RefPtr<DirectoryLock> directoryLock =
QuotaManager::Get()->CreateDirectoryLock(
GetConnection()->GetPersistenceType(), mQuotaInfo,
mozilla::dom::quota::Client::SDB,
/* aExclusive */ false);
mState = State::DirectoryOpenPending; mState = State::DirectoryOpenPending;
RefPtr<DirectoryLock> pendingDirectoryLock = directoryLock->Acquire(this);
QuotaManager::Get()->OpenDirectory(GetConnection()->GetPersistenceType(),
mQuotaInfo,
mozilla::dom::quota::Client::SDB,
/* aExclusive */ false, this);
return NS_OK; return NS_OK;
} }