Bug Summary

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