From 9ab967ef1ee8c6e2fcfe10f8e712b97c3dd0caf0 Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Thu, 22 Aug 2019 20:51:09 +0000 Subject: [PATCH] Bug 1563023 - Part 2: Add support for getting origin usage from memory; r=asuth This patch modifies getUsageForPrincipal to support getting origin usage from memory. Support for getting group usage is factored out to a standalone method called Estimate. Operations based on NormalOriginOperationBase can now avoid directory locking if they don't touch disk. Differential Revision: https://phabricator.services.mozilla.com/D38087 --HG-- extra : moz-landing-system : lando --- dom/quota/ActorsChild.cpp | 21 ++- dom/quota/ActorsChild.h | 2 + dom/quota/ActorsParent.cpp | 239 +++++++++++++++++++-------- dom/quota/OriginScope.h | 42 +++++ dom/quota/PQuota.ipdl | 8 +- dom/quota/PQuotaRequest.ipdl | 7 + dom/quota/PQuotaUsageRequest.ipdl | 1 - dom/quota/PersistenceType.h | 3 + dom/quota/QuotaManager.h | 4 +- dom/quota/QuotaManagerService.cpp | 31 +++- dom/quota/QuotaResults.cpp | 20 ++- dom/quota/QuotaResults.h | 17 +- dom/quota/StorageManager.cpp | 69 ++++---- dom/quota/UsageInfo.h | 12 +- dom/quota/nsIQuotaManagerService.idl | 31 +++- dom/quota/nsIQuotaResults.idl | 6 + 16 files changed, 375 insertions(+), 138 deletions(-) diff --git a/dom/quota/ActorsChild.cpp b/dom/quota/ActorsChild.cpp index 52d0e24a0ee0..b3aa81b1558a 100644 --- a/dom/quota/ActorsChild.cpp +++ b/dom/quota/ActorsChild.cpp @@ -165,8 +165,8 @@ void QuotaUsageRequestChild::HandleResponse( AssertIsOnOwningThread(); MOZ_ASSERT(mRequest); - RefPtr result = new OriginUsageResult( - aResponse.usage(), aResponse.fileUsage(), aResponse.limit()); + RefPtr result = + new OriginUsageResult(aResponse.usage(), aResponse.fileUsage()); RefPtr variant = new nsVariant(); variant->SetAsInterface(NS_GET_IID(nsIQuotaOriginUsageResult), result); @@ -263,6 +263,19 @@ void QuotaRequestChild::HandleResponse(bool aResponse) { mRequest->SetResult(variant); } +void QuotaRequestChild::HandleResponse(const EstimateResponse& aResponse) { + AssertIsOnOwningThread(); + MOZ_ASSERT(mRequest); + + RefPtr result = + new EstimateResult(aResponse.usage(), aResponse.limit()); + + RefPtr variant = new nsVariant(); + variant->SetAsInterface(NS_GET_IID(nsIQuotaEstimateResult), result); + + mRequest->SetResult(variant); +} + void QuotaRequestChild::HandleResponse(const nsTArray& aResponse) { AssertIsOnOwningThread(); MOZ_ASSERT(mRequest); @@ -325,6 +338,10 @@ mozilla::ipc::IPCResult QuotaRequestChild::Recv__delete__( HandleResponse(aResponse.get_PersistedResponse().persisted()); break; + case RequestResponse::TEstimateResponse: + HandleResponse(aResponse.get_EstimateResponse()); + break; + case RequestResponse::TListInitializedOriginsResponse: HandleResponse(aResponse.get_ListInitializedOriginsResponse().origins()); break; diff --git a/dom/quota/ActorsChild.h b/dom/quota/ActorsChild.h index 1ba3676e94d3..e1e3a7dc740c 100644 --- a/dom/quota/ActorsChild.h +++ b/dom/quota/ActorsChild.h @@ -129,6 +129,8 @@ class QuotaRequestChild final : public PQuotaRequestChild { void HandleResponse(bool aResponse); + void HandleResponse(const EstimateResponse& aResponse); + void HandleResponse(const nsTArray& aResponse); // IPDL methods are only called by IPDL. diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 333f7716dc42..864282c83bac 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -868,7 +868,6 @@ class OriginOperationBase : public BackgroundThreadObject, public Runnable { bool mActorDestroyed; protected: - bool mNeedsMainThreadInit; bool mNeedsQuotaManagerInit; public: @@ -892,7 +891,6 @@ class OriginOperationBase : public BackgroundThreadObject, public Runnable { mResultCode(NS_OK), mState(State_Initial), mActorDestroyed(false), - mNeedsMainThreadInit(false), mNeedsQuotaManagerInit(false) {} // Reference counted. @@ -991,6 +989,7 @@ class NormalOriginOperationBase : public OriginOperationBase, Nullable mClientType; mozilla::Atomic mCanceled; const bool mExclusive; + bool mNeedsDirectoryLocking; public: void RunImmediately() { @@ -1004,7 +1003,8 @@ class NormalOriginOperationBase : public OriginOperationBase, const OriginScope& aOriginScope, bool aExclusive) : mPersistenceType(aPersistenceType), mOriginScope(aOriginScope), - mExclusive(aExclusive) { + mExclusive(aExclusive), + mNeedsDirectoryLocking(true) { AssertIsOnOwningThread(); } @@ -1186,23 +1186,16 @@ class GetUsageOp final : public QuotaUsageRequestBase, }; class GetOriginUsageOp final : public QuotaUsageRequestBase { - // If mGetGroupUsage is false, we use mUsageInfo to record the origin usage - // and the file usage. Otherwise, we use it to record the group usage and the - // limit. UsageInfo mUsageInfo; - - const OriginUsageParams mParams; nsCString mSuffix; nsCString mGroup; - bool mGetGroupUsage; + bool mFromMemory; public: explicit GetOriginUsageOp(const UsageRequestParams& aParams); - MOZ_IS_CLASS_INIT bool Init(Quota* aQuota) override; - private: - ~GetOriginUsageOp() {} + ~GetOriginUsageOp() = default; virtual nsresult DoDirectoryWork(QuotaManager* aQuotaManager) override; @@ -1381,6 +1374,22 @@ class PersistOp final : public PersistRequestBase { void GetResponse(RequestResponse& aResponse) override; }; +class EstimateOp final : public QuotaRequestBase { + nsCString mGroup; + uint64_t mUsage; + uint64_t mLimit; + + public: + explicit EstimateOp(const RequestParams& aParams); + + private: + ~EstimateOp() = default; + + virtual nsresult DoDirectoryWork(QuotaManager* aQuotaManager) override; + + void GetResponse(RequestResponse& aResponse) override; +}; + class ListInitializedOriginsOp final : public QuotaRequestBase, public TraverseRepositoryHelper { // XXX Bug 1521541 will make each origin has it's own state. @@ -6071,36 +6080,55 @@ uint64_t QuotaManager::GetGroupLimit() const { std::max(x, 10 MB)); } -void QuotaManager::GetGroupUsageAndLimit(const nsACString& aGroup, - UsageInfo* aUsageInfo) { +uint64_t QuotaManager::GetGroupUsage(const nsACString& aGroup) { AssertIsOnIOThread(); - MOZ_ASSERT(aUsageInfo); + + uint64_t usage = 0; { MutexAutoLock lock(mQuotaMutex); - aUsageInfo->SetLimit(GetGroupLimit()); - aUsageInfo->ResetUsage(); - GroupInfoPair* pair; - if (!mGroupInfoPairs.Get(aGroup, &pair)) { - return; - } - - // Calculate temporary group usage - RefPtr temporaryGroupInfo = - pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY); - if (temporaryGroupInfo) { - aUsageInfo->AppendToDatabaseUsage(temporaryGroupInfo->mUsage); - } - - // Calculate default group usage - RefPtr defaultGroupInfo = - pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT); - if (defaultGroupInfo) { - aUsageInfo->AppendToDatabaseUsage(defaultGroupInfo->mUsage); + if (mGroupInfoPairs.Get(aGroup, &pair)) { + for (const PersistenceType type : kBestEffortPersistenceTypes) { + RefPtr groupInfo = pair->LockedGetGroupInfo(type); + if (groupInfo) { + AssertNoOverflow(usage, groupInfo->mUsage); + usage += groupInfo->mUsage; + } + } } } + + return usage; +} + +uint64_t QuotaManager::GetOriginUsage(const nsACString& aGroup, + const nsACString& aOrigin) { + AssertIsOnIOThread(); + + uint64_t usage = 0; + + { + MutexAutoLock lock(mQuotaMutex); + + GroupInfoPair* pair; + if (mGroupInfoPairs.Get(aGroup, &pair)) { + for (const PersistenceType type : kBestEffortPersistenceTypes) { + RefPtr groupInfo = pair->LockedGetGroupInfo(type); + if (groupInfo) { + RefPtr originInfo = + groupInfo->LockedGetOriginInfo(aOrigin); + if (originInfo) { + AssertNoOverflow(usage, originInfo->LockedUsage()); + usage += originInfo->LockedUsage(); + } + } + } + } + } + + return usage; } void QuotaManager::NotifyStoragePressure(uint64_t aUsage) { @@ -7131,8 +7159,16 @@ void NormalOriginOperationBase::Open() { AdvanceState(); - QuotaManager::Get()->OpenDirectoryInternal(mPersistenceType, mOriginScope, - mClientType, mExclusive, this); + if (mNeedsDirectoryLocking) { + QuotaManager::Get()->OpenDirectoryInternal(mPersistenceType, mOriginScope, + mClientType, mExclusive, this); + } else { + nsresult rv = DirectoryOpen(); + if (NS_WARN_IF(NS_FAILED(rv))) { + Finish(rv); + return; + } + } } void NormalOriginOperationBase::UnblockOpen() { @@ -7141,7 +7177,9 @@ void NormalOriginOperationBase::UnblockOpen() { SendResults(); - mDirectoryLock = nullptr; + if (mNeedsDirectoryLocking) { + mDirectoryLock = nullptr; + } AdvanceState(); } @@ -7370,6 +7408,18 @@ bool Quota::VerifyRequestParams(const RequestParams& aParams) const { break; } + case RequestParams::TEstimateParams: { + const EstimateParams& params = aParams.get_EstimateParams(); + + if (NS_WARN_IF( + !QuotaManager::IsPrincipalInfoValid(params.principalInfo()))) { + ASSERT_UNLESS_FUZZING(); + return false; + } + + break; + } + default: MOZ_CRASH("Should never get here!"); } @@ -7506,6 +7556,10 @@ PQuotaRequestParent* Quota::AllocPQuotaRequestParent( actor = new PersistOp(aParams); break; + case RequestParams::TEstimateParams: + actor = new EstimateOp(aParams); + break; + case RequestParams::TListInitializedOriginsParams: actor = new ListInitializedOriginsOp(); break; @@ -7975,29 +8029,24 @@ void GetUsageOp::GetResponse(UsageRequestResponse& aResponse) { } } -GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams) - : mParams(aParams.get_OriginUsageParams()), - mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage()) { +GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams) { AssertIsOnOwningThread(); MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams); -} -bool GetOriginUsageOp::Init(Quota* aQuota) { - AssertIsOnOwningThread(); - MOZ_ASSERT(aQuota); + const OriginUsageParams& params = aParams.get_OriginUsageParams(); - if (NS_WARN_IF(!QuotaUsageRequestBase::Init(aQuota))) { - return false; + QuotaManager::GetInfoFromValidatedPrincipalInfo( + params.principalInfo(), &mSuffix, &mGroup, mOriginScope.AsOriginSetter()); + + mFromMemory = params.fromMemory(); + + // Overwrite NormalOriginOperationBase default values. + if (mFromMemory) { + mNeedsDirectoryLocking = false; } - // Figure out which origin we're dealing with. - nsCString origin; - QuotaManager::GetInfoFromValidatedPrincipalInfo(mParams.principalInfo(), - &mSuffix, &mGroup, &origin); - - mOriginScope.SetFromOrigin(origin); - - return true; + // Overwrite OriginOperationBase default values. + mNeedsQuotaManagerInit = true; } nsresult GetOriginUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) { @@ -8008,23 +8057,28 @@ nsresult GetOriginUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) { nsresult rv; - if (mGetGroupUsage) { - // Ensure temporary storage is initialized first. It will initialize all - // origins for temporary storage including origins belonging to our group by - // traversing the repositories. EnsureStorageIsInitialized is needed before - // EnsureTemporaryStorageIsInitialized. + if (mFromMemory) { + // This must be called before EnsureTemporaryStorageIsInitialized. rv = aQuotaManager->EnsureStorageIsInitialized(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + // Ensure temporary storage is initialized. If temporary storage hasn't been + // initialized yet, the method will initialize it by traversing the + // repositories for temporary and default storage (including our origin). rv = aQuotaManager->EnsureTemporaryStorageIsInitialized(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - // Get cached usage and limit (the method doesn't have to stat any files). - aQuotaManager->GetGroupUsageAndLimit(mGroup, &mUsageInfo); + // Get cached usage (the method doesn't have to stat any files). + uint64_t usage = + aQuotaManager->GetOriginUsage(mGroup, mOriginScope.GetOrigin()); + + // File usage is not tracked in memory separately, so just add to the + // database usage. + mUsageInfo.AppendToDatabaseUsage(usage); return NS_OK; } @@ -8049,15 +8103,8 @@ void GetOriginUsageOp::GetResponse(UsageRequestResponse& aResponse) { OriginUsageResponse usageResponse; - // We'll get the group usage when mGetGroupUsage is true and get the - // origin usage when mGetGroupUsage is false. usageResponse.usage() = mUsageInfo.TotalUsage(); - - if (mGetGroupUsage) { - usageResponse.limit() = mUsageInfo.Limit(); - } else { - usageResponse.fileUsage() = mUsageInfo.FileUsage(); - } + usageResponse.fileUsage() = mUsageInfo.FileUsage(); aResponse = usageResponse; } @@ -8756,6 +8803,60 @@ void PersistOp::GetResponse(RequestResponse& aResponse) { aResponse = PersistResponse(); } +EstimateOp::EstimateOp(const RequestParams& aParams) + : QuotaRequestBase(/* aExclusive */ false), mUsage(0), mLimit(0) { + AssertIsOnOwningThread(); + MOZ_ASSERT(aParams.type() == RequestParams::TEstimateParams); + + QuotaManager::GetInfoFromValidatedPrincipalInfo( + aParams.get_EstimateParams().principalInfo(), nullptr, &mGroup, nullptr); + + // Overwrite NormalOriginOperationBase default values. + mNeedsDirectoryLocking = false; + + // Overwrite OriginOperationBase default values. + mNeedsQuotaManagerInit = true; +} + +nsresult EstimateOp::DoDirectoryWork(QuotaManager* aQuotaManager) { + AssertIsOnIOThread(); + + AUTO_PROFILER_LABEL("EstimateOp::DoDirectoryWork", OTHER); + + // This must be called before EnsureTemporaryStorageIsInitialized. + nsresult rv = aQuotaManager->EnsureStorageIsInitialized(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Ensure temporary storage is initialized. If temporary storage hasn't been + // initialized yet, the method will initialize it by traversing the + // repositories for temporary and default storage (including origins belonging + // to our group). + rv = aQuotaManager->EnsureTemporaryStorageIsInitialized(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Get cached usage (the method doesn't have to stat any files). + mUsage = aQuotaManager->GetGroupUsage(mGroup); + + mLimit = aQuotaManager->GetGroupLimit(); + + return NS_OK; +} + +void EstimateOp::GetResponse(RequestResponse& aResponse) { + AssertIsOnOwningThread(); + + EstimateResponse estimateResponse; + + estimateResponse.usage() = mUsage; + estimateResponse.limit() = mLimit; + + aResponse = estimateResponse; +} + ListInitializedOriginsOp::ListInitializedOriginsOp() : QuotaRequestBase(/* aExclusive */ false), TraverseRepositoryHelper() { AssertIsOnOwningThread(); diff --git a/dom/quota/OriginScope.h b/dom/quota/OriginScope.h index 90e3c9e96a07..8b92a565de5b 100644 --- a/dom/quota/OriginScope.h +++ b/dom/quota/OriginScope.h @@ -232,6 +232,48 @@ class OriginScope { OriginScope Clone() { return OriginScope(mData); } + template + class Setter { + typedef void (OriginScope::*Method)(const U& aOrigin); + + OriginScope* mOriginScope; + Method mMethod; + T mData; + + public: + Setter(OriginScope* aOriginScope, Method aMethod) + : mOriginScope(aOriginScope), mMethod(aMethod) {} + + Setter(Setter&& aOther) + : mOriginScope(aOther.mOriginScope), + mMethod(aOther.mMethod), + mData(std::move(aOther.mData)) {} + + ~Setter() { ((*mOriginScope).*mMethod)(mData); } + + operator T&() { return mData; } + + operator T*() { return &mData; } + + private: + Setter() = delete; + Setter(const Setter&) = delete; + Setter& operator=(const Setter&) = delete; + Setter& operator=(const Setter&&) = delete; + }; + + /** + * Magic helper for cases where you are calling a method that takes a + * ns(A)CString outparam to write an origin into. This method returns a helper + * temporary that returns the underlying string storage, then on the + * destruction of the temporary at the conclusion of the call, automatically + * invokes SetFromOrigin using the origin value that was written into the + * string. + */ + Setter AsOriginSetter() { + return Setter(this, &OriginScope::SetFromOrigin); + } + private: // Move constructors explicit OriginScope(const Origin&& aOrigin) : mData(aOrigin) {} diff --git a/dom/quota/PQuota.ipdl b/dom/quota/PQuota.ipdl index 79bc95abd26e..c632909e7836 100644 --- a/dom/quota/PQuota.ipdl +++ b/dom/quota/PQuota.ipdl @@ -48,7 +48,7 @@ struct AllUsageParams struct OriginUsageParams { PrincipalInfo principalInfo; - bool getGroupUsage; + bool fromMemory; }; union UsageRequestParams @@ -100,6 +100,11 @@ struct PersistParams PrincipalInfo principalInfo; }; +struct EstimateParams +{ + PrincipalInfo principalInfo; +}; + struct ListInitializedOriginsParams { }; @@ -116,6 +121,7 @@ union RequestParams ResetAllParams; PersistedParams; PersistParams; + EstimateParams; ListInitializedOriginsParams; }; diff --git a/dom/quota/PQuotaRequest.ipdl b/dom/quota/PQuotaRequest.ipdl index bb700f80b43e..471c2a87dd82 100644 --- a/dom/quota/PQuotaRequest.ipdl +++ b/dom/quota/PQuotaRequest.ipdl @@ -50,6 +50,12 @@ struct PersistResponse { }; +struct EstimateResponse +{ + uint64_t usage; + uint64_t limit; +}; + struct ListInitializedOriginsResponse { nsCString[] origins; @@ -68,6 +74,7 @@ union RequestResponse ResetAllResponse; PersistedResponse; PersistResponse; + EstimateResponse; ListInitializedOriginsResponse; }; diff --git a/dom/quota/PQuotaUsageRequest.ipdl b/dom/quota/PQuotaUsageRequest.ipdl index f1751ba006fb..d7f6b4f3ee80 100644 --- a/dom/quota/PQuotaUsageRequest.ipdl +++ b/dom/quota/PQuotaUsageRequest.ipdl @@ -25,7 +25,6 @@ struct OriginUsageResponse { uint64_t usage; uint64_t fileUsage; - uint64_t limit; }; union UsageRequestResponse diff --git a/dom/quota/PersistenceType.h b/dom/quota/PersistenceType.h index faeff3323422..bcd1f76d210c 100644 --- a/dom/quota/PersistenceType.h +++ b/dom/quota/PersistenceType.h @@ -22,6 +22,9 @@ enum PersistenceType { PERSISTENCE_TYPE_INVALID }; +static const PersistenceType kBestEffortPersistenceTypes[] = { + PERSISTENCE_TYPE_TEMPORARY, PERSISTENCE_TYPE_DEFAULT}; + static const PersistenceType kAllPersistenceTypes[] = { PERSISTENCE_TYPE_PERSISTENT, PERSISTENCE_TYPE_TEMPORARY, PERSISTENCE_TYPE_DEFAULT}; diff --git a/dom/quota/QuotaManager.h b/dom/quota/QuotaManager.h index 0026cbce67a2..efdea34828cd 100644 --- a/dom/quota/QuotaManager.h +++ b/dom/quota/QuotaManager.h @@ -384,7 +384,9 @@ class QuotaManager final : public BackgroundThreadObject { uint64_t GetGroupLimit() const; - void GetGroupUsageAndLimit(const nsACString& aGroup, UsageInfo* aUsageInfo); + uint64_t GetGroupUsage(const nsACString& aGroup); + + uint64_t GetOriginUsage(const nsACString& aGroup, const nsACString& aOrigin); void NotifyStoragePressure(uint64_t aUsage); diff --git a/dom/quota/QuotaManagerService.cpp b/dom/quota/QuotaManagerService.cpp index 8919bca21148..3dd5aab42ac4 100644 --- a/dom/quota/QuotaManagerService.cpp +++ b/dom/quota/QuotaManagerService.cpp @@ -500,7 +500,7 @@ QuotaManagerService::GetUsage(nsIQuotaUsageCallback* aCallback, bool aGetAll, NS_IMETHODIMP QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback, - bool aGetGroupUsage, + bool aFromMemory, nsIQuotaUsageRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); @@ -516,7 +516,7 @@ QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, return rv; } - params.getGroupUsage() = aGetGroupUsage; + params.fromMemory() = aFromMemory; nsAutoPtr info(new UsageRequestInfo(request, params)); @@ -740,6 +740,33 @@ QuotaManagerService::Persist(nsIPrincipal* aPrincipal, return NS_OK; } +NS_IMETHODIMP +QuotaManagerService::Estimate(nsIPrincipal* aPrincipal, + nsIQuotaRequest** _retval) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aPrincipal); + + RefPtr request = new Request(aPrincipal); + + EstimateParams params; + + nsresult rv = + CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsAutoPtr info(new RequestInfo(request, params)); + + rv = InitiateRequest(info); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + request.forget(_retval); + return NS_OK; +} + NS_IMETHODIMP QuotaManagerService::ListInitializedOrigins(nsIQuotaCallback* aCallback, nsIQuotaRequest** _retval) { diff --git a/dom/quota/QuotaResults.cpp b/dom/quota/QuotaResults.cpp index 0fbf7749f749..c8b10d8073cf 100644 --- a/dom/quota/QuotaResults.cpp +++ b/dom/quota/QuotaResults.cpp @@ -49,9 +49,8 @@ UsageResult::GetLastAccessed(uint64_t* aLastAccessed) { return NS_OK; } -OriginUsageResult::OriginUsageResult(uint64_t aUsage, uint64_t aFileUsage, - uint64_t aLimit) - : mUsage(aUsage), mFileUsage(aFileUsage), mLimit(aLimit) {} +OriginUsageResult::OriginUsageResult(uint64_t aUsage, uint64_t aFileUsage) + : mUsage(aUsage), mFileUsage(aFileUsage) {} NS_IMPL_ISUPPORTS(OriginUsageResult, nsIQuotaOriginUsageResult) @@ -71,8 +70,21 @@ OriginUsageResult::GetFileUsage(uint64_t* aFileUsage) { return NS_OK; } +EstimateResult::EstimateResult(uint64_t aUsage, uint64_t aLimit) + : mUsage(aUsage), mLimit(aLimit) {} + +NS_IMPL_ISUPPORTS(EstimateResult, nsIQuotaEstimateResult) + NS_IMETHODIMP -OriginUsageResult::GetLimit(uint64_t* aLimit) { +EstimateResult::GetUsage(uint64_t* aUsage) { + MOZ_ASSERT(aUsage); + + *aUsage = mUsage; + return NS_OK; +} + +NS_IMETHODIMP +EstimateResult::GetLimit(uint64_t* aLimit) { MOZ_ASSERT(aLimit); *aLimit = mLimit; diff --git a/dom/quota/QuotaResults.h b/dom/quota/QuotaResults.h index f5a91dc43ce3..f34223786431 100644 --- a/dom/quota/QuotaResults.h +++ b/dom/quota/QuotaResults.h @@ -33,10 +33,9 @@ class UsageResult : public nsIQuotaUsageResult { class OriginUsageResult : public nsIQuotaOriginUsageResult { uint64_t mUsage; uint64_t mFileUsage; - uint64_t mLimit; public: - OriginUsageResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit); + OriginUsageResult(uint64_t aUsage, uint64_t aFileUsage); private: virtual ~OriginUsageResult() {} @@ -45,6 +44,20 @@ class OriginUsageResult : public nsIQuotaOriginUsageResult { NS_DECL_NSIQUOTAORIGINUSAGERESULT }; +class EstimateResult : public nsIQuotaEstimateResult { + uint64_t mUsage; + uint64_t mLimit; + + public: + EstimateResult(uint64_t aUsage, uint64_t aLimit); + + private: + virtual ~EstimateResult() {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIQUOTAESTIMATERESULT +}; + class InitializedOriginsResult : public nsIQuotaInitializedOriginsResult { nsCString mOrigin; diff --git a/dom/quota/StorageManager.cpp b/dom/quota/StorageManager.cpp index a6d7a85cdf2f..c1bc60322118 100644 --- a/dom/quota/StorageManager.cpp +++ b/dom/quota/StorageManager.cpp @@ -27,8 +27,7 @@ namespace { // This class is used to get quota usage, request persist and check persisted // status callbacks. -class RequestResolver final : public nsIQuotaCallback, - public nsIQuotaUsageCallback { +class RequestResolver final : public nsIQuotaCallback { public: enum Type { Estimate, Persist, Persisted }; @@ -65,7 +64,6 @@ class RequestResolver final : public nsIQuotaCallback, NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIQUOTACALLBACK - NS_DECL_NSIQUOTAUSAGECALLBACK private: ~RequestResolver() {} @@ -74,8 +72,7 @@ class RequestResolver final : public nsIQuotaCallback, nsresult GetPersisted(nsIVariant* aResult); - template - nsresult OnCompleteOrUsageResult(T* aRequest); + nsresult OnCompleteInternal(nsIQuotaRequest* aRequest); nsresult Finish(); }; @@ -164,24 +161,35 @@ class PersistentStoragePermissionRequest final ~PersistentStoragePermissionRequest() = default; }; -nsresult GetUsageForPrincipal(nsIPrincipal* aPrincipal, - nsIQuotaUsageCallback* aCallback, - nsIQuotaUsageRequest** aRequest) { +nsresult Estimate(nsIPrincipal* aPrincipal, nsIQuotaCallback* aCallback, + nsIQuotaRequest** aRequest) { MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aCallback); MOZ_ASSERT(aRequest); + // Firefox and Quota Manager have always used the schemeless origin group + // (https://storage.spec.whatwg.org/#schemeless-origin-group) for quota limit + // purposes. This has been to prevent a site/eTLD+1 from claiming more than + // its fair share of storage through the use of sub-domains. Because the limit + // is at the group level and the usage needs to make sense in the context of + // that limit, we also expose the group usage. Bug 1374970 reflects this + // reality and bug 1305665 tracks our plan to eliminate our use of groups for + // this. + nsCOMPtr qms = QuotaManagerService::GetOrCreate(); if (NS_WARN_IF(!qms)) { return NS_ERROR_FAILURE; } - nsresult rv = - qms->GetUsageForPrincipal(aPrincipal, aCallback, true, aRequest); + nsCOMPtr request; + nsresult rv = qms->Estimate(aPrincipal, getter_AddRefs(request)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + MOZ_ALWAYS_SUCCEEDS(request->SetCallback(aCallback)); + + request.forget(aRequest); return NS_OK; }; @@ -275,9 +283,8 @@ already_AddRefed ExecuteOpOnMainOrWorkerThread( RefPtr resolver = new RequestResolver(RequestResolver::Type::Estimate, promise); - RefPtr request; - aRv = - GetUsageForPrincipal(principal, resolver, getter_AddRefs(request)); + RefPtr request; + aRv = Estimate(principal, resolver, getter_AddRefs(request)); break; } @@ -389,7 +396,7 @@ void RequestResolver::ResolveOrReject() { } } -NS_IMPL_ISUPPORTS(RequestResolver, nsIQuotaUsageCallback, nsIQuotaCallback) +NS_IMPL_ISUPPORTS(RequestResolver, nsIQuotaCallback) nsresult RequestResolver::GetStorageEstimate(nsIVariant* aResult) { MOZ_ASSERT(aResult); @@ -406,15 +413,14 @@ nsresult RequestResolver::GetStorageEstimate(nsIVariant* aResult) { free(iid); - nsCOMPtr originUsageResult = - do_QueryInterface(supports); - MOZ_ASSERT(originUsageResult); + nsCOMPtr estimateResult = do_QueryInterface(supports); + MOZ_ASSERT(estimateResult); MOZ_ALWAYS_SUCCEEDS( - originUsageResult->GetUsage(&mStorageEstimate.mUsage.Construct())); + estimateResult->GetUsage(&mStorageEstimate.mUsage.Construct())); MOZ_ALWAYS_SUCCEEDS( - originUsageResult->GetLimit(&mStorageEstimate.mQuota.Construct())); + estimateResult->GetLimit(&mStorageEstimate.mQuota.Construct())); return NS_OK; } @@ -446,8 +452,7 @@ nsresult RequestResolver::GetPersisted(nsIVariant* aResult) { return NS_OK; } -template -nsresult RequestResolver::OnCompleteOrUsageResult(T* aRequest) { +nsresult RequestResolver::OnCompleteInternal(nsIQuotaRequest* aRequest) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRequest); @@ -512,22 +517,7 @@ RequestResolver::OnComplete(nsIQuotaRequest* aRequest) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRequest); - mResultCode = OnCompleteOrUsageResult(aRequest); - - nsresult rv = Finish(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - return NS_OK; -} - -NS_IMETHODIMP -RequestResolver::OnUsageResult(nsIQuotaUsageRequest* aRequest) { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aRequest); - - mResultCode = OnCompleteOrUsageResult(aRequest); + mResultCode = OnCompleteInternal(aRequest); nsresult rv = Finish(); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -567,9 +557,8 @@ bool EstimateWorkerMainThreadRunnable::MainThreadRun() { RefPtr resolver = new RequestResolver(RequestResolver::Type::Estimate, mProxy); - RefPtr request; - nsresult rv = - GetUsageForPrincipal(principal, resolver, getter_AddRefs(request)); + RefPtr request; + nsresult rv = Estimate(principal, resolver, getter_AddRefs(request)); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } diff --git a/dom/quota/UsageInfo.h b/dom/quota/UsageInfo.h index f3d6eae83bf8..6f28de9437b3 100644 --- a/dom/quota/UsageInfo.h +++ b/dom/quota/UsageInfo.h @@ -16,7 +16,7 @@ BEGIN_QUOTA_NAMESPACE class UsageInfo { public: - UsageInfo() : mDatabaseUsage(0), mFileUsage(0), mLimit(0) {} + UsageInfo() : mDatabaseUsage(0), mFileUsage(0) {} virtual ~UsageInfo() {} @@ -33,25 +33,16 @@ class UsageInfo { IncrementUsage(&mFileUsage, aUsage); } - void SetLimit(uint64_t aLimit) { mLimit = aLimit; } - uint64_t DatabaseUsage() { return mDatabaseUsage; } uint64_t FileUsage() { return mFileUsage; } - uint64_t Limit() { return mLimit; } - uint64_t TotalUsage() { uint64_t totalUsage = mDatabaseUsage; IncrementUsage(&totalUsage, mFileUsage); return totalUsage; } - void ResetUsage() { - mDatabaseUsage = 0; - mFileUsage = 0; - } - static void IncrementUsage(uint64_t* aUsage, uint64_t aDelta) { MOZ_ASSERT(aUsage); CheckedUint64 value = *aUsage; @@ -66,7 +57,6 @@ class UsageInfo { private: uint64_t mDatabaseUsage; uint64_t mFileUsage; - uint64_t mLimit; }; END_QUOTA_NAMESPACE diff --git a/dom/quota/nsIQuotaManagerService.idl b/dom/quota/nsIQuotaManagerService.idl index 9e94ac048682..cc74200106fe 100644 --- a/dom/quota/nsIQuotaManagerService.idl +++ b/dom/quota/nsIQuotaManagerService.idl @@ -75,16 +75,18 @@ interface nsIQuotaManagerService : nsISupports * A principal for the origin whose usage is being queried. * @param aCallback * The callback that will be called when the usage is available. - * @param aGetGroupUsage - * An optional flag to indicate whether getting group usage and limit - * or origin usage and file usage. The default value is false. + * @param aFromMemory + * An optional flag to indicate whether the cached usage should be + * obtained. The default value is false. Note that this operation may + * still be delayed by other operations on the QM I/O thread that are + * peforming I/O. * Note: Origin usage here represents total usage of an origin. However, - * group usage here represents only non-persistent usage of a group. + * cached usage here represents only non-persistent usage of an origin. */ [must_use] nsIQuotaUsageRequest getUsageForPrincipal(in nsIPrincipal aPrincipal, in nsIQuotaUsageCallback aCallback, - [optional] in boolean aGetGroupUsage); + [optional] in boolean aFromMemory); /** * Schedules an asynchronous callback that will inspect all origins and @@ -221,4 +223,23 @@ interface nsIQuotaManagerService : nsISupports */ [must_use] nsIQuotaRequest persist(in nsIPrincipal aPrincipal); + + /** + * Given an origin, asynchronously calculate its group quota usage and quota + * limit. An origin's group is the set of all origins that share the same + * eTLD+1. This method is intended to be used for our implementation of the + * StorageManager.estimate() method. When we fix bug 1305665 and stop tracking + * quota limits on a group basis, this method will switch to operating on + * origins. Callers should strongly consider whether they want to be using + * getUsageForPrincipal() instead. + * + * This mechanism uses cached quota values and does not perform any I/O on its + * own, but it may be delayed by QuotaManager operations that do need to + * perform I/O on the QuotaManager I/O thread. + * + * @param aPrincipal + * A principal for the origin (group) which we want to estimate. + */ + [must_use] nsIQuotaRequest + estimate(in nsIPrincipal aPrincipal); }; diff --git a/dom/quota/nsIQuotaResults.idl b/dom/quota/nsIQuotaResults.idl index 648a0b1780d8..206f4f183063 100644 --- a/dom/quota/nsIQuotaResults.idl +++ b/dom/quota/nsIQuotaResults.idl @@ -24,6 +24,12 @@ interface nsIQuotaOriginUsageResult : nsISupports readonly attribute unsigned long long usage; readonly attribute unsigned long long fileUsage; +}; + +[scriptable, function, uuid(9827fc69-7ea9-48ef-b30d-2e2ae0451ec0)] +interface nsIQuotaEstimateResult : nsISupports +{ + readonly attribute unsigned long long usage; readonly attribute unsigned long long limit; };