зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
bfdca4825f
Коммит
1f967af681
|
@ -7,6 +7,7 @@
|
||||||
#include "ActorsParent.h"
|
#include "ActorsParent.h"
|
||||||
|
|
||||||
// Local includes
|
// Local includes
|
||||||
|
#include "Flatten.h"
|
||||||
#include "InitializationTypes.h"
|
#include "InitializationTypes.h"
|
||||||
#include "OriginScope.h"
|
#include "OriginScope.h"
|
||||||
#include "QuotaCommon.h"
|
#include "QuotaCommon.h"
|
||||||
|
@ -7128,11 +7129,11 @@ QuotaManager::CollectLRUOriginInfosUntil(Collect&& aCollect, Pred&& aPred) {
|
||||||
return originInfos;
|
return originInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
QuotaManager::OriginInfosFlatTraversable
|
QuotaManager::OriginInfosNestedTraversable
|
||||||
QuotaManager::LockedGetOriginInfosExceedingGroupLimit() const {
|
QuotaManager::LockedGetOriginInfosExceedingGroupLimit() const {
|
||||||
mQuotaMutex.AssertCurrentThreadOwns();
|
mQuotaMutex.AssertCurrentThreadOwns();
|
||||||
|
|
||||||
OriginInfosFlatTraversable originInfos;
|
OriginInfosNestedTraversable originInfos;
|
||||||
|
|
||||||
for (const auto& entry : mGroupInfoPairs) {
|
for (const auto& entry : mGroupInfoPairs) {
|
||||||
const auto& pair = entry.GetData();
|
const auto& pair = entry.GetData();
|
||||||
|
@ -7159,9 +7160,7 @@ QuotaManager::LockedGetOriginInfosExceedingGroupLimit() const {
|
||||||
MOZ_ASSERT(quotaManager, "Shouldn't be null!");
|
MOZ_ASSERT(quotaManager, "Shouldn't be null!");
|
||||||
|
|
||||||
if (groupUsage > quotaManager->GetGroupLimit()) {
|
if (groupUsage > quotaManager->GetGroupLimit()) {
|
||||||
// XXX Instead of appending into a flat array, return an array of
|
originInfos.AppendElement(CollectLRUOriginInfosUntil(
|
||||||
// arrays.
|
|
||||||
originInfos.AppendElements(CollectLRUOriginInfosUntil(
|
|
||||||
[&temporaryGroupInfo, &defaultGroupInfo](auto inserter) {
|
[&temporaryGroupInfo, &defaultGroupInfo](auto inserter) {
|
||||||
MaybeInsertOriginInfos(std::move(inserter), temporaryGroupInfo,
|
MaybeInsertOriginInfos(std::move(inserter), temporaryGroupInfo,
|
||||||
defaultGroupInfo,
|
defaultGroupInfo,
|
||||||
|
@ -7183,7 +7182,7 @@ QuotaManager::LockedGetOriginInfosExceedingGroupLimit() const {
|
||||||
|
|
||||||
QuotaManager::OriginInfosFlatTraversable
|
QuotaManager::OriginInfosFlatTraversable
|
||||||
QuotaManager::LockedGetOriginInfosExceedingGlobalLimit(
|
QuotaManager::LockedGetOriginInfosExceedingGlobalLimit(
|
||||||
const OriginInfosFlatTraversable& aAlreadyDoomedOriginInfos,
|
const OriginInfosNestedTraversable& aAlreadyDoomedOriginInfos,
|
||||||
const uint64_t aAlreadyDoomedUsage) const {
|
const uint64_t aAlreadyDoomedUsage) const {
|
||||||
mQuotaMutex.AssertCurrentThreadOwns();
|
mQuotaMutex.AssertCurrentThreadOwns();
|
||||||
|
|
||||||
|
@ -7199,7 +7198,13 @@ QuotaManager::LockedGetOriginInfosExceedingGlobalLimit(
|
||||||
inserter, pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY),
|
inserter, pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY),
|
||||||
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT),
|
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT),
|
||||||
[&aAlreadyDoomedOriginInfos](const auto& originInfo) {
|
[&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();
|
!originInfo->LockedPersisted();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -7216,24 +7221,28 @@ QuotaManager::LockedGetOriginInfosExceedingGlobalLimit(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QuotaManager::OriginInfosFlatTraversable
|
QuotaManager::OriginInfosNestedTraversable
|
||||||
QuotaManager::GetOriginInfosExceedingLimits() const {
|
QuotaManager::GetOriginInfosExceedingLimits() const {
|
||||||
MutexAutoLock lock(mQuotaMutex);
|
MutexAutoLock lock(mQuotaMutex);
|
||||||
|
|
||||||
auto originInfos = LockedGetOriginInfosExceedingGroupLimit();
|
auto originInfos = LockedGetOriginInfosExceedingGroupLimit();
|
||||||
|
|
||||||
const uint64_t doomedUsage =
|
const uint64_t doomedUsage = std::accumulate(
|
||||||
std::accumulate(originInfos.cbegin(), originInfos.cend(), uint64_t(0),
|
originInfos.cbegin(), originInfos.cend(), uint64_t(0),
|
||||||
[](uint64_t oldValue, const auto& originInfo) {
|
[](uint64_t oldValue, const auto& currentOriginInfos) {
|
||||||
return oldValue + originInfo->LockedUsage();
|
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
|
// Evicting origins that exceed their group limit also affects the global
|
||||||
// temporary storage usage. If the global temporary storage limit would still
|
// temporary storage usage. If the global temporary storage limit would still
|
||||||
// be exceeded after evicting the origins that were already selected, we need
|
// be exceeded after evicting the origins that were already selected, we need
|
||||||
// to specifically evict origins to get below the global limit.
|
// to specifically evict origins to get below the global limit.
|
||||||
if (mTemporaryStorageUsage - doomedUsage > mTemporaryStorageLimit) {
|
if (mTemporaryStorageUsage - doomedUsage > mTemporaryStorageLimit) {
|
||||||
originInfos.AppendElements(
|
originInfos.AppendElement(
|
||||||
LockedGetOriginInfosExceedingGlobalLimit(originInfos, doomedUsage));
|
LockedGetOriginInfosExceedingGlobalLimit(originInfos, doomedUsage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7241,13 +7250,12 @@ QuotaManager::GetOriginInfosExceedingLimits() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuotaManager::ClearOrigins(
|
void QuotaManager::ClearOrigins(
|
||||||
const OriginInfosFlatTraversable& aDoomedOriginInfos) {
|
const OriginInfosNestedTraversable& aDoomedOriginInfos) {
|
||||||
AssertIsOnIOThread();
|
AssertIsOnIOThread();
|
||||||
|
|
||||||
// XXX Does this need to be done a) in order and/or b) sequentially?
|
// 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
|
for (const auto& doomedOriginInfo :
|
||||||
// sufficient to chain the ranges for iteration.
|
Flatten<OriginInfosFlatTraversable::elem_type>(aDoomedOriginInfos)) {
|
||||||
for (const auto& doomedOriginInfo : aDoomedOriginInfos) {
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mQuotaMutex);
|
MutexAutoLock lock(mQuotaMutex);
|
||||||
|
@ -7269,7 +7277,8 @@ void QuotaManager::ClearOrigins(
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mQuotaMutex);
|
MutexAutoLock lock(mQuotaMutex);
|
||||||
|
|
||||||
for (const auto& doomedOriginInfo : aDoomedOriginInfos) {
|
for (const auto& doomedOriginInfo :
|
||||||
|
Flatten<OriginInfosFlatTraversable::elem_type>(aDoomedOriginInfos)) {
|
||||||
// LockedRemoveQuotaForOrigin might remove the group info;
|
// LockedRemoveQuotaForOrigin might remove the group info;
|
||||||
// OriginInfo::mGroupInfo is only a raw pointer, so we need to store the
|
// OriginInfo::mGroupInfo is only a raw pointer, so we need to store the
|
||||||
// information for calling OriginClearCompleted below in a separate array.
|
// information for calling OriginClearCompleted below in a separate array.
|
||||||
|
|
|
@ -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 =
|
using OriginInfosFlatTraversable =
|
||||||
nsTArray<NotNull<RefPtr<const OriginInfo>>>;
|
nsTArray<NotNull<RefPtr<const OriginInfo>>>;
|
||||||
|
|
||||||
OriginInfosFlatTraversable LockedGetOriginInfosExceedingGroupLimit() const;
|
using OriginInfosNestedTraversable =
|
||||||
|
nsTArray<nsTArray<NotNull<RefPtr<const OriginInfo>>>>;
|
||||||
|
|
||||||
|
OriginInfosNestedTraversable LockedGetOriginInfosExceedingGroupLimit() const;
|
||||||
|
|
||||||
OriginInfosFlatTraversable LockedGetOriginInfosExceedingGlobalLimit(
|
OriginInfosFlatTraversable LockedGetOriginInfosExceedingGlobalLimit(
|
||||||
const OriginInfosFlatTraversable& aAlreadyDoomedOriginInfos,
|
const OriginInfosNestedTraversable& aAlreadyDoomedOriginInfos,
|
||||||
uint64_t aAlreadyDoomedUsage) const;
|
uint64_t aAlreadyDoomedUsage) const;
|
||||||
|
|
||||||
OriginInfosFlatTraversable GetOriginInfosExceedingLimits() const;
|
OriginInfosNestedTraversable GetOriginInfosExceedingLimits() const;
|
||||||
|
|
||||||
void ClearOrigins(const OriginInfosFlatTraversable& aDoomedOriginInfos);
|
void ClearOrigins(const OriginInfosNestedTraversable& aDoomedOriginInfos);
|
||||||
|
|
||||||
void CleanupTemporaryStorage();
|
void CleanupTemporaryStorage();
|
||||||
|
|
||||||
|
|
|
@ -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{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{1, 2, 3, 4}), flattened);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla::dom::quota
|
|
@ -7,6 +7,7 @@
|
||||||
UNIFIED_SOURCES = [
|
UNIFIED_SOURCES = [
|
||||||
"TestCheckedUnsafePtr.cpp",
|
"TestCheckedUnsafePtr.cpp",
|
||||||
"TestEncryptedStream.cpp",
|
"TestEncryptedStream.cpp",
|
||||||
|
"TestFlatten.cpp",
|
||||||
"TestQuotaCommon.cpp",
|
"TestQuotaCommon.cpp",
|
||||||
"TestQuotaManager.cpp",
|
"TestQuotaManager.cpp",
|
||||||
"TestUsageInfo.cpp",
|
"TestUsageInfo.cpp",
|
||||||
|
|
Загрузка…
Ссылка в новой задаче