Bug 1587258 - QM: Add support for creating specialized directory locks from existing directory locks; r=asuth

Differential Revision: https://phabricator.services.mozilla.com/D48657

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jan Varga 2019-10-10 14:55:53 +00:00
parent ff268df84b
commit 9dd55053d6
2 changed files with 115 additions and 16 deletions

View File

@ -677,6 +677,7 @@ class DirectoryLockImpl final : public DirectoryLock {
// registraction/unregistration from updating origin access time, etc.
const bool mInternal;
bool mRegistered;
bool mInvalidated;
public:
@ -706,13 +707,17 @@ class DirectoryLockImpl final : public DirectoryLock {
bool IsInternal() const { return mInternal; }
void SetRegistered(bool aRegistered) { mRegistered = aRegistered; }
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);
bool MustWaitFor(const DirectoryLockImpl& aLock) const;
void AddBlockingLock(DirectoryLockImpl* aLock) {
AssertIsOnOwningThread();
@ -747,12 +752,24 @@ class DirectoryLockImpl final : public DirectoryLock {
NS_INLINE_DECL_REFCOUNTING(DirectoryLockImpl, override)
void Log() override;
already_AddRefed<DirectoryLock> Specialize(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
Client::Type aClientType) const;
void Log() const;
private:
~DirectoryLockImpl();
};
const DirectoryLockImpl* GetDirectoryLockImpl(
const DirectoryLock* aDirectoryLock) {
MOZ_ASSERT(aDirectoryLock);
return static_cast<const DirectoryLockImpl*>(aDirectoryLock);
}
class QuotaManager::Observer final : public nsIObserver {
static Observer* sInstance;
@ -2667,6 +2684,15 @@ bool RecvShutdownQuotaManager() {
* Directory lock
******************************************************************************/
already_AddRefed<DirectoryLock> DirectoryLock::Specialize(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, Client::Type aClientType) const {
return GetDirectoryLockImpl(this)->Specialize(aPersistenceType, aGroup,
aOrigin, aClientType);
}
void DirectoryLock::Log() const { GetDirectoryLockImpl(this)->Log(); }
DirectoryLockImpl::DirectoryLockImpl(
QuotaManager* aQuotaManager,
const Nullable<PersistenceType>& aPersistenceType, const nsACString& aGroup,
@ -2680,6 +2706,7 @@ DirectoryLockImpl::DirectoryLockImpl(
mOpenListener(aOpenListener),
mExclusive(aExclusive),
mInternal(aInternal),
mRegistered(false),
mInvalidated(false) {
AssertIsOnOwningThread();
MOZ_ASSERT(aQuotaManager);
@ -2704,7 +2731,11 @@ DirectoryLockImpl::~DirectoryLockImpl() {
mBlocking.Clear();
mQuotaManager->UnregisterDirectoryLock(this);
if (mRegistered) {
mQuotaManager->UnregisterDirectoryLock(this);
}
MOZ_ASSERT(!mRegistered);
}
#ifdef DEBUG
@ -2716,29 +2747,24 @@ void DirectoryLockImpl::AssertIsOnOwningThread() const {
#endif // DEBUG
bool DirectoryLockImpl::MustWaitFor(const DirectoryLockImpl& aExistingLock) {
bool DirectoryLockImpl::Overlaps(const DirectoryLockImpl& aLock) const {
AssertIsOnOwningThread();
// Waiting is never required if the ops in comparison represent shared locks.
if (!aExistingLock.mExclusive && !mExclusive) {
return false;
}
// If the persistence types don't overlap, the op can proceed.
if (!aExistingLock.mPersistenceType.IsNull() && !mPersistenceType.IsNull() &&
aExistingLock.mPersistenceType.Value() != mPersistenceType.Value()) {
if (!aLock.mPersistenceType.IsNull() && !mPersistenceType.IsNull() &&
aLock.mPersistenceType.Value() != mPersistenceType.Value()) {
return false;
}
// If the origin scopes don't overlap, the op can proceed.
bool match = aExistingLock.mOriginScope.Matches(mOriginScope);
bool match = aLock.mOriginScope.Matches(mOriginScope);
if (!match) {
return false;
}
// If the client types don't overlap, the op can proceed.
if (!aExistingLock.mClientType.IsNull() && !mClientType.IsNull() &&
aExistingLock.mClientType.Value() != mClientType.Value()) {
if (!aLock.mClientType.IsNull() && !mClientType.IsNull() &&
aLock.mClientType.Value() != mClientType.Value()) {
return false;
}
@ -2747,6 +2773,18 @@ bool DirectoryLockImpl::MustWaitFor(const DirectoryLockImpl& aExistingLock) {
return true;
}
bool DirectoryLockImpl::MustWaitFor(const DirectoryLockImpl& aLock) const {
AssertIsOnOwningThread();
// Waiting is never required if the ops in comparison represent shared locks.
if (!aLock.mExclusive && !mExclusive) {
return false;
}
// Wait if the ops overlap.
return Overlaps(aLock);
}
void DirectoryLockImpl::NotifyOpenListener() {
AssertIsOnOwningThread();
MOZ_ASSERT(mQuotaManager);
@ -2763,7 +2801,59 @@ void DirectoryLockImpl::NotifyOpenListener() {
mQuotaManager->RemovePendingDirectoryLock(this);
}
void DirectoryLockImpl::Log() {
already_AddRefed<DirectoryLock> DirectoryLockImpl::Specialize(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, Client::Type aClientType) const {
AssertIsOnOwningThread();
MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_INVALID);
MOZ_ASSERT(!aGroup.IsEmpty());
MOZ_ASSERT(!aOrigin.IsEmpty());
MOZ_ASSERT(aClientType < Client::TypeMax());
MOZ_ASSERT(!mOpenListener);
MOZ_ASSERT(mBlockedOn.IsEmpty());
if (NS_WARN_IF(mExclusive)) {
return nullptr;
}
RefPtr<DirectoryLockImpl> lock = new DirectoryLockImpl(
mQuotaManager, Nullable<PersistenceType>(aPersistenceType), aGroup,
OriginScope::FromOrigin(aOrigin), Nullable<Client::Type>(aClientType),
/* aExclusive */ false, mInternal, /* aOpenListener */ nullptr);
if (NS_WARN_IF(!Overlaps(*lock))) {
return nullptr;
}
#ifdef DEBUG
for (uint32_t index = mQuotaManager->mDirectoryLocks.Length(); index > 0;
index--) {
DirectoryLockImpl* existingLock = mQuotaManager->mDirectoryLocks[index - 1];
if (existingLock != this && !existingLock->MustWaitFor(*this)) {
MOZ_ASSERT(!existingLock->MustWaitFor(*lock));
}
}
#endif
for (const auto& blockedLock : mBlocking) {
MOZ_ASSERT(blockedLock);
if (blockedLock->MustWaitFor(*lock)) {
lock->AddBlockingLock(blockedLock);
blockedLock->AddBlockedOnLock(lock);
}
}
mQuotaManager->RegisterDirectoryLock(lock);
if (mInvalidated) {
lock->Invalidate();
}
return lock.forget();
}
void DirectoryLockImpl::Log() const {
AssertIsOnOwningThread();
if (!QM_LOG_TEST()) {
@ -3525,6 +3615,8 @@ void QuotaManager::RegisterDirectoryLock(DirectoryLockImpl* aLock) {
}
array->AppendElement(aLock);
}
aLock->SetRegistered(true);
}
void QuotaManager::UnregisterDirectoryLock(DirectoryLockImpl* aLock) {
@ -3558,6 +3650,8 @@ void QuotaManager::UnregisterDirectoryLock(DirectoryLockImpl* aLock) {
}
}
}
aLock->SetRegistered(false);
}
void QuotaManager::RemovePendingDirectoryLock(DirectoryLockImpl* aLock) {

View File

@ -63,7 +63,12 @@ class DirectoryLock : public RefCountedObject {
friend class DirectoryLockImpl;
public:
virtual void Log() = 0;
already_AddRefed<DirectoryLock> Specialize(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
Client::Type aClientType) const;
void Log() const;
private:
DirectoryLock() {}