Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/cache2/./../../../netwerk/cache2/CacheStorageService.cpp
Warning:line 1848, column 3
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_netwerk_cache21.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/cache2 -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/cache2 -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/netwerk/cache2 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/cache2 -I /root/firefox-clang/netwerk/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_netwerk_cache21.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "CacheStorageService.h"
6
7#include "CacheEntry.h"
8#include "CacheFileIOManager.h"
9#include "CacheFileUtils.h"
10#include "CacheIndex.h"
11#include "CacheIndexIterator.h"
12#include "CacheLog.h"
13#include "CacheObserver.h"
14#include "CacheStorage.h"
15#include "ErrorList.h"
16#include "mozilla/AtomicBitfields.h"
17#include "mozilla/DebugOnly.h"
18#include "mozilla/IntegerPrintfMacros.h"
19#include "mozilla/Services.h"
20#include "mozilla/StaticPrefs_network.h"
21#include "mozilla/StoragePrincipalHelper.h"
22#include "mozilla/TimeStamp.h"
23#include "mozilla/glean/NetwerkCache2Metrics.h"
24#include "mozilla/glean/NetwerkMetrics.h"
25#include "mozilla/glean/NetwerkProtocolHttpMetrics.h"
26#include "mozilla/net/NoVarySearchUtils.h"
27#include "nsCOMPtr.h"
28#include "nsContentUtils.h"
29#include "nsICacheStorageVisitor.h"
30#include "nsIFile.h"
31#include "nsIObserverService.h"
32#include "nsIURI.h"
33#include "nsNetCID.h"
34#include "nsNetUtil.h"
35#include "nsQueryObject.h"
36#include "nsServiceManagerUtils.h"
37#include "nsXULAppAPI.h"
38
39namespace mozilla::net {
40
41// static
42GlobalEntryTables* CacheStorageService::sGlobalEntryTables = nullptr;
43StaticMutex CacheStorageService::sLock;
44
45namespace {
46
47void AppendMemoryStorageTag(nsAutoCString& key) {
48 // Using DEL as the very last ascii-7 character we can use in the list of
49 // attributes
50 key.Append('\x7f');
51 key.Append(',');
52}
53
54} // namespace
55
56CacheMemoryConsumer::CacheMemoryConsumer(uint32_t aFlags) {
57 StoreFlags(aFlags);
58}
59
60void CacheMemoryConsumer::DoMemoryReport(uint32_t aCurrentSize) {
61 if (!(LoadFlags() & DONT_REPORT) && CacheStorageService::Self()) {
62 CacheStorageService::Self()->OnMemoryConsumptionChange(this, aCurrentSize);
63 }
64}
65
66CacheStorageService::MemoryPool::MemoryPool(EType aType) : mType(aType) {}
67
68CacheStorageService::MemoryPool::~MemoryPool() {
69 if (mMemorySize != 0) {
70 NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Network cache reported memory consumption is not at 0, probably "
"leaking?", "Error", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 72); MOZ_PretendNoReturn(); } while (0)
71 "Network cache reported memory consumption is not at 0, probably "do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Network cache reported memory consumption is not at 0, probably "
"leaking?", "Error", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 72); MOZ_PretendNoReturn(); } while (0)
72 "leaking?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Network cache reported memory consumption is not at 0, probably "
"leaking?", "Error", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 72); MOZ_PretendNoReturn(); } while (0)
;
73 }
74}
75
76uint32_t CacheStorageService::MemoryPool::Limit() const {
77 uint32_t limit = 0;
78
79 switch (mType) {
80 case DISK:
81 limit = CacheObserver::MetadataMemoryLimit();
82 break;
83 case MEMORY:
84 limit = CacheObserver::MemoryCacheCapacity();
85 break;
86 default:
87 MOZ_CRASH("Bad pool type")do { do { } while (false); MOZ_ReportCrash("" "Bad pool type"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 87); AnnotateMozCrashReason
("MOZ_CRASH(" "Bad pool type" ")"); do { MOZ_CrashSequence(__null
, 87); __attribute__((nomerge)) ::abort(); } while (false); }
while (false)
;
88 }
89
90 static const uint32_t kMaxLimit = 0x3FFFFF;
91 if (limit > kMaxLimit) {
92 LOG((" a memory limit (%u) is unexpectedly high, clipping to %u", limit,do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " a memory limit (%u) is unexpectedly high, clipping to %u"
, limit, kMaxLimit); } } while (0)
93 kMaxLimit))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " a memory limit (%u) is unexpectedly high, clipping to %u"
, limit, kMaxLimit); } } while (0)
;
94 limit = kMaxLimit;
95 }
96
97 return limit << 10;
98}
99
100NS_IMPL_ISUPPORTS(CacheStorageService, nsICacheStorageService,MozExternalRefCountType CacheStorageService::AddRef(void) { static_assert
(!std::is_destructible_v<CacheStorageService>, "Reference-counted class "
"CacheStorageService" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 102
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheStorageService" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CacheStorageService" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"CacheStorageService\" != nullptr" " (" "Must specify a name"
")", "./../../../netwerk/cache2/CacheStorageService.cpp", 102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheStorageService\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 102); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CacheStorageService" " not thread-safe"); nsrefcnt count = ++
mRefCnt; NS_LogAddRef((this), (count), ("CacheStorageService"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
CacheStorageService::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../netwerk/cache2/CacheStorageService.cpp", 102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 102
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheStorageService" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CacheStorageService" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"CacheStorageService\" != nullptr" " (" "Must specify a name"
")", "./../../../netwerk/cache2/CacheStorageService.cpp", 102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheStorageService\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 102); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CacheStorageService" " not thread-safe"); const char* const
nametmp = "CacheStorageService"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
CacheStorageService::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 102); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(5 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<CacheStorageService, nsICacheStorageService
>, int32_t( reinterpret_cast<char*>(static_cast<nsICacheStorageService
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsIMemoryReporter>
, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsITimerCallback>,
int32_t( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsICacheTesting>, int32_t
( reinterpret_cast<char*>(static_cast<nsICacheTesting
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsINamed>, int32_t
( reinterpret_cast<char*>(static_cast<nsINamed*>(
(CacheStorageService*)0x1000)) - reinterpret_cast<char*>
((CacheStorageService*)0x1000))}, {&mozilla::detail::kImplementedIID
<CacheStorageService, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsICacheStorageService*>((CacheStorageService*)0x1000))) -
reinterpret_cast<char*>((CacheStorageService*)0x1000))
}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
101 nsIMemoryReporter, nsITimerCallback, nsICacheTesting,MozExternalRefCountType CacheStorageService::AddRef(void) { static_assert
(!std::is_destructible_v<CacheStorageService>, "Reference-counted class "
"CacheStorageService" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 102
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheStorageService" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CacheStorageService" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"CacheStorageService\" != nullptr" " (" "Must specify a name"
")", "./../../../netwerk/cache2/CacheStorageService.cpp", 102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheStorageService\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 102); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CacheStorageService" " not thread-safe"); nsrefcnt count = ++
mRefCnt; NS_LogAddRef((this), (count), ("CacheStorageService"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
CacheStorageService::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../netwerk/cache2/CacheStorageService.cpp", 102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 102
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheStorageService" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CacheStorageService" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"CacheStorageService\" != nullptr" " (" "Must specify a name"
")", "./../../../netwerk/cache2/CacheStorageService.cpp", 102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheStorageService\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 102); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CacheStorageService" " not thread-safe"); const char* const
nametmp = "CacheStorageService"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
CacheStorageService::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 102); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(5 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<CacheStorageService, nsICacheStorageService
>, int32_t( reinterpret_cast<char*>(static_cast<nsICacheStorageService
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsIMemoryReporter>
, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsITimerCallback>,
int32_t( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsICacheTesting>, int32_t
( reinterpret_cast<char*>(static_cast<nsICacheTesting
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsINamed>, int32_t
( reinterpret_cast<char*>(static_cast<nsINamed*>(
(CacheStorageService*)0x1000)) - reinterpret_cast<char*>
((CacheStorageService*)0x1000))}, {&mozilla::detail::kImplementedIID
<CacheStorageService, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsICacheStorageService*>((CacheStorageService*)0x1000))) -
reinterpret_cast<char*>((CacheStorageService*)0x1000))
}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
102 nsINamed)MozExternalRefCountType CacheStorageService::AddRef(void) { static_assert
(!std::is_destructible_v<CacheStorageService>, "Reference-counted class "
"CacheStorageService" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 102
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheStorageService" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CacheStorageService" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"CacheStorageService\" != nullptr" " (" "Must specify a name"
")", "./../../../netwerk/cache2/CacheStorageService.cpp", 102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheStorageService\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 102); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CacheStorageService" " not thread-safe"); nsrefcnt count = ++
mRefCnt; NS_LogAddRef((this), (count), ("CacheStorageService"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
CacheStorageService::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../netwerk/cache2/CacheStorageService.cpp", 102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 102
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheStorageService" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CacheStorageService" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"CacheStorageService\" != nullptr" " (" "Must specify a name"
")", "./../../../netwerk/cache2/CacheStorageService.cpp", 102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheStorageService\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 102); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CacheStorageService" " not thread-safe"); const char* const
nametmp = "CacheStorageService"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
CacheStorageService::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 102); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(5 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<CacheStorageService, nsICacheStorageService
>, int32_t( reinterpret_cast<char*>(static_cast<nsICacheStorageService
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsIMemoryReporter>
, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsITimerCallback>,
int32_t( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsICacheTesting>, int32_t
( reinterpret_cast<char*>(static_cast<nsICacheTesting
*>((CacheStorageService*)0x1000)) - reinterpret_cast<char
*>((CacheStorageService*)0x1000))}, {&mozilla::detail::
kImplementedIID<CacheStorageService, nsINamed>, int32_t
( reinterpret_cast<char*>(static_cast<nsINamed*>(
(CacheStorageService*)0x1000)) - reinterpret_cast<char*>
((CacheStorageService*)0x1000))}, {&mozilla::detail::kImplementedIID
<CacheStorageService, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsICacheStorageService*>((CacheStorageService*)0x1000))) -
reinterpret_cast<char*>((CacheStorageService*)0x1000))
}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
103
104CacheStorageService* CacheStorageService::sSelf = nullptr;
105
106CacheStorageService::CacheStorageService() {
107 CacheFileIOManager::Init();
108
109 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 109); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence
(__null, 109); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
110 MOZ_ASSERT(!sSelf)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sSelf)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!sSelf))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!sSelf", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sSelf" ")")
; do { MOZ_CrashSequence(__null, 110); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
111
112 sSelf = this;
113 sGlobalEntryTables = new GlobalEntryTables();
114
115 RegisterStrongMemoryReporter(do_AddRef(this));
116}
117
118CacheStorageService::~CacheStorageService() {
119 LOG(("CacheStorageService::~CacheStorageService"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::~CacheStorageService"
); } } while (0)
;
120 sSelf = nullptr;
121}
122
123void CacheStorageService::Shutdown() {
124 StaticMutexAutoLock lock(sLock);
125
126 if (mShutdown) return;
127
128 LOG(("CacheStorageService::Shutdown - start"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::Shutdown - start"
); } } while (0)
;
129
130 mShutdown = true;
131
132 nsCOMPtr<nsIRunnable> event =
133 NewRunnableMethod("net::CacheStorageService::ShutdownBackground", this,
134 &CacheStorageService::ShutdownBackground);
135 Dispatch(event);
136
137#ifdef NS_FREE_PERMANENT_DATA
138 // Clear pending callbacks on all entries before dropping them.
139 // Each pending Callback holds a RefPtr<CacheEntry> back to its owning
140 // entry, forming a prevent-release cycle that the destructor alone
141 // cannot break.
142 for (const auto& table : sGlobalEntryTables->Values()) {
143 for (const auto& entry : table->Values()) {
144 entry->ClearCallbacks();
145 }
146 }
147 sGlobalEntryTables->Clear();
148 delete sGlobalEntryTables;
149#endif
150 sGlobalEntryTables = nullptr;
151
152 LOG(("CacheStorageService::Shutdown - done"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::Shutdown - done"
); } } while (0)
;
153}
154
155void CacheStorageService::ShutdownBackground() {
156 LOG(("CacheStorageService::ShutdownBackground - start"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ShutdownBackground - start"
); } } while (0)
;
157
158 MOZ_ASSERT(IsOnManagementThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsOnManagementThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsOnManagementThread()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsOnManagementThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 158); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsOnManagementThread()" ")"); do { MOZ_CrashSequence
(__null, 158); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
159
160 {
161 StaticMutexAutoLock lock(sLock);
162
163 // Cancel purge timer to avoid leaking.
164 if (mPurgeTimer) {
165 LOG((" freeing the timer"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " freeing the timer"
); } } while (0)
;
166 mPurgeTimer->Cancel();
167 }
168 }
169
170#ifdef NS_FREE_PERMANENT_DATA
171 // Properly unregister entries before clearing the lists to maintain
172 // the invariant that IsRegistered() reflects actual list membership.
173 // This prevents crashes if pending UNREGISTER operations run after shutdown.
174 RefPtr<CacheEntry> entry;
175 while ((entry = Pool(MemoryPool::EType::DISK).mManagedEntries.popFirst())) {
176 entry->SetRegistered(false);
177 }
178 while ((entry = Pool(MemoryPool::EType::MEMORY).mManagedEntries.popFirst())) {
179 entry->SetRegistered(false);
180 }
181#endif
182
183 LOG(("CacheStorageService::ShutdownBackground - done"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ShutdownBackground - done"
); } } while (0)
;
184}
185
186// Internal management methods
187
188namespace CacheStorageServiceInternal {
189
190// WalkCacheRunnable
191// Base class for particular storage entries visiting
192class WalkCacheRunnable : public Runnable,
193 public CacheStorageService::EntryInfoCallback {
194 protected:
195 WalkCacheRunnable(nsICacheStorageVisitor* aVisitor, bool aVisitEntries)
196 : Runnable("net::WalkCacheRunnable"),
197 mService(CacheStorageService::Self()),
198 mCallback(aVisitor) {
199 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 199); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 199); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
200 StoreNotifyStorage(true);
201 StoreVisitEntries(aVisitEntries);
202 }
203
204 virtual ~WalkCacheRunnable() {
205 if (mCallback) {
206 ProxyReleaseMainThread("WalkCacheRunnable::mCallback", mCallback);
207 }
208 }
209
210 RefPtr<CacheStorageService> mService;
211 nsCOMPtr<nsICacheStorageVisitor> mCallback;
212
213 uint64_t mSize{0};
214
215 // clang-format off
216 MOZ_ATOMIC_BITFIELDS(mAtomicBitfields, 8, (std::atomic_uint8_t mAtomicBitfields{0}; static const size_t mAtomicBitfields_USED_BITS
= 1 + 1; static const size_t mAtomicBitfieldsNotifyStorage =
mAtomicBitfields_USED_BITS - (1 + 1);; static const size_t mAtomicBitfieldsVisitEntries
= mAtomicBitfields_USED_BITS - (1);; static_assert(mAtomicBitfields_USED_BITS
<= 8, "mAtomicBitfields" ": Maximum bits (" "8" ") exceeded for MOZ_ATOMIC_BITFIELDS instance"
); static_assert(8 > 1, "mAtomicBitfields" ": MOZ_ATOMIC_BITFIELDS field too big"
); static_assert(std::is_unsigned<bool>(), "mAtomicBitfields"
": MOZ_ATOMIC_BITFIELDS doesn't support signed payloads"); bool
LoadNotifyStorage() const { uint8_t fieldSize, mask, masked,
value; size_t offset = mAtomicBitfieldsNotifyStorage; fieldSize
= 1; mask = ((1ull << fieldSize) - 1ull) << offset
; masked = mAtomicBitfields.load() & mask; value = (masked
>> offset); return value; } void StoreNotifyStorage(bool
aValue) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(((uint64_t)aValue) < (1ull << 1))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((uint64_t)aValue) < (1ull << 1)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("((uint64_t)aValue) < (1ull << 1)"
" (" "Stored value exceeded capacity of bitfield!" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((uint64_t)aValue) < (1ull << 1)"
") (" "Stored value exceeded capacity of bitfield!" ")"); do
{ MOZ_CrashSequence(__null, 219); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); uint8_t fieldSize
, mask, resizedValue, packedValue, oldValue, clearedValue, newValue
; size_t offset = mAtomicBitfieldsNotifyStorage; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; resizedValue
= aValue; packedValue = (resizedValue << offset) &
mask; oldValue = mAtomicBitfields.load(); do { clearedValue =
oldValue & ~mask; newValue = clearedValue | packedValue;
} while (!mAtomicBitfields.compare_exchange_weak(oldValue, newValue
)); } static_assert(8 > 1, "mAtomicBitfields" ": MOZ_ATOMIC_BITFIELDS field too big"
); static_assert(std::is_unsigned<bool>(), "mAtomicBitfields"
": MOZ_ATOMIC_BITFIELDS doesn't support signed payloads"); bool
LoadVisitEntries() const { uint8_t fieldSize, mask, masked, value
; size_t offset = mAtomicBitfieldsVisitEntries; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; masked
= mAtomicBitfields.load() & mask; value = (masked >>
offset); return value; } void StoreVisitEntries(bool aValue)
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(((uint64_t)aValue) < (1ull << 1))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((uint64_t)aValue) < (1ull << 1)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("((uint64_t)aValue) < (1ull << 1)"
" (" "Stored value exceeded capacity of bitfield!" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((uint64_t)aValue) < (1ull << 1)"
") (" "Stored value exceeded capacity of bitfield!" ")"); do
{ MOZ_CrashSequence(__null, 219); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); uint8_t fieldSize
, mask, resizedValue, packedValue, oldValue, clearedValue, newValue
; size_t offset = mAtomicBitfieldsVisitEntries; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; resizedValue
= aValue; packedValue = (resizedValue << offset) &
mask; oldValue = mAtomicBitfields.load(); do { clearedValue =
oldValue & ~mask; newValue = clearedValue | packedValue;
} while (!mAtomicBitfields.compare_exchange_weak(oldValue, newValue
)); }
217 (bool, NotifyStorage, 1),std::atomic_uint8_t mAtomicBitfields{0}; static const size_t mAtomicBitfields_USED_BITS
= 1 + 1; static const size_t mAtomicBitfieldsNotifyStorage =
mAtomicBitfields_USED_BITS - (1 + 1);; static const size_t mAtomicBitfieldsVisitEntries
= mAtomicBitfields_USED_BITS - (1);; static_assert(mAtomicBitfields_USED_BITS
<= 8, "mAtomicBitfields" ": Maximum bits (" "8" ") exceeded for MOZ_ATOMIC_BITFIELDS instance"
); static_assert(8 > 1, "mAtomicBitfields" ": MOZ_ATOMIC_BITFIELDS field too big"
); static_assert(std::is_unsigned<bool>(), "mAtomicBitfields"
": MOZ_ATOMIC_BITFIELDS doesn't support signed payloads"); bool
LoadNotifyStorage() const { uint8_t fieldSize, mask, masked,
value; size_t offset = mAtomicBitfieldsNotifyStorage; fieldSize
= 1; mask = ((1ull << fieldSize) - 1ull) << offset
; masked = mAtomicBitfields.load() & mask; value = (masked
>> offset); return value; } void StoreNotifyStorage(bool
aValue) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(((uint64_t)aValue) < (1ull << 1))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((uint64_t)aValue) < (1ull << 1)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("((uint64_t)aValue) < (1ull << 1)"
" (" "Stored value exceeded capacity of bitfield!" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((uint64_t)aValue) < (1ull << 1)"
") (" "Stored value exceeded capacity of bitfield!" ")"); do
{ MOZ_CrashSequence(__null, 219); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); uint8_t fieldSize
, mask, resizedValue, packedValue, oldValue, clearedValue, newValue
; size_t offset = mAtomicBitfieldsNotifyStorage; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; resizedValue
= aValue; packedValue = (resizedValue << offset) &
mask; oldValue = mAtomicBitfields.load(); do { clearedValue =
oldValue & ~mask; newValue = clearedValue | packedValue;
} while (!mAtomicBitfields.compare_exchange_weak(oldValue, newValue
)); } static_assert(8 > 1, "mAtomicBitfields" ": MOZ_ATOMIC_BITFIELDS field too big"
); static_assert(std::is_unsigned<bool>(), "mAtomicBitfields"
": MOZ_ATOMIC_BITFIELDS doesn't support signed payloads"); bool
LoadVisitEntries() const { uint8_t fieldSize, mask, masked, value
; size_t offset = mAtomicBitfieldsVisitEntries; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; masked
= mAtomicBitfields.load() & mask; value = (masked >>
offset); return value; } void StoreVisitEntries(bool aValue)
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(((uint64_t)aValue) < (1ull << 1))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((uint64_t)aValue) < (1ull << 1)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("((uint64_t)aValue) < (1ull << 1)"
" (" "Stored value exceeded capacity of bitfield!" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((uint64_t)aValue) < (1ull << 1)"
") (" "Stored value exceeded capacity of bitfield!" ")"); do
{ MOZ_CrashSequence(__null, 219); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); uint8_t fieldSize
, mask, resizedValue, packedValue, oldValue, clearedValue, newValue
; size_t offset = mAtomicBitfieldsVisitEntries; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; resizedValue
= aValue; packedValue = (resizedValue << offset) &
mask; oldValue = mAtomicBitfields.load(); do { clearedValue =
oldValue & ~mask; newValue = clearedValue | packedValue;
} while (!mAtomicBitfields.compare_exchange_weak(oldValue, newValue
)); }
218 (bool, VisitEntries, 1)std::atomic_uint8_t mAtomicBitfields{0}; static const size_t mAtomicBitfields_USED_BITS
= 1 + 1; static const size_t mAtomicBitfieldsNotifyStorage =
mAtomicBitfields_USED_BITS - (1 + 1);; static const size_t mAtomicBitfieldsVisitEntries
= mAtomicBitfields_USED_BITS - (1);; static_assert(mAtomicBitfields_USED_BITS
<= 8, "mAtomicBitfields" ": Maximum bits (" "8" ") exceeded for MOZ_ATOMIC_BITFIELDS instance"
); static_assert(8 > 1, "mAtomicBitfields" ": MOZ_ATOMIC_BITFIELDS field too big"
); static_assert(std::is_unsigned<bool>(), "mAtomicBitfields"
": MOZ_ATOMIC_BITFIELDS doesn't support signed payloads"); bool
LoadNotifyStorage() const { uint8_t fieldSize, mask, masked,
value; size_t offset = mAtomicBitfieldsNotifyStorage; fieldSize
= 1; mask = ((1ull << fieldSize) - 1ull) << offset
; masked = mAtomicBitfields.load() & mask; value = (masked
>> offset); return value; } void StoreNotifyStorage(bool
aValue) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(((uint64_t)aValue) < (1ull << 1))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((uint64_t)aValue) < (1ull << 1)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("((uint64_t)aValue) < (1ull << 1)"
" (" "Stored value exceeded capacity of bitfield!" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((uint64_t)aValue) < (1ull << 1)"
") (" "Stored value exceeded capacity of bitfield!" ")"); do
{ MOZ_CrashSequence(__null, 219); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); uint8_t fieldSize
, mask, resizedValue, packedValue, oldValue, clearedValue, newValue
; size_t offset = mAtomicBitfieldsNotifyStorage; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; resizedValue
= aValue; packedValue = (resizedValue << offset) &
mask; oldValue = mAtomicBitfields.load(); do { clearedValue =
oldValue & ~mask; newValue = clearedValue | packedValue;
} while (!mAtomicBitfields.compare_exchange_weak(oldValue, newValue
)); } static_assert(8 > 1, "mAtomicBitfields" ": MOZ_ATOMIC_BITFIELDS field too big"
); static_assert(std::is_unsigned<bool>(), "mAtomicBitfields"
": MOZ_ATOMIC_BITFIELDS doesn't support signed payloads"); bool
LoadVisitEntries() const { uint8_t fieldSize, mask, masked, value
; size_t offset = mAtomicBitfieldsVisitEntries; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; masked
= mAtomicBitfields.load() & mask; value = (masked >>
offset); return value; } void StoreVisitEntries(bool aValue)
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(((uint64_t)aValue) < (1ull << 1))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((uint64_t)aValue) < (1ull << 1)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("((uint64_t)aValue) < (1ull << 1)"
" (" "Stored value exceeded capacity of bitfield!" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((uint64_t)aValue) < (1ull << 1)"
") (" "Stored value exceeded capacity of bitfield!" ")"); do
{ MOZ_CrashSequence(__null, 219); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); uint8_t fieldSize
, mask, resizedValue, packedValue, oldValue, clearedValue, newValue
; size_t offset = mAtomicBitfieldsVisitEntries; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; resizedValue
= aValue; packedValue = (resizedValue << offset) &
mask; oldValue = mAtomicBitfields.load(); do { clearedValue =
oldValue & ~mask; newValue = clearedValue | packedValue;
} while (!mAtomicBitfields.compare_exchange_weak(oldValue, newValue
)); }
219 ))std::atomic_uint8_t mAtomicBitfields{0}; static const size_t mAtomicBitfields_USED_BITS
= 1 + 1; static const size_t mAtomicBitfieldsNotifyStorage =
mAtomicBitfields_USED_BITS - (1 + 1);; static const size_t mAtomicBitfieldsVisitEntries
= mAtomicBitfields_USED_BITS - (1);; static_assert(mAtomicBitfields_USED_BITS
<= 8, "mAtomicBitfields" ": Maximum bits (" "8" ") exceeded for MOZ_ATOMIC_BITFIELDS instance"
); static_assert(8 > 1, "mAtomicBitfields" ": MOZ_ATOMIC_BITFIELDS field too big"
); static_assert(std::is_unsigned<bool>(), "mAtomicBitfields"
": MOZ_ATOMIC_BITFIELDS doesn't support signed payloads"); bool
LoadNotifyStorage() const { uint8_t fieldSize, mask, masked,
value; size_t offset = mAtomicBitfieldsNotifyStorage; fieldSize
= 1; mask = ((1ull << fieldSize) - 1ull) << offset
; masked = mAtomicBitfields.load() & mask; value = (masked
>> offset); return value; } void StoreNotifyStorage(bool
aValue) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(((uint64_t)aValue) < (1ull << 1))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((uint64_t)aValue) < (1ull << 1)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("((uint64_t)aValue) < (1ull << 1)"
" (" "Stored value exceeded capacity of bitfield!" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((uint64_t)aValue) < (1ull << 1)"
") (" "Stored value exceeded capacity of bitfield!" ")"); do
{ MOZ_CrashSequence(__null, 219); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); uint8_t fieldSize
, mask, resizedValue, packedValue, oldValue, clearedValue, newValue
; size_t offset = mAtomicBitfieldsNotifyStorage; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; resizedValue
= aValue; packedValue = (resizedValue << offset) &
mask; oldValue = mAtomicBitfields.load(); do { clearedValue =
oldValue & ~mask; newValue = clearedValue | packedValue;
} while (!mAtomicBitfields.compare_exchange_weak(oldValue, newValue
)); } static_assert(8 > 1, "mAtomicBitfields" ": MOZ_ATOMIC_BITFIELDS field too big"
); static_assert(std::is_unsigned<bool>(), "mAtomicBitfields"
": MOZ_ATOMIC_BITFIELDS doesn't support signed payloads"); bool
LoadVisitEntries() const { uint8_t fieldSize, mask, masked, value
; size_t offset = mAtomicBitfieldsVisitEntries; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; masked
= mAtomicBitfields.load() & mask; value = (masked >>
offset); return value; } void StoreVisitEntries(bool aValue)
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(((uint64_t)aValue) < (1ull << 1))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((uint64_t)aValue) < (1ull << 1)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("((uint64_t)aValue) < (1ull << 1)"
" (" "Stored value exceeded capacity of bitfield!" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((uint64_t)aValue) < (1ull << 1)"
") (" "Stored value exceeded capacity of bitfield!" ")"); do
{ MOZ_CrashSequence(__null, 219); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); uint8_t fieldSize
, mask, resizedValue, packedValue, oldValue, clearedValue, newValue
; size_t offset = mAtomicBitfieldsVisitEntries; fieldSize = 1
; mask = ((1ull << fieldSize) - 1ull) << offset; resizedValue
= aValue; packedValue = (resizedValue << offset) &
mask; oldValue = mAtomicBitfields.load(); do { clearedValue =
oldValue & ~mask; newValue = clearedValue | packedValue;
} while (!mAtomicBitfields.compare_exchange_weak(oldValue, newValue
)); }
220 // clang-format on
221
222 Atomic<bool> mCancel{false};
223};
224
225// WalkMemoryCacheRunnable
226// Responsible to visit memory storage and walk
227// all entries on it asynchronously.
228class WalkMemoryCacheRunnable : public WalkCacheRunnable {
229 public:
230 WalkMemoryCacheRunnable(nsILoadContextInfo* aLoadInfo, bool aVisitEntries,
231 nsICacheStorageVisitor* aVisitor)
232 : WalkCacheRunnable(aVisitor, aVisitEntries) {
233 CacheFileUtils::AppendKeyPrefix(aLoadInfo, mContextKey);
234 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 234); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 234); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
235 }
236
237 nsresult Walk() { return mService->Dispatch(this); }
238
239 private:
240 NS_IMETHODvirtual nsresult Run() override {
241 if (CacheStorageService::IsOnManagementThread()) {
242 LOG(("WalkMemoryCacheRunnable::Run - collecting [this=%p]", this))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WalkMemoryCacheRunnable::Run - collecting [this=%p]"
, this); } } while (0)
;
243 // First, walk, count and grab all entries from the storage
244
245 StaticMutexAutoLock lock(CacheStorageService::sLock);
246
247 if (!CacheStorageService::IsRunning()) return NS_ERROR_NOT_INITIALIZED;
248
249 // Count the entries to allocate the array memory all at once.
250 size_t numEntries = 0;
251 for (const auto& entries :
252 CacheStorageService::sGlobalEntryTables->Values()) {
253 if (entries->Type() != CacheEntryTable::MEMORY_ONLY) {
254 continue;
255 }
256 numEntries += entries->Values().Count();
257 }
258 mEntryArray.SetCapacity(numEntries);
259
260 // Collect the entries.
261 for (const auto& entries :
262 CacheStorageService::sGlobalEntryTables->Values()) {
263 if (entries->Type() != CacheEntryTable::MEMORY_ONLY) {
264 continue;
265 }
266
267 for (CacheEntry* entry : entries->Values()) {
268 MOZ_ASSERT(!entry->IsUsingDisk())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!entry->IsUsingDisk())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!entry->IsUsingDisk()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!entry->IsUsingDisk()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 268); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!entry->IsUsingDisk()" ")"); do { MOZ_CrashSequence
(__null, 268); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
269
270 mSize += entry->GetMetadataMemoryConsumption();
271
272 int64_t size;
273 if (NS_SUCCEEDED(entry->GetDataSize(&size))((bool)(__builtin_expect(!!(!NS_FAILED_impl(entry->GetDataSize
(&size))), 1)))
) {
274 mSize += size;
275 }
276 mEntryArray.AppendElement(entry);
277 }
278 }
279
280 // Next, we dispatch to the main thread
281 } else if (NS_IsMainThread()) {
282 LOG(("WalkMemoryCacheRunnable::Run - notifying [this=%p]", this))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WalkMemoryCacheRunnable::Run - notifying [this=%p]"
, this); } } while (0)
;
283
284 if (LoadNotifyStorage()) {
285 LOG((" storage"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " storage"); } }
while (0)
;
286
287 uint64_t capacity = CacheObserver::MemoryCacheCapacity();
288 capacity <<= 10; // kilobytes to bytes
289
290 // Second, notify overall storage info
291 mCallback->OnCacheStorageInfo(mEntryArray.Length(), mSize, capacity,
292 nullptr);
293 if (!LoadVisitEntries()) return NS_OK; // done
294
295 StoreNotifyStorage(false);
296
297 } else {
298 LOG((" entry [left=%zu, canceled=%d]", mEntryArray.Length(),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " entry [left=%zu, canceled=%d]"
, mEntryArray.Length(), (bool)mCancel); } } while (0)
299 (bool)mCancel))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " entry [left=%zu, canceled=%d]"
, mEntryArray.Length(), (bool)mCancel); } } while (0)
;
300
301 // Third, notify each entry until depleted or canceled.
302 if (mNextEntryIdx >= mEntryArray.Length() || mCancel) {
303 mCallback->OnCacheEntryVisitCompleted();
304 return NS_OK; // done
305 }
306
307 // Grab the next entry.
308 RefPtr<CacheEntry> entry = std::move(mEntryArray[mNextEntryIdx++]);
309
310 // Invokes this->OnEntryInfo, that calls the callback with all
311 // information of the entry.
312 CacheStorageService::GetCacheEntryInfo(entry, this);
313 }
314 } else {
315 MOZ_CRASH("Bad thread")do { do { } while (false); MOZ_ReportCrash("" "Bad thread", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 315); AnnotateMozCrashReason("MOZ_CRASH(" "Bad thread" ")")
; do { MOZ_CrashSequence(__null, 315); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
316 return NS_ERROR_FAILURE;
317 }
318
319 NS_DispatchToMainThread(this);
320 return NS_OK;
321 }
322
323 virtual ~WalkMemoryCacheRunnable() {
324 if (mCallback) {
325 ProxyReleaseMainThread("WalkMemoryCacheRunnable::mCallback", mCallback);
326 }
327 }
328
329 virtual void OnEntryInfo(const nsACString& aURISpec,
330 const nsACString& aIdEnhance, int64_t aDataSize,
331 int64_t aAltDataSize, uint32_t aFetchCount,
332 uint32_t aLastModifiedTime, uint32_t aExpirationTime,
333 bool aPinned, nsILoadContextInfo* aInfo) override {
334 nsresult rv;
335
336 nsCOMPtr<nsIURI> uri;
337 rv = NS_NewURI(getter_AddRefs(uri), aURISpec);
338 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
339 return;
340 }
341
342 rv = mCallback->OnCacheEntryInfo(uri, aIdEnhance, aDataSize, aAltDataSize,
343 aFetchCount, aLastModifiedTime,
344 aExpirationTime, aPinned, aInfo);
345 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
346 LOG((" callback failed, canceling the walk"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " callback failed, canceling the walk"
); } } while (0)
;
347 mCancel = true;
348 }
349 }
350
351 private:
352 nsCString mContextKey;
353 nsTArray<RefPtr<CacheEntry>> mEntryArray;
354 size_t mNextEntryIdx{0};
355};
356
357// WalkDiskCacheRunnable
358// Using the cache index information to get the list of files per context.
359class WalkDiskCacheRunnable : public WalkCacheRunnable {
360 public:
361 WalkDiskCacheRunnable(nsILoadContextInfo* aLoadInfo, bool aVisitEntries,
362 nsICacheStorageVisitor* aVisitor)
363 : WalkCacheRunnable(aVisitor, aVisitEntries),
364 mLoadInfo(aLoadInfo),
365 mPass(COLLECT_STATS),
366 mCount(0) {}
367
368 nsresult Walk() {
369 // TODO, bug 998693
370 // Initial index build should be forced here so that about:cache soon
371 // after startup gives some meaningfull results.
372
373 // Dispatch to the INDEX level in hope that very recent cache entries
374 // information gets to the index list before we grab the index iterator
375 // for the first time. This tries to avoid miss of entries that has
376 // been created right before the visit is required.
377 RefPtr<CacheIOThread> thread = CacheFileIOManager::IOThread();
378 NS_ENSURE_TRUE(thread, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(thread)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "thread" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 378); return
NS_ERROR_NOT_INITIALIZED; } } while (false)
;
379
380 return thread->Dispatch(this, CacheIOThread::INDEX);
381 }
382
383 private:
384 // Invokes OnCacheEntryInfo callback for each single found entry.
385 // There is one instance of this class per one entry.
386 class OnCacheEntryInfoRunnable : public Runnable {
387 public:
388 explicit OnCacheEntryInfoRunnable(WalkDiskCacheRunnable* aWalker)
389 : Runnable("net::WalkDiskCacheRunnable::OnCacheEntryInfoRunnable"),
390 mWalker(aWalker) {}
391
392 NS_IMETHODvirtual nsresult Run() override {
393 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 393); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 393); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
394
395 nsresult rv;
396
397 nsCOMPtr<nsIURI> uri;
398 rv = NS_NewURI(getter_AddRefs(uri), mURISpec);
399 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
400 return NS_OK;
401 }
402
403 rv = mWalker->mCallback->OnCacheEntryInfo(
404 uri, mIdEnhance, mDataSize, mAltDataSize, mFetchCount,
405 mLastModifiedTime, mExpirationTime, mPinned, mInfo);
406 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
407 mWalker->mCancel = true;
408 }
409
410 return NS_OK;
411 }
412
413 RefPtr<WalkDiskCacheRunnable> mWalker;
414
415 nsCString mURISpec;
416 nsCString mIdEnhance;
417 int64_t mDataSize{0};
418 int64_t mAltDataSize{0};
419 uint32_t mFetchCount{0};
420 uint32_t mLastModifiedTime{0};
421 uint32_t mExpirationTime{0};
422 bool mPinned{false};
423 nsCOMPtr<nsILoadContextInfo> mInfo;
424 };
425
426 NS_IMETHODvirtual nsresult Run() override {
427 // The main loop
428 nsresult rv;
429
430 if (CacheStorageService::IsOnManagementThread()) {
431 switch (mPass) {
432 case COLLECT_STATS:
433 // Get quickly the cache stats.
434 uint32_t size;
435 rv = CacheIndex::GetCacheStats(mLoadInfo, &size, &mCount);
436 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
437 if (LoadVisitEntries()) {
438 // both onStorageInfo and onCompleted are expected
439 NS_DispatchToMainThread(this);
440 }
441 return NS_DispatchToMainThread(this);
442 }
443
444 mSize = static_cast<uint64_t>(size) << 10;
445
446 // Invoke onCacheStorageInfo with valid information.
447 NS_DispatchToMainThread(this);
448
449 if (!LoadVisitEntries()) {
450 return NS_OK; // done
451 }
452
453 mPass = ITERATE_METADATA;
454 [[fallthrough]];
455
456 case ITERATE_METADATA:
457 // Now grab the context iterator.
458 if (!mIter) {
459 rv =
460 CacheIndex::GetIterator(mLoadInfo, true, getter_AddRefs(mIter));
461 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
462 // Invoke onCacheEntryVisitCompleted now
463 return NS_DispatchToMainThread(this);
464 }
465 }
466
467 while (!mCancel && !CacheObserver::ShuttingDown()) {
468 if (CacheIOThread::YieldAndRerun()) return NS_OK;
469
470 SHA1Sum::Hash hash;
471 rv = mIter->GetNextHash(&hash);
472 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) break; // done (or error?)
473
474 // This synchronously invokes OnEntryInfo on this class where we
475 // redispatch to the main thread for the consumer callback.
476 CacheFileIOManager::GetEntryInfo(&hash, this);
477 }
478
479 // Invoke onCacheEntryVisitCompleted on the main thread
480 NS_DispatchToMainThread(this);
481 }
482 } else if (NS_IsMainThread()) {
483 if (LoadNotifyStorage()) {
484 nsCOMPtr<nsIFile> dir;
485 CacheFileIOManager::GetCacheDirectory(getter_AddRefs(dir));
486 uint64_t capacity = CacheObserver::DiskCacheCapacity();
487 capacity <<= 10; // kilobytes to bytes
488 mCallback->OnCacheStorageInfo(mCount, mSize, capacity, dir);
489 StoreNotifyStorage(false);
490 } else {
491 mCallback->OnCacheEntryVisitCompleted();
492 }
493 } else {
494 MOZ_CRASH("Bad thread")do { do { } while (false); MOZ_ReportCrash("" "Bad thread", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 494); AnnotateMozCrashReason("MOZ_CRASH(" "Bad thread" ")")
; do { MOZ_CrashSequence(__null, 494); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
495 return NS_ERROR_FAILURE;
496 }
497
498 return NS_OK;
499 }
500
501 virtual void OnEntryInfo(const nsACString& aURISpec,
502 const nsACString& aIdEnhance, int64_t aDataSize,
503 int64_t aAltDataSize, uint32_t aFetchCount,
504 uint32_t aLastModifiedTime, uint32_t aExpirationTime,
505 bool aPinned, nsILoadContextInfo* aInfo) override {
506 // Called directly from CacheFileIOManager::GetEntryInfo.
507
508 // Invoke onCacheEntryInfo on the main thread for this entry.
509 RefPtr<OnCacheEntryInfoRunnable> info = new OnCacheEntryInfoRunnable(this);
510 info->mURISpec = aURISpec;
511 info->mIdEnhance = aIdEnhance;
512 info->mDataSize = aDataSize;
513 info->mAltDataSize = aAltDataSize;
514 info->mFetchCount = aFetchCount;
515 info->mLastModifiedTime = aLastModifiedTime;
516 info->mExpirationTime = aExpirationTime;
517 info->mPinned = aPinned;
518 info->mInfo = aInfo;
519
520 NS_DispatchToMainThread(info);
521 }
522
523 RefPtr<nsILoadContextInfo> mLoadInfo;
524 enum {
525 // First, we collect stats for the load context.
526 COLLECT_STATS,
527
528 // Second, if demanded, we iterate over the entries gethered
529 // from the iterator and call CacheFileIOManager::GetEntryInfo
530 // for each found entry.
531 ITERATE_METADATA,
532 } mPass;
533
534 RefPtr<CacheIndexIterator> mIter;
535 uint32_t mCount;
536};
537
538} // namespace CacheStorageServiceInternal
539
540void CacheStorageService::DropPrivateBrowsingEntries() {
541 StaticMutexAutoLock lock(sLock);
542
543 if (mShutdown) return;
544
545 nsTArray<nsCString> keys;
546 for (const nsACString& key : sGlobalEntryTables->Keys()) {
547 nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(key);
548 if (info && info->IsPrivate()) {
549 keys.AppendElement(key);
550 }
551 }
552
553 for (uint32_t i = 0; i < keys.Length(); ++i) {
554 DoomStorageEntries(keys[i], nullptr, true, false, nullptr);
555 }
556}
557
558// Helper methods
559
560// static
561bool CacheStorageService::IsOnManagementThread() {
562 RefPtr<CacheStorageService> service = Self();
563 if (!service) return false;
564
565 nsCOMPtr<nsIEventTarget> target = service->Thread();
566 if (!target) return false;
567
568 bool currentThread;
569 nsresult rv = target->IsOnCurrentThread(&currentThread);
570 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && currentThread;
571}
572
573already_AddRefed<nsIEventTarget> CacheStorageService::Thread() const {
574 return CacheFileIOManager::IOTarget();
575}
576
577nsresult CacheStorageService::Dispatch(nsIRunnable* aEvent) {
578 RefPtr<CacheIOThread> cacheIOThread = CacheFileIOManager::IOThread();
579 if (!cacheIOThread) return NS_ERROR_NOT_AVAILABLE;
580
581 return cacheIOThread->Dispatch(aEvent, CacheIOThread::MANAGEMENT);
582}
583
584namespace CacheStorageEvictHelper {
585
586nsresult ClearStorage(bool const aPrivate, bool const aAnonymous,
587 OriginAttributes& aOa) {
588 nsresult rv;
589
590 aOa.SyncAttributesWithPrivateBrowsing(aPrivate);
591 RefPtr<LoadContextInfo> info = GetLoadContextInfo(aAnonymous, aOa);
592
593 nsCOMPtr<nsICacheStorage> storage;
594 RefPtr<CacheStorageService> service = CacheStorageService::Self();
595 NS_ENSURE_TRUE(service, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(service)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "service" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 595); return
NS_ERROR_FAILURE; } } while (false)
;
596
597 // Clear disk storage
598 rv = service->DiskCacheStorage(info, getter_AddRefs(storage));
599 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 599); return rv; } } while (false)
;
600 rv = storage->AsyncEvictStorage(nullptr);
601 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 601); return rv; } } while (false)
;
602
603 // Clear memory storage
604 rv = service->MemoryCacheStorage(info, getter_AddRefs(storage));
605 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 605); return rv; } } while (false)
;
606 rv = storage->AsyncEvictStorage(nullptr);
607 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 607); return rv; } } while (false)
;
608
609 return NS_OK;
610}
611
612nsresult Run(OriginAttributes& aOa) {
613 nsresult rv;
614
615 // Clear all [private X anonymous] combinations
616 rv = ClearStorage(false, false, aOa);
617 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 617); return rv; } } while (false)
;
618 rv = ClearStorage(false, true, aOa);
619 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 619); return rv; } } while (false)
;
620 rv = ClearStorage(true, false, aOa);
621 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 621); return rv; } } while (false)
;
622 rv = ClearStorage(true, true, aOa);
623 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 623); return rv; } } while (false)
;
624
625 return NS_OK;
626}
627
628} // namespace CacheStorageEvictHelper
629
630// nsICacheStorageService
631
632NS_IMETHODIMPnsresult CacheStorageService::MemoryCacheStorage(
633 nsILoadContextInfo* aLoadContextInfo, nsICacheStorage** _retval) {
634 NS_ENSURE_ARG(_retval)do { if ((__builtin_expect(!!(!(_retval)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "_retval" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 634); return
NS_ERROR_INVALID_ARG; } } while (false)
;
635
636 nsCOMPtr<nsICacheStorage> storage =
637 new CacheStorage(aLoadContextInfo, false, false, false);
638 storage.forget(_retval);
639 return NS_OK;
640}
641
642NS_IMETHODIMPnsresult CacheStorageService::DiskCacheStorage(
643 nsILoadContextInfo* aLoadContextInfo, nsICacheStorage** _retval) {
644 NS_ENSURE_ARG(_retval)do { if ((__builtin_expect(!!(!(_retval)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "_retval" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 644); return
NS_ERROR_INVALID_ARG; } } while (false)
;
645
646 // TODO save some heap granularity - cache commonly used storages.
647
648 // When disk cache is disabled, still provide a storage, but just keep stuff
649 // in memory.
650 bool useDisk = CacheObserver::UseDiskCache();
651
652 nsCOMPtr<nsICacheStorage> storage = new CacheStorage(
653 aLoadContextInfo, useDisk, false /* size limit */, false /* don't pin */);
654 storage.forget(_retval);
655 return NS_OK;
656}
657
658NS_IMETHODIMPnsresult CacheStorageService::PinningCacheStorage(
659 nsILoadContextInfo* aLoadContextInfo, nsICacheStorage** _retval) {
660 NS_ENSURE_ARG(aLoadContextInfo)do { if ((__builtin_expect(!!(!(aLoadContextInfo)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aLoadContextInfo" ") failed"
, nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 660); return NS_ERROR_INVALID_ARG; } } while (false)
;
661 NS_ENSURE_ARG(_retval)do { if ((__builtin_expect(!!(!(_retval)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "_retval" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 661); return
NS_ERROR_INVALID_ARG; } } while (false)
;
662
663 // When disk cache is disabled don't pretend we cache.
664 if (!CacheObserver::UseDiskCache()) {
665 return NS_ERROR_NOT_AVAILABLE;
666 }
667
668 nsCOMPtr<nsICacheStorage> storage =
669 new CacheStorage(aLoadContextInfo, true /* use disk */,
670 true /* ignore size checks */, true /* pin */);
671 storage.forget(_retval);
672 return NS_OK;
673}
674
675NS_IMETHODIMPnsresult CacheStorageService::Clear() {
676 nsresult rv;
677
678 // Tell the index to block notification to AsyncGetDiskConsumption.
679 // Will be allowed again from CacheFileContextEvictor::EvictEntries()
680 // when all the context have been removed from disk.
681 CacheIndex::OnAsyncEviction(true);
682
683 StaticMutexAutoLock lock(sLock);
684
685 {
686 mozilla::MutexAutoLock forcedValidEntriesLock(mForcedValidEntriesLock);
687 mForcedValidEntries.Clear();
688 }
689
690 NS_ENSURE_TRUE(!mShutdown, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(!mShutdown)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!mShutdown" ") failed",
nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 690); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
691
692 const auto keys = ToTArray<nsTArray<nsCString>>(sGlobalEntryTables->Keys());
693 for (const auto& key : keys) {
694 DoomStorageEntries(key, nullptr, true, false, nullptr);
695 }
696
697 // Passing null as a load info means to evict all contexts.
698 // EvictByContext() respects the entry pinning. EvictAll() does not.
699 rv = CacheFileIOManager::EvictByContext(nullptr, false, u""_ns);
700 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 700); return rv; } } while (false)
;
701
702 return NS_OK;
703}
704
705NS_IMETHODIMPnsresult CacheStorageService::ClearOriginsByPrincipal(
706 nsIPrincipal* aPrincipal) {
707 nsresult rv;
708
709 if (NS_WARN_IF(!aPrincipal)NS_warn_if_impl(!aPrincipal, "!aPrincipal", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 709)
) {
710 return NS_ERROR_FAILURE;
711 }
712
713 nsAutoString origin;
714 rv = nsContentUtils::GetWebExposedOriginSerialization(aPrincipal, origin);
715 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 715); return rv; } } while (false)
;
716 LOG(("CacheStorageService::ClearOriginsByPrincipal %s",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearOriginsByPrincipal %s"
, NS_ConvertUTF16toUTF8(origin).get()); } } while (0)
717 NS_ConvertUTF16toUTF8(origin).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearOriginsByPrincipal %s"
, NS_ConvertUTF16toUTF8(origin).get()); } } while (0)
;
718
719 rv = ClearOriginInternal(origin, aPrincipal->OriginAttributesRef(), true);
720 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 720); return rv; } } while (false)
;
721
722 rv = ClearOriginInternal(origin, aPrincipal->OriginAttributesRef(), false);
723 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 723); return rv; } } while (false)
;
724
725 return NS_OK;
726}
727
728NS_IMETHODIMPnsresult CacheStorageService::ClearOriginsByOriginAttributes(
729 const nsAString& aOriginAttributes) {
730 nsresult rv;
731 LOG(("CacheStorageService::ClearOriginsByOriginAttributes %s",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearOriginsByOriginAttributes %s"
, NS_ConvertUTF16toUTF8(aOriginAttributes).get()); } } while (
0)
732 NS_ConvertUTF16toUTF8(aOriginAttributes).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearOriginsByOriginAttributes %s"
, NS_ConvertUTF16toUTF8(aOriginAttributes).get()); } } while (
0)
;
733
734 if (NS_WARN_IF(aOriginAttributes.IsEmpty())NS_warn_if_impl(aOriginAttributes.IsEmpty(), "aOriginAttributes.IsEmpty()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 734)
) {
735 return NS_ERROR_FAILURE;
736 }
737
738 OriginAttributes oa;
739 if (!oa.Init(aOriginAttributes)) {
740 NS_ERROR("Could not parse the argument for OriginAttributes")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Could not parse the argument for OriginAttributes"
, "Error", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 740); MOZ_PretendNoReturn(); } while (0)
;
741 return NS_ERROR_FAILURE;
742 }
743
744 rv = CacheStorageEvictHelper::Run(oa);
745 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 745); return rv; } } while (false)
;
746
747 return NS_OK;
748}
749
750static bool RemoveExactEntry(CacheEntryTable* aEntries, nsACString const& aKey,
751 CacheEntry* aEntry, bool aOverwrite) {
752 RefPtr<CacheEntry> existingEntry;
753 if (!aEntries->Get(aKey, getter_AddRefs(existingEntry))) {
754 LOG(("RemoveExactEntry [entry=%p already gone]", aEntry))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "RemoveExactEntry [entry=%p already gone]"
, aEntry); } } while (0)
;
755 return false; // Already removed...
756 }
757
758 if (!aOverwrite && existingEntry != aEntry) {
759 LOG(("RemoveExactEntry [entry=%p already replaced]", aEntry))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "RemoveExactEntry [entry=%p already replaced]"
, aEntry); } } while (0)
;
760 return false; // Already replaced...
761 }
762
763 LOG(("RemoveExactEntry [entry=%p removed]", aEntry))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "RemoveExactEntry [entry=%p removed]"
, aEntry); } } while (0)
;
764 aEntries->Remove(aKey);
765 return true;
766}
767
768NS_IMETHODIMPnsresult CacheStorageService::ClearBaseDomain(
769 const nsAString& aBaseDomain) {
770 LOG(("CacheStorageService::ClearBaseDomain %s",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearBaseDomain %s"
, NS_ConvertUTF16toUTF8(aBaseDomain).get()); } } while (0)
771 NS_ConvertUTF16toUTF8(aBaseDomain).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearBaseDomain %s"
, NS_ConvertUTF16toUTF8(aBaseDomain).get()); } } while (0)
;
772 StaticMutexAutoLock lock(sLock);
773 if (sGlobalEntryTables) {
774 if (mShutdown) return NS_ERROR_NOT_AVAILABLE;
775
776 nsCString cBaseDomain = NS_ConvertUTF16toUTF8(aBaseDomain);
777
778 nsTArray<nsCString> keys;
779 for (const auto& globalEntry : *sGlobalEntryTables) {
780 // Match by partitionKey base domain. This should cover most cache entries
781 // because we statically partition the cache. Most first party cache
782 // entries will also have a partitionKey set where the partitionKey base
783 // domain will match the entry URI base domain.
784 const nsACString& key = globalEntry.GetKey();
785 nsCOMPtr<nsILoadContextInfo> info =
786 CacheFileUtils::ParseKey(globalEntry.GetKey());
787
788 if (info &&
789 StoragePrincipalHelper::PartitionKeyHasBaseDomain(
790 info->OriginAttributesPtr()->mPartitionKey, aBaseDomain)) {
791 keys.AppendElement(key);
792 continue;
793 }
794
795 // If we didn't get a partitionKey match, try to match by entry URI. This
796 // requires us to iterate over all entries.
797 CacheEntryTable* table = globalEntry.GetWeak();
798 MOZ_ASSERT(table)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(table)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(table))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("table", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 798); AnnotateMozCrashReason("MOZ_ASSERT" "(" "table" ")");
do { MOZ_CrashSequence(__null, 798); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
799
800 nsTArray<RefPtr<CacheEntry>> entriesToDelete;
801
802 for (CacheEntry* entry : table->Values()) {
803 nsIURI* uri = entry->GetURI();
804 if (NS_WARN_IF(!uri)NS_warn_if_impl(!uri, "!uri", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 804)
) {
805 continue;
806 }
807
808 nsAutoCString host;
809 nsresult rv = uri->GetHost(host);
810 // Some entries may not have valid hosts. We can skip them.
811 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || host.IsEmpty()) {
812 continue;
813 }
814
815 bool hasRootDomain = false;
816 rv = HasRootDomain(host, cBaseDomain, &hasRootDomain);
817 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 817)
) {
818 continue;
819 }
820 if (hasRootDomain) {
821 entriesToDelete.AppendElement(entry);
822 }
823 }
824
825 // Clear individual matched entries.
826 for (RefPtr<CacheEntry>& entry : entriesToDelete) {
827 nsAutoCString entryKey;
828 nsresult rv = entry->HashingKey(entryKey);
829 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
830 NS_ERROR("aEntry->HashingKey() failed?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aEntry->HashingKey() failed?"
, "Error", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 830); MOZ_PretendNoReturn(); } while (0)
;
831 return rv;
832 }
833
834 RemoveExactEntry(table, entryKey, entry, false /* don't overwrite */);
835 }
836 }
837
838 // Clear matched keys.
839 for (uint32_t i = 0; i < keys.Length(); ++i) {
840 LOG(("CacheStorageService::ClearBaseDomain Dooming %s", keys[i].get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearBaseDomain Dooming %s"
, keys[i].get()); } } while (0)
;
841 DoomStorageEntries(keys[i], nullptr, true, false, nullptr);
842 }
843 }
844
845 return CacheFileIOManager::EvictByContext(nullptr, false /* pinned */, u""_ns,
846 aBaseDomain);
847}
848
849nsresult CacheStorageService::ClearOriginInternal(
850 const nsAString& aOrigin, const OriginAttributes& aOriginAttributes,
851 bool aAnonymous) {
852 nsresult rv;
853
854 RefPtr<LoadContextInfo> info =
855 GetLoadContextInfo(aAnonymous, aOriginAttributes);
856 if (NS_WARN_IF(!info)NS_warn_if_impl(!info, "!info", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 856)
) {
857 return NS_ERROR_FAILURE;
858 }
859
860 StaticMutexAutoLock lock(sLock);
861
862 if (sGlobalEntryTables) {
863 for (const auto& globalEntry : *sGlobalEntryTables) {
864 bool matches = false;
865 rv = CacheFileUtils::KeyMatchesLoadContextInfo(globalEntry.GetKey(), info,
866 &matches);
867 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 867); return rv; } } while (false)
;
868 if (!matches) {
869 continue;
870 }
871
872 CacheEntryTable* table = globalEntry.GetWeak();
873 MOZ_ASSERT(table)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(table)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(table))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("table", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 873); AnnotateMozCrashReason("MOZ_ASSERT" "(" "table" ")");
do { MOZ_CrashSequence(__null, 873); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
874
875 nsTArray<RefPtr<CacheEntry>> entriesToDelete;
876
877 for (CacheEntry* entry : table->Values()) {
878 nsIURI* uri = entry->GetURI();
879 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(uri)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "uri" ") failed", nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 879); return NS_ERROR_UNEXPECTED; } } while (false)
;
880
881 nsAutoString origin;
882 rv = nsContentUtils::GetWebExposedOriginSerialization(uri, origin);
883 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 883); return rv; } } while (false)
;
884
885 if (origin != aOrigin) {
886 continue;
887 }
888
889 entriesToDelete.AppendElement(entry);
890 }
891
892 for (RefPtr<CacheEntry>& entry : entriesToDelete) {
893 nsAutoCString entryKey;
894 rv = entry->HashingKey(entryKey);
895 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
896 NS_ERROR("aEntry->HashingKey() failed?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aEntry->HashingKey() failed?"
, "Error", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 896); MOZ_PretendNoReturn(); } while (0)
;
897 return rv;
898 }
899 MOZ_ASSERT_IF(info->IsPrivate(), !entry->IsUsingDisk())do { if (info->IsPrivate()) { do { static_assert( mozilla::
detail::AssertionConditionType<decltype(!entry->IsUsingDisk
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!entry->IsUsingDisk()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!entry->IsUsingDisk()", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!entry->IsUsingDisk()"
")"); do { MOZ_CrashSequence(__null, 899); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
900 RemoveExactEntry(table, entryKey, entry, false /* don't overwrite */);
901 }
902 }
903 }
904
905 if (!info->IsPrivate()) {
906 rv = CacheFileIOManager::EvictByContext(info, false /* pinned */, aOrigin);
907 }
908 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 908); return rv; } } while (false)
;
909
910 return NS_OK;
911}
912
913NS_IMETHODIMPnsresult CacheStorageService::ClearOriginDictionary(nsIURI* aURI) {
914 LOG(("CacheStorageService::ClearOriginDictionary"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearOriginDictionary"
); } } while (0)
;
915 // Note: due to cookie samesite rules, we need to clean for all ports
916 DictionaryCache::RemoveDictionariesForOrigin(aURI);
917 return NS_OK;
918}
919
920NS_IMETHODIMPnsresult CacheStorageService::ClearAllOriginDictionaries() {
921 LOG(("CacheStorageService::ClearAllOriginDictionaries"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearAllOriginDictionaries"
); } } while (0)
;
922 DictionaryCache::RemoveAllDictionaries();
923 return NS_OK;
924}
925
926NS_IMETHODIMPnsresult CacheStorageService::PurgeFromMemory(uint32_t aWhat) {
927 uint32_t what;
928
929 switch (aWhat) {
930 case PURGE_DISK_DATA_ONLY:
931 what = CacheEntry::PURGE_DATA_ONLY_DISK_BACKED;
932 break;
933
934 case PURGE_DISK_ALL:
935 what = CacheEntry::PURGE_WHOLE_ONLY_DISK_BACKED;
936 break;
937
938 case PURGE_EVERYTHING:
939 what = CacheEntry::PURGE_WHOLE;
940 break;
941
942 default:
943 return NS_ERROR_INVALID_ARG;
944 }
945
946 nsCOMPtr<nsIRunnable> event = new PurgeFromMemoryRunnable(this, what);
947
948 return Dispatch(event);
949}
950
951NS_IMETHODIMPnsresult CacheStorageService::PurgeFromMemoryRunnable::Run() {
952 if (NS_IsMainThread()) {
953 nsCOMPtr<nsIObserverService> observerService =
954 mozilla::services::GetObserverService();
955 if (observerService) {
956 observerService->NotifyObservers(
957 nullptr, "cacheservice:purge-memory-pools", nullptr);
958 }
959
960 return NS_OK;
961 }
962
963 if (mService) {
964 // Note that we seem to come here only in the case of "memory-pressure"
965 // being notified (or in case of tests), so we start from purging in-memory
966 // entries first and ignore minprogress for disk entries.
967 // TODO not all flags apply to both pools.
968 mService->Pool(MemoryPool::EType::MEMORY)
969 .PurgeAll(mWhat, StaticPrefs::network_cache_purge_minprogress_memory());
970 mService->Pool(MemoryPool::EType::DISK).PurgeAll(mWhat, 0);
971 mService = nullptr;
972 }
973
974 NS_DispatchToMainThread(this);
975 return NS_OK;
976}
977
978NS_IMETHODIMPnsresult CacheStorageService::AsyncGetDiskConsumption(
979 nsICacheStorageConsumptionObserver* aObserver) {
980 NS_ENSURE_ARG(aObserver)do { if ((__builtin_expect(!!(!(aObserver)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObserver" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 980); return
NS_ERROR_INVALID_ARG; } } while (false)
;
981
982 nsresult rv;
983
984 rv = CacheIndex::AsyncGetDiskConsumption(aObserver);
985 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 985); return rv; } } while (false)
;
986
987 return NS_OK;
988}
989
990NS_IMETHODIMPnsresult CacheStorageService::GetIoTarget(nsIEventTarget** aEventTarget) {
991 NS_ENSURE_ARG(aEventTarget)do { if ((__builtin_expect(!!(!(aEventTarget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEventTarget" ") failed"
, nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 991); return NS_ERROR_INVALID_ARG; } } while (false)
;
992
993 nsCOMPtr<nsIEventTarget> ioTarget = CacheFileIOManager::IOTarget();
994 ioTarget.forget(aEventTarget);
995
996 return NS_OK;
997}
998
999NS_IMETHODIMPnsresult CacheStorageService::AsyncVisitAllStorages(
1000 nsICacheStorageVisitor* aVisitor, bool aVisitEntries) {
1001 LOG(("CacheStorageService::AsyncVisitAllStorages [cb=%p]", aVisitor))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::AsyncVisitAllStorages [cb=%p]"
, aVisitor); } } while (0)
;
1002 NS_ENSURE_FALSE(mShutdown, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(!(mShutdown))), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!(mShutdown)" ") failed"
, nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1002); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
1003
1004 // Walking the disk cache also walks the memory cache.
1005 RefPtr<CacheStorageServiceInternal::WalkDiskCacheRunnable> event =
1006 new CacheStorageServiceInternal::WalkDiskCacheRunnable(
1007 nullptr, aVisitEntries, aVisitor);
1008 return event->Walk();
1009}
1010
1011// Methods used by CacheEntry for management of in-memory structures.
1012
1013void CacheStorageService::RegisterEntry(CacheEntry* aEntry) {
1014 MOZ_ASSERT(IsOnManagementThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsOnManagementThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsOnManagementThread()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsOnManagementThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1014);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsOnManagementThread()"
")"); do { MOZ_CrashSequence(__null, 1014); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1015
1016 if (mShutdown || !aEntry->CanRegister()) return;
1017
1018 TelemetryRecordEntryCreation(aEntry);
1019
1020 LOG(("CacheStorageService::RegisterEntry [entry=%p]", aEntry))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::RegisterEntry [entry=%p]"
, aEntry); } } while (0)
;
1021
1022 MemoryPool& pool = Pool(aEntry->IsUsingDisk());
1023 pool.mManagedEntries.insertBack(aEntry);
1024
1025 aEntry->SetRegistered(true);
1026}
1027
1028void CacheStorageService::UnregisterEntry(CacheEntry* aEntry) {
1029 MOZ_ASSERT(IsOnManagementThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsOnManagementThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsOnManagementThread()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsOnManagementThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1029);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsOnManagementThread()"
")"); do { MOZ_CrashSequence(__null, 1029); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1030
1031 if (!aEntry->IsRegistered()) return;
1032
1033 TelemetryRecordEntryRemoval(aEntry);
1034
1035 LOG(("CacheStorageService::UnregisterEntry [entry=%p]", aEntry))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::UnregisterEntry [entry=%p]"
, aEntry); } } while (0)
;
1036
1037 MemoryPool& pool = Pool(aEntry->IsUsingDisk());
1038 aEntry->removeFrom(pool.mManagedEntries);
1039
1040 // Note: aEntry->CanRegister() since now returns false
1041 aEntry->SetRegistered(false);
1042}
1043
1044static bool AddExactEntry(CacheEntryTable* aEntries, nsACString const& aKey,
1045 CacheEntry* aEntry, bool aOverwrite) {
1046 RefPtr<CacheEntry> existingEntry;
1047 if (!aOverwrite && aEntries->Get(aKey, getter_AddRefs(existingEntry))) {
1048 bool equals = existingEntry == aEntry;
1049 LOG(("AddExactEntry [entry=%p equals=%d]", aEntry, equals))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AddExactEntry [entry=%p equals=%d]"
, aEntry, equals); } } while (0)
;
1050 return equals; // Already there...
1051 }
1052
1053 LOG(("AddExactEntry [entry=%p put]", aEntry))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AddExactEntry [entry=%p put]"
, aEntry); } } while (0)
;
1054 aEntries->InsertOrUpdate(aKey, RefPtr{aEntry});
1055 return true;
1056}
1057
1058bool CacheStorageService::RemoveEntry(CacheEntry* aEntry,
1059 bool aOnlyUnreferenced) {
1060 LOG(("CacheStorageService::RemoveEntry [entry=%p]", aEntry))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::RemoveEntry [entry=%p]"
, aEntry); } } while (0)
;
1061
1062 nsAutoCString entryKey;
1063 nsresult rv = aEntry->HashingKey(entryKey);
1064 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1065 NS_ERROR("aEntry->HashingKey() failed?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aEntry->HashingKey() failed?"
, "Error", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1065); MOZ_PretendNoReturn(); } while (0)
;
1066 return false;
1067 }
1068
1069 StaticMutexAutoLock lock(sLock);
1070
1071 if (mShutdown) {
1072 LOG((" after shutdown"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " after shutdown"
); } } while (0)
;
1073 return false;
1074 }
1075
1076 if (aOnlyUnreferenced) {
1077 if (aEntry->IsReferenced()) {
1078 LOG((" still referenced, not removing"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " still referenced, not removing"
); } } while (0)
;
1079 return false;
1080 }
1081
1082 if (!aEntry->IsUsingDisk() &&
1083 IsForcedValidEntry(aEntry->GetStorageID(), entryKey)) {
1084 LOG((" forced valid, not removing"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " forced valid, not removing"
); } } while (0)
;
1085 return false;
1086 }
1087 }
1088
1089 CacheEntryTable* entries;
1090 if (sGlobalEntryTables->Get(aEntry->GetStorageID(), &entries)) {
1091 RemoveExactEntry(entries, entryKey, aEntry, false /* don't overwrite */);
1092 }
1093
1094 nsAutoCString memoryStorageID(aEntry->GetStorageID());
1095 AppendMemoryStorageTag(memoryStorageID);
1096
1097 if (sGlobalEntryTables->Get(memoryStorageID, &entries)) {
1098 RemoveExactEntry(entries, entryKey, aEntry, false /* don't overwrite */);
1099 }
1100
1101 return true;
1102}
1103
1104void CacheStorageService::RecordMemoryOnlyEntry(CacheEntry* aEntry,
1105 bool aOnlyInMemory,
1106 bool aOverwrite) {
1107 LOG(do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::RecordMemoryOnlyEntry [entry=%p, memory=%d, "
"overwrite=%d]", aEntry, aOnlyInMemory, aOverwrite); } } while
(0)
1108 ("CacheStorageService::RecordMemoryOnlyEntry [entry=%p, memory=%d, "do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::RecordMemoryOnlyEntry [entry=%p, memory=%d, "
"overwrite=%d]", aEntry, aOnlyInMemory, aOverwrite); } } while
(0)
1109 "overwrite=%d]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::RecordMemoryOnlyEntry [entry=%p, memory=%d, "
"overwrite=%d]", aEntry, aOnlyInMemory, aOverwrite); } } while
(0)
1110 aEntry, aOnlyInMemory, aOverwrite))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::RecordMemoryOnlyEntry [entry=%p, memory=%d, "
"overwrite=%d]", aEntry, aOnlyInMemory, aOverwrite); } } while
(0)
;
1111 // This method is responsible to put this entry to a special record hashtable
1112 // that contains only entries that are stored in memory.
1113 // Keep in mind that every entry, regardless of whether is in-memory-only or
1114 // not is always recorded in the storage master hash table, the one identified
1115 // by CacheEntry.StorageID().
1116
1117 sLock.AssertCurrentThreadOwns();
1118
1119 if (mShutdown) {
1120 LOG((" after shutdown"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " after shutdown"
); } } while (0)
;
1121 return;
1122 }
1123
1124 nsresult rv;
1125
1126 nsAutoCString entryKey;
1127 rv = aEntry->HashingKey(entryKey);
1128 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1129 NS_ERROR("aEntry->HashingKey() failed?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aEntry->HashingKey() failed?"
, "Error", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1129); MOZ_PretendNoReturn(); } while (0)
;
1130 return;
1131 }
1132
1133 CacheEntryTable* entries = nullptr;
1134 nsAutoCString memoryStorageID(aEntry->GetStorageID());
1135 AppendMemoryStorageTag(memoryStorageID);
1136
1137 if (!sGlobalEntryTables->Get(memoryStorageID, &entries)) {
1138 if (!aOnlyInMemory) {
1139 LOG((" not recorded as memory only"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " not recorded as memory only"
); } } while (0)
;
1140 return;
1141 }
1142
1143 entries = sGlobalEntryTables
1144 ->InsertOrUpdate(
1145 memoryStorageID,
1146 MakeUnique<CacheEntryTable>(CacheEntryTable::MEMORY_ONLY))
1147 .get();
1148 LOG((" new memory-only storage table for %s", memoryStorageID.get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " new memory-only storage table for %s"
, memoryStorageID.get()); } } while (0)
;
1149 }
1150
1151 if (aOnlyInMemory) {
1152 AddExactEntry(entries, entryKey, aEntry, aOverwrite);
1153 } else {
1154 RemoveExactEntry(entries, entryKey, aEntry, aOverwrite);
1155 }
1156}
1157
1158// Checks if a cache entry is forced valid (will be loaded directly from cache
1159// without further validation) - see nsICacheEntry.idl for further details
1160bool CacheStorageService::IsForcedValidEntry(nsACString const& aContextKey,
1161 nsACString const& aEntryKey) {
1162 return IsForcedValidEntry(aContextKey + aEntryKey);
1163}
1164
1165bool CacheStorageService::IsForcedValidEntry(
1166 nsACString const& aContextEntryKey) {
1167 mozilla::MutexAutoLock lock(mForcedValidEntriesLock);
1168
1169 ForcedValidData data;
1170
1171 if (!mForcedValidEntries.Get(aContextEntryKey, &data)) {
1172 return false;
1173 }
1174
1175 if (data.validUntil.IsNull()) {
1176 MOZ_ASSERT_UNREACHABLE("the timeStamp should never be null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"the timeStamp should never be null" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1176); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "the timeStamp should never be null"
")"); do { MOZ_CrashSequence(__null, 1176); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1177 return false;
1178 }
1179
1180 // Entry timeout not reached yet
1181 if (TimeStamp::NowLoRes() <= data.validUntil) {
1182 return true;
1183 }
1184
1185 // Entry timeout has been reached
1186 mForcedValidEntries.Remove(aContextEntryKey);
1187
1188 return false;
1189}
1190
1191void CacheStorageService::MarkForcedValidEntryUse(nsACString const& aContextKey,
1192 nsACString const& aEntryKey) {
1193 mozilla::MutexAutoLock lock(mForcedValidEntriesLock);
1194
1195 ForcedValidData data;
1196
1197 if (!mForcedValidEntries.Get(aContextKey + aEntryKey, &data)) {
1198 return;
1199 }
1200
1201 data.viewed = true;
1202 mForcedValidEntries.InsertOrUpdate(aContextKey + aEntryKey, data);
1203}
1204
1205// Registers a cache entry in the No-Vary-Search secondary index so that
1206// future cache lookups for variant URLs can find it without scanning the
1207// entire entry table.
1208//
1209// When a response carrying a No-Vary-Search header is stored, this method
1210// is called to record the mapping:
1211// aBasePath (scheme://host:port/path) → aFullKey (the full cache entry key)
1212//
1213// On a subsequent exact-key cache miss, AddStorageEntry() consults this index
1214// to find candidate entries sharing the same base path and checks each one for
1215// URL equivalence under its stored NVS header
1216// (see "equivalent modulo variation config",
1217// https://www.ietf.org/archive/id/draft-ietf-httpbis-no-vary-search-05.html#section-6).
1218//
1219// Must be called with sLock NOT held; acquires sLock internally.
1220void CacheStorageService::NoteNoVarySearchEntry(const nsACString& aContextKey,
1221 const nsACString& aBasePath,
1222 const nsACString& aFullKey) {
1223 StaticMutexAutoLock lock(sLock);
1224 CacheEntryTable* entries = sGlobalEntryTables->Get(aContextKey);
1225 if (entries) {
1226 entries->NoteNoVarySearchEntry(aBasePath, aFullKey);
1227 }
1228}
1229
1230void CacheStorageService::NoteNoVarySearchEntry(nsICacheEntry* aEntry,
1231 nsIURI* aURI) {
1232 RefPtr<CacheEntryHandle> handle = do_QueryObject(aEntry);
1233 if (handle) {
1234 handle->Entry()->NoteNoVarySearchEntry(aURI);
1235 }
1236}
1237
1238// Allows a cache entry to be loaded directly from cache without further
1239// validation - see nsICacheEntry.idl for further details
1240void CacheStorageService::ForceEntryValidFor(nsACString const& aContextKey,
1241 nsACString const& aEntryKey,
1242 uint32_t aSecondsToTheFuture) {
1243 mozilla::MutexAutoLock lock(mForcedValidEntriesLock);
1244
1245 TimeStamp now = TimeStamp::NowLoRes();
1246 ForcedValidEntriesPrune(now);
1247
1248 ForcedValidData data;
1249 data.validUntil = now + TimeDuration::FromSeconds(aSecondsToTheFuture);
1250 data.viewed = false;
1251
1252 mForcedValidEntries.InsertOrUpdate(aContextKey + aEntryKey, data);
1253}
1254
1255void CacheStorageService::RemoveEntryForceValid(nsACString const& aContextKey,
1256 nsACString const& aEntryKey) {
1257 mozilla::MutexAutoLock lock(mForcedValidEntriesLock);
1258
1259 LOG(("CacheStorageService::RemoveEntryForceValid context='%s' entryKey=%s",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::RemoveEntryForceValid context='%s' entryKey=%s"
, TPromiseFlatString<char>(aContextKey).get(), TPromiseFlatString
<char>(aEntryKey).get()); } } while (0)
1260 PromiseFlatCString(aContextKey).get(),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::RemoveEntryForceValid context='%s' entryKey=%s"
, TPromiseFlatString<char>(aContextKey).get(), TPromiseFlatString
<char>(aEntryKey).get()); } } while (0)
1261 PromiseFlatCString(aEntryKey).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::RemoveEntryForceValid context='%s' entryKey=%s"
, TPromiseFlatString<char>(aContextKey).get(), TPromiseFlatString
<char>(aEntryKey).get()); } } while (0)
;
1262 mForcedValidEntries.Remove(aContextKey + aEntryKey);
1263}
1264
1265// Cleans out the old entries in mForcedValidEntries
1266void CacheStorageService::ForcedValidEntriesPrune(TimeStamp& now) {
1267 static TimeDuration const oneMinute = TimeDuration::FromSeconds(60);
1268 static TimeStamp dontPruneUntil = now + oneMinute;
1269 if (now < dontPruneUntil) return;
1270
1271 for (auto iter = mForcedValidEntries.Iter(); !iter.Done(); iter.Next()) {
1272 if (iter.Data().validUntil < now) {
1273 iter.Remove();
1274 }
1275 }
1276 dontPruneUntil = now + oneMinute;
1277}
1278
1279void CacheStorageService::OnMemoryConsumptionChange(
1280 CacheMemoryConsumer* aConsumer, uint32_t aCurrentMemoryConsumption) {
1281 LOG(("CacheStorageService::OnMemoryConsumptionChange [consumer=%p, size=%u]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::OnMemoryConsumptionChange [consumer=%p, size=%u]"
, aConsumer, aCurrentMemoryConsumption); } } while (0)
1282 aConsumer, aCurrentMemoryConsumption))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::OnMemoryConsumptionChange [consumer=%p, size=%u]"
, aConsumer, aCurrentMemoryConsumption); } } while (0)
;
1283
1284 uint32_t savedMemorySize = aConsumer->LoadReportedMemoryConsumption();
1285 if (savedMemorySize == aCurrentMemoryConsumption) return;
1286
1287 // Exchange saved size with current one.
1288 aConsumer->StoreReportedMemoryConsumption(aCurrentMemoryConsumption);
1289
1290 bool usingDisk = !(aConsumer->LoadFlags() & CacheMemoryConsumer::MEMORY_ONLY);
1291 bool overLimit = Pool(usingDisk).OnMemoryConsumptionChange(
1292 savedMemorySize, aCurrentMemoryConsumption);
1293
1294 if (!overLimit) return;
1295
1296 // It's likely the timer has already been set when we get here,
1297 // check outside the lock to save resources.
1298#ifdef MOZ_TSAN
1299 if (mPurgeTimerActive) {
1300#else
1301 if (mPurgeTimer) {
1302#endif
1303 return;
1304 }
1305
1306 // We don't know if this is called under the service lock or not,
1307 // hence rather dispatch.
1308 RefPtr<nsIEventTarget> cacheIOTarget = Thread();
1309 if (!cacheIOTarget) return;
1310
1311 // Dispatch as a priority task, we want to set the purge timer
1312 // ASAP to prevent vain redispatch of this event.
1313 nsCOMPtr<nsIRunnable> event = NewRunnableMethod(
1314 "net::CacheStorageService::SchedulePurgeOverMemoryLimit", this,
1315 &CacheStorageService::SchedulePurgeOverMemoryLimit);
1316 cacheIOTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
1317}
1318
1319bool CacheStorageService::MemoryPool::OnMemoryConsumptionChange(
1320 uint32_t aSavedMemorySize, uint32_t aCurrentMemoryConsumption) {
1321 mMemorySize -= aSavedMemorySize;
1322 mMemorySize += aCurrentMemoryConsumption;
1323
1324 LOG((" mMemorySize=%u (+%u,-%u)", uint32_t(mMemorySize),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " mMemorySize=%u (+%u,-%u)"
, uint32_t(mMemorySize), aCurrentMemoryConsumption, aSavedMemorySize
); } } while (0)
1325 aCurrentMemoryConsumption, aSavedMemorySize))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " mMemorySize=%u (+%u,-%u)"
, uint32_t(mMemorySize), aCurrentMemoryConsumption, aSavedMemorySize
); } } while (0)
;
1326
1327 // Bypass purging when memory has not grew up significantly
1328 if (aCurrentMemoryConsumption <= aSavedMemorySize) return false;
1329
1330 return mMemorySize > Limit();
1331}
1332
1333void CacheStorageService::SchedulePurgeOverMemoryLimit() {
1334 LOG(("CacheStorageService::SchedulePurgeOverMemoryLimit"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::SchedulePurgeOverMemoryLimit"
); } } while (0)
;
1335
1336 StaticMutexAutoLock lock(sLock);
1337
1338 if (mShutdown) {
1339 LOG((" past shutdown"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " past shutdown"
); } } while (0)
;
1340 return;
1341 }
1342
1343 if (mPurgeTimer) {
1344 LOG((" timer already up"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " timer already up"
); } } while (0)
;
1345 return;
1346 }
1347
1348 mPurgeTimer = NS_NewTimer();
1349 if (mPurgeTimer) {
1350#ifdef MOZ_TSAN
1351 mPurgeTimerActive = true;
1352#endif
1353 nsresult rv;
1354 rv = mPurgeTimer->InitWithCallback(this, 1000, nsITimer::TYPE_ONE_SHOT);
1355 LOG((" timer init rv=0x%08" PRIx32, static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " timer init rv=0x%08"
"x", static_cast<uint32_t>(rv)); } } while (0)
;
1356 }
1357}
1358
1359NS_IMETHODIMPnsresult
1360CacheStorageService::Notify(nsITimer* aTimer) {
1361 LOG(("CacheStorageService::Notify"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::Notify"
); } } while (0)
;
1362
1363 StaticMutexAutoLock lock(sLock);
1364
1365 if (aTimer == mPurgeTimer) {
1366#ifdef MOZ_TSAN
1367 mPurgeTimerActive = false;
1368#endif
1369 mPurgeTimer = nullptr;
1370
1371 if (!mShutdown) {
1372 nsCOMPtr<nsIRunnable> event = NewRunnableMethod(
1373 "net::CacheStorageService::PurgeExpiredOrOverMemoryLimit", this,
1374 &CacheStorageService::PurgeExpiredOrOverMemoryLimit);
1375 Dispatch(event);
1376 }
1377 }
1378
1379 return NS_OK;
1380}
1381
1382NS_IMETHODIMPnsresult
1383CacheStorageService::GetName(nsACString& aName) {
1384 aName.AssignLiteral("CacheStorageService");
1385 return NS_OK;
1386}
1387
1388void CacheStorageService::PurgeExpiredOrOverMemoryLimit() {
1389 MOZ_ASSERT(IsOnManagementThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsOnManagementThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsOnManagementThread()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsOnManagementThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1389);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsOnManagementThread()"
")"); do { MOZ_CrashSequence(__null, 1389); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1390
1391 LOG(("CacheStorageService::PurgeExpiredOrOverMemoryLimit"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::PurgeExpiredOrOverMemoryLimit"
); } } while (0)
;
1392
1393 if (mShutdown) return;
1394
1395 static TimeDuration const kFourSeconds = TimeDuration::FromSeconds(4);
1396 TimeStamp now = TimeStamp::NowLoRes();
1397
1398 if (!mLastPurgeTime.IsNull() && now - mLastPurgeTime < kFourSeconds) {
1399 LOG((" bypassed, too soon"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " bypassed, too soon"
); } } while (0)
;
1400 return;
1401 }
1402
1403 mLastPurgeTime = now;
1404
1405 // We start purging memory entries first as we care more about RAM over
1406 // disk space beeing freed in case we are interrupted.
1407 Pool(MemoryPool::EType::MEMORY).PurgeExpiredOrOverMemoryLimit();
1408 Pool(MemoryPool::EType::DISK).PurgeExpiredOrOverMemoryLimit();
1409}
1410
1411void CacheStorageService::MemoryPool::PurgeExpiredOrOverMemoryLimit() {
1412 if (StaticPrefs::network_cache_purge_disable()) {
1413 return;
1414 }
1415 TimeStamp start(TimeStamp::Now());
1416
1417 uint32_t const memoryLimit = Limit();
1418 size_t minprogress =
1419 (mType == EType::DISK)
1420 ? StaticPrefs::network_cache_purge_minprogress_disk()
1421 : StaticPrefs::network_cache_purge_minprogress_memory();
1422
1423 // We always purge expired entries, even if under our limit.
1424 size_t numExpired = PurgeExpired(minprogress);
1425 if (numExpired > 0) {
1426 LOG((" found and purged %zu expired entries", numExpired))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " found and purged %zu expired entries"
, numExpired); } } while (0)
;
1427 }
1428 minprogress = (minprogress > numExpired) ? minprogress - numExpired : 0;
1429
1430 // If we are still under pressure, purge LFU entries until we aren't.
1431 if (mMemorySize > memoryLimit) {
1432 // Do not enter PurgeByFrecency if we reached the minimum and are asked to
1433 // deliver entries.
1434 if (minprogress == 0 && CacheIOThread::YieldAndRerun()) {
1435 return;
1436 }
1437
1438 auto r = PurgeByFrecency(minprogress);
1439 if (MOZ_LIKELY(r.isOk())(__builtin_expect(!!(r.isOk()), 1))) {
1440 size_t numPurged = r.unwrap();
1441 LOG((do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " memory data consumption over the limit, abandoned %zu LFU entries"
, numPurged); } } while (0)
1442 " memory data consumption over the limit, abandoned %zu LFU entries",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " memory data consumption over the limit, abandoned %zu LFU entries"
, numPurged); } } while (0)
1443 numPurged))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " memory data consumption over the limit, abandoned %zu LFU entries"
, numPurged); } } while (0)
;
1444 } else {
1445 // If we hit an error (OOM), do an emergency PurgeAll.
1446 size_t numPurged = PurgeAll(CacheEntry::PURGE_WHOLE, minprogress);
1447 LOG(do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " memory data consumption over the limit, emergency purged all %zu "
"entries", numPurged); } } while (0)
1448 (" memory data consumption over the limit, emergency purged all %zu "do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " memory data consumption over the limit, emergency purged all %zu "
"entries", numPurged); } } while (0)
1449 "entries",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " memory data consumption over the limit, emergency purged all %zu "
"entries", numPurged); } } while (0)
1450 numPurged))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " memory data consumption over the limit, emergency purged all %zu "
"entries", numPurged); } } while (0)
;
1451 }
1452 }
1453
1454 LOG((" purging took %1.2fms", (TimeStamp::Now() - start).ToMilliseconds()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " purging took %1.2fms"
, (TimeStamp::Now() - start).ToMilliseconds()); } } while (0)
;
1455}
1456
1457// This function purges ALL expired entries.
1458size_t CacheStorageService::MemoryPool::PurgeExpired(size_t minprogress) {
1459 MOZ_ASSERT(IsOnManagementThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsOnManagementThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsOnManagementThread()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsOnManagementThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1459);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsOnManagementThread()"
")"); do { MOZ_CrashSequence(__null, 1459); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1460
1461 uint32_t now = NowInSeconds()PRTimeToSeconds(PR_Now());
1462
1463 size_t numPurged = 0;
1464 // Scan for items to purge. mManagedEntries is not sorted but comparing just
1465 // one integer should be faster than anything else, so go scan.
1466 RefPtr<CacheEntry> entry = mManagedEntries.getFirst();
1467 while (entry) {
1468 // Get the next entry before we may be removed from our list.
1469 RefPtr<CacheEntry> nextEntry = entry->getNext();
1470
1471 if (entry->GetExpirationTime() <= now) {
1472 // Purge will modify our mManagedEntries list but we are prepared for it.
1473 if (entry->Purge(CacheEntry::PURGE_WHOLE)) {
1474 numPurged++;
1475 LOG((" purged expired, entry=%p, exptime=%u (now=%u)", entry.get(),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " purged expired, entry=%p, exptime=%u (now=%u)"
, entry.get(), entry->GetExpirationTime(), now); } } while
(0)
1476 entry->GetExpirationTime(), now))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " purged expired, entry=%p, exptime=%u (now=%u)"
, entry.get(), entry->GetExpirationTime(), now); } } while
(0)
;
1477 }
1478 }
1479
1480 entry = std::move(nextEntry);
1481
1482 // To have some progress even under load, we do the check only after
1483 // purging at least minprogress items if under pressure.
1484 if ((numPurged >= minprogress || mMemorySize <= Limit()) &&
1485 CacheIOThread::YieldAndRerun()) {
1486 break;
1487 }
1488 }
1489
1490 return numPurged;
1491}
1492
1493Result<size_t, nsresult> CacheStorageService::MemoryPool::PurgeByFrecency(
1494 size_t minprogress) {
1495 MOZ_ASSERT(IsOnManagementThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsOnManagementThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsOnManagementThread()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsOnManagementThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1495);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsOnManagementThread()"
")"); do { MOZ_CrashSequence(__null, 1495); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1496
1497 // Pretend the limit is 10% lower so that we get rid of more entries at one
1498 // shot and save the sorting below.
1499 uint32_t const memoryLimit = (uint32_t)(Limit() * 0.9);
1500 if (mMemorySize <= memoryLimit) {
1501 return 0;
1502 }
1503
1504 LOG(("MemoryPool::PurgeByFrecency, len=%zu", mManagedEntries.length()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "MemoryPool::PurgeByFrecency, len=%zu"
, mManagedEntries.length()); } } while (0)
;
1505
1506 // We want to have an array snapshot for sorting and iterating.
1507 struct mayPurgeEntry {
1508 RefPtr<CacheEntry> mEntry;
1509 double mFrecency;
1510
1511 explicit mayPurgeEntry(CacheEntry* aEntry) {
1512 mEntry = aEntry;
1513 mFrecency = aEntry->GetFrecency();
1514 }
1515
1516 bool operator<(const mayPurgeEntry& aOther) const {
1517 return mFrecency < aOther.mFrecency;
1518 }
1519 };
1520
1521 nsTArray<mayPurgeEntry> mayPurgeSorted;
1522 if (!mayPurgeSorted.SetCapacity(mManagedEntries.length(),
1523 mozilla::fallible)) {
1524 return Err(NS_ERROR_OUT_OF_MEMORY);
1525 }
1526 {
1527 StaticMutexAutoLock lock(CacheStorageService::Self()->Lock());
1528
1529 for (const auto& entry : mManagedEntries) {
1530 // Referenced items cannot be purged and we deliberately want to not
1531 // look at '0' frecency entries, these are new entries and can be
1532 // ignored. Also, any dict: (CompressionDictionary) entries for an
1533 // origin should not be purged unless empty - they will empty out as
1534 // the cache entries referenced by them are purged until they are empty.
1535 if (!entry->IsReferenced() && entry->GetFrecency() > 0.0 &&
1536 (!entry->GetEnhanceID().EqualsLiteral("dict:") ||
1537 entry->GetMetadataMemoryConsumption() == 0)) {
1538 mayPurgeEntry copy(entry);
1539 mayPurgeSorted.AppendElement(std::move(copy));
1540 } else {
1541 if (entry->GetEnhanceID().EqualsLiteral("dict:")) {
1542 LOG(do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Ignored Entry is a dictionary origin, metadata size %d, "
"referenced %d, Frecency %f", entry->GetMetadataMemoryConsumption
(), entry->IsReferenced(), entry->GetFrecency()); } } while
(0)
1543 ("*** Ignored Entry is a dictionary origin, metadata size %d, "do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Ignored Entry is a dictionary origin, metadata size %d, "
"referenced %d, Frecency %f", entry->GetMetadataMemoryConsumption
(), entry->IsReferenced(), entry->GetFrecency()); } } while
(0)
1544 "referenced %d, Frecency %f",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Ignored Entry is a dictionary origin, metadata size %d, "
"referenced %d, Frecency %f", entry->GetMetadataMemoryConsumption
(), entry->IsReferenced(), entry->GetFrecency()); } } while
(0)
1545 entry->GetMetadataMemoryConsumption(), entry->IsReferenced(),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Ignored Entry is a dictionary origin, metadata size %d, "
"referenced %d, Frecency %f", entry->GetMetadataMemoryConsumption
(), entry->IsReferenced(), entry->GetFrecency()); } } while
(0)
1546 entry->GetFrecency()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Ignored Entry is a dictionary origin, metadata size %d, "
"referenced %d, Frecency %f", entry->GetMetadataMemoryConsumption
(), entry->IsReferenced(), entry->GetFrecency()); } } while
(0)
;
1547 }
1548 }
1549 }
1550 }
1551 if (mayPurgeSorted.Length() == 0) {
1552 return 0;
1553 }
1554 mayPurgeSorted.Sort();
1555
1556 size_t numPurged = 0;
1557
1558 for (auto& checkPurge : mayPurgeSorted) {
1559 if (mMemorySize <= memoryLimit) {
1560 break;
1561 }
1562
1563 // Ensure it's deleted immediately if purged so we can record the
1564 // mMemorySize savings
1565 RefPtr<CacheEntry> entry = std::move(checkPurge.mEntry);
1566
1567 if (entry->Purge(CacheEntry::PURGE_WHOLE)) {
1568 numPurged++;
1569 LOG((" abandoned (%d), entry=%p, frecency=%1.10f",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " abandoned (%d), entry=%p, frecency=%1.10f"
, CacheEntry::PURGE_WHOLE, entry.get(), entry->GetFrecency
()); } } while (0)
1570 CacheEntry::PURGE_WHOLE, entry.get(), entry->GetFrecency()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " abandoned (%d), entry=%p, frecency=%1.10f"
, CacheEntry::PURGE_WHOLE, entry.get(), entry->GetFrecency
()); } } while (0)
;
1571 }
1572
1573 if (numPurged >= minprogress && CacheIOThread::YieldAndRerun()) {
1574 LOG(("MemoryPool::PurgeByFrecency interrupted"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "MemoryPool::PurgeByFrecency interrupted"
); } } while (0)
;
1575 return numPurged;
1576 }
1577 }
1578
1579 LOG(do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "MemoryPool::PurgeByFrecency done, purged %zu - mMemorySize %u, "
"memoryLimit %u", numPurged, (uint32_t)mMemorySize, memoryLimit
); } } while (0)
1580 ("MemoryPool::PurgeByFrecency done, purged %zu - mMemorySize %u, "do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "MemoryPool::PurgeByFrecency done, purged %zu - mMemorySize %u, "
"memoryLimit %u", numPurged, (uint32_t)mMemorySize, memoryLimit
); } } while (0)
1581 "memoryLimit %u",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "MemoryPool::PurgeByFrecency done, purged %zu - mMemorySize %u, "
"memoryLimit %u", numPurged, (uint32_t)mMemorySize, memoryLimit
); } } while (0)
1582 numPurged, (uint32_t)mMemorySize, memoryLimit))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "MemoryPool::PurgeByFrecency done, purged %zu - mMemorySize %u, "
"memoryLimit %u", numPurged, (uint32_t)mMemorySize, memoryLimit
); } } while (0)
;
1583
1584 return numPurged;
1585}
1586
1587size_t CacheStorageService::MemoryPool::PurgeAll(uint32_t aWhat,
1588 size_t minprogress) {
1589 LOG(("CacheStorageService::MemoryPool::PurgeAll aWhat=%d", aWhat))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::MemoryPool::PurgeAll aWhat=%d"
, aWhat); } } while (0)
;
1590 MOZ_ASSERT(IsOnManagementThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsOnManagementThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsOnManagementThread()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsOnManagementThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1590);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsOnManagementThread()"
")"); do { MOZ_CrashSequence(__null, 1590); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1591
1592 size_t numPurged = 0;
1593
1594 RefPtr<CacheEntry> entry = mManagedEntries.getFirst();
1595 while (entry) {
1596 if (numPurged >= minprogress && CacheIOThread::YieldAndRerun()) break;
1597
1598 // Get the next entry before we may be removed from our list.
1599 RefPtr<CacheEntry> nextEntry = entry->getNext();
1600
1601 if (entry->Purge(aWhat)) {
1602 numPurged++;
1603 LOG((" abandoned entry=%p", entry.get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " abandoned entry=%p"
, entry.get()); } } while (0)
;
1604 }
1605
1606 entry = std::move(nextEntry);
1607 }
1608
1609 return numPurged;
1610}
1611
1612// Methods exposed to and used by CacheStorage.
1613
1614nsresult CacheStorageService::AddStorageEntry(CacheStorage const* aStorage,
1615 nsIURI* aURI,
1616 const nsACString& aIdExtension,
1617 uint32_t aFlags,
1618 CacheEntryHandle** aResult) {
1619 NS_ENSURE_FALSE(mShutdown, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(!(mShutdown))), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!(mShutdown)" ") failed"
, nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1619); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
1620
1621 NS_ENSURE_ARG(aStorage)do { if ((__builtin_expect(!!(!(aStorage)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStorage" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1621);
return NS_ERROR_INVALID_ARG; } } while (false)
;
1622
1623 nsAutoCString contextKey;
1624 CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
1625
1626 return AddStorageEntry(contextKey, aURI, aIdExtension,
1627 aStorage->WriteToDisk(), aStorage->SkipSizeCheck(),
1628 aStorage->Pinning(), aFlags, aResult);
1629}
1630
1631nsresult CacheStorageService::AddStorageEntry(
1632 const nsACString& aContextKey, nsIURI* aURI, const nsACString& aIdExtension,
1633 bool aWriteToDisk, bool aSkipSizeCheck, bool aPin, uint32_t aFlags,
1634 CacheEntryHandle** aResult) {
1635 NS_ENSURE_ARG(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1635);
return NS_ERROR_INVALID_ARG; } } while (false)
;
1636
1637 nsresult rv;
1638
1639 nsAutoCString entryKey;
1640 rv = CacheEntry::HashingKey(""_ns, aIdExtension, aURI, entryKey);
1641 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1641); return rv; } } while (false)
;
1642
1643 LOG(("CacheStorageService::AddStorageEntry [entryKey=%s, contextKey=%s]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::AddStorageEntry [entryKey=%s, contextKey=%s]"
, entryKey.get(), TPromiseFlatString<char>(aContextKey)
.get()); } } while (0)
1644 entryKey.get(), PromiseFlatCString(aContextKey).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::AddStorageEntry [entryKey=%s, contextKey=%s]"
, entryKey.get(), TPromiseFlatString<char>(aContextKey)
.get()); } } while (0)
;
1645
1646 RefPtr<CacheEntry> entry;
1647 RefPtr<CacheEntryHandle> handle;
1648
1649 bool nvsHadCandidates = false;
1650 bool nvsMatched = false;
1651 nsAutoCString nvsMatchedRuleLabel;
1652
1653 {
1654 StaticMutexAutoLock lock(sLock);
1655
1656 NS_ENSURE_FALSE(mShutdown, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(!(mShutdown))), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!(mShutdown)" ") failed"
, nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1656); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
1657
1658 // Ensure storage table
1659 CacheEntryTable* const entries =
1660 sGlobalEntryTables
1661 ->LookupOrInsertWith(
1662 aContextKey,
1663 [&aContextKey] {
1664 LOG((" new storage entries table for context '%s'",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " new storage entries table for context '%s'"
, TPromiseFlatString<char>(aContextKey).get()); } } while
(0)
1665 PromiseFlatCString(aContextKey).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " new storage entries table for context '%s'"
, TPromiseFlatString<char>(aContextKey).get()); } } while
(0)
;
1666 return MakeUnique<CacheEntryTable>(
1667 CacheEntryTable::ALL_ENTRIES);
1668 })
1669 .get();
1670
1671 bool entryExists = entries->Get(entryKey, getter_AddRefs(entry));
1672 if (!entryExists && (aFlags & nsICacheStorage::OPEN_READONLY) &&
1673 (aFlags & nsICacheStorage::OPEN_SECRETLY) &&
1674 StaticPrefs::network_cache_bug1708673()) {
1675 return NS_ERROR_CACHE_KEY_NOT_FOUND;
1676 }
1677
1678 // No-Vary-Search secondary lookup on exact-key miss.
1679 // Implements the "equivalent modulo variation config" algorithm:
1680 // https://www.ietf.org/archive/id/draft-ietf-httpbis-no-vary-search-05.html#section-6
1681 //
1682 // On an exact-key miss, consult mNoVarySearchIndex to find cached entries
1683 // that share the same base path (scheme://host:port/path) and carry a
1684 // No-Vary-Search header. For each candidate, parse its stored NVS header
1685 // and check whether the incoming URL is equivalent to the candidate URL
1686 // under those NVS rules. The first matching candidate is used as the cache
1687 // hit. OPEN_TRUNCATE is excluded because truncation always creates a new
1688 // entry regardless of equivalence.
1689 if (StaticPrefs::network_cache_no_vary_search() && !entryExists &&
1690 !(aFlags & nsICacheStorage::OPEN_TRUNCATE)) {
1691 nsAutoCString basePath;
1692 if (NS_SUCCEEDED(ExtractNoVarySearchBasePath(aURI, basePath))((bool)(__builtin_expect(!!(!NS_FAILED_impl(ExtractNoVarySearchBasePath
(aURI, basePath))), 1)))
) {
1693 auto candidates = entries->mNoVarySearchIndex.Lookup(basePath);
1694 if (candidates) {
1695 nvsHadCandidates = true;
1696 for (const auto& fullKey : *candidates) {
1697 RefPtr<CacheEntry> candidate;
1698 if (!entries->Get(fullKey, getter_AddRefs(candidate))) {
1699 continue;
1700 }
1701
1702 if (!candidate->GetEnhanceID().Equals(aIdExtension)) {
1703 continue;
1704 }
1705
1706 nsAutoCString nvsVal;
1707 candidate->GetMetaDataElement("no-vary-search",
1708 getter_Copies(nvsVal));
1709 if (nvsVal.IsEmpty()) {
1710 continue;
1711 }
1712
1713 auto data = ParseNoVarySearchHeader(nvsVal);
1714 if (URLsAreEquivalentModuloVariationConfig(
1715 aURI, candidate->GetURI(), data)) {
1716 nvsMatched = true;
1717 nvsMatchedRuleLabel = NoVarySearchRuleLabel(data.paramsRule);
1718 entry = candidate;
1719 entryExists = true;
1720 break;
1721 }
1722 }
1723 }
1724 }
1725 }
1726
1727 if (entryExists && (aFlags & nsICacheStorage::OPEN_COMPLETE_ONLY)) {
1728 bool ready = false;
1729 // We're looking for complete files, even if they're being revalidated
1730 // (for dictionaries)
1731 entry->GetReadyOrRevalidating(&ready);
1732 if (!ready) {
1733 return NS_ERROR_CACHE_KEY_NOT_FOUND;
1734 }
1735 }
1736
1737 bool replace = aFlags & nsICacheStorage::OPEN_TRUNCATE;
1738
1739 if (entryExists && !replace) {
1740 // check whether we want to turn this entry to a memory-only.
1741 if (MOZ_UNLIKELY(!aWriteToDisk)(__builtin_expect(!!(!aWriteToDisk), 0)) && MOZ_LIKELY(entry->IsUsingDisk())(__builtin_expect(!!(entry->IsUsingDisk()), 1))) {
1742 LOG((" entry is persistent but we want mem-only, replacing it"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " entry is persistent but we want mem-only, replacing it"
); } } while (0)
;
1743 replace = true;
1744 }
1745 }
1746
1747 // If truncate is demanded, delete and doom the current entry
1748 if (entryExists && replace) {
1749 entries->Remove(entryKey);
1750
1751 LOG((" dooming entry %p for %s because of OPEN_TRUNCATE", entry.get(),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " dooming entry %p for %s because of OPEN_TRUNCATE"
, entry.get(), entryKey.get()); } } while (0)
1752 entryKey.get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " dooming entry %p for %s because of OPEN_TRUNCATE"
, entry.get(), entryKey.get()); } } while (0)
;
1753 // On purpose called under the lock to prevent races of doom and open on
1754 // I/O thread No need to remove from both memory-only and all-entries
1755 // tables. The new entry will overwrite the shadow entry in its ctor.
1756 entry->DoomAlreadyRemoved();
1757
1758 entry = nullptr;
1759 entryExists = false;
1760
1761 // Would only lead to deleting force-valid timestamp again. We don't need
1762 // the replace information anymore after this point anyway.
1763 replace = false;
1764 }
1765
1766 // Ensure entry for the particular URL
1767 if (!entryExists) {
1768 // When replacing with a new entry, always remove the current force-valid
1769 // timestamp, this is the only place to do it.
1770 if (replace) {
1771 RemoveEntryForceValid(aContextKey, entryKey);
1772 }
1773
1774 // Entry is not in the hashtable or has just been truncated...
1775 entry = new CacheEntry(aContextKey, aURI, aIdExtension, aWriteToDisk,
1776 aSkipSizeCheck, aPin);
1777 entries->InsertOrUpdate(entryKey, RefPtr{entry});
1778 LOG((" new entry %p for %s", entry.get(), entryKey.get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " new entry %p for %s"
, entry.get(), entryKey.get()); } } while (0)
;
1779 }
1780
1781 if (entry) {
1782 // Here, if this entry was not for a long time referenced by any consumer,
1783 // gets again first 'handles count' reference.
1784 handle = entry->NewHandle();
1785 }
1786 }
1787
1788 // Glean must not be called while holding sLock, so record the NVS outcome
1789 // here, after the lock has been released.
1790 if (nvsHadCandidates) {
1791 if (nvsMatched) {
1792 glean::network::no_vary_search_match.Get("matched"_ns).Add(1);
1793 glean::network::no_vary_search_hit_by_rule.Get(nvsMatchedRuleLabel)
1794 .Add(1);
1795 } else {
1796 glean::network::no_vary_search_match.Get("not_matched"_ns).Add(1);
1797 }
1798 }
1799
1800 handle.forget(aResult);
1801 return NS_OK;
1802}
1803
1804nsresult CacheStorageService::CheckStorageEntry(CacheStorage const* aStorage,
1805 nsIURI* aURI,
1806 const nsACString& aIdExtension,
1807 bool* aResult) {
1808 NS_ENSURE_ARG(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1808);
return NS_ERROR_INVALID_ARG; } } while (false)
;
1809
1810 nsresult rv;
1811
1812 nsAutoCString contextKey;
1813 CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
1814
1815 if (!aStorage->WriteToDisk()) {
1816 AppendMemoryStorageTag(contextKey);
1817 }
1818
1819 LOG(("CacheStorageService::CheckStorageEntry [uri=%s, eid=%s, contextKey=%s]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::CheckStorageEntry [uri=%s, eid=%s, contextKey=%s]"
, aURI->GetSpecOrDefault().get(), TPromiseFlatString<char
>(aIdExtension).get(), contextKey.get()); } } while (0)
1820 aURI->GetSpecOrDefault().get(), PromiseFlatCString(aIdExtension).get(),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::CheckStorageEntry [uri=%s, eid=%s, contextKey=%s]"
, aURI->GetSpecOrDefault().get(), TPromiseFlatString<char
>(aIdExtension).get(), contextKey.get()); } } while (0)
1821 contextKey.get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::CheckStorageEntry [uri=%s, eid=%s, contextKey=%s]"
, aURI->GetSpecOrDefault().get(), TPromiseFlatString<char
>(aIdExtension).get(), contextKey.get()); } } while (0)
;
1822
1823 {
1824 StaticMutexAutoLock lock(sLock);
1825
1826 NS_ENSURE_FALSE(mShutdown, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(!(mShutdown))), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!(mShutdown)" ") failed"
, nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1826); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
1827
1828 nsAutoCString entryKey;
1829 rv = CacheEntry::HashingKey(""_ns, aIdExtension, aURI, entryKey);
1830 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1830); return rv; } } while (false)
;
1831
1832 CacheEntryTable* entries;
1833 if ((*aResult = sGlobalEntryTables->Get(contextKey, &entries)) &&
1834 entries->GetWeak(entryKey, aResult)) {
1835 LOG((" found in hash tables"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " found in hash tables"
); } } while (0)
;
1836 return NS_OK;
1837 }
1838 }
1839
1840 if (!aStorage->WriteToDisk()) {
1841 // Memory entry, nothing more to do.
1842 LOG((" not found in hash tables"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " not found in hash tables"
); } } while (0)
;
1843 return NS_OK;
1844 }
1845
1846 // Disk entry, not found in the hashtable, check the index.
1847 nsAutoCString fileKey;
1848 rv = CacheEntry::HashingKey(contextKey, aIdExtension, aURI, fileKey);
Value stored to 'rv' is never read
1849
1850 CacheIndex::EntryStatus status;
1851 rv = CacheIndex::HasEntry(fileKey, &status);
1852 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || status == CacheIndex::DO_NOT_KNOW) {
1853 LOG((" index doesn't know, rv=0x%08" PRIx32, static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " index doesn't know, rv=0x%08"
"x", static_cast<uint32_t>(rv)); } } while (0)
;
1854 return NS_ERROR_NOT_AVAILABLE;
1855 }
1856
1857 *aResult = status == CacheIndex::EXISTS;
1858 LOG((" %sfound in index", *aResult ? "" : "not "))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %sfound in index"
, *aResult ? "" : "not "); } } while (0)
;
1859 return NS_OK;
1860}
1861
1862nsresult CacheStorageService::GetCacheIndexEntryAttrs(
1863 CacheStorage const* aStorage, nsIURI* aURI, const nsACString& aIdExtension,
1864 bool* aHasAltData, uint32_t* aFileSizeKb) {
1865 NS_ENSURE_ARG(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1865);
return NS_ERROR_INVALID_ARG; } } while (false)
;
1866
1867 nsresult rv;
1868
1869 nsAutoCString contextKey;
1870 CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
1871
1872 LOG(do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::GetCacheIndexEntryAttrs [uri=%s, eid=%s, "
"contextKey=%s]", aURI->GetSpecOrDefault().get(), TPromiseFlatString
<char>(aIdExtension).get(), contextKey.get()); } } while
(0)
1873 ("CacheStorageService::GetCacheIndexEntryAttrs [uri=%s, eid=%s, "do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::GetCacheIndexEntryAttrs [uri=%s, eid=%s, "
"contextKey=%s]", aURI->GetSpecOrDefault().get(), TPromiseFlatString
<char>(aIdExtension).get(), contextKey.get()); } } while
(0)
1874 "contextKey=%s]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::GetCacheIndexEntryAttrs [uri=%s, eid=%s, "
"contextKey=%s]", aURI->GetSpecOrDefault().get(), TPromiseFlatString
<char>(aIdExtension).get(), contextKey.get()); } } while
(0)
1875 aURI->GetSpecOrDefault().get(), PromiseFlatCString(aIdExtension).get(),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::GetCacheIndexEntryAttrs [uri=%s, eid=%s, "
"contextKey=%s]", aURI->GetSpecOrDefault().get(), TPromiseFlatString
<char>(aIdExtension).get(), contextKey.get()); } } while
(0)
1876 contextKey.get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::GetCacheIndexEntryAttrs [uri=%s, eid=%s, "
"contextKey=%s]", aURI->GetSpecOrDefault().get(), TPromiseFlatString
<char>(aIdExtension).get(), contextKey.get()); } } while
(0)
;
1877
1878 nsAutoCString fileKey;
1879 rv = CacheEntry::HashingKey(contextKey, aIdExtension, aURI, fileKey);
1880 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1881 return rv;
1882 }
1883
1884 *aHasAltData = false;
1885 *aFileSizeKb = 0;
1886 auto closure = [&aHasAltData, &aFileSizeKb](const CacheIndexEntry* entry) {
1887 *aHasAltData = entry->GetHasAltData();
1888 *aFileSizeKb = entry->GetFileSize();
1889 };
1890
1891 CacheIndex::EntryStatus status;
1892 rv = CacheIndex::HasEntry(fileKey, &status, closure);
1893 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1894 return rv;
1895 }
1896
1897 if (status != CacheIndex::EXISTS) {
1898 return NS_ERROR_CACHE_KEY_NOT_FOUND;
1899 }
1900
1901 return NS_OK;
1902}
1903
1904namespace {
1905
1906class CacheEntryDoomByKeyCallback : public CacheFileIOListener,
1907 public nsIRunnable {
1908 public:
1909 NS_DECL_THREADSAFE_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::true_type; protected
: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public:
1910 NS_DECL_NSIRUNNABLEvirtual nsresult Run(void) override;
1911
1912 explicit CacheEntryDoomByKeyCallback(nsICacheEntryDoomCallback* aCallback)
1913 : mCallback(aCallback), mResult(NS_ERROR_NOT_INITIALIZED) {}
1914
1915 private:
1916 virtual ~CacheEntryDoomByKeyCallback();
1917
1918 NS_IMETHODvirtual nsresult OnFileOpened(CacheFileHandle* aHandle, nsresult aResult) override {
1919 return NS_OK;
1920 }
1921 NS_IMETHODvirtual nsresult OnDataWritten(CacheFileHandle* aHandle, const char* aBuf,
1922 nsresult aResult) override {
1923 return NS_OK;
1924 }
1925 NS_IMETHODvirtual nsresult OnDataRead(CacheFileHandle* aHandle, char* aBuf,
1926 nsresult aResult) override {
1927 return NS_OK;
1928 }
1929 NS_IMETHODvirtual nsresult OnFileDoomed(CacheFileHandle* aHandle, nsresult aResult) override;
1930 NS_IMETHODvirtual nsresult OnEOFSet(CacheFileHandle* aHandle, nsresult aResult) override {
1931 return NS_OK;
1932 }
1933 NS_IMETHODvirtual nsresult OnFileRenamed(CacheFileHandle* aHandle,
1934 nsresult aResult) override {
1935 return NS_OK;
1936 }
1937
1938 nsCOMPtr<nsICacheEntryDoomCallback> mCallback;
1939 nsresult mResult;
1940};
1941
1942CacheEntryDoomByKeyCallback::~CacheEntryDoomByKeyCallback() {
1943 if (mCallback) {
1944 ProxyReleaseMainThread("CacheEntryDoomByKeyCallback::mCallback", mCallback);
1945 }
1946}
1947
1948NS_IMETHODIMPnsresult CacheEntryDoomByKeyCallback::OnFileDoomed(
1949 CacheFileHandle* aHandle, nsresult aResult) {
1950 if (!mCallback) return NS_OK;
1951
1952 mResult = aResult;
1953 if (NS_IsMainThread()) {
1954 Run();
1955 } else {
1956 NS_DispatchToMainThread(this);
1957 }
1958
1959 return NS_OK;
1960}
1961
1962NS_IMETHODIMPnsresult CacheEntryDoomByKeyCallback::Run() {
1963 mCallback->OnCacheEntryDoomed(mResult);
1964 return NS_OK;
1965}
1966
1967NS_IMPL_ISUPPORTS(CacheEntryDoomByKeyCallback, CacheFileIOListener,MozExternalRefCountType CacheEntryDoomByKeyCallback::AddRef(void
) { static_assert(!std::is_destructible_v<CacheEntryDoomByKeyCallback
>, "Reference-counted class " "CacheEntryDoomByKeyCallback"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1968
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheEntryDoomByKeyCallback" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("CacheEntryDoomByKeyCallback" != nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("\"CacheEntryDoomByKeyCallback\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheEntryDoomByKeyCallback\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1968); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("CacheEntryDoomByKeyCallback" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"CacheEntryDoomByKeyCallback"), (uint32_t)(sizeof(*this))); return
count; } MozExternalRefCountType CacheEntryDoomByKeyCallback
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1968
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheEntryDoomByKeyCallback" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("CacheEntryDoomByKeyCallback" != nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("\"CacheEntryDoomByKeyCallback\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheEntryDoomByKeyCallback\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1968); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("CacheEntryDoomByKeyCallback" " not thread-safe"
); const char* const nametmp = "CacheEntryDoomByKeyCallback";
nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult CacheEntryDoomByKeyCallback::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<CacheEntryDoomByKeyCallback, CacheFileIOListener
>, int32_t( reinterpret_cast<char*>(static_cast<CacheFileIOListener
*>((CacheEntryDoomByKeyCallback*)0x1000)) - reinterpret_cast
<char*>((CacheEntryDoomByKeyCallback*)0x1000))}, {&
mozilla::detail::kImplementedIID<CacheEntryDoomByKeyCallback
, nsIRunnable>, int32_t( reinterpret_cast<char*>(static_cast
<nsIRunnable*>((CacheEntryDoomByKeyCallback*)0x1000)) -
reinterpret_cast<char*>((CacheEntryDoomByKeyCallback*)
0x1000))}, {&mozilla::detail::kImplementedIID<CacheEntryDoomByKeyCallback
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<CacheFileIOListener*>
((CacheEntryDoomByKeyCallback*)0x1000))) - reinterpret_cast<
char*>((CacheEntryDoomByKeyCallback*)0x1000))}, { nullptr,
0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
1968 nsIRunnable)MozExternalRefCountType CacheEntryDoomByKeyCallback::AddRef(void
) { static_assert(!std::is_destructible_v<CacheEntryDoomByKeyCallback
>, "Reference-counted class " "CacheEntryDoomByKeyCallback"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1968
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheEntryDoomByKeyCallback" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("CacheEntryDoomByKeyCallback" != nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("\"CacheEntryDoomByKeyCallback\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheEntryDoomByKeyCallback\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1968); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("CacheEntryDoomByKeyCallback" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"CacheEntryDoomByKeyCallback"), (uint32_t)(sizeof(*this))); return
count; } MozExternalRefCountType CacheEntryDoomByKeyCallback
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1968
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CacheEntryDoomByKeyCallback" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("CacheEntryDoomByKeyCallback" != nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("\"CacheEntryDoomByKeyCallback\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CacheEntryDoomByKeyCallback\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1968); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("CacheEntryDoomByKeyCallback" " not thread-safe"
); const char* const nametmp = "CacheEntryDoomByKeyCallback";
nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult CacheEntryDoomByKeyCallback::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1968); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<CacheEntryDoomByKeyCallback, CacheFileIOListener
>, int32_t( reinterpret_cast<char*>(static_cast<CacheFileIOListener
*>((CacheEntryDoomByKeyCallback*)0x1000)) - reinterpret_cast
<char*>((CacheEntryDoomByKeyCallback*)0x1000))}, {&
mozilla::detail::kImplementedIID<CacheEntryDoomByKeyCallback
, nsIRunnable>, int32_t( reinterpret_cast<char*>(static_cast
<nsIRunnable*>((CacheEntryDoomByKeyCallback*)0x1000)) -
reinterpret_cast<char*>((CacheEntryDoomByKeyCallback*)
0x1000))}, {&mozilla::detail::kImplementedIID<CacheEntryDoomByKeyCallback
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<CacheFileIOListener*>
((CacheEntryDoomByKeyCallback*)0x1000))) - reinterpret_cast<
char*>((CacheEntryDoomByKeyCallback*)0x1000))}, { nullptr,
0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
;
1969
1970} // namespace
1971
1972nsresult CacheStorageService::DoomStorageEntry(
1973 CacheStorage const* aStorage, nsIURI* aURI, const nsACString& aIdExtension,
1974 nsICacheEntryDoomCallback* aCallback) {
1975 NS_ENSURE_ARG(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1975);
return NS_ERROR_INVALID_ARG; } } while (false)
;
1976
1977 LOG(("CacheStorageService::DoomStorageEntry %s",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::DoomStorageEntry %s"
, aURI->GetSpecOrDefault().get()); } } while (0)
1978 aURI->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::DoomStorageEntry %s"
, aURI->GetSpecOrDefault().get()); } } while (0)
;
1979
1980 NS_ENSURE_ARG(aStorage)do { if ((__builtin_expect(!!(!(aStorage)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStorage" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 1980);
return NS_ERROR_INVALID_ARG; } } while (false)
;
1981
1982 nsAutoCString contextKey;
1983 CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
1984
1985 nsAutoCString entryKey;
1986 nsresult rv = CacheEntry::HashingKey(""_ns, aIdExtension, aURI, entryKey);
1987 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1987); return rv; } } while (false)
;
1988
1989 RefPtr<CacheEntry> entry;
1990 {
1991 StaticMutexAutoLock lock(sLock);
1992
1993 NS_ENSURE_FALSE(mShutdown, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(!(mShutdown))), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!(mShutdown)" ") failed"
, nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 1993); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
1994
1995 CacheEntryTable* entries;
1996 if (sGlobalEntryTables->Get(contextKey, &entries)) {
1997 if (entries->Get(entryKey, getter_AddRefs(entry))) {
1998 if (aStorage->WriteToDisk() || !entry->IsUsingDisk()) {
1999 // When evicting from disk storage, purge
2000 // When evicting from memory storage and the entry is memory-only,
2001 // purge
2002 LOG(do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " purging entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
2003 (" purging entry %p for %s [storage use disk=%d, entry use "do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " purging entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
2004 "disk=%d]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " purging entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
2005 entry.get(), entryKey.get(), aStorage->WriteToDisk(),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " purging entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
2006 entry->IsUsingDisk()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " purging entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
;
2007 entries->Remove(entryKey);
2008 } else {
2009 // Otherwise, leave it
2010 LOG(do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " leaving entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
2011 (" leaving entry %p for %s [storage use disk=%d, entry use "do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " leaving entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
2012 "disk=%d]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " leaving entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
2013 entry.get(), entryKey.get(), aStorage->WriteToDisk(),do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " leaving entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
2014 entry->IsUsingDisk()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " leaving entry %p for %s [storage use disk=%d, entry use "
"disk=%d]", entry.get(), entryKey.get(), aStorage->WriteToDisk
(), entry->IsUsingDisk()); } } while (0)
;
2015 entry = nullptr;
2016 }
2017 }
2018 }
2019
2020 if (!entry) {
2021 RemoveEntryForceValid(contextKey, entryKey);
2022 }
2023 }
2024
2025 if (entry) {
2026 LOG((" dooming entry %p for %s", entry.get(), entryKey.get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " dooming entry %p for %s"
, entry.get(), entryKey.get()); } } while (0)
;
2027 return entry->AsyncDoom(aCallback);
2028 }
2029
2030 LOG((" no entry loaded for %s", entryKey.get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " no entry loaded for %s"
, entryKey.get()); } } while (0)
;
2031
2032 if (aStorage->WriteToDisk()) {
2033 nsAutoCString contextKey;
2034 CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
2035
2036 rv = CacheEntry::HashingKey(contextKey, aIdExtension, aURI, entryKey);
2037 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 2037); return rv; } } while (false)
;
2038
2039 LOG((" dooming file only for %s", entryKey.get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " dooming file only for %s"
, entryKey.get()); } } while (0)
;
2040
2041 RefPtr<CacheEntryDoomByKeyCallback> callback(
2042 new CacheEntryDoomByKeyCallback(aCallback));
2043 rv = CacheFileIOManager::DoomFileByKey(entryKey, callback);
2044 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 2044); return rv; } } while (false)
;
2045
2046 return NS_OK;
2047 }
2048
2049 class Callback : public Runnable {
2050 public:
2051 explicit Callback(nsICacheEntryDoomCallback* aCallback)
2052 : mozilla::Runnable("Callback"), mCallback(aCallback) {}
2053 NS_IMETHODvirtual nsresult Run() override {
2054 mCallback->OnCacheEntryDoomed(NS_ERROR_NOT_AVAILABLE);
2055 return NS_OK;
2056 }
2057 nsCOMPtr<nsICacheEntryDoomCallback> mCallback;
2058 };
2059
2060 if (aCallback) {
2061 RefPtr<Runnable> callback = new Callback(aCallback);
2062 return NS_DispatchToMainThread(callback);
2063 }
2064
2065 return NS_OK;
2066}
2067
2068nsresult CacheStorageService::DoomStorageEntries(
2069 CacheStorage const* aStorage, nsICacheEntryDoomCallback* aCallback) {
2070 LOG(("CacheStorageService::DoomStorageEntries"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::DoomStorageEntries"
); } } while (0)
;
2071
2072 NS_ENSURE_FALSE(mShutdown, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(!(mShutdown))), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!(mShutdown)" ") failed"
, nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 2072); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
2073 NS_ENSURE_ARG(aStorage)do { if ((__builtin_expect(!!(!(aStorage)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStorage" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 2073);
return NS_ERROR_INVALID_ARG; } } while (false)
;
2074
2075 nsAutoCString contextKey;
2076 CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
2077
2078 StaticMutexAutoLock lock(sLock);
2079
2080 return DoomStorageEntries(contextKey, aStorage->LoadInfo(),
2081 aStorage->WriteToDisk(), aStorage->Pinning(),
2082 aCallback);
2083}
2084
2085nsresult CacheStorageService::DoomStorageEntries(
2086 const nsACString& aContextKey, nsILoadContextInfo* aContext,
2087 bool aDiskStorage, bool aPinned, nsICacheEntryDoomCallback* aCallback) {
2088 LOG(("CacheStorageService::DoomStorageEntries [context=%s]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::DoomStorageEntries [context=%s]"
, TPromiseFlatString<char>(aContextKey).get()); } } while
(0)
2089 PromiseFlatCString(aContextKey).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::DoomStorageEntries [context=%s]"
, TPromiseFlatString<char>(aContextKey).get()); } } while
(0)
;
2090
2091 sLock.AssertCurrentThreadOwns();
2092
2093 NS_ENSURE_TRUE(!mShutdown, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(!mShutdown)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!mShutdown" ") failed",
nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 2093); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
2094
2095 nsAutoCString memoryStorageID(aContextKey);
2096 AppendMemoryStorageTag(memoryStorageID);
2097
2098 if (aDiskStorage) {
2099 LOG((" dooming disk+memory storage of %s",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " dooming disk+memory storage of %s"
, TPromiseFlatString<char>(aContextKey).get()); } } while
(0)
2100 PromiseFlatCString(aContextKey).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " dooming disk+memory storage of %s"
, TPromiseFlatString<char>(aContextKey).get()); } } while
(0)
;
2101
2102 // Walk one by one and remove entries according their pin status
2103 CacheEntryTable *diskEntries, *memoryEntries;
2104 if (sGlobalEntryTables->Get(aContextKey, &diskEntries)) {
2105 sGlobalEntryTables->Get(memoryStorageID, &memoryEntries);
2106
2107 for (auto iter = diskEntries->Iter(); !iter.Done(); iter.Next()) {
2108 auto entry = iter.Data();
2109 if (entry->DeferOrBypassRemovalOnPinStatus(aPinned)) {
2110 continue;
2111 }
2112
2113 if (memoryEntries) {
2114 RemoveExactEntry(memoryEntries, iter.Key(), entry, false);
2115 }
2116 diskEntries->RemoveNoVarySearchEntryByKey(iter.Key());
2117 iter.Remove();
2118 }
2119 }
2120
2121 if (aContext && !aContext->IsPrivate()) {
2122 LOG((" dooming disk entries"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " dooming disk entries"
); } } while (0)
;
2123 CacheFileIOManager::EvictByContext(aContext, aPinned, u""_ns);
2124 }
2125 } else {
2126 LOG((" dooming memory-only storage of %s",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " dooming memory-only storage of %s"
, TPromiseFlatString<char>(aContextKey).get()); } } while
(0)
2127 PromiseFlatCString(aContextKey).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " dooming memory-only storage of %s"
, TPromiseFlatString<char>(aContextKey).get()); } } while
(0)
;
2128
2129 // Remove the memory entries table from the global tables.
2130 // Since we store memory entries also in the disk entries table
2131 // we need to remove the memory entries from the disk table one
2132 // by one manually.
2133 mozilla::UniquePtr<CacheEntryTable> memoryEntries;
2134 sGlobalEntryTables->Remove(memoryStorageID, &memoryEntries);
2135
2136 CacheEntryTable* diskEntries;
2137 if (memoryEntries && sGlobalEntryTables->Get(aContextKey, &diskEntries)) {
2138 for (const auto& memoryEntry : *memoryEntries) {
2139 const auto& entry = memoryEntry.GetData();
2140 RemoveExactEntry(diskEntries, memoryEntry.GetKey(), entry, false);
2141 }
2142 }
2143 }
2144
2145 {
2146 mozilla::MutexAutoLock lock(mForcedValidEntriesLock);
2147
2148 if (aContext) {
2149 for (auto iter = mForcedValidEntries.Iter(); !iter.Done(); iter.Next()) {
2150 bool matches;
2151 DebugOnly<nsresult> rv = CacheFileUtils::KeyMatchesLoadContextInfo(
2152 iter.Key(), aContext, &matches);
2153 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../netwerk/cache2/CacheStorageService.cpp"
, 2153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2153); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2154
2155 if (matches) {
2156 iter.Remove();
2157 }
2158 }
2159 } else {
2160 mForcedValidEntries.Clear();
2161 }
2162 }
2163
2164 // An artificial callback. This is a candidate for removal tho. In the new
2165 // cache any 'doom' or 'evict' function ensures that the entry or entries
2166 // being doomed is/are not accessible after the function returns. So there is
2167 // probably no need for a callback - has no meaning. But for compatibility
2168 // with the old cache that is still in the tree we keep the API similar to be
2169 // able to make tests as well as other consumers work for now.
2170 class Callback : public Runnable {
2171 public:
2172 explicit Callback(nsICacheEntryDoomCallback* aCallback)
2173 : mozilla::Runnable("Callback"), mCallback(aCallback) {}
2174 NS_IMETHODvirtual nsresult Run() override {
2175 mCallback->OnCacheEntryDoomed(NS_OK);
2176 return NS_OK;
2177 }
2178 nsCOMPtr<nsICacheEntryDoomCallback> mCallback;
2179 };
2180
2181 if (aCallback) {
2182 RefPtr<Runnable> callback = new Callback(aCallback);
2183 return NS_DispatchToMainThread(callback);
2184 }
2185
2186 return NS_OK;
2187}
2188
2189nsresult CacheStorageService::WalkStorageEntries(
2190 CacheStorage const* aStorage, bool aVisitEntries,
2191 nsICacheStorageVisitor* aVisitor) {
2192 LOG(("CacheStorageService::WalkStorageEntries [cb=%p, visitentries=%d]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::WalkStorageEntries [cb=%p, visitentries=%d]"
, aVisitor, aVisitEntries); } } while (0)
2193 aVisitor, aVisitEntries))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::WalkStorageEntries [cb=%p, visitentries=%d]"
, aVisitor, aVisitEntries); } } while (0)
;
2194 NS_ENSURE_FALSE(mShutdown, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(!(mShutdown))), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!(mShutdown)" ") failed"
, nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 2194); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
2195
2196 NS_ENSURE_ARG(aStorage)do { if ((__builtin_expect(!!(!(aStorage)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStorage" ") failed", nullptr
, "./../../../netwerk/cache2/CacheStorageService.cpp", 2196);
return NS_ERROR_INVALID_ARG; } } while (false)
;
2197
2198 if (aStorage->WriteToDisk()) {
2199 RefPtr<CacheStorageServiceInternal::WalkDiskCacheRunnable> event =
2200 new CacheStorageServiceInternal::WalkDiskCacheRunnable(
2201 aStorage->LoadInfo(), aVisitEntries, aVisitor);
2202 return event->Walk();
2203 }
2204
2205 RefPtr<CacheStorageServiceInternal::WalkMemoryCacheRunnable> event =
2206 new CacheStorageServiceInternal::WalkMemoryCacheRunnable(
2207 aStorage->LoadInfo(), aVisitEntries, aVisitor);
2208 return event->Walk();
2209}
2210
2211void CacheStorageService::CacheFileDoomed(const nsACString& aKey,
2212 nsILoadContextInfo* aLoadContextInfo,
2213 const nsACString& aIdExtension,
2214 const nsACString& aURISpec) {
2215 nsAutoCString contextKey;
2216 CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, contextKey);
2217
2218 nsAutoCString entryKey;
2219 CacheEntry::HashingKey(""_ns, aIdExtension, aURISpec, entryKey);
2220
2221 StaticMutexAutoLock lock(sLock);
2222
2223 if (mShutdown) {
2224 return;
2225 }
2226
2227 CacheEntryTable* entries;
2228 RefPtr<CacheEntry> entry;
2229
2230 if (sGlobalEntryTables->Get(contextKey, &entries) &&
2231 entries->Get(entryKey, getter_AddRefs(entry))) {
2232 if (entry->IsFileDoomed()) {
2233 // Need to remove under the lock to avoid possible race leading
2234 // to duplication of the entry per its key.
2235 RemoveExactEntry(entries, entryKey, entry, false);
2236 entry->DoomAlreadyRemoved();
2237 }
2238
2239 // Entry found, but it's not the entry that has been found doomed
2240 // by the lower eviction layer. Just leave everything unchanged.
2241 return;
2242 }
2243
2244 RemoveEntryForceValid(contextKey, entryKey);
2245}
2246
2247bool CacheStorageService::GetCacheEntryInfo(
2248 nsILoadContextInfo* aLoadContextInfo, const nsACString& aIdExtension,
2249 const nsACString& aURISpec, EntryInfoCallback* aCallback) {
2250 nsAutoCString contextKey;
2251 CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, contextKey);
2252
2253 nsAutoCString entryKey;
2254 CacheEntry::HashingKey(""_ns, aIdExtension, aURISpec, entryKey);
2255
2256 RefPtr<CacheEntry> entry;
2257 {
2258 StaticMutexAutoLock lock(sLock);
2259
2260 if (mShutdown) {
2261 return false;
2262 }
2263
2264 CacheEntryTable* entries;
2265 if (!sGlobalEntryTables->Get(contextKey, &entries)) {
2266 return false;
2267 }
2268
2269 if (!entries->Get(entryKey, getter_AddRefs(entry))) {
2270 return false;
2271 }
2272 }
2273
2274 GetCacheEntryInfo(entry, aCallback);
2275 return true;
2276}
2277
2278// static
2279void CacheStorageService::GetCacheEntryInfo(CacheEntry* aEntry,
2280 EntryInfoCallback* aCallback) {
2281 nsAutoCString uriSpec;
2282 if (nsIURI* uri = aEntry->GetURI()) {
2283 uri->GetAsciiSpec(uriSpec);
2284 }
2285 nsCString const enhanceId = aEntry->GetEnhanceID();
2286
2287 nsAutoCString entryKey;
2288 aEntry->HashingKeyWithStorage(entryKey);
2289
2290 nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(entryKey);
2291
2292 uint32_t dataSize;
2293 if (NS_FAILED(aEntry->GetStorageDataSize(&dataSize))((bool)(__builtin_expect(!!(NS_FAILED_impl(aEntry->GetStorageDataSize
(&dataSize))), 0)))
) {
2294 dataSize = 0;
2295 }
2296 int64_t altDataSize;
2297 if (NS_FAILED(aEntry->GetAltDataSize(&altDataSize))((bool)(__builtin_expect(!!(NS_FAILED_impl(aEntry->GetAltDataSize
(&altDataSize))), 0)))
) {
2298 altDataSize = 0;
2299 }
2300 uint32_t fetchCount;
2301 if (NS_FAILED(aEntry->GetFetchCount(&fetchCount))((bool)(__builtin_expect(!!(NS_FAILED_impl(aEntry->GetFetchCount
(&fetchCount))), 0)))
) {
2302 fetchCount = 0;
2303 }
2304 uint32_t lastModified;
2305 if (NS_FAILED(aEntry->GetLastModified(&lastModified))((bool)(__builtin_expect(!!(NS_FAILED_impl(aEntry->GetLastModified
(&lastModified))), 0)))
) {
2306 lastModified = 0;
2307 }
2308 uint32_t expirationTime;
2309 if (NS_FAILED(aEntry->GetExpirationTime(&expirationTime))((bool)(__builtin_expect(!!(NS_FAILED_impl(aEntry->GetExpirationTime
(&expirationTime))), 0)))
) {
2310 expirationTime = 0;
2311 }
2312
2313 aCallback->OnEntryInfo(uriSpec, enhanceId, dataSize, altDataSize, fetchCount,
2314 lastModified, expirationTime, aEntry->IsPinned(),
2315 info);
2316}
2317
2318// static
2319uint32_t CacheStorageService::CacheQueueSize(bool highPriority) {
2320 RefPtr<CacheIOThread> thread = CacheFileIOManager::IOThread();
2321 // The thread will be null at shutdown.
2322 if (!thread) {
2323 return 0;
2324 }
2325 return thread->QueueSize(highPriority);
2326}
2327
2328// Telemetry collection
2329
2330namespace {
2331
2332bool TelemetryEntryKey(CacheEntry const* entry, nsAutoCString& key) {
2333 nsAutoCString entryKey;
2334 nsresult rv = entry->HashingKey(entryKey);
2335 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return false;
2336
2337 if (entry->GetStorageID().IsEmpty()) {
2338 // Hopefully this will be const-copied, saves some memory
2339 key = std::move(entryKey);
2340 } else {
2341 key.Assign(entry->GetStorageID());
2342 key.Append(':');
2343 key.Append(entryKey);
2344 }
2345
2346 return true;
2347}
2348
2349} // namespace
2350
2351void CacheStorageService::TelemetryPrune(TimeStamp& now) {
2352 static TimeDuration const oneMinute = TimeDuration::FromSeconds(60);
2353 static TimeStamp dontPruneUntil = now + oneMinute;
2354 if (now < dontPruneUntil) return;
2355
2356 static TimeDuration const fifteenMinutes = TimeDuration::FromSeconds(900);
2357 for (auto iter = mPurgeTimeStamps.Iter(); !iter.Done(); iter.Next()) {
2358 if (now - iter.Data() > fifteenMinutes) {
2359 // We are not interested in resurrection of entries after 15 minutes
2360 // of time. This is also the limit for the telemetry.
2361 iter.Remove();
2362 }
2363 }
2364 dontPruneUntil = now + oneMinute;
2365}
2366
2367void CacheStorageService::TelemetryRecordEntryCreation(
2368 CacheEntry const* entry) {
2369 MOZ_ASSERT(CacheStorageService::IsOnManagementThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(CacheStorageService::IsOnManagementThread())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(CacheStorageService::IsOnManagementThread()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("CacheStorageService::IsOnManagementThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 2369);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "CacheStorageService::IsOnManagementThread()"
")"); do { MOZ_CrashSequence(__null, 2369); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2370
2371 nsAutoCString key;
2372 if (!TelemetryEntryKey(entry, key)) return;
2373
2374 TimeStamp now = TimeStamp::NowLoRes();
2375 TelemetryPrune(now);
2376
2377 // When an entry is craeted (registered actually) we check if there is
2378 // a timestamp marked when this very same cache entry has been removed
2379 // (deregistered) because of over-memory-limit purging. If there is such
2380 // a timestamp found accumulate telemetry on how long the entry was away.
2381 TimeStamp timeStamp;
2382 if (!mPurgeTimeStamps.Get(key, &timeStamp)) return;
2383
2384 mPurgeTimeStamps.Remove(key);
2385
2386 glean::network::http_cache_entry_reload_time.AccumulateRawDuration(
2387 TimeStamp::NowLoRes() - timeStamp);
2388}
2389
2390void CacheStorageService::TelemetryRecordEntryRemoval(CacheEntry* entry) {
2391 MOZ_ASSERT(CacheStorageService::IsOnManagementThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(CacheStorageService::IsOnManagementThread())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(CacheStorageService::IsOnManagementThread()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("CacheStorageService::IsOnManagementThread()"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 2391);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "CacheStorageService::IsOnManagementThread()"
")"); do { MOZ_CrashSequence(__null, 2391); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2392
2393 // Doomed entries must not be considered, we are only interested in purged
2394 // entries. Note that the mIsDoomed flag is always set before deregistration
2395 // happens.
2396 if (entry->IsDoomed()) return;
2397
2398 nsAutoCString key;
2399 if (!TelemetryEntryKey(entry, key)) return;
2400
2401 // When an entry is removed (deregistered actually) we put a timestamp for
2402 // this entry to the hashtable so that when the entry is created (registered)
2403 // again we know how long it was away. Also accumulate number of AsyncOpen
2404 // calls on the entry, this tells us how efficiently the pool actually works.
2405
2406 TimeStamp now = TimeStamp::NowLoRes();
2407 TelemetryPrune(now);
2408 mPurgeTimeStamps.InsertOrUpdate(key, now);
2409
2410 glean::network::http_cache_entry_reuse_count.AccumulateSingleSample(
2411 entry->UseCount());
2412 if (Telemetry::CanRecordPrereleaseData()) {
2413 glean::network::http_cache_entry_alive_time.AccumulateRawDuration(
2414 TimeStamp::NowLoRes() - entry->LoadStart());
2415 }
2416}
2417
2418// nsIMemoryReporter
2419
2420size_t CacheStorageService::SizeOfExcludingThis(
2421 mozilla::MallocSizeOf mallocSizeOf) const {
2422 sLock.AssertCurrentThreadOwns();
2423
2424 size_t n = 0;
2425 // The elemets are referenced by sGlobalEntryTables and are reported from
2426 // there.
2427
2428 // Entries reported manually in CacheStorageService::CollectReports callback
2429 if (sGlobalEntryTables) {
2430 n += sGlobalEntryTables->ShallowSizeOfIncludingThis(mallocSizeOf);
2431 }
2432 n += mPurgeTimeStamps.SizeOfExcludingThis(mallocSizeOf);
2433
2434 return n;
2435}
2436
2437size_t CacheStorageService::SizeOfIncludingThis(
2438 mozilla::MallocSizeOf mallocSizeOf) const {
2439 return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
2440}
2441
2442NS_IMETHODIMPnsresult
2443CacheStorageService::CollectReports(nsIHandleReportCallback* aHandleReport,
2444 nsISupports* aData, bool aAnonymize) {
2445 StaticMutexAutoLock lock(sLock);
2446 MOZ_COLLECT_REPORT("explicit/network/cache2/io", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/cache2/io"
), KIND_HEAP, UNITS_BYTES, CacheFileIOManager::SizeOfIncludingThis
(MallocSizeOf), nsLiteralCString("Memory used by the cache IO manager."
), aData)
2447 CacheFileIOManager::SizeOfIncludingThis(MallocSizeOf),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/cache2/io"
), KIND_HEAP, UNITS_BYTES, CacheFileIOManager::SizeOfIncludingThis
(MallocSizeOf), nsLiteralCString("Memory used by the cache IO manager."
), aData)
2448 "Memory used by the cache IO manager.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/cache2/io"
), KIND_HEAP, UNITS_BYTES, CacheFileIOManager::SizeOfIncludingThis
(MallocSizeOf), nsLiteralCString("Memory used by the cache IO manager."
), aData)
;
2449
2450 MOZ_COLLECT_REPORT("explicit/network/cache2/index", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/cache2/index"
), KIND_HEAP, UNITS_BYTES, CacheIndex::SizeOfIncludingThis(MallocSizeOf
), nsLiteralCString("Memory used by the cache index."), aData
)
2451 CacheIndex::SizeOfIncludingThis(MallocSizeOf),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/cache2/index"
), KIND_HEAP, UNITS_BYTES, CacheIndex::SizeOfIncludingThis(MallocSizeOf
), nsLiteralCString("Memory used by the cache index."), aData
)
2452 "Memory used by the cache index.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/cache2/index"
), KIND_HEAP, UNITS_BYTES, CacheIndex::SizeOfIncludingThis(MallocSizeOf
), nsLiteralCString("Memory used by the cache index."), aData
)
;
2453
2454 // Report the service instance, this doesn't report entries, done lower
2455 MOZ_COLLECT_REPORT("explicit/network/cache2/service", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/cache2/service"
), KIND_HEAP, UNITS_BYTES, SizeOfIncludingThis(MallocSizeOf),
nsLiteralCString("Memory used by the cache storage service."
), aData)
2456 SizeOfIncludingThis(MallocSizeOf),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/cache2/service"
), KIND_HEAP, UNITS_BYTES, SizeOfIncludingThis(MallocSizeOf),
nsLiteralCString("Memory used by the cache storage service."
), aData)
2457 "Memory used by the cache storage service.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/cache2/service"
), KIND_HEAP, UNITS_BYTES, SizeOfIncludingThis(MallocSizeOf),
nsLiteralCString("Memory used by the cache storage service."
), aData)
;
2458
2459 // Report all entries, each storage separately (by the context key)
2460 //
2461 // References are:
2462 // sGlobalEntryTables to N CacheEntryTable
2463 // CacheEntryTable to N CacheEntry
2464 // CacheEntry to 1 CacheFile
2465 // CacheFile to
2466 // N CacheFileChunk (keeping the actual data)
2467 // 1 CacheFileMetadata (keeping http headers etc.)
2468 // 1 CacheFileOutputStream
2469 // N CacheFileInputStream
2470 if (sGlobalEntryTables) {
2471 for (const auto& globalEntry : *sGlobalEntryTables) {
2472 CacheStorageService::Self()->Lock().AssertCurrentThreadOwns();
2473
2474 CacheEntryTable* table = globalEntry.GetWeak();
2475
2476 size_t size = 0;
2477 mozilla::MallocSizeOf mallocSizeOf = CacheStorageService::MallocSizeOf;
2478
2479 size += table->ShallowSizeOfIncludingThis(mallocSizeOf);
2480 for (const auto& tableEntry : *table) {
2481 size += tableEntry.GetKey().SizeOfExcludingThisIfUnshared(mallocSizeOf);
2482
2483 // Bypass memory-only entries, those will be reported when iterating the
2484 // memory only table. Memory-only entries are stored in both ALL_ENTRIES
2485 // and MEMORY_ONLY hashtables.
2486 RefPtr<mozilla::net::CacheEntry> const& entry = tableEntry.GetData();
2487 if (table->Type() == CacheEntryTable::MEMORY_ONLY ||
2488 entry->IsUsingDisk()) {
2489 size += entry->SizeOfIncludingThis(mallocSizeOf);
2490 }
2491 }
2492
2493 aHandleReport->Callback(
2494 ""_ns,
2495 nsPrintfCString(
2496 "explicit/network/cache2/%s-storage(%s)",
2497 table->Type() == CacheEntryTable::MEMORY_ONLY ? "memory" : "disk",
2498 aAnonymize ? "<anonymized>"
2499 : PromiseFlatCStringTPromiseFlatString<char>(globalEntry.GetKey()).get()),
2500 nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, size,
2501 "Memory used by the cache storage."_ns, aData);
2502 }
2503 }
2504
2505 return NS_OK;
2506}
2507
2508// nsICacheTesting
2509
2510NS_IMETHODIMPnsresult
2511CacheStorageService::IOThreadSuspender::Run() {
2512 MonitorAutoLock mon(mMon);
2513 while (!mSignaled) {
2514 mon.Wait();
2515 }
2516 return NS_OK;
2517}
2518
2519void CacheStorageService::IOThreadSuspender::Notify() {
2520 MonitorAutoLock mon(mMon);
2521 mSignaled = true;
2522 mon.Notify();
2523}
2524
2525NS_IMETHODIMPnsresult
2526CacheStorageService::SuspendCacheIOThread(uint32_t aLevel) {
2527 RefPtr<CacheIOThread> thread = CacheFileIOManager::IOThread();
2528 if (!thread) {
2529 return NS_ERROR_NOT_AVAILABLE;
2530 }
2531
2532 MOZ_ASSERT(!mActiveIOSuspender)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mActiveIOSuspender)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mActiveIOSuspender))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!mActiveIOSuspender"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 2532);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mActiveIOSuspender"
")"); do { MOZ_CrashSequence(__null, 2532); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2533 mActiveIOSuspender = new IOThreadSuspender();
2534 return thread->Dispatch(mActiveIOSuspender, aLevel);
2535}
2536
2537NS_IMETHODIMPnsresult
2538CacheStorageService::ResumeCacheIOThread() {
2539 MOZ_ASSERT(mActiveIOSuspender)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mActiveIOSuspender)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mActiveIOSuspender))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mActiveIOSuspender"
, "./../../../netwerk/cache2/CacheStorageService.cpp", 2539);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mActiveIOSuspender"
")"); do { MOZ_CrashSequence(__null, 2539); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2540
2541 RefPtr<IOThreadSuspender> suspender;
2542 suspender.swap(mActiveIOSuspender);
2543 suspender->Notify();
2544 return NS_OK;
2545}
2546
2547NS_IMETHODIMPnsresult
2548CacheStorageService::Flush(nsIObserver* aObserver) {
2549 RefPtr<CacheIOThread> thread = CacheFileIOManager::IOThread();
2550 if (!thread) {
2551 return NS_ERROR_NOT_AVAILABLE;
2552 }
2553
2554 nsCOMPtr<nsIObserverService> observerService =
2555 mozilla::services::GetObserverService();
2556 if (!observerService) {
2557 return NS_ERROR_NOT_AVAILABLE;
2558 }
2559
2560 // Adding as weak, the consumer is responsible to keep the reference
2561 // until notified.
2562 observerService->AddObserver(aObserver, "cacheservice:purge-memory-pools",
2563 false);
2564
2565 // This runnable will do the purging and when done, notifies the above
2566 // observer. We dispatch it to the CLOSE level, so all data writes scheduled
2567 // up to this time will be done before this purging happens.
2568 RefPtr<CacheStorageService::PurgeFromMemoryRunnable> r =
2569 new CacheStorageService::PurgeFromMemoryRunnable(this,
2570 CacheEntry::PURGE_WHOLE);
2571
2572 return thread->Dispatch(r, CacheIOThread::WRITE);
2573}
2574
2575NS_IMETHODIMPnsresult
2576CacheStorageService::ShutdownCacheForTesting() {
2577 // Drop the in-memory entry table so that entries must be re-loaded from disk
2578 // after the simulated restart; otherwise post-restart opens would find the
2579 // original CacheEntry objects (with their data/metadata still in memory) and
2580 // never exercise the disk index rebuild / metadata reload paths.
2581 {
2582 StaticMutexAutoLock lock(sLock);
2583 if (sGlobalEntryTables) {
2584#ifdef NS_FREE_PERMANENT_DATA
2585 // Break the pending-callback prevent-release cycle before dropping the
2586 // table; ClearCallbacks() only exists in NS_FREE_PERMANENT_DATA builds.
2587 for (const auto& table : sGlobalEntryTables->Values()) {
2588 for (const auto& entry : table->Values()) {
2589 entry->ClearCallbacks();
2590 }
2591 }
2592#endif
2593 sGlobalEntryTables->Clear();
2594 }
2595 }
2596 return CacheFileIOManager::Shutdown();
2597}
2598
2599NS_IMETHODIMPnsresult
2600CacheStorageService::StartupCacheForTesting() {
2601 // ShutdownCacheForTesting() went through CacheFileIOManager::Shutdown(),
2602 // which permanently shuts the DictionaryCache down; undo that so it works
2603 // again.
2604 DictionaryCache::ResetShutdownForTesting();
2605
2606 nsresult rv = CacheFileIOManager::Init();
2607 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/cache2/CacheStorageService.cpp"
, 2607); return rv; } } while (false)
;
2608 return CacheFileIOManager::OnProfile();
2609}
2610
2611NS_IMETHODIMPnsresult
2612CacheStorageService::ClearDictionaryCacheMemory() {
2613 LOG(("CacheStorageService::ClearDictionaryCacheMemory"))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearDictionaryCacheMemory"
); } } while (0)
;
2614 RefPtr<DictionaryCache> cache = DictionaryCache::GetInstance();
2615 if (cache) {
2616 cache->Clear();
2617 }
2618 return NS_OK;
2619}
2620
2621NS_IMETHODIMPnsresult
2622CacheStorageService::CorruptDictionaryHash(const nsACString& aURI) {
2623 LOG(("CacheStorageService::CorruptDictionaryHash [uri=%s]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::CorruptDictionaryHash [uri=%s]"
, TPromiseFlatString<char>(aURI).get()); } } while (0)
2624 PromiseFlatCString(aURI).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::CorruptDictionaryHash [uri=%s]"
, TPromiseFlatString<char>(aURI).get()); } } while (0)
;
2625 RefPtr<DictionaryCache> cache = DictionaryCache::GetInstance();
2626 if (cache) {
2627 cache->CorruptHashForTesting(aURI);
2628 }
2629 return NS_OK;
2630}
2631
2632NS_IMETHODIMPnsresult
2633CacheStorageService::ClearDictionaryDataForTesting(const nsACString& aURI) {
2634 LOG(("CacheStorageService::ClearDictionaryDataForTesting [uri=%s]",do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearDictionaryDataForTesting [uri=%s]"
, TPromiseFlatString<char>(aURI).get()); } } while (0)
2635 PromiseFlatCString(aURI).get()))do { const ::mozilla::LogModule* moz_real_module = gCache2Log
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "CacheStorageService::ClearDictionaryDataForTesting [uri=%s]"
, TPromiseFlatString<char>(aURI).get()); } } while (0)
;
2636 RefPtr<DictionaryCache> cache = DictionaryCache::GetInstance();
2637 if (cache) {
2638 cache->ClearDictionaryDataForTesting(aURI);
2639 }
2640 return NS_OK;
2641}
2642
2643} // namespace mozilla::net