Bug Summary

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