Bug 1563023 - Part 1: Implement per client usage tracking; r=asuth

This patch adds a fixed-size array of client usages to OriginInfo and modifies
quota tracking APIs to require the client type to be passed in.
A new method ResetUsageForClient is implemented. The method is used during
client-specific origin clearing. ResetUsageForClient is much faster than calling
GetUsageForOrigin and calling DecreaseUsageForOrigin after that.
LockedUsage now has an assertion that verifies that the total sum of client
usages matches total origin usage. This method should be called instead of
touching mUsage directly.
A new assertion is added to GetQuotaObject which verifies that passed file
belongs to the given persistence type, origin, and client.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jan Varga 2019-08-22 13:06:48 +00:00
parent bb991b5d3a
commit 9f906cd7c4
12 changed files with 353 additions and 134 deletions

View File

@ -26,6 +26,7 @@ namespace dom {
namespace cache {
using mozilla::dom::quota::AssertIsOnIOThread;
using mozilla::dom::quota::Client;
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
using mozilla::dom::quota::PersistenceType;
@ -210,10 +211,14 @@ nsresult OpenDBConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
nsAutoCString type;
PersistenceTypeToText(PERSISTENCE_TYPE_DEFAULT, type);
nsAutoCString clientType;
Client::TypeToText(Client::DOMCACHE, clientType);
rv = NS_MutateURI(mutator)
.SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type +
NS_LITERAL_CSTRING("&group=") + aQuotaInfo.mGroup +
NS_LITERAL_CSTRING("&origin=") + aQuotaInfo.mOrigin +
NS_LITERAL_CSTRING("&clientType=") + clientType +
NS_LITERAL_CSTRING("&cache=private"))
.Finalize(dbFileUrl);
if (NS_WARN_IF(NS_FAILED(rv))) {

View File

@ -27,6 +27,7 @@ namespace mozilla {
namespace dom {
namespace cache {
using mozilla::dom::quota::Client;
using mozilla::dom::quota::FileInputStream;
using mozilla::dom::quota::FileOutputStream;
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
@ -205,8 +206,9 @@ nsresult BodyStartWriteStream(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
return NS_ERROR_FILE_ALREADY_EXISTS;
}
nsCOMPtr<nsIOutputStream> fileStream = CreateFileOutputStream(
PERSISTENCE_TYPE_DEFAULT, aQuotaInfo.mGroup, aQuotaInfo.mOrigin, tmpFile);
nsCOMPtr<nsIOutputStream> fileStream =
CreateFileOutputStream(PERSISTENCE_TYPE_DEFAULT, aQuotaInfo.mGroup,
aQuotaInfo.mOrigin, Client::DOMCACHE, tmpFile);
if (NS_WARN_IF(!fileStream)) {
return NS_ERROR_UNEXPECTED;
}
@ -298,7 +300,7 @@ nsresult BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
nsCOMPtr<nsIInputStream> fileStream =
CreateFileInputStream(PERSISTENCE_TYPE_DEFAULT, aQuotaInfo.mGroup,
aQuotaInfo.mOrigin, finalFile);
aQuotaInfo.mOrigin, Client::DOMCACHE, finalFile);
if (NS_WARN_IF(!fileStream)) {
return NS_ERROR_UNEXPECTED;
}
@ -329,9 +331,9 @@ nsresult BodyMaybeUpdatePaddingSize(const QuotaInfo& aQuotaInfo,
MOZ_DIAGNOSTIC_ASSERT(quotaManager);
int64_t fileSize = 0;
RefPtr<QuotaObject> quotaObject =
quotaManager->GetQuotaObject(PERSISTENCE_TYPE_DEFAULT, aQuotaInfo.mGroup,
aQuotaInfo.mOrigin, bodyFile, -1, &fileSize);
RefPtr<QuotaObject> quotaObject = quotaManager->GetQuotaObject(
PERSISTENCE_TYPE_DEFAULT, aQuotaInfo.mGroup, aQuotaInfo.mOrigin,
Client::DOMCACHE, bodyFile, -1, &fileSize);
MOZ_DIAGNOSTIC_ASSERT(quotaObject);
MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
// XXXtt: bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1422815
@ -740,7 +742,7 @@ void DecreaseUsageForQuotaInfo(const QuotaInfo& aQuotaInfo,
quotaManager->DecreaseUsageForOrigin(PERSISTENCE_TYPE_DEFAULT,
aQuotaInfo.mGroup, aQuotaInfo.mOrigin,
aUpdatingSize);
Client::DOMCACHE, aUpdatingSize);
}
// static

View File

@ -3895,6 +3895,9 @@ nsresult GetDatabaseFileURL(nsIFile* aDatabaseFile,
nsAutoCString type;
PersistenceTypeToText(aPersistenceType, type);
nsAutoCString clientType;
Client::TypeToText(Client::IDB, clientType);
nsAutoCString telemetryFilenameClause;
if (aTelemetryId) {
telemetryFilenameClause.AssignLiteral("&telemetryFilename=indexedDB-");
@ -3906,6 +3909,7 @@ nsresult GetDatabaseFileURL(nsIFile* aDatabaseFile,
.SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type +
NS_LITERAL_CSTRING("&group=") + aGroup +
NS_LITERAL_CSTRING("&origin=") + aOrigin +
NS_LITERAL_CSTRING("&clientType=") + clientType +
NS_LITERAL_CSTRING("&cache=private") +
telemetryFilenameClause)
.Finalize(fileUrl);
@ -8709,7 +8713,7 @@ nsresult DeleteFile(nsIFile* aDirectory, const nsAString& aFilename,
if (aQuotaManager && fileSize > 0) {
aQuotaManager->DecreaseUsageForOrigin(aPersistenceType, aGroup, aOrigin,
fileSize);
Client::IDB, fileSize);
}
return NS_OK;
@ -8930,7 +8934,7 @@ nsresult RemoveDatabaseFilesAndDirectory(nsIFile* aBaseDirectory,
if (aQuotaManager && usage) {
aQuotaManager->DecreaseUsageForOrigin(aPersistenceType, aGroup, aOrigin,
usage);
Client::IDB, usage);
}
if (NS_FAILED(rv)) {
@ -10271,9 +10275,9 @@ void DatabaseConnection::UpdateRefcountFunction::Reset() {
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager);
quotaManager->DecreaseUsageForOrigin(aFileManager->Type(),
aFileManager->Group(),
aFileManager->Origin(), fileSize);
quotaManager->DecreaseUsageForOrigin(
aFileManager->Type(), aFileManager->Group(), aFileManager->Origin(),
Client::IDB, fileSize);
}
file = FileManager::GetFileForId(mJournalDirectory, aId);
@ -16690,9 +16694,9 @@ nsresult DeleteFilesRunnable::DeleteFile(int64_t aFileId) {
QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "Shouldn't be null!");
quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
mFileManager->Group(),
mFileManager->Origin(), fileSize);
quotaManager->DecreaseUsageForOrigin(
mFileManager->Type(), mFileManager->Group(), mFileManager->Origin(),
Client::IDB, fileSize);
}
file = mFileManager->GetFileForId(mJournalDirectory, aFileId);
@ -19024,13 +19028,13 @@ already_AddRefed<nsISupports> MutableFile::CreateStream(bool aReadOnly) {
if (aReadOnly) {
RefPtr<FileInputStream> stream =
CreateFileInputStream(persistenceType, group, origin, mFile, -1, -1,
nsIFileInputStream::DEFER_OPEN);
CreateFileInputStream(persistenceType, group, origin, Client::IDB,
mFile, -1, -1, nsIFileInputStream::DEFER_OPEN);
result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream);
} else {
RefPtr<FileStream> stream =
CreateFileStream(persistenceType, group, origin, mFile, -1, -1,
nsIFileStream::DEFER_OPEN);
CreateFileStream(persistenceType, group, origin, Client::IDB, mFile, -1,
-1, nsIFileStream::DEFER_OPEN);
result = NS_ISUPPORTS_CAST(nsIFileStream*, stream);
}
if (NS_WARN_IF(!result)) {
@ -27022,7 +27026,7 @@ nsresult FileHelper::CreateFileFromStream(nsIFile* aFile, nsIFile* aJournalFile,
// Now try to copy the stream.
RefPtr<FileOutputStream> fileOutputStream =
CreateFileOutputStream(mFileManager->Type(), mFileManager->Group(),
mFileManager->Origin(), aFile);
mFileManager->Origin(), Client::IDB, aFile);
if (NS_WARN_IF(!fileOutputStream)) {
return NS_ERROR_FAILURE;
}
@ -27068,9 +27072,9 @@ nsresult FileHelper::RemoveFile(nsIFile* aFile, nsIFile* aJournalFile) {
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager);
quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
mFileManager->Group(),
mFileManager->Origin(), fileSize);
quotaManager->DecreaseUsageForOrigin(
mFileManager->Type(), mFileManager->Group(), mFileManager->Origin(),
Client::IDB, fileSize);
}
rv = aJournalFile->Remove(false);

View File

@ -7455,7 +7455,8 @@ already_AddRefed<QuotaObject> PrepareDatastoreOp::GetQuotaObject() {
MOZ_ASSERT(quotaManager);
RefPtr<QuotaObject> quotaObject = quotaManager->GetQuotaObject(
PERSISTENCE_TYPE_DEFAULT, mGroup, mOrigin, mDatabaseFilePath, mUsage);
PERSISTENCE_TYPE_DEFAULT, mGroup, mOrigin,
mozilla::dom::quota::Client::LS, mDatabaseFilePath, mUsage);
MOZ_ASSERT(quotaObject);
return quotaObject.forget();

View File

@ -128,6 +128,9 @@ const char QuotaManager::kReplaceChars[] = CONTROL_CHARACTERS "/:*?\"<>|\\";
namespace {
template <typename T>
void AssertNoOverflow(uint64_t aDest, T aArg);
/*******************************************************************************
* Constants
******************************************************************************/
@ -601,13 +604,23 @@ namespace {
} // namespace
class ClientUsageArray final : public AutoTArray<uint64_t, Client::TYPE_MAX> {
public:
ClientUsageArray() {
for (uint32_t index = 0; index < uint32_t(Client::TypeMax()); index++) {
AppendElement(0);
}
}
};
class OriginInfo final {
friend class GroupInfo;
friend class QuotaManager;
friend class QuotaObject;
public:
OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin, uint64_t aUsage,
OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin,
const ClientUsageArray& aClientUsages, uint64_t aUsage,
int64_t aAccessTime, bool aPersisted, bool aDirectoryExists);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
@ -619,6 +632,15 @@ class OriginInfo final {
int64_t LockedUsage() const {
AssertCurrentThreadOwnsQuotaMutex();
#ifdef DEBUG
uint64_t usage = 0;
for (uint32_t index = 0; index < uint32_t(Client::TypeMax()); index++) {
AssertNoOverflow(usage, mClientUsages[index]);
usage += mClientUsages[index];
}
MOZ_ASSERT(mUsage == usage);
#endif
return mUsage;
}
@ -642,7 +664,9 @@ class OriginInfo final {
MOZ_ASSERT(!mQuotaObjects.Count());
}
void LockedDecreaseUsage(int64_t aSize);
void LockedDecreaseUsage(Client::Type aClientType, int64_t aSize);
void LockedResetUsageForClient(Client::Type aClientType);
void LockedUpdateAccessTime(int64_t aAccessTime) {
AssertCurrentThreadOwnsQuotaMutex();
@ -653,7 +677,7 @@ class OriginInfo final {
void LockedPersist();
nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects;
ClientUsageArray mClientUsages;
GroupInfo* mGroupInfo;
const nsCString mOrigin;
uint64_t mUsage;
@ -2825,6 +2849,9 @@ bool QuotaObject::LockedMaybeUpdateSize(int64_t aSize, bool aTruncate) {
AssertNoUnderflow(mOriginInfo->mUsage, delta);
mOriginInfo->mUsage -= delta;
AssertNoUnderflow(mOriginInfo->mClientUsages[mClientType], delta);
mOriginInfo->mClientUsages[mClientType] -= delta;
mSize = aSize;
}
return true;
@ -2838,6 +2865,9 @@ bool QuotaObject::LockedMaybeUpdateSize(int64_t aSize, bool aTruncate) {
uint64_t delta = aSize - mSize;
AssertNoOverflow(mOriginInfo->mClientUsages[mClientType], delta);
uint64_t newClientUsage = mOriginInfo->mClientUsages[mClientType] + delta;
AssertNoOverflow(mOriginInfo->mUsage, delta);
uint64_t newUsage = mOriginInfo->mUsage + delta;
@ -2932,6 +2962,9 @@ bool QuotaObject::LockedMaybeUpdateSize(int64_t aSize, bool aTruncate) {
AssertNoUnderflow(aSize, mSize);
delta = aSize - mSize;
AssertNoOverflow(mOriginInfo->mClientUsages[mClientType], delta);
newClientUsage = mOriginInfo->mClientUsages[mClientType] + delta;
AssertNoOverflow(mOriginInfo->mUsage, delta);
newUsage = mOriginInfo->mUsage + delta;
@ -2969,6 +3002,8 @@ bool QuotaObject::LockedMaybeUpdateSize(int64_t aSize, bool aTruncate) {
// Ok, we successfully freed enough space and the operation can continue
// without throwing the quota error.
mOriginInfo->mClientUsages[mClientType] = newClientUsage;
mOriginInfo->mUsage = newUsage;
if (!mOriginInfo->LockedPersisted()) {
groupInfo->mUsage = newGroupUsage;
@ -2990,6 +3025,8 @@ bool QuotaObject::LockedMaybeUpdateSize(int64_t aSize, bool aTruncate) {
return true;
}
mOriginInfo->mClientUsages[mClientType] = newClientUsage;
mOriginInfo->mUsage = newUsage;
if (!mOriginInfo->LockedPersisted()) {
groupInfo->mUsage = newGroupUsage;
@ -3346,7 +3383,7 @@ uint64_t QuotaManager::CollectOriginsForEviction(
break;
}
sizeToBeFreed += inactiveOrigins[index]->mUsage;
sizeToBeFreed += inactiveOrigins[index]->LockedUsage();
}
if (sizeToBeFreed >= aMinSizeToBeFreed) {
@ -3517,6 +3554,7 @@ void QuotaManager::Shutdown() {
void QuotaManager::InitQuotaForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
const ClientUsageArray& aClientUsages,
uint64_t aUsageBytes, int64_t aAccessTime,
bool aPersisted) {
AssertIsOnIOThread();
@ -3527,9 +3565,9 @@ void QuotaManager::InitQuotaForOrigin(PersistenceType aPersistenceType,
RefPtr<GroupInfo> groupInfo =
LockedGetOrCreateGroupInfo(aPersistenceType, aGroup);
RefPtr<OriginInfo> originInfo =
new OriginInfo(groupInfo, aOrigin, aUsageBytes, aAccessTime, aPersisted,
/* aDirectoryExists */ true);
RefPtr<OriginInfo> originInfo = new OriginInfo(
groupInfo, aOrigin, aClientUsages, aUsageBytes, aAccessTime, aPersisted,
/* aDirectoryExists */ true);
groupInfo->LockedAddOriginInfo(originInfo);
}
@ -3547,8 +3585,9 @@ void QuotaManager::EnsureQuotaForOrigin(PersistenceType aPersistenceType,
RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
if (!originInfo) {
originInfo = new OriginInfo(
groupInfo, aOrigin, /* aUsageBytes */ 0, /* aAccessTime */ PR_Now(),
/* aPersisted */ false, /* aDirectoryExists */ false);
groupInfo, aOrigin, ClientUsageArray(), /* aUsageBytes */ 0,
/* aAccessTime */ PR_Now(), /* aPersisted */ false,
/* aDirectoryExists */ false);
groupInfo->LockedAddOriginInfo(originInfo);
}
}
@ -3576,8 +3615,8 @@ void QuotaManager::NoteOriginDirectoryCreated(PersistenceType aPersistenceType,
} else {
timestamp = PR_Now();
RefPtr<OriginInfo> originInfo = new OriginInfo(
groupInfo, aOrigin, /* aUsageBytes */ 0, /* aAccessTime */ timestamp,
aPersisted, /* aDirectoryExists */ true);
groupInfo, aOrigin, ClientUsageArray(), /* aUsageBytes */ 0,
/* aAccessTime */ timestamp, aPersisted, /* aDirectoryExists */ true);
groupInfo->LockedAddOriginInfo(originInfo);
}
@ -3587,6 +3626,7 @@ void QuotaManager::NoteOriginDirectoryCreated(PersistenceType aPersistenceType,
void QuotaManager::DecreaseUsageForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
Client::Type aClientType,
int64_t aSize) {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
@ -3605,7 +3645,32 @@ void QuotaManager::DecreaseUsageForOrigin(PersistenceType aPersistenceType,
RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
if (originInfo) {
originInfo->LockedDecreaseUsage(aSize);
originInfo->LockedDecreaseUsage(aClientType, aSize);
}
}
void QuotaManager::ResetUsageForClient(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
Client::Type aClientType) {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
MutexAutoLock lock(mQuotaMutex);
GroupInfoPair* pair;
if (!mGroupInfoPairs.Get(aGroup, &pair)) {
return;
}
RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
if (!groupInfo) {
return;
}
RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
if (originInfo) {
originInfo->LockedResetUsageForClient(aClientType);
}
}
@ -3671,8 +3736,8 @@ void QuotaManager::RemoveQuota() {
already_AddRefed<QuotaObject> QuotaManager::GetQuotaObject(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, nsIFile* aFile, int64_t aFileSize,
int64_t* aFileSizeOut /* = nullptr */) {
const nsACString& aOrigin, Client::Type aClientType, nsIFile* aFile,
int64_t aFileSize, int64_t* aFileSizeOut /* = nullptr */) {
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (aFileSizeOut) {
@ -3687,6 +3752,34 @@ already_AddRefed<QuotaObject> QuotaManager::GetQuotaObject(
nsresult rv = aFile->GetPath(path);
NS_ENSURE_SUCCESS(rv, nullptr);
#ifdef DEBUG
nsCOMPtr<nsIFile> directory;
rv = GetDirectoryForOrigin(aPersistenceType, aOrigin,
getter_AddRefs(directory));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsAutoString clientType;
rv = Client::TypeToText(aClientType, clientType);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
rv = directory->Append(clientType);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsString directoryPath;
rv = directory->GetPath(directoryPath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
MOZ_ASSERT(StringBeginsWith(path, directoryPath));
#endif
int64_t fileSize;
if (aFileSize == -1) {
@ -3731,7 +3824,7 @@ already_AddRefed<QuotaObject> QuotaManager::GetQuotaObject(
QuotaObject* quotaObject;
if (!originInfo->mQuotaObjects.Get(path, &quotaObject)) {
// Create a new QuotaObject.
quotaObject = new QuotaObject(originInfo, path, fileSize);
quotaObject = new QuotaObject(originInfo, aClientType, path, fileSize);
// Put it to the hashtable. The hashtable is not responsible to delete
// the QuotaObject.
@ -3754,8 +3847,8 @@ already_AddRefed<QuotaObject> QuotaManager::GetQuotaObject(
already_AddRefed<QuotaObject> QuotaManager::GetQuotaObject(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, const nsAString& aPath, int64_t aFileSize,
int64_t* aFileSizeOut /* = nullptr */) {
const nsACString& aOrigin, Client::Type aClientType, const nsAString& aPath,
int64_t aFileSize, int64_t* aFileSizeOut /* = nullptr */) {
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (aFileSizeOut) {
@ -3766,8 +3859,8 @@ already_AddRefed<QuotaObject> QuotaManager::GetQuotaObject(
nsresult rv = NS_NewLocalFile(aPath, false, getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, nullptr);
return GetQuotaObject(aPersistenceType, aGroup, aOrigin, file, aFileSize,
aFileSizeOut);
return GetQuotaObject(aPersistenceType, aGroup, aOrigin, aClientType, file,
aFileSize, aFileSizeOut);
}
Nullable<bool> QuotaManager::OriginPersisted(const nsACString& aGroup,
@ -4171,10 +4264,10 @@ nsresult QuotaManager::InitializeOrigin(PersistenceType aPersistenceType,
// We need to initialize directories of all clients if they exists and also
// get the total usage to initialize the quota.
nsAutoPtr<UsageInfo> usageInfo;
if (trackQuota) {
usageInfo = new UsageInfo();
}
ClientUsageArray clientUsages;
uint64_t usage = 0;
// A keeper to defer the return only in Nightly, so that the telemetry data
// for whole profile can be collected
@ -4274,15 +4367,25 @@ nsresult QuotaManager::InitializeOrigin(PersistenceType aPersistenceType,
CONTINUE_IN_NIGHTLY_RETURN_IN_OTHERS(NS_ERROR_UNEXPECTED);
}
Atomic<bool> dummy(false);
UsageInfo usageInfo;
rv = mClients[clientType]->InitOrigin(aPersistenceType, aGroup, aOrigin,
/* aCanceled */ dummy, usageInfo,
/* aCanceled */ Atomic<bool>(false),
trackQuota ? &usageInfo : nullptr,
/* aForGetUsage */ false);
if (NS_WARN_IF(NS_FAILED(rv))) {
// error should have reported in InitOrigin
RECORD_IN_NIGHTLY(statusKeeper, rv);
CONTINUE_IN_NIGHTLY_RETURN_IN_OTHERS(rv);
}
if (trackQuota) {
uint64_t clientUsage = usageInfo.TotalUsage();
clientUsages[clientType] = clientUsage;
AssertNoOverflow(usage, clientUsage);
usage += clientUsage;
}
}
if (NS_WARN_IF(NS_FAILED(rv))) {
REPORT_TELEMETRY_INIT_ERR(kQuotaInternalError, Ori_GetNextFile);
@ -4299,8 +4402,8 @@ nsresult QuotaManager::InitializeOrigin(PersistenceType aPersistenceType,
#endif
if (trackQuota) {
InitQuotaForOrigin(aPersistenceType, aGroup, aOrigin,
usageInfo->TotalUsage(), aAccessTime, aPersisted);
InitQuotaForOrigin(aPersistenceType, aGroup, aOrigin, clientUsages, usage,
aAccessTime, aPersisted);
}
return NS_OK;
@ -6410,7 +6513,7 @@ void QuotaManager::CheckTemporaryStorageLimits() {
}
doomedOriginInfos.AppendElement(originInfo);
groupUsage -= originInfo->mUsage;
groupUsage -= originInfo->LockedUsage();
if (groupUsage <= quotaManager->GetGroupLimit()) {
break;
@ -6422,7 +6525,7 @@ void QuotaManager::CheckTemporaryStorageLimits() {
uint64_t usage = 0;
for (uint32_t index = 0; index < doomedOriginInfos.Length(); index++) {
usage += doomedOriginInfos[index]->mUsage;
usage += doomedOriginInfos[index]->LockedUsage();
}
if (mTemporaryStorageUsage - usage > mTemporaryStorageLimit) {
@ -6461,7 +6564,7 @@ void QuotaManager::CheckTemporaryStorageLimits() {
break;
}
usage += originInfos[i]->mUsage;
usage += originInfos[i]->LockedUsage();
}
doomedOriginInfos.AppendElements(originInfos);
@ -6600,24 +6703,39 @@ bool QuotaManager::IsSanitizedOriginValid(const nsACString& aSanitizedOrigin) {
******************************************************************************/
OriginInfo::OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin,
uint64_t aUsage, int64_t aAccessTime, bool aPersisted,
const ClientUsageArray& aClientUsages, uint64_t aUsage,
int64_t aAccessTime, bool aPersisted,
bool aDirectoryExists)
: mGroupInfo(aGroupInfo),
: mClientUsages(aClientUsages),
mGroupInfo(aGroupInfo),
mOrigin(aOrigin),
mUsage(aUsage),
mAccessTime(aAccessTime),
mPersisted(aPersisted),
mDirectoryExists(aDirectoryExists) {
MOZ_ASSERT(aGroupInfo);
MOZ_ASSERT(aClientUsages.Length() == Client::TypeMax());
MOZ_ASSERT_IF(aPersisted,
aGroupInfo->mPersistenceType == PERSISTENCE_TYPE_DEFAULT);
#ifdef DEBUG
uint64_t usage = 0;
for (uint32_t index = 0; index < uint32_t(Client::TypeMax()); index++) {
AssertNoOverflow(usage, aClientUsages[index]);
usage += aClientUsages[index];
}
MOZ_ASSERT(aUsage == usage);
#endif
MOZ_COUNT_CTOR(OriginInfo);
}
void OriginInfo::LockedDecreaseUsage(int64_t aSize) {
void OriginInfo::LockedDecreaseUsage(Client::Type aClientType, int64_t aSize) {
AssertCurrentThreadOwnsQuotaMutex();
AssertNoUnderflow(mClientUsages[aClientType], aSize);
mClientUsages[aClientType] -= aSize;
AssertNoUnderflow(mUsage, aSize);
mUsage -= aSize;
@ -6633,6 +6751,28 @@ void OriginInfo::LockedDecreaseUsage(int64_t aSize) {
quotaManager->mTemporaryStorageUsage -= aSize;
}
void OriginInfo::LockedResetUsageForClient(Client::Type aClientType) {
AssertCurrentThreadOwnsQuotaMutex();
uint64_t size = mClientUsages[aClientType];
mClientUsages[aClientType] = 0;
AssertNoUnderflow(mUsage, size);
mUsage -= size;
if (!LockedPersisted()) {
AssertNoUnderflow(mGroupInfo->mUsage, size);
mGroupInfo->mUsage -= size;
}
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager);
AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, size);
quotaManager->mTemporaryStorageUsage -= size;
}
void OriginInfo::LockedPersist() {
AssertCurrentThreadOwnsQuotaMutex();
MOZ_ASSERT(mGroupInfo->mPersistenceType == PERSISTENCE_TYPE_DEFAULT);
@ -6666,16 +6806,18 @@ void GroupInfo::LockedAddOriginInfo(OriginInfo* aOriginInfo) {
"Replacing an existing entry!");
mOriginInfos.AppendElement(aOriginInfo);
uint64_t usage = aOriginInfo->LockedUsage();
if (!aOriginInfo->LockedPersisted()) {
AssertNoOverflow(mUsage, aOriginInfo->mUsage);
mUsage += aOriginInfo->mUsage;
AssertNoOverflow(mUsage, usage);
mUsage += usage;
}
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager);
AssertNoOverflow(quotaManager->mTemporaryStorageUsage, aOriginInfo->mUsage);
quotaManager->mTemporaryStorageUsage += aOriginInfo->mUsage;
AssertNoOverflow(quotaManager->mTemporaryStorageUsage, usage);
quotaManager->mTemporaryStorageUsage += usage;
}
void GroupInfo::LockedRemoveOriginInfo(const nsACString& aOrigin) {
@ -6683,17 +6825,18 @@ void GroupInfo::LockedRemoveOriginInfo(const nsACString& aOrigin) {
for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
if (mOriginInfos[index]->mOrigin == aOrigin) {
uint64_t usage = mOriginInfos[index]->LockedUsage();
if (!mOriginInfos[index]->LockedPersisted()) {
AssertNoUnderflow(mUsage, mOriginInfos[index]->mUsage);
mUsage -= mOriginInfos[index]->mUsage;
AssertNoUnderflow(mUsage, usage);
mUsage -= usage;
}
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager);
AssertNoUnderflow(quotaManager->mTemporaryStorageUsage,
mOriginInfos[index]->mUsage);
quotaManager->mTemporaryStorageUsage -= mOriginInfos[index]->mUsage;
AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, usage);
quotaManager->mTemporaryStorageUsage -= usage;
mOriginInfos.RemoveElementAt(index);
@ -6711,13 +6854,15 @@ void GroupInfo::LockedRemoveOriginInfos() {
for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
OriginInfo* originInfo = mOriginInfos[index - 1];
uint64_t usage = originInfo->LockedUsage();
if (!originInfo->LockedPersisted()) {
AssertNoUnderflow(mUsage, originInfo->mUsage);
mUsage -= originInfo->mUsage;
AssertNoUnderflow(mUsage, usage);
mUsage -= usage;
}
AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, originInfo->mUsage);
quotaManager->mTemporaryStorageUsage -= originInfo->mUsage;
AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, usage);
quotaManager->mTemporaryStorageUsage -= usage;
mOriginInfos.RemoveElementAt(index - 1);
}
@ -8199,17 +8344,8 @@ void ClearRequestBase::DeleteFiles(QuotaManager* aQuotaManager,
return;
}
bool initialized;
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
initialized = aQuotaManager->IsOriginInitialized(origin);
} else {
initialized = aQuotaManager->IsTemporaryStorageInitialized();
}
bool hasOtherClient = false;
UsageInfo usageInfo;
if (!mClientType.IsNull()) {
// Checking whether there is any other client in the directory is needed.
// If there is not, removing whole directory is needed.
@ -8275,18 +8411,6 @@ void ClearRequestBase::DeleteFiles(QuotaManager* aQuotaManager,
continue;
}
}
if (initialized) {
Client* client = aQuotaManager->GetClient(mClientType.Value());
MOZ_ASSERT(client);
Atomic<bool> dummy(false);
rv = client->GetUsageForOrigin(aPersistenceType, group, origin, dummy,
&usageInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
}
}
for (uint32_t index = 0; index < 10; index++) {
@ -8304,6 +8428,13 @@ void ClearRequestBase::DeleteFiles(QuotaManager* aQuotaManager,
NS_WARNING("Failed to remove directory, giving up!");
}
bool initialized;
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
initialized = aQuotaManager->IsOriginInitialized(origin);
} else {
initialized = aQuotaManager->IsTemporaryStorageInitialized();
}
// If it hasn't been initialized, we don't need to update the quota and
// notify the removing client.
if (!initialized) {
@ -8314,8 +8445,8 @@ void ClearRequestBase::DeleteFiles(QuotaManager* aQuotaManager,
if (hasOtherClient) {
MOZ_ASSERT(!mClientType.IsNull());
aQuotaManager->DecreaseUsageForOrigin(aPersistenceType, group, origin,
usageInfo.TotalUsage());
aQuotaManager->ResetUsageForClient(aPersistenceType, group, origin,
mClientType.Value());
} else {
aQuotaManager->RemoveQuotaForOrigin(aPersistenceType, group, origin);
}

View File

@ -58,6 +58,33 @@ class Client {
virtual Type GetType() = 0;
static void TypeToText(Type aType, nsACString& aText) {
switch (aType) {
case IDB:
aText.AssignLiteral(IDB_DIRECTORY_NAME);
return;
case DOMCACHE:
aText.AssignLiteral(DOMCACHE_DIRECTORY_NAME);
return;
case SDB:
aText.AssignLiteral(SDB_DIRECTORY_NAME);
return;
case LS:
if (CachedNextGenLocalStorageEnabled()) {
aText.AssignLiteral(LS_DIRECTORY_NAME);
return;
}
MOZ_FALLTHROUGH;
case TYPE_MAX:
default:
MOZ_CRASH("Bad client type value!");
}
}
static nsresult TypeToText(Type aType, nsAString& aText) {
switch (aType) {
case IDB:
@ -88,6 +115,27 @@ class Client {
return NS_OK;
}
static Type TypeFromText(const nsACString& aText) {
if (aText.EqualsLiteral(IDB_DIRECTORY_NAME)) {
return IDB;
}
if (aText.EqualsLiteral(DOMCACHE_DIRECTORY_NAME)) {
return DOMCACHE;
}
if (aText.EqualsLiteral(SDB_DIRECTORY_NAME)) {
return SDB;
}
if (CachedNextGenLocalStorageEnabled() &&
aText.EqualsLiteral(LS_DIRECTORY_NAME)) {
return LS;
}
MOZ_CRASH("Should never get here!");
}
static nsresult TypeFromText(const nsAString& aText, Type& aType) {
if (aText.EqualsLiteral(IDB_DIRECTORY_NAME)) {
aType = IDB;

View File

@ -44,7 +44,8 @@ nsresult FileQuotaStream<FileStreamBase>::DoOpen() {
NS_ASSERTION(!mQuotaObject, "Creating quota object more than once?");
mQuotaObject = quotaManager->GetQuotaObject(
mPersistenceType, mGroup, mOrigin, FileStreamBase::mOpenParams.localFile);
mPersistenceType, mGroup, mOrigin, mClientType,
FileStreamBase::mOpenParams.localFile);
nsresult rv = FileStreamBase::DoOpen();
NS_ENSURE_SUCCESS(rv, rv);
@ -83,10 +84,10 @@ NS_IMETHODIMP FileQuotaStreamWithWrite<FileStreamBase>::Write(
already_AddRefed<FileInputStream> CreateFileInputStream(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags, int32_t aPerm,
int32_t aBehaviorFlags) {
const nsACString& aOrigin, Client::Type aClientType, nsIFile* aFile,
int32_t aIOFlags, int32_t aPerm, int32_t aBehaviorFlags) {
RefPtr<FileInputStream> stream =
new FileInputStream(aPersistenceType, aGroup, aOrigin);
new FileInputStream(aPersistenceType, aGroup, aOrigin, aClientType);
nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
NS_ENSURE_SUCCESS(rv, nullptr);
return stream.forget();
@ -94,22 +95,21 @@ already_AddRefed<FileInputStream> CreateFileInputStream(
already_AddRefed<FileOutputStream> CreateFileOutputStream(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags, int32_t aPerm,
int32_t aBehaviorFlags) {
const nsACString& aOrigin, Client::Type aClientType, nsIFile* aFile,
int32_t aIOFlags, int32_t aPerm, int32_t aBehaviorFlags) {
RefPtr<FileOutputStream> stream =
new FileOutputStream(aPersistenceType, aGroup, aOrigin);
new FileOutputStream(aPersistenceType, aGroup, aOrigin, aClientType);
nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
NS_ENSURE_SUCCESS(rv, nullptr);
return stream.forget();
}
already_AddRefed<FileStream> CreateFileStream(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
nsIFile* aFile, int32_t aIOFlags,
int32_t aPerm,
int32_t aBehaviorFlags) {
RefPtr<FileStream> stream = new FileStream(aPersistenceType, aGroup, aOrigin);
already_AddRefed<FileStream> CreateFileStream(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, Client::Type aClientType, nsIFile* aFile,
int32_t aIOFlags, int32_t aPerm, int32_t aBehaviorFlags) {
RefPtr<FileStream> stream =
new FileStream(aPersistenceType, aGroup, aOrigin, aClientType);
nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
NS_ENSURE_SUCCESS(rv, nullptr);
return stream.forget();

View File

@ -28,8 +28,11 @@ class FileQuotaStream : public FileStreamBase {
protected:
FileQuotaStream(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin)
: mPersistenceType(aPersistenceType), mGroup(aGroup), mOrigin(aOrigin) {}
const nsACString& aOrigin, Client::Type aClientType)
: mPersistenceType(aPersistenceType),
mGroup(aGroup),
mOrigin(aOrigin),
mClientType(aClientType) {}
// nsFileStreamBase override
virtual nsresult DoOpen() override;
@ -37,6 +40,7 @@ class FileQuotaStream : public FileStreamBase {
PersistenceType mPersistenceType;
nsCString mGroup;
nsCString mOrigin;
Client::Type mClientType;
RefPtr<QuotaObject> mQuotaObject;
};
@ -49,8 +53,10 @@ class FileQuotaStreamWithWrite : public FileQuotaStream<FileStreamBase> {
protected:
FileQuotaStreamWithWrite(PersistenceType aPersistenceType,
const nsACString& aGroup, const nsACString& aOrigin)
: FileQuotaStream<FileStreamBase>(aPersistenceType, aGroup, aOrigin) {}
const nsACString& aGroup, const nsACString& aOrigin,
Client::Type aClientType)
: FileQuotaStream<FileStreamBase>(aPersistenceType, aGroup, aOrigin,
aClientType) {}
};
class FileInputStream : public FileQuotaStream<nsFileInputStream> {
@ -59,8 +65,9 @@ class FileInputStream : public FileQuotaStream<nsFileInputStream> {
FileQuotaStream<nsFileInputStream>)
FileInputStream(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin)
: FileQuotaStream<nsFileInputStream>(aPersistenceType, aGroup, aOrigin) {}
const nsACString& aOrigin, Client::Type aClientType)
: FileQuotaStream<nsFileInputStream>(aPersistenceType, aGroup, aOrigin,
aClientType) {}
private:
virtual ~FileInputStream() { Close(); }
@ -72,9 +79,9 @@ class FileOutputStream : public FileQuotaStreamWithWrite<nsFileOutputStream> {
FileOutputStream, FileQuotaStreamWithWrite<nsFileOutputStream>);
FileOutputStream(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin)
const nsACString& aOrigin, Client::Type aClientType)
: FileQuotaStreamWithWrite<nsFileOutputStream>(aPersistenceType, aGroup,
aOrigin) {}
aOrigin, aClientType) {}
private:
virtual ~FileOutputStream() { Close(); }
@ -86,9 +93,9 @@ class FileStream : public FileQuotaStreamWithWrite<nsFileStream> {
FileQuotaStreamWithWrite<nsFileStream>)
FileStream(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin)
const nsACString& aOrigin, Client::Type aClientType)
: FileQuotaStreamWithWrite<nsFileStream>(aPersistenceType, aGroup,
aOrigin) {}
aOrigin, aClientType) {}
private:
virtual ~FileStream() { Close(); }
@ -96,18 +103,18 @@ class FileStream : public FileQuotaStreamWithWrite<nsFileStream> {
already_AddRefed<FileInputStream> CreateFileInputStream(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
const nsACString& aOrigin, Client::Type aClientType, nsIFile* aFile,
int32_t aIOFlags = -1, int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
already_AddRefed<FileOutputStream> CreateFileOutputStream(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
const nsACString& aOrigin, Client::Type aClientType, nsIFile* aFile,
int32_t aIOFlags = -1, int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
already_AddRefed<FileStream> CreateFileStream(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
const nsACString& aOrigin, Client::Type aClientType, nsIFile* aFile,
int32_t aIOFlags = -1, int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
END_QUOTA_NAMESPACE

View File

@ -46,6 +46,7 @@ class PrincipalInfo;
BEGIN_QUOTA_NAMESPACE
class ClientUsageArray;
class DirectoryLockImpl;
class GroupInfo;
class GroupInfoPair;
@ -153,6 +154,7 @@ class QuotaManager final : public BackgroundThreadObject {
*/
void InitQuotaForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup, const nsACString& aOrigin,
const ClientUsageArray& aClientUsages,
uint64_t aUsageBytes, int64_t aAccessTime,
bool aPersisted);
@ -181,9 +183,15 @@ class QuotaManager final : public BackgroundThreadObject {
const nsACString& aOrigin, bool aPersisted,
int64_t& aTimestamp);
// XXX clients can use QuotaObject instead of calling this method directly.
void DecreaseUsageForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin, int64_t aSize);
const nsACString& aOrigin,
Client::Type aClientType, int64_t aSize);
void ResetUsageForClient(PersistenceType aPersistenceType,
const nsACString& aGroup, const nsACString& aOrigin,
Client::Type aClientType);
void UpdateOriginAccessTime(PersistenceType aPersistenceType,
const nsACString& aGroup,
@ -198,16 +206,15 @@ class QuotaManager final : public BackgroundThreadObject {
LockedRemoveQuotaForOrigin(aPersistenceType, aGroup, aOrigin);
}
already_AddRefed<QuotaObject> GetQuotaObject(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
nsIFile* aFile,
int64_t aFileSize = -1,
int64_t* aFileSizeOut = nullptr);
already_AddRefed<QuotaObject> GetQuotaObject(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, Client::Type aClientType, nsIFile* aFile,
int64_t aFileSize = -1, int64_t* aFileSizeOut = nullptr);
already_AddRefed<QuotaObject> GetQuotaObject(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
Client::Type aClientType,
const nsAString& aPath,
int64_t aFileSize = -1,
int64_t* aFileSizeOut = nullptr);

View File

@ -11,6 +11,7 @@
#include "nsDataHashtable.h"
#include "Client.h"
#include "PersistenceType.h"
BEGIN_QUOTA_NAMESPACE
@ -40,10 +41,12 @@ class QuotaObject {
void EnableQuotaCheck();
private:
QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize)
QuotaObject(OriginInfo* aOriginInfo, Client::Type aClientType,
const nsAString& aPath, int64_t aSize)
: mOriginInfo(aOriginInfo),
mPath(aPath),
mSize(aSize),
mClientType(aClientType),
mQuotaCheckDisabled(false),
mWritingDone(false) {
MOZ_COUNT_CTOR(QuotaObject);
@ -67,7 +70,7 @@ class QuotaObject {
OriginInfo* mOriginInfo;
nsString mPath;
int64_t mSize;
Client::Type mClientType;
bool mQuotaCheckDisabled;
bool mWritingDone;
};

View File

@ -1119,7 +1119,8 @@ nsresult OpenOp::SendToIOThread() {
return NS_ERROR_FAILURE;
}
mFileStream = new FileStream(PERSISTENCE_TYPE_DEFAULT, mGroup, mOrigin);
mFileStream = new FileStream(PERSISTENCE_TYPE_DEFAULT, mGroup, mOrigin,
mozilla::dom::quota::Client::SDB);
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager);

View File

@ -319,6 +319,15 @@ already_AddRefed<QuotaObject> GetQuotaObjectFromNameAndParameters(
return nullptr;
}
const char* clientType =
sqlite3_uri_parameter(zURIParameterKey, "clientType");
if (!clientType) {
NS_WARNING(
"SQLite URI had 'persistenceType', 'group' and 'origin' but not "
"'clientType'?!");
return nullptr;
}
// Re-escape group and origin to make sure we get the right quota group and
// origin.
nsAutoCString escGroup;
@ -339,7 +348,8 @@ already_AddRefed<QuotaObject> GetQuotaObjectFromNameAndParameters(
return quotaManager->GetQuotaObject(
PersistenceTypeFromText(nsDependentCString(persistenceType)), escGroup,
escOrigin, NS_ConvertUTF8toUTF16(zName));
escOrigin, Client::TypeFromText(nsDependentCString(clientType)),
NS_ConvertUTF8toUTF16(zName));
}
void MaybeEstablishQuotaControl(const char* zName, telemetry_file* pFile,