Bug 1685677 - Extract functions from CheckTemporaryStorageLimits and rename it to CleanupTemporaryStorage. r=dom-workers-and-storage-reviewers,janv

Extracts parts of CheckTemporaryStorageLimits into the following new private
member functions of QuotaManager:
* LockedGetOriginInfosExceedingGroupLimit
* LockedGetOriginInfosExceedingGlobalLimit
* GetOriginInfosExceedingLimits
* ClearOrigins

Differential Revision: https://phabricator.services.mozilla.com/D101145
This commit is contained in:
Simon Giesecke 2021-02-02 10:10:21 +00:00
parent b0327ecf3c
commit 0da4951ba0
3 changed files with 187 additions and 134 deletions

View File

@ -952,13 +952,13 @@ class OriginInfo final {
class OriginInfoLRUComparator {
public:
bool Equals(const NotNull<RefPtr<OriginInfo>>& a,
const NotNull<RefPtr<OriginInfo>>& b) const {
bool Equals(const NotNull<RefPtr<const OriginInfo>>& a,
const NotNull<RefPtr<const OriginInfo>>& b) const {
return a->LockedAccessTime() == b->LockedAccessTime();
}
bool LessThan(const NotNull<RefPtr<OriginInfo>>& a,
const NotNull<RefPtr<OriginInfo>>& b) const {
bool LessThan(const NotNull<RefPtr<const OriginInfo>>& a,
const NotNull<RefPtr<const OriginInfo>>& b) const {
return a->LockedAccessTime() < b->LockedAccessTime();
}
};
@ -3783,8 +3783,8 @@ uint64_t QuotaManager::CollectOriginsForEviction(
static void GetInactiveOriginInfos(
const nsTArray<NotNull<RefPtr<OriginInfo>>>& aOriginInfos,
const nsTArray<NotNull<DirectoryLockImpl*>>& aLocks,
nsTArray<NotNull<RefPtr<OriginInfo>>>& aInactiveOriginInfos) {
for (const NotNull<RefPtr<OriginInfo>>& originInfo : aOriginInfos) {
OriginInfosFlatTraversable& aInactiveOriginInfos) {
for (const auto& originInfo : aOriginInfos) {
MOZ_ASSERT(originInfo->mGroupInfo->mPersistenceType !=
PERSISTENCE_TYPE_PERSISTENT);
@ -3832,7 +3832,7 @@ uint64_t QuotaManager::CollectOriginsForEviction(
}
}
nsTArray<NotNull<RefPtr<OriginInfo>>> inactiveOrigins;
OriginInfosFlatTraversable inactiveOrigins;
// Enumerate and process inactive origins. This must be protected by the
// mutex.
@ -6549,7 +6549,7 @@ nsresult QuotaManager::EnsureTemporaryStorageIsInitialized() {
mTemporaryStorageLimit = GetTemporaryStorageLimit(
/* aAvailableSpaceBytes */ diskSpaceAvailable + mTemporaryStorageUsage);
CheckTemporaryStorageLimits();
CleanupTemporaryStorage();
return NS_OK;
}
@ -7091,150 +7091,195 @@ already_AddRefed<OriginInfo> QuotaManager::LockedGetOriginInfo(
return nullptr;
}
void QuotaManager::CheckTemporaryStorageLimits() {
AssertIsOnIOThread();
QuotaManager::OriginInfosFlatTraversable
QuotaManager::LockedGetOriginInfosExceedingGroupLimit() const {
mQuotaMutex.AssertCurrentThreadOwns();
const auto doomedOrigins = [this] {
const auto doomedOriginInfos = [this] {
nsTArray<NotNull<RefPtr<OriginInfo>>> doomedOriginInfos;
MutexAutoLock lock(mQuotaMutex);
OriginInfosFlatTraversable originInfos;
for (const auto& entry : mGroupInfoPairs) {
const auto& pair = entry.GetData();
for (const auto& entry : mGroupInfoPairs) {
const auto& pair = entry.GetData();
MOZ_ASSERT(!entry.GetKey().IsEmpty());
MOZ_ASSERT(pair);
MOZ_ASSERT(!entry.GetKey().IsEmpty());
MOZ_ASSERT(pair);
uint64_t groupUsage = 0;
uint64_t groupUsage = 0;
RefPtr<GroupInfo> temporaryGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
if (temporaryGroupInfo) {
groupUsage += temporaryGroupInfo->mUsage;
}
const RefPtr<GroupInfo> temporaryGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
if (temporaryGroupInfo) {
groupUsage += temporaryGroupInfo->mUsage;
}
RefPtr<GroupInfo> defaultGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
if (defaultGroupInfo) {
groupUsage += defaultGroupInfo->mUsage;
}
const RefPtr<GroupInfo> defaultGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
if (defaultGroupInfo) {
groupUsage += defaultGroupInfo->mUsage;
}
if (groupUsage > 0) {
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager, "Shouldn't be null!");
if (groupUsage > 0) {
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager, "Shouldn't be null!");
if (groupUsage > quotaManager->GetGroupLimit()) {
nsTArray<NotNull<RefPtr<OriginInfo>>> originInfos;
if (temporaryGroupInfo) {
originInfos.AppendElements(temporaryGroupInfo->mOriginInfos);
}
if (defaultGroupInfo) {
originInfos.AppendElements(defaultGroupInfo->mOriginInfos);
}
originInfos.Sort(OriginInfoLRUComparator());
for (uint32_t i = 0; i < originInfos.Length(); i++) {
const NotNull<RefPtr<OriginInfo>>& originInfo = originInfos[i];
if (originInfo->LockedPersisted()) {
continue;
}
doomedOriginInfos.AppendElement(originInfo);
groupUsage -= originInfo->LockedUsage();
if (groupUsage <= quotaManager->GetGroupLimit()) {
break;
}
}
if (groupUsage > quotaManager->GetGroupLimit()) {
const auto allOriginInfosLRUSorted = [&temporaryGroupInfo,
&defaultGroupInfo] {
OriginInfosFlatTraversable originInfos;
if (temporaryGroupInfo) {
originInfos.AppendElements(temporaryGroupInfo->mOriginInfos);
}
}
}
if (defaultGroupInfo) {
originInfos.AppendElements(defaultGroupInfo->mOriginInfos);
}
originInfos.Sort(OriginInfoLRUComparator());
return originInfos;
}();
uint64_t usage = std::accumulate(
doomedOriginInfos.cbegin(), doomedOriginInfos.cend(), uint64_t(0),
[](uint64_t oldValue, const auto& originInfo) {
return oldValue + originInfo->LockedUsage();
});
if (mTemporaryStorageUsage - usage > mTemporaryStorageLimit) {
nsTArray<NotNull<RefPtr<OriginInfo>>> originInfos;
for (const auto& entry : mGroupInfoPairs) {
const auto& pair = entry.GetData();
MOZ_ASSERT(!entry.GetKey().IsEmpty());
MOZ_ASSERT(pair);
RefPtr<GroupInfo> groupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
if (groupInfo) {
originInfos.AppendElements(groupInfo->mOriginInfos);
for (const auto& originInfo : allOriginInfosLRUSorted) {
// XXX We can remove these before sorting and then just truncate the
// existing array at the right point.
if (originInfo->LockedPersisted()) {
continue;
}
groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
if (groupInfo) {
originInfos.AppendElements(groupInfo->mOriginInfos);
}
}
originInfos.AppendElement(originInfo);
groupUsage -= originInfo->LockedUsage();
originInfos.RemoveElementsBy(
[&doomedOriginInfos](const auto& originInfo) {
return doomedOriginInfos.Contains(originInfo) ||
originInfo->LockedPersisted();
});
originInfos.Sort(OriginInfoLRUComparator());
for (uint32_t i = 0; i < originInfos.Length(); i++) {
if (mTemporaryStorageUsage - usage <= mTemporaryStorageLimit) {
originInfos.TruncateLength(i);
if (groupUsage <= quotaManager->GetGroupLimit()) {
break;
}
usage += originInfos[i]->LockedUsage();
}
doomedOriginInfos.AppendElements(originInfos);
}
}
}
return doomedOriginInfos;
}();
return originInfos;
}
for (const auto& doomedOriginInfo : doomedOriginInfos) {
#ifdef DEBUG
{
MutexAutoLock lock(mQuotaMutex);
MOZ_ASSERT(!doomedOriginInfo->LockedPersisted());
}
#endif
QuotaManager::OriginInfosFlatTraversable
QuotaManager::LockedGetOriginInfosExceedingGlobalLimit(
const OriginInfosFlatTraversable& aAlreadyDoomedOriginInfos,
const uint64_t aAlreadyDoomedUsage) const {
mQuotaMutex.AssertCurrentThreadOwns();
DeleteFilesForOrigin(doomedOriginInfo->mGroupInfo->mPersistenceType,
doomedOriginInfo->mOrigin);
OriginInfosFlatTraversable originInfos;
for (const auto& entry : mGroupInfoPairs) {
const auto& pair = entry.GetData();
MOZ_ASSERT(!entry.GetKey().IsEmpty());
MOZ_ASSERT(pair);
RefPtr<GroupInfo> groupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
if (groupInfo) {
originInfos.AppendElements(groupInfo->mOriginInfos);
}
nsTArray<OriginParams> doomedOrigins;
groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
if (groupInfo) {
originInfos.AppendElements(groupInfo->mOriginInfos);
}
}
originInfos.RemoveElementsBy(
[&aAlreadyDoomedOriginInfos](const auto& originInfo) {
return aAlreadyDoomedOriginInfos.Contains(originInfo) ||
originInfo->LockedPersisted();
});
originInfos.Sort(OriginInfoLRUComparator());
uint64_t doomedUsage = 0;
for (uint32_t i = 0; i < originInfos.Length(); i++) {
if (mTemporaryStorageUsage - aAlreadyDoomedUsage - doomedUsage <=
mTemporaryStorageLimit) {
originInfos.TruncateLength(i);
break;
}
doomedUsage += originInfos[i]->LockedUsage();
}
return originInfos;
}
QuotaManager::OriginInfosFlatTraversable
QuotaManager::GetOriginInfosExceedingLimits() const {
MutexAutoLock lock(mQuotaMutex);
auto originInfos = LockedGetOriginInfosExceedingGroupLimit();
const uint64_t doomedUsage =
std::accumulate(originInfos.cbegin(), originInfos.cend(), uint64_t(0),
[](uint64_t oldValue, const auto& originInfo) {
return oldValue + originInfo->LockedUsage();
});
// Evicting origins that exceed their group limit also affects the global
// temporary storage usage. If the global temporary storage limit would still
// be exceeded after evicting the origins that were already selected, we need
// to specifically evict origins to get below the global limit.
if (mTemporaryStorageUsage - doomedUsage > mTemporaryStorageLimit) {
originInfos.AppendElements(
LockedGetOriginInfosExceedingGlobalLimit(originInfos, doomedUsage));
}
return originInfos;
}
void QuotaManager::ClearOrigins(
const OriginInfosFlatTraversable& aDoomedOriginInfos) {
AssertIsOnIOThread();
// XXX Does this need to be done a) in order and/or b) sequentially?
// XXX We don't need to concatenate the results of the two steps. It would be
// sufficient to chain the ranges for iteration.
for (const auto& doomedOriginInfo : aDoomedOriginInfos) {
#ifdef DEBUG
{
MutexAutoLock lock(mQuotaMutex);
for (const auto& doomedOriginInfo : doomedOriginInfos) {
PersistenceType persistenceType =
doomedOriginInfo->mGroupInfo->mPersistenceType;
const GroupAndOrigin groupAndOrigin = {
doomedOriginInfo->mGroupInfo->mGroup, doomedOriginInfo->mOrigin};
LockedRemoveQuotaForOrigin(persistenceType, groupAndOrigin);
doomedOrigins.EmplaceBack(
OriginParams(persistenceType, groupAndOrigin.mOrigin));
}
MOZ_ASSERT(!doomedOriginInfo->LockedPersisted());
}
#endif
return doomedOrigins;
}();
DeleteFilesForOrigin(doomedOriginInfo->mGroupInfo->mPersistenceType,
doomedOriginInfo->mOrigin);
}
for (const OriginParams& doomedOrigin : doomedOrigins) {
OriginClearCompleted(doomedOrigin.mPersistenceType, doomedOrigin.mOrigin,
struct OriginParams {
nsCString mOrigin;
PersistenceType mPersistenceType;
};
nsTArray<OriginParams> clearedOrigins;
{
MutexAutoLock lock(mQuotaMutex);
for (const auto& doomedOriginInfo : aDoomedOriginInfos) {
// LockedRemoveQuotaForOrigin might remove the group info;
// OriginInfo::mGroupInfo is only a raw pointer, so we need to store the
// information for calling OriginClearCompleted below in a separate array.
clearedOrigins.AppendElement(
OriginParams{doomedOriginInfo->mOrigin,
doomedOriginInfo->mGroupInfo->mPersistenceType});
LockedRemoveQuotaForOrigin(
doomedOriginInfo->mGroupInfo->mPersistenceType,
{doomedOriginInfo->mGroupInfo->mGroup, doomedOriginInfo->mOrigin});
}
}
for (const auto& clearedOrigin : clearedOrigins) {
OriginClearCompleted(clearedOrigin.mPersistenceType, clearedOrigin.mOrigin,
Nullable<Client::Type>());
}
}
void QuotaManager::CleanupTemporaryStorage() {
AssertIsOnIOThread();
ClearOrigins(GetOriginInfosExceedingLimits());
if (mTemporaryStorageUsage > mTemporaryStorageLimit) {
// If disk space is still low after origin clear, notify storage pressure.

View File

@ -114,14 +114,6 @@ class NS_NO_VTABLE OpenDirectoryListener : public RefCountedObject {
virtual ~OpenDirectoryListener() = default;
};
struct OriginParams {
OriginParams(PersistenceType aPersistenceType, const nsACString& aOrigin)
: mOrigin(aOrigin), mPersistenceType(aPersistenceType) {}
nsCString mOrigin;
PersistenceType mPersistenceType;
};
class QuotaManager final : public BackgroundThreadObject {
friend class DirectoryLockImpl;
friend class GroupInfo;
@ -566,7 +558,20 @@ class QuotaManager final : public BackgroundThreadObject {
int64_t aAccessTime, bool aPersisted,
nsIFile* aDirectory);
void CheckTemporaryStorageLimits();
using OriginInfosFlatTraversable =
nsTArray<NotNull<RefPtr<const OriginInfo>>>;
OriginInfosFlatTraversable LockedGetOriginInfosExceedingGroupLimit() const;
OriginInfosFlatTraversable LockedGetOriginInfosExceedingGlobalLimit(
const OriginInfosFlatTraversable& aAlreadyDoomedOriginInfos,
uint64_t aAlreadyDoomedUsage) const;
OriginInfosFlatTraversable GetOriginInfosExceedingLimits() const;
void ClearOrigins(const OriginInfosFlatTraversable& aDoomedOriginInfos);
void CleanupTemporaryStorage();
void DeleteFilesForOrigin(PersistenceType aPersistenceType,
const nsACString& aOrigin);
@ -605,7 +610,7 @@ class QuotaManager final : public BackgroundThreadObject {
// Accesses to mQuotaManagerShutdownSteps must be protected by mQuotaMutex.
nsCString mQuotaManagerShutdownSteps;
mozilla::Mutex mQuotaMutex;
mutable mozilla::Mutex mQuotaMutex;
nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;

View File

@ -77,7 +77,10 @@ struct CopyablePtr {
T mPtr;
template <typename U>
explicit CopyablePtr(U aPtr) : mPtr{std::move(aPtr)} {}
explicit CopyablePtr(U&& aPtr) : mPtr{std::forward<U>(aPtr)} {}
template <typename U>
explicit CopyablePtr(CopyablePtr<U> aPtr) : mPtr{std::move(aPtr.mPtr)} {}
};
} // namespace detail