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
This commit is contained in:
Jan Varga 2019-08-22 20:51:09 +00:00
parent ca724248e4
commit 9ab967ef1e
16 changed files with 375 additions and 138 deletions

View File

@ -165,8 +165,8 @@ void QuotaUsageRequestChild::HandleResponse(
AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
RefPtr<OriginUsageResult> result = new OriginUsageResult(
aResponse.usage(), aResponse.fileUsage(), aResponse.limit());
RefPtr<OriginUsageResult> result =
new OriginUsageResult(aResponse.usage(), aResponse.fileUsage());
RefPtr<nsVariant> 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<EstimateResult> result =
new EstimateResult(aResponse.usage(), aResponse.limit());
RefPtr<nsVariant> variant = new nsVariant();
variant->SetAsInterface(NS_GET_IID(nsIQuotaEstimateResult), result);
mRequest->SetResult(variant);
}
void QuotaRequestChild::HandleResponse(const nsTArray<nsCString>& 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;

View File

@ -129,6 +129,8 @@ class QuotaRequestChild final : public PQuotaRequestChild {
void HandleResponse(bool aResponse);
void HandleResponse(const EstimateResponse& aResponse);
void HandleResponse(const nsTArray<nsCString>& aResponse);
// IPDL methods are only called by IPDL.

View File

@ -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<Client::Type> mClientType;
mozilla::Atomic<bool> 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<uint64_t>(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<GroupInfo> temporaryGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
if (temporaryGroupInfo) {
aUsageInfo->AppendToDatabaseUsage(temporaryGroupInfo->mUsage);
}
// Calculate default group usage
RefPtr<GroupInfo> defaultGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
if (defaultGroupInfo) {
aUsageInfo->AppendToDatabaseUsage(defaultGroupInfo->mUsage);
if (mGroupInfoPairs.Get(aGroup, &pair)) {
for (const PersistenceType type : kBestEffortPersistenceTypes) {
RefPtr<GroupInfo> 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> groupInfo = pair->LockedGetGroupInfo(type);
if (groupInfo) {
RefPtr<OriginInfo> 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();

View File

@ -232,6 +232,48 @@ class OriginScope {
OriginScope Clone() { return OriginScope(mData); }
template <typename T, typename U>
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<nsCString, nsACString> AsOriginSetter() {
return Setter<nsCString, nsACString>(this, &OriginScope::SetFromOrigin);
}
private:
// Move constructors
explicit OriginScope(const Origin&& aOrigin) : mData(aOrigin) {}

View File

@ -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;
};

View File

@ -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;
};

View File

@ -25,7 +25,6 @@ struct OriginUsageResponse
{
uint64_t usage;
uint64_t fileUsage;
uint64_t limit;
};
union UsageRequestResponse

View File

@ -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};

View File

@ -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);

View File

@ -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<PendingRequestInfo> 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> request = new Request(aPrincipal);
EstimateParams params;
nsresult rv =
CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsAutoPtr<PendingRequestInfo> 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) {

View File

@ -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;

View File

@ -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;

View File

@ -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 <typename T>
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<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
if (NS_WARN_IF(!qms)) {
return NS_ERROR_FAILURE;
}
nsresult rv =
qms->GetUsageForPrincipal(aPrincipal, aCallback, true, aRequest);
nsCOMPtr<nsIQuotaRequest> 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<Promise> ExecuteOpOnMainOrWorkerThread(
RefPtr<RequestResolver> resolver =
new RequestResolver(RequestResolver::Type::Estimate, promise);
RefPtr<nsIQuotaUsageRequest> request;
aRv =
GetUsageForPrincipal(principal, resolver, getter_AddRefs(request));
RefPtr<nsIQuotaRequest> 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<nsIQuotaOriginUsageResult> originUsageResult =
do_QueryInterface(supports);
MOZ_ASSERT(originUsageResult);
nsCOMPtr<nsIQuotaEstimateResult> 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 <typename T>
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<RequestResolver> resolver =
new RequestResolver(RequestResolver::Type::Estimate, mProxy);
RefPtr<nsIQuotaUsageRequest> request;
nsresult rv =
GetUsageForPrincipal(principal, resolver, getter_AddRefs(request));
RefPtr<nsIQuotaRequest> request;
nsresult rv = Estimate(principal, resolver, getter_AddRefs(request));
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}

View File

@ -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

View File

@ -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);
};

View File

@ -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;
};