зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
bb69a13c52
Коммит
a8d359bfc5
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче