Bug Summary

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