mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1685677 - Don't unnecessarily materialize a flattened array of OriginInfo*. r=dom-workers-and-storage-reviewers,janv
Differential Revision: https://phabricator.services.mozilla.com/D101151
This commit is contained in:
parent
7cba0698f2
commit
af53bb423a
@ -7,6 +7,7 @@
|
||||
#include "ActorsParent.h"
|
||||
|
||||
// Local includes
|
||||
#include "Flatten.h"
|
||||
#include "InitializationTypes.h"
|
||||
#include "OriginScope.h"
|
||||
#include "QuotaCommon.h"
|
||||
@ -7128,11 +7129,11 @@ QuotaManager::CollectLRUOriginInfosUntil(Collect&& aCollect, Pred&& aPred) {
|
||||
return originInfos;
|
||||
}
|
||||
|
||||
QuotaManager::OriginInfosFlatTraversable
|
||||
QuotaManager::OriginInfosNestedTraversable
|
||||
QuotaManager::LockedGetOriginInfosExceedingGroupLimit() const {
|
||||
mQuotaMutex.AssertCurrentThreadOwns();
|
||||
|
||||
OriginInfosFlatTraversable originInfos;
|
||||
OriginInfosNestedTraversable originInfos;
|
||||
|
||||
for (const auto& entry : mGroupInfoPairs) {
|
||||
const auto& pair = entry.GetData();
|
||||
@ -7159,9 +7160,7 @@ QuotaManager::LockedGetOriginInfosExceedingGroupLimit() const {
|
||||
MOZ_ASSERT(quotaManager, "Shouldn't be null!");
|
||||
|
||||
if (groupUsage > quotaManager->GetGroupLimit()) {
|
||||
// XXX Instead of appending into a flat array, return an array of
|
||||
// arrays.
|
||||
originInfos.AppendElements(CollectLRUOriginInfosUntil(
|
||||
originInfos.AppendElement(CollectLRUOriginInfosUntil(
|
||||
[&temporaryGroupInfo, &defaultGroupInfo](auto inserter) {
|
||||
MaybeInsertOriginInfos(std::move(inserter), temporaryGroupInfo,
|
||||
defaultGroupInfo,
|
||||
@ -7183,7 +7182,7 @@ QuotaManager::LockedGetOriginInfosExceedingGroupLimit() const {
|
||||
|
||||
QuotaManager::OriginInfosFlatTraversable
|
||||
QuotaManager::LockedGetOriginInfosExceedingGlobalLimit(
|
||||
const OriginInfosFlatTraversable& aAlreadyDoomedOriginInfos,
|
||||
const OriginInfosNestedTraversable& aAlreadyDoomedOriginInfos,
|
||||
const uint64_t aAlreadyDoomedUsage) const {
|
||||
mQuotaMutex.AssertCurrentThreadOwns();
|
||||
|
||||
@ -7199,7 +7198,13 @@ QuotaManager::LockedGetOriginInfosExceedingGlobalLimit(
|
||||
inserter, pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY),
|
||||
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT),
|
||||
[&aAlreadyDoomedOriginInfos](const auto& originInfo) {
|
||||
return !aAlreadyDoomedOriginInfos.Contains(originInfo) &&
|
||||
return !std::any_of(aAlreadyDoomedOriginInfos.cbegin(),
|
||||
aAlreadyDoomedOriginInfos.cend(),
|
||||
// XXX This should capture originInfo by
|
||||
// value, but it can't due to Bug 1421435.
|
||||
[&originInfo](const auto& array) {
|
||||
return array.Contains(originInfo);
|
||||
}) &&
|
||||
!originInfo->LockedPersisted();
|
||||
});
|
||||
}
|
||||
@ -7216,24 +7221,28 @@ QuotaManager::LockedGetOriginInfosExceedingGlobalLimit(
|
||||
});
|
||||
}
|
||||
|
||||
QuotaManager::OriginInfosFlatTraversable
|
||||
QuotaManager::OriginInfosNestedTraversable
|
||||
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();
|
||||
});
|
||||
const uint64_t doomedUsage = std::accumulate(
|
||||
originInfos.cbegin(), originInfos.cend(), uint64_t(0),
|
||||
[](uint64_t oldValue, const auto& currentOriginInfos) {
|
||||
return std::accumulate(currentOriginInfos.cbegin(),
|
||||
currentOriginInfos.cend(), oldValue,
|
||||
[](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(
|
||||
originInfos.AppendElement(
|
||||
LockedGetOriginInfosExceedingGlobalLimit(originInfos, doomedUsage));
|
||||
}
|
||||
|
||||
@ -7241,13 +7250,12 @@ QuotaManager::GetOriginInfosExceedingLimits() const {
|
||||
}
|
||||
|
||||
void QuotaManager::ClearOrigins(
|
||||
const OriginInfosFlatTraversable& aDoomedOriginInfos) {
|
||||
const OriginInfosNestedTraversable& 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) {
|
||||
for (const auto& doomedOriginInfo :
|
||||
Flatten<OriginInfosFlatTraversable::elem_type>(aDoomedOriginInfos)) {
|
||||
#ifdef DEBUG
|
||||
{
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
@ -7269,7 +7277,8 @@ void QuotaManager::ClearOrigins(
|
||||
{
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
for (const auto& doomedOriginInfo : aDoomedOriginInfos) {
|
||||
for (const auto& doomedOriginInfo :
|
||||
Flatten<OriginInfosFlatTraversable::elem_type>(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.
|
||||
|
118
dom/quota/Flatten.h
Normal file
118
dom/quota/Flatten.h
Normal file
@ -0,0 +1,118 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOM_QUOTA_FLATTEN_H_
|
||||
#define DOM_QUOTA_FLATTEN_H_
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
// XXX This should be moved to MFBT.
|
||||
|
||||
namespace mozilla::dom::quota {
|
||||
|
||||
namespace detail {
|
||||
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
template <typename T, typename NestedRange>
|
||||
auto Flatten(NestedRange&& aRange) -> std::enable_if_t<
|
||||
std::is_same_v<T, std::decay_t<typename decltype(begin(
|
||||
std::declval<const NestedRange&>()))::value_type>>,
|
||||
std::conditional_t<std::is_rvalue_reference_v<NestedRange>,
|
||||
std::decay_t<NestedRange>, NestedRange>> {
|
||||
return std::forward<NestedRange>(aRange);
|
||||
}
|
||||
|
||||
template <typename T, typename NestedRange>
|
||||
struct FlatIter {
|
||||
using OuterIterator =
|
||||
decltype(begin(std::declval<const std::decay_t<NestedRange>&>()));
|
||||
using InnerIterator =
|
||||
decltype(begin(*begin(std::declval<const std::decay_t<NestedRange>&>())));
|
||||
|
||||
explicit FlatIter(const NestedRange& aRange, OuterIterator aIter)
|
||||
: mOuterIter{std::move(aIter)}, mOuterEnd{end(aRange)} {
|
||||
InitInner();
|
||||
}
|
||||
|
||||
const T& operator*() const { return *mInnerIter; }
|
||||
|
||||
FlatIter& operator++() {
|
||||
++mInnerIter;
|
||||
if (mInnerIter == mInnerEnd) {
|
||||
++mOuterIter;
|
||||
InitInner();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!=(const FlatIter& aOther) const {
|
||||
return mOuterIter != aOther.mOuterIter ||
|
||||
(mOuterIter != mOuterEnd && mInnerIter != aOther.mInnerIter);
|
||||
}
|
||||
|
||||
private:
|
||||
void InitInner() {
|
||||
while (mOuterIter != mOuterEnd) {
|
||||
const typename OuterIterator::value_type& innerRange = *mOuterIter;
|
||||
|
||||
mInnerIter = begin(innerRange);
|
||||
mInnerEnd = end(innerRange);
|
||||
|
||||
if (mInnerIter != mInnerEnd) {
|
||||
break;
|
||||
}
|
||||
|
||||
++mOuterIter;
|
||||
}
|
||||
}
|
||||
|
||||
OuterIterator mOuterIter;
|
||||
const OuterIterator mOuterEnd;
|
||||
|
||||
InnerIterator mInnerIter;
|
||||
InnerIterator mInnerEnd;
|
||||
};
|
||||
|
||||
template <typename T, typename NestedRange>
|
||||
struct FlatRange {
|
||||
explicit FlatRange(NestedRange aRange) : mRange{std::move(aRange)} {}
|
||||
|
||||
auto begin() const {
|
||||
using std::begin;
|
||||
return FlatIter<T, NestedRange>{mRange, begin(mRange)};
|
||||
}
|
||||
auto end() const {
|
||||
using std::end;
|
||||
return FlatIter<T, NestedRange>{mRange, end(mRange)};
|
||||
}
|
||||
|
||||
private:
|
||||
NestedRange mRange;
|
||||
};
|
||||
|
||||
template <typename T, typename NestedRange>
|
||||
auto Flatten(NestedRange&& aRange) -> std::enable_if_t<
|
||||
!std::is_same_v<
|
||||
T, std::decay_t<typename decltype(begin(
|
||||
std::declval<const std::decay_t<NestedRange>&>()))::value_type>>,
|
||||
FlatRange<T, NestedRange>> {
|
||||
return FlatRange<T, NestedRange>{std::forward<NestedRange>(aRange)};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename NestedRange>
|
||||
auto Flatten(NestedRange&& aRange) -> decltype(auto) {
|
||||
return detail::Flatten<T>(std::forward<NestedRange>(aRange));
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom::quota
|
||||
|
||||
#endif
|
@ -561,15 +561,18 @@ class QuotaManager final : public BackgroundThreadObject {
|
||||
using OriginInfosFlatTraversable =
|
||||
nsTArray<NotNull<RefPtr<const OriginInfo>>>;
|
||||
|
||||
OriginInfosFlatTraversable LockedGetOriginInfosExceedingGroupLimit() const;
|
||||
using OriginInfosNestedTraversable =
|
||||
nsTArray<nsTArray<NotNull<RefPtr<const OriginInfo>>>>;
|
||||
|
||||
OriginInfosNestedTraversable LockedGetOriginInfosExceedingGroupLimit() const;
|
||||
|
||||
OriginInfosFlatTraversable LockedGetOriginInfosExceedingGlobalLimit(
|
||||
const OriginInfosFlatTraversable& aAlreadyDoomedOriginInfos,
|
||||
const OriginInfosNestedTraversable& aAlreadyDoomedOriginInfos,
|
||||
uint64_t aAlreadyDoomedUsage) const;
|
||||
|
||||
OriginInfosFlatTraversable GetOriginInfosExceedingLimits() const;
|
||||
OriginInfosNestedTraversable GetOriginInfosExceedingLimits() const;
|
||||
|
||||
void ClearOrigins(const OriginInfosFlatTraversable& aDoomedOriginInfos);
|
||||
void ClearOrigins(const OriginInfosNestedTraversable& aDoomedOriginInfos);
|
||||
|
||||
void CleanupTemporaryStorage();
|
||||
|
||||
|
74
dom/quota/test/gtest/TestFlatten.cpp
Normal file
74
dom/quota/test/gtest/TestFlatten.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Flatten.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla::dom::quota {
|
||||
|
||||
TEST(Flatten, FlatEmpty)
|
||||
{
|
||||
for (const auto& item : Flatten<int>(nsTArray<int>{})) {
|
||||
Unused << item;
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Flatten, NestedOuterEmpty)
|
||||
{
|
||||
for (const auto& item : Flatten<int>(nsTArray<CopyableTArray<int>>{})) {
|
||||
Unused << item;
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Flatten, NestedInnerEmpty)
|
||||
{
|
||||
for (const auto& item :
|
||||
Flatten<int>(nsTArray<CopyableTArray<int>>{CopyableTArray<int>{}})) {
|
||||
Unused << item;
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Flatten, NestedInnerSingular)
|
||||
{
|
||||
nsTArray<int> flattened;
|
||||
for (const auto& item :
|
||||
Flatten<int>(nsTArray<CopyableTArray<int>>{CopyableTArray<int>{1}})) {
|
||||
flattened.AppendElement(item);
|
||||
}
|
||||
|
||||
EXPECT_EQ(nsTArray{1}, flattened);
|
||||
}
|
||||
|
||||
TEST(Flatten, NestedInnerSingulars)
|
||||
{
|
||||
nsTArray<int> flattened;
|
||||
for (const auto& item : Flatten<int>(nsTArray<CopyableTArray<int>>{
|
||||
CopyableTArray<int>{1}, CopyableTArray<int>{2}})) {
|
||||
flattened.AppendElement(item);
|
||||
}
|
||||
|
||||
EXPECT_EQ((nsTArray<int>{{1, 2}}), flattened);
|
||||
}
|
||||
|
||||
TEST(Flatten, NestedInnerNonSingulars)
|
||||
{
|
||||
nsTArray<int> flattened;
|
||||
for (const auto& item : Flatten<int>(nsTArray<CopyableTArray<int>>{
|
||||
CopyableTArray<int>{1, 2}, CopyableTArray<int>{3, 4}})) {
|
||||
flattened.AppendElement(item);
|
||||
}
|
||||
|
||||
EXPECT_EQ((nsTArray<int>{{1, 2, 3, 4}}), flattened);
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom::quota
|
@ -7,6 +7,7 @@
|
||||
UNIFIED_SOURCES = [
|
||||
"TestCheckedUnsafePtr.cpp",
|
||||
"TestEncryptedStream.cpp",
|
||||
"TestFlatten.cpp",
|
||||
"TestQuotaCommon.cpp",
|
||||
"TestQuotaManager.cpp",
|
||||
"TestUsageInfo.cpp",
|
||||
|
Loading…
Reference in New Issue
Block a user