1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/disk_cache/blockfile/rankings.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include <limits>
10*6777b538SAndroid Build Coastguard Worker #include <memory>
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/process/process.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
15*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
16*6777b538SAndroid Build Coastguard Worker #include "net/base/net_export.h"
17*6777b538SAndroid Build Coastguard Worker #include "net/disk_cache/blockfile/backend_impl.h"
18*6777b538SAndroid Build Coastguard Worker #include "net/disk_cache/blockfile/disk_format.h"
19*6777b538SAndroid Build Coastguard Worker #include "net/disk_cache/blockfile/entry_impl.h"
20*6777b538SAndroid Build Coastguard Worker #include "net/disk_cache/blockfile/errors.h"
21*6777b538SAndroid Build Coastguard Worker #include "net/disk_cache/blockfile/stress_support.h"
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
24*6777b538SAndroid Build Coastguard Worker #include <windows.h>
25*6777b538SAndroid Build Coastguard Worker #endif
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker using base::Time;
28*6777b538SAndroid Build Coastguard Worker using base::TimeTicks;
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Worker namespace disk_cache {
31*6777b538SAndroid Build Coastguard Worker // This is used by crash_cache.exe to generate unit test files.
32*6777b538SAndroid Build Coastguard Worker NET_EXPORT_PRIVATE RankCrashes g_rankings_crash = NO_CRASH;
33*6777b538SAndroid Build Coastguard Worker }
34*6777b538SAndroid Build Coastguard Worker
35*6777b538SAndroid Build Coastguard Worker namespace {
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker enum Operation {
38*6777b538SAndroid Build Coastguard Worker INSERT = 1,
39*6777b538SAndroid Build Coastguard Worker REMOVE
40*6777b538SAndroid Build Coastguard Worker };
41*6777b538SAndroid Build Coastguard Worker
42*6777b538SAndroid Build Coastguard Worker // This class provides a simple lock for the LRU list of rankings. Whenever an
43*6777b538SAndroid Build Coastguard Worker // entry is to be inserted or removed from the list, a transaction object should
44*6777b538SAndroid Build Coastguard Worker // be created to keep track of the operation. If the process crashes before
45*6777b538SAndroid Build Coastguard Worker // finishing the operation, the transaction record (stored as part of the user
46*6777b538SAndroid Build Coastguard Worker // data on the file header) can be used to finish the operation.
47*6777b538SAndroid Build Coastguard Worker class Transaction {
48*6777b538SAndroid Build Coastguard Worker public:
49*6777b538SAndroid Build Coastguard Worker // addr is the cache address of the node being inserted or removed. We want to
50*6777b538SAndroid Build Coastguard Worker // avoid having the compiler doing optimizations on when to read or write
51*6777b538SAndroid Build Coastguard Worker // from user_data because it is the basis of the crash detection. Maybe
52*6777b538SAndroid Build Coastguard Worker // volatile is not enough for that, but it should be a good hint.
53*6777b538SAndroid Build Coastguard Worker Transaction(volatile disk_cache::LruData* data, disk_cache::Addr addr,
54*6777b538SAndroid Build Coastguard Worker Operation op, int list);
55*6777b538SAndroid Build Coastguard Worker
56*6777b538SAndroid Build Coastguard Worker Transaction(const Transaction&) = delete;
57*6777b538SAndroid Build Coastguard Worker Transaction& operator=(const Transaction&) = delete;
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker ~Transaction();
60*6777b538SAndroid Build Coastguard Worker private:
61*6777b538SAndroid Build Coastguard Worker raw_ptr<volatile disk_cache::LruData> data_;
62*6777b538SAndroid Build Coastguard Worker };
63*6777b538SAndroid Build Coastguard Worker
Transaction(volatile disk_cache::LruData * data,disk_cache::Addr addr,Operation op,int list)64*6777b538SAndroid Build Coastguard Worker Transaction::Transaction(volatile disk_cache::LruData* data,
65*6777b538SAndroid Build Coastguard Worker disk_cache::Addr addr, Operation op, int list)
66*6777b538SAndroid Build Coastguard Worker : data_(data) {
67*6777b538SAndroid Build Coastguard Worker DCHECK(!data_->transaction);
68*6777b538SAndroid Build Coastguard Worker DCHECK(addr.is_initialized());
69*6777b538SAndroid Build Coastguard Worker data_->operation = op;
70*6777b538SAndroid Build Coastguard Worker data_->operation_list = list;
71*6777b538SAndroid Build Coastguard Worker data_->transaction = addr.value();
72*6777b538SAndroid Build Coastguard Worker }
73*6777b538SAndroid Build Coastguard Worker
~Transaction()74*6777b538SAndroid Build Coastguard Worker Transaction::~Transaction() {
75*6777b538SAndroid Build Coastguard Worker DCHECK(data_->transaction);
76*6777b538SAndroid Build Coastguard Worker data_->transaction = 0;
77*6777b538SAndroid Build Coastguard Worker data_->operation = 0;
78*6777b538SAndroid Build Coastguard Worker data_->operation_list = 0;
79*6777b538SAndroid Build Coastguard Worker }
80*6777b538SAndroid Build Coastguard Worker
81*6777b538SAndroid Build Coastguard Worker // Code locations that can generate crashes.
82*6777b538SAndroid Build Coastguard Worker enum CrashLocation {
83*6777b538SAndroid Build Coastguard Worker ON_INSERT_1, ON_INSERT_2, ON_INSERT_3, ON_INSERT_4, ON_REMOVE_1, ON_REMOVE_2,
84*6777b538SAndroid Build Coastguard Worker ON_REMOVE_3, ON_REMOVE_4, ON_REMOVE_5, ON_REMOVE_6, ON_REMOVE_7, ON_REMOVE_8
85*6777b538SAndroid Build Coastguard Worker };
86*6777b538SAndroid Build Coastguard Worker
87*6777b538SAndroid Build Coastguard Worker // Simulates a crash (by exiting the process without graceful shutdown) on debug
88*6777b538SAndroid Build Coastguard Worker // builds, according to the value of g_rankings_crash. This used by
89*6777b538SAndroid Build Coastguard Worker // crash_cache.exe to generate unit-test files.
GenerateCrash(CrashLocation location)90*6777b538SAndroid Build Coastguard Worker void GenerateCrash(CrashLocation location) {
91*6777b538SAndroid Build Coastguard Worker #if !defined(NDEBUG) && !BUILDFLAG(IS_IOS)
92*6777b538SAndroid Build Coastguard Worker if (disk_cache::NO_CRASH == disk_cache::g_rankings_crash)
93*6777b538SAndroid Build Coastguard Worker return;
94*6777b538SAndroid Build Coastguard Worker switch (location) {
95*6777b538SAndroid Build Coastguard Worker case ON_INSERT_1:
96*6777b538SAndroid Build Coastguard Worker switch (disk_cache::g_rankings_crash) {
97*6777b538SAndroid Build Coastguard Worker case disk_cache::INSERT_ONE_1:
98*6777b538SAndroid Build Coastguard Worker case disk_cache::INSERT_LOAD_1:
99*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
100*6777b538SAndroid Build Coastguard Worker default:
101*6777b538SAndroid Build Coastguard Worker break;
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker break;
104*6777b538SAndroid Build Coastguard Worker case ON_INSERT_2:
105*6777b538SAndroid Build Coastguard Worker if (disk_cache::INSERT_EMPTY_1 == disk_cache::g_rankings_crash)
106*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
107*6777b538SAndroid Build Coastguard Worker break;
108*6777b538SAndroid Build Coastguard Worker case ON_INSERT_3:
109*6777b538SAndroid Build Coastguard Worker switch (disk_cache::g_rankings_crash) {
110*6777b538SAndroid Build Coastguard Worker case disk_cache::INSERT_EMPTY_2:
111*6777b538SAndroid Build Coastguard Worker case disk_cache::INSERT_ONE_2:
112*6777b538SAndroid Build Coastguard Worker case disk_cache::INSERT_LOAD_2:
113*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
114*6777b538SAndroid Build Coastguard Worker default:
115*6777b538SAndroid Build Coastguard Worker break;
116*6777b538SAndroid Build Coastguard Worker }
117*6777b538SAndroid Build Coastguard Worker break;
118*6777b538SAndroid Build Coastguard Worker case ON_INSERT_4:
119*6777b538SAndroid Build Coastguard Worker switch (disk_cache::g_rankings_crash) {
120*6777b538SAndroid Build Coastguard Worker case disk_cache::INSERT_EMPTY_3:
121*6777b538SAndroid Build Coastguard Worker case disk_cache::INSERT_ONE_3:
122*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
123*6777b538SAndroid Build Coastguard Worker default:
124*6777b538SAndroid Build Coastguard Worker break;
125*6777b538SAndroid Build Coastguard Worker }
126*6777b538SAndroid Build Coastguard Worker break;
127*6777b538SAndroid Build Coastguard Worker case ON_REMOVE_1:
128*6777b538SAndroid Build Coastguard Worker switch (disk_cache::g_rankings_crash) {
129*6777b538SAndroid Build Coastguard Worker case disk_cache::REMOVE_ONE_1:
130*6777b538SAndroid Build Coastguard Worker case disk_cache::REMOVE_HEAD_1:
131*6777b538SAndroid Build Coastguard Worker case disk_cache::REMOVE_TAIL_1:
132*6777b538SAndroid Build Coastguard Worker case disk_cache::REMOVE_LOAD_1:
133*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
134*6777b538SAndroid Build Coastguard Worker default:
135*6777b538SAndroid Build Coastguard Worker break;
136*6777b538SAndroid Build Coastguard Worker }
137*6777b538SAndroid Build Coastguard Worker break;
138*6777b538SAndroid Build Coastguard Worker case ON_REMOVE_2:
139*6777b538SAndroid Build Coastguard Worker if (disk_cache::REMOVE_ONE_2 == disk_cache::g_rankings_crash)
140*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
141*6777b538SAndroid Build Coastguard Worker break;
142*6777b538SAndroid Build Coastguard Worker case ON_REMOVE_3:
143*6777b538SAndroid Build Coastguard Worker if (disk_cache::REMOVE_ONE_3 == disk_cache::g_rankings_crash)
144*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
145*6777b538SAndroid Build Coastguard Worker break;
146*6777b538SAndroid Build Coastguard Worker case ON_REMOVE_4:
147*6777b538SAndroid Build Coastguard Worker if (disk_cache::REMOVE_HEAD_2 == disk_cache::g_rankings_crash)
148*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
149*6777b538SAndroid Build Coastguard Worker break;
150*6777b538SAndroid Build Coastguard Worker case ON_REMOVE_5:
151*6777b538SAndroid Build Coastguard Worker if (disk_cache::REMOVE_TAIL_2 == disk_cache::g_rankings_crash)
152*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
153*6777b538SAndroid Build Coastguard Worker break;
154*6777b538SAndroid Build Coastguard Worker case ON_REMOVE_6:
155*6777b538SAndroid Build Coastguard Worker if (disk_cache::REMOVE_TAIL_3 == disk_cache::g_rankings_crash)
156*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
157*6777b538SAndroid Build Coastguard Worker break;
158*6777b538SAndroid Build Coastguard Worker case ON_REMOVE_7:
159*6777b538SAndroid Build Coastguard Worker switch (disk_cache::g_rankings_crash) {
160*6777b538SAndroid Build Coastguard Worker case disk_cache::REMOVE_ONE_4:
161*6777b538SAndroid Build Coastguard Worker case disk_cache::REMOVE_LOAD_2:
162*6777b538SAndroid Build Coastguard Worker case disk_cache::REMOVE_HEAD_3:
163*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
164*6777b538SAndroid Build Coastguard Worker default:
165*6777b538SAndroid Build Coastguard Worker break;
166*6777b538SAndroid Build Coastguard Worker }
167*6777b538SAndroid Build Coastguard Worker break;
168*6777b538SAndroid Build Coastguard Worker case ON_REMOVE_8:
169*6777b538SAndroid Build Coastguard Worker switch (disk_cache::g_rankings_crash) {
170*6777b538SAndroid Build Coastguard Worker case disk_cache::REMOVE_HEAD_4:
171*6777b538SAndroid Build Coastguard Worker case disk_cache::REMOVE_LOAD_3:
172*6777b538SAndroid Build Coastguard Worker base::Process::TerminateCurrentProcessImmediately(0);
173*6777b538SAndroid Build Coastguard Worker default:
174*6777b538SAndroid Build Coastguard Worker break;
175*6777b538SAndroid Build Coastguard Worker }
176*6777b538SAndroid Build Coastguard Worker break;
177*6777b538SAndroid Build Coastguard Worker default:
178*6777b538SAndroid Build Coastguard Worker NOTREACHED();
179*6777b538SAndroid Build Coastguard Worker return;
180*6777b538SAndroid Build Coastguard Worker }
181*6777b538SAndroid Build Coastguard Worker #endif // NDEBUG
182*6777b538SAndroid Build Coastguard Worker }
183*6777b538SAndroid Build Coastguard Worker
184*6777b538SAndroid Build Coastguard Worker // Update the timestamp fields of |node|.
UpdateTimes(disk_cache::CacheRankingsBlock * node,bool modified)185*6777b538SAndroid Build Coastguard Worker void UpdateTimes(disk_cache::CacheRankingsBlock* node, bool modified) {
186*6777b538SAndroid Build Coastguard Worker base::Time now = base::Time::Now();
187*6777b538SAndroid Build Coastguard Worker node->Data()->last_used = now.ToInternalValue();
188*6777b538SAndroid Build Coastguard Worker if (modified)
189*6777b538SAndroid Build Coastguard Worker node->Data()->last_modified = now.ToInternalValue();
190*6777b538SAndroid Build Coastguard Worker }
191*6777b538SAndroid Build Coastguard Worker
192*6777b538SAndroid Build Coastguard Worker } // namespace
193*6777b538SAndroid Build Coastguard Worker
194*6777b538SAndroid Build Coastguard Worker namespace disk_cache {
195*6777b538SAndroid Build Coastguard Worker
ScopedRankingsBlock()196*6777b538SAndroid Build Coastguard Worker Rankings::ScopedRankingsBlock::ScopedRankingsBlock() : rankings_(nullptr) {}
197*6777b538SAndroid Build Coastguard Worker
ScopedRankingsBlock(Rankings * rankings)198*6777b538SAndroid Build Coastguard Worker Rankings::ScopedRankingsBlock::ScopedRankingsBlock(Rankings* rankings)
199*6777b538SAndroid Build Coastguard Worker : rankings_(rankings) {}
200*6777b538SAndroid Build Coastguard Worker
ScopedRankingsBlock(Rankings * rankings,CacheRankingsBlock * node)201*6777b538SAndroid Build Coastguard Worker Rankings::ScopedRankingsBlock::ScopedRankingsBlock(Rankings* rankings,
202*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock* node)
203*6777b538SAndroid Build Coastguard Worker : std::unique_ptr<CacheRankingsBlock>(node), rankings_(rankings) {}
204*6777b538SAndroid Build Coastguard Worker
205*6777b538SAndroid Build Coastguard Worker Rankings::Iterator::Iterator() = default;
206*6777b538SAndroid Build Coastguard Worker
Reset()207*6777b538SAndroid Build Coastguard Worker void Rankings::Iterator::Reset() {
208*6777b538SAndroid Build Coastguard Worker if (my_rankings) {
209*6777b538SAndroid Build Coastguard Worker for (auto* node : nodes) {
210*6777b538SAndroid Build Coastguard Worker ScopedRankingsBlock(my_rankings, node);
211*6777b538SAndroid Build Coastguard Worker }
212*6777b538SAndroid Build Coastguard Worker }
213*6777b538SAndroid Build Coastguard Worker my_rankings = nullptr;
214*6777b538SAndroid Build Coastguard Worker nodes = {nullptr, nullptr, nullptr};
215*6777b538SAndroid Build Coastguard Worker list = List::NO_USE;
216*6777b538SAndroid Build Coastguard Worker }
217*6777b538SAndroid Build Coastguard Worker
218*6777b538SAndroid Build Coastguard Worker Rankings::Rankings() = default;
219*6777b538SAndroid Build Coastguard Worker
220*6777b538SAndroid Build Coastguard Worker Rankings::~Rankings() = default;
221*6777b538SAndroid Build Coastguard Worker
Init(BackendImpl * backend,bool count_lists)222*6777b538SAndroid Build Coastguard Worker bool Rankings::Init(BackendImpl* backend, bool count_lists) {
223*6777b538SAndroid Build Coastguard Worker DCHECK(!init_);
224*6777b538SAndroid Build Coastguard Worker if (init_)
225*6777b538SAndroid Build Coastguard Worker return false;
226*6777b538SAndroid Build Coastguard Worker
227*6777b538SAndroid Build Coastguard Worker backend_ = backend;
228*6777b538SAndroid Build Coastguard Worker control_data_ = backend_->GetLruData();
229*6777b538SAndroid Build Coastguard Worker count_lists_ = count_lists;
230*6777b538SAndroid Build Coastguard Worker
231*6777b538SAndroid Build Coastguard Worker ReadHeads();
232*6777b538SAndroid Build Coastguard Worker ReadTails();
233*6777b538SAndroid Build Coastguard Worker
234*6777b538SAndroid Build Coastguard Worker if (control_data_->transaction)
235*6777b538SAndroid Build Coastguard Worker CompleteTransaction();
236*6777b538SAndroid Build Coastguard Worker
237*6777b538SAndroid Build Coastguard Worker init_ = true;
238*6777b538SAndroid Build Coastguard Worker return true;
239*6777b538SAndroid Build Coastguard Worker }
240*6777b538SAndroid Build Coastguard Worker
Reset()241*6777b538SAndroid Build Coastguard Worker void Rankings::Reset() {
242*6777b538SAndroid Build Coastguard Worker init_ = false;
243*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < LAST_ELEMENT; i++) {
244*6777b538SAndroid Build Coastguard Worker heads_[i].set_value(0);
245*6777b538SAndroid Build Coastguard Worker tails_[i].set_value(0);
246*6777b538SAndroid Build Coastguard Worker }
247*6777b538SAndroid Build Coastguard Worker control_data_ = nullptr;
248*6777b538SAndroid Build Coastguard Worker }
249*6777b538SAndroid Build Coastguard Worker
Insert(CacheRankingsBlock * node,bool modified,List list)250*6777b538SAndroid Build Coastguard Worker void Rankings::Insert(CacheRankingsBlock* node, bool modified, List list) {
251*6777b538SAndroid Build Coastguard Worker DCHECK(node->HasData());
252*6777b538SAndroid Build Coastguard Worker Addr& my_head = heads_[list];
253*6777b538SAndroid Build Coastguard Worker Addr& my_tail = tails_[list];
254*6777b538SAndroid Build Coastguard Worker Transaction lock(control_data_, node->address(), INSERT, list);
255*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock head(backend_->File(my_head), my_head);
256*6777b538SAndroid Build Coastguard Worker if (my_head.is_initialized()) {
257*6777b538SAndroid Build Coastguard Worker if (!GetRanking(&head))
258*6777b538SAndroid Build Coastguard Worker return;
259*6777b538SAndroid Build Coastguard Worker
260*6777b538SAndroid Build Coastguard Worker if (head.Data()->prev != my_head.value() && // Normal path.
261*6777b538SAndroid Build Coastguard Worker head.Data()->prev != node->address().value()) { // FinishInsert().
262*6777b538SAndroid Build Coastguard Worker backend_->CriticalError(ERR_INVALID_LINKS);
263*6777b538SAndroid Build Coastguard Worker return;
264*6777b538SAndroid Build Coastguard Worker }
265*6777b538SAndroid Build Coastguard Worker
266*6777b538SAndroid Build Coastguard Worker head.Data()->prev = node->address().value();
267*6777b538SAndroid Build Coastguard Worker head.Store();
268*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_INSERT_1);
269*6777b538SAndroid Build Coastguard Worker UpdateIterators(&head);
270*6777b538SAndroid Build Coastguard Worker }
271*6777b538SAndroid Build Coastguard Worker
272*6777b538SAndroid Build Coastguard Worker node->Data()->next = my_head.value();
273*6777b538SAndroid Build Coastguard Worker node->Data()->prev = node->address().value();
274*6777b538SAndroid Build Coastguard Worker my_head.set_value(node->address().value());
275*6777b538SAndroid Build Coastguard Worker
276*6777b538SAndroid Build Coastguard Worker if (!my_tail.is_initialized() || my_tail.value() == node->address().value()) {
277*6777b538SAndroid Build Coastguard Worker my_tail.set_value(node->address().value());
278*6777b538SAndroid Build Coastguard Worker node->Data()->next = my_tail.value();
279*6777b538SAndroid Build Coastguard Worker WriteTail(list);
280*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_INSERT_2);
281*6777b538SAndroid Build Coastguard Worker }
282*6777b538SAndroid Build Coastguard Worker
283*6777b538SAndroid Build Coastguard Worker UpdateTimes(node, modified);
284*6777b538SAndroid Build Coastguard Worker node->Store();
285*6777b538SAndroid Build Coastguard Worker // Make sure other aliased in-memory copies get synchronized.
286*6777b538SAndroid Build Coastguard Worker UpdateIterators(node);
287*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_INSERT_3);
288*6777b538SAndroid Build Coastguard Worker
289*6777b538SAndroid Build Coastguard Worker // The last thing to do is move our head to point to a node already stored.
290*6777b538SAndroid Build Coastguard Worker WriteHead(list);
291*6777b538SAndroid Build Coastguard Worker IncrementCounter(list);
292*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_INSERT_4);
293*6777b538SAndroid Build Coastguard Worker backend_->FlushIndex();
294*6777b538SAndroid Build Coastguard Worker }
295*6777b538SAndroid Build Coastguard Worker
296*6777b538SAndroid Build Coastguard Worker // If a, b and r are elements on the list, and we want to remove r, the possible
297*6777b538SAndroid Build Coastguard Worker // states for the objects if a crash happens are (where y(x, z) means for object
298*6777b538SAndroid Build Coastguard Worker // y, prev is x and next is z):
299*6777b538SAndroid Build Coastguard Worker // A. One element:
300*6777b538SAndroid Build Coastguard Worker // 1. r(r, r), head(r), tail(r) initial state
301*6777b538SAndroid Build Coastguard Worker // 2. r(r, r), head(0), tail(r) WriteHead()
302*6777b538SAndroid Build Coastguard Worker // 3. r(r, r), head(0), tail(0) WriteTail()
303*6777b538SAndroid Build Coastguard Worker // 4. r(0, 0), head(0), tail(0) next.Store()
304*6777b538SAndroid Build Coastguard Worker //
305*6777b538SAndroid Build Coastguard Worker // B. Remove a random element:
306*6777b538SAndroid Build Coastguard Worker // 1. a(x, r), r(a, b), b(r, y), head(x), tail(y) initial state
307*6777b538SAndroid Build Coastguard Worker // 2. a(x, r), r(a, b), b(a, y), head(x), tail(y) next.Store()
308*6777b538SAndroid Build Coastguard Worker // 3. a(x, b), r(a, b), b(a, y), head(x), tail(y) prev.Store()
309*6777b538SAndroid Build Coastguard Worker // 4. a(x, b), r(0, 0), b(a, y), head(x), tail(y) node.Store()
310*6777b538SAndroid Build Coastguard Worker //
311*6777b538SAndroid Build Coastguard Worker // C. Remove head:
312*6777b538SAndroid Build Coastguard Worker // 1. r(r, b), b(r, y), head(r), tail(y) initial state
313*6777b538SAndroid Build Coastguard Worker // 2. r(r, b), b(r, y), head(b), tail(y) WriteHead()
314*6777b538SAndroid Build Coastguard Worker // 3. r(r, b), b(b, y), head(b), tail(y) next.Store()
315*6777b538SAndroid Build Coastguard Worker // 4. r(0, 0), b(b, y), head(b), tail(y) prev.Store()
316*6777b538SAndroid Build Coastguard Worker //
317*6777b538SAndroid Build Coastguard Worker // D. Remove tail:
318*6777b538SAndroid Build Coastguard Worker // 1. a(x, r), r(a, r), head(x), tail(r) initial state
319*6777b538SAndroid Build Coastguard Worker // 2. a(x, r), r(a, r), head(x), tail(a) WriteTail()
320*6777b538SAndroid Build Coastguard Worker // 3. a(x, a), r(a, r), head(x), tail(a) prev.Store()
321*6777b538SAndroid Build Coastguard Worker // 4. a(x, a), r(0, 0), head(x), tail(a) next.Store()
Remove(CacheRankingsBlock * node,List list,bool strict)322*6777b538SAndroid Build Coastguard Worker void Rankings::Remove(CacheRankingsBlock* node, List list, bool strict) {
323*6777b538SAndroid Build Coastguard Worker DCHECK(node->HasData());
324*6777b538SAndroid Build Coastguard Worker
325*6777b538SAndroid Build Coastguard Worker Addr next_addr(node->Data()->next);
326*6777b538SAndroid Build Coastguard Worker Addr prev_addr(node->Data()->prev);
327*6777b538SAndroid Build Coastguard Worker if (!next_addr.is_initialized() || next_addr.is_separate_file() ||
328*6777b538SAndroid Build Coastguard Worker !prev_addr.is_initialized() || prev_addr.is_separate_file()) {
329*6777b538SAndroid Build Coastguard Worker if (next_addr.is_initialized() || prev_addr.is_initialized()) {
330*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Invalid rankings info.";
331*6777b538SAndroid Build Coastguard Worker STRESS_NOTREACHED();
332*6777b538SAndroid Build Coastguard Worker }
333*6777b538SAndroid Build Coastguard Worker return;
334*6777b538SAndroid Build Coastguard Worker }
335*6777b538SAndroid Build Coastguard Worker
336*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock next(backend_->File(next_addr), next_addr);
337*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr);
338*6777b538SAndroid Build Coastguard Worker if (!GetRanking(&next) || !GetRanking(&prev)) {
339*6777b538SAndroid Build Coastguard Worker STRESS_NOTREACHED();
340*6777b538SAndroid Build Coastguard Worker return;
341*6777b538SAndroid Build Coastguard Worker }
342*6777b538SAndroid Build Coastguard Worker
343*6777b538SAndroid Build Coastguard Worker if (!CheckLinks(node, &prev, &next, &list))
344*6777b538SAndroid Build Coastguard Worker return;
345*6777b538SAndroid Build Coastguard Worker
346*6777b538SAndroid Build Coastguard Worker Transaction lock(control_data_, node->address(), REMOVE, list);
347*6777b538SAndroid Build Coastguard Worker prev.Data()->next = next.address().value();
348*6777b538SAndroid Build Coastguard Worker next.Data()->prev = prev.address().value();
349*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_REMOVE_1);
350*6777b538SAndroid Build Coastguard Worker
351*6777b538SAndroid Build Coastguard Worker CacheAddr node_value = node->address().value();
352*6777b538SAndroid Build Coastguard Worker Addr& my_head = heads_[list];
353*6777b538SAndroid Build Coastguard Worker Addr& my_tail = tails_[list];
354*6777b538SAndroid Build Coastguard Worker if (node_value == my_head.value() || node_value == my_tail.value()) {
355*6777b538SAndroid Build Coastguard Worker if (my_head.value() == my_tail.value()) {
356*6777b538SAndroid Build Coastguard Worker my_head.set_value(0);
357*6777b538SAndroid Build Coastguard Worker my_tail.set_value(0);
358*6777b538SAndroid Build Coastguard Worker
359*6777b538SAndroid Build Coastguard Worker WriteHead(list);
360*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_REMOVE_2);
361*6777b538SAndroid Build Coastguard Worker WriteTail(list);
362*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_REMOVE_3);
363*6777b538SAndroid Build Coastguard Worker } else if (node_value == my_head.value()) {
364*6777b538SAndroid Build Coastguard Worker my_head.set_value(next.address().value());
365*6777b538SAndroid Build Coastguard Worker next.Data()->prev = next.address().value();
366*6777b538SAndroid Build Coastguard Worker
367*6777b538SAndroid Build Coastguard Worker WriteHead(list);
368*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_REMOVE_4);
369*6777b538SAndroid Build Coastguard Worker } else if (node_value == my_tail.value()) {
370*6777b538SAndroid Build Coastguard Worker my_tail.set_value(prev.address().value());
371*6777b538SAndroid Build Coastguard Worker prev.Data()->next = prev.address().value();
372*6777b538SAndroid Build Coastguard Worker
373*6777b538SAndroid Build Coastguard Worker WriteTail(list);
374*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_REMOVE_5);
375*6777b538SAndroid Build Coastguard Worker
376*6777b538SAndroid Build Coastguard Worker // Store the new tail to make sure we can undo the operation if we crash.
377*6777b538SAndroid Build Coastguard Worker prev.Store();
378*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_REMOVE_6);
379*6777b538SAndroid Build Coastguard Worker }
380*6777b538SAndroid Build Coastguard Worker }
381*6777b538SAndroid Build Coastguard Worker
382*6777b538SAndroid Build Coastguard Worker // Nodes out of the list can be identified by invalid pointers.
383*6777b538SAndroid Build Coastguard Worker node->Data()->next = 0;
384*6777b538SAndroid Build Coastguard Worker node->Data()->prev = 0;
385*6777b538SAndroid Build Coastguard Worker
386*6777b538SAndroid Build Coastguard Worker // The last thing to get to disk is the node itself, so before that there is
387*6777b538SAndroid Build Coastguard Worker // enough info to recover.
388*6777b538SAndroid Build Coastguard Worker next.Store();
389*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_REMOVE_7);
390*6777b538SAndroid Build Coastguard Worker prev.Store();
391*6777b538SAndroid Build Coastguard Worker GenerateCrash(ON_REMOVE_8);
392*6777b538SAndroid Build Coastguard Worker node->Store();
393*6777b538SAndroid Build Coastguard Worker DecrementCounter(list);
394*6777b538SAndroid Build Coastguard Worker if (strict)
395*6777b538SAndroid Build Coastguard Worker UpdateIteratorsForRemoved(node_value, &next);
396*6777b538SAndroid Build Coastguard Worker
397*6777b538SAndroid Build Coastguard Worker UpdateIterators(&next);
398*6777b538SAndroid Build Coastguard Worker UpdateIterators(&prev);
399*6777b538SAndroid Build Coastguard Worker backend_->FlushIndex();
400*6777b538SAndroid Build Coastguard Worker }
401*6777b538SAndroid Build Coastguard Worker
402*6777b538SAndroid Build Coastguard Worker // A crash in between Remove and Insert will lead to a dirty entry not on the
403*6777b538SAndroid Build Coastguard Worker // list. We want to avoid that case as much as we can (as while waiting for IO),
404*6777b538SAndroid Build Coastguard Worker // but the net effect is just an assert on debug when attempting to remove the
405*6777b538SAndroid Build Coastguard Worker // entry. Otherwise we'll need reentrant transactions, which is an overkill.
UpdateRank(CacheRankingsBlock * node,bool modified,List list)406*6777b538SAndroid Build Coastguard Worker void Rankings::UpdateRank(CacheRankingsBlock* node, bool modified, List list) {
407*6777b538SAndroid Build Coastguard Worker Addr& my_head = heads_[list];
408*6777b538SAndroid Build Coastguard Worker if (my_head.value() == node->address().value()) {
409*6777b538SAndroid Build Coastguard Worker UpdateTimes(node, modified);
410*6777b538SAndroid Build Coastguard Worker node->set_modified();
411*6777b538SAndroid Build Coastguard Worker return;
412*6777b538SAndroid Build Coastguard Worker }
413*6777b538SAndroid Build Coastguard Worker
414*6777b538SAndroid Build Coastguard Worker Remove(node, list, true);
415*6777b538SAndroid Build Coastguard Worker Insert(node, modified, list);
416*6777b538SAndroid Build Coastguard Worker }
417*6777b538SAndroid Build Coastguard Worker
GetNext(CacheRankingsBlock * node,List list)418*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock* Rankings::GetNext(CacheRankingsBlock* node, List list) {
419*6777b538SAndroid Build Coastguard Worker ScopedRankingsBlock next(this);
420*6777b538SAndroid Build Coastguard Worker if (!node) {
421*6777b538SAndroid Build Coastguard Worker Addr& my_head = heads_[list];
422*6777b538SAndroid Build Coastguard Worker if (!my_head.is_initialized())
423*6777b538SAndroid Build Coastguard Worker return nullptr;
424*6777b538SAndroid Build Coastguard Worker next.reset(new CacheRankingsBlock(backend_->File(my_head), my_head));
425*6777b538SAndroid Build Coastguard Worker } else {
426*6777b538SAndroid Build Coastguard Worker if (!node->HasData())
427*6777b538SAndroid Build Coastguard Worker node->Load();
428*6777b538SAndroid Build Coastguard Worker Addr& my_tail = tails_[list];
429*6777b538SAndroid Build Coastguard Worker if (!my_tail.is_initialized())
430*6777b538SAndroid Build Coastguard Worker return nullptr;
431*6777b538SAndroid Build Coastguard Worker if (my_tail.value() == node->address().value())
432*6777b538SAndroid Build Coastguard Worker return nullptr;
433*6777b538SAndroid Build Coastguard Worker Addr address(node->Data()->next);
434*6777b538SAndroid Build Coastguard Worker if (address.value() == node->address().value())
435*6777b538SAndroid Build Coastguard Worker return nullptr; // Another tail? fail it.
436*6777b538SAndroid Build Coastguard Worker next.reset(new CacheRankingsBlock(backend_->File(address), address));
437*6777b538SAndroid Build Coastguard Worker }
438*6777b538SAndroid Build Coastguard Worker
439*6777b538SAndroid Build Coastguard Worker TrackRankingsBlock(next.get(), true);
440*6777b538SAndroid Build Coastguard Worker
441*6777b538SAndroid Build Coastguard Worker if (!GetRanking(next.get()))
442*6777b538SAndroid Build Coastguard Worker return nullptr;
443*6777b538SAndroid Build Coastguard Worker
444*6777b538SAndroid Build Coastguard Worker ConvertToLongLived(next.get());
445*6777b538SAndroid Build Coastguard Worker if (node && !CheckSingleLink(node, next.get()))
446*6777b538SAndroid Build Coastguard Worker return nullptr;
447*6777b538SAndroid Build Coastguard Worker
448*6777b538SAndroid Build Coastguard Worker return next.release();
449*6777b538SAndroid Build Coastguard Worker }
450*6777b538SAndroid Build Coastguard Worker
GetPrev(CacheRankingsBlock * node,List list)451*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock* Rankings::GetPrev(CacheRankingsBlock* node, List list) {
452*6777b538SAndroid Build Coastguard Worker ScopedRankingsBlock prev(this);
453*6777b538SAndroid Build Coastguard Worker if (!node) {
454*6777b538SAndroid Build Coastguard Worker Addr& my_tail = tails_[list];
455*6777b538SAndroid Build Coastguard Worker if (!my_tail.is_initialized())
456*6777b538SAndroid Build Coastguard Worker return nullptr;
457*6777b538SAndroid Build Coastguard Worker prev.reset(new CacheRankingsBlock(backend_->File(my_tail), my_tail));
458*6777b538SAndroid Build Coastguard Worker } else {
459*6777b538SAndroid Build Coastguard Worker if (!node->HasData())
460*6777b538SAndroid Build Coastguard Worker node->Load();
461*6777b538SAndroid Build Coastguard Worker Addr& my_head = heads_[list];
462*6777b538SAndroid Build Coastguard Worker if (!my_head.is_initialized())
463*6777b538SAndroid Build Coastguard Worker return nullptr;
464*6777b538SAndroid Build Coastguard Worker if (my_head.value() == node->address().value())
465*6777b538SAndroid Build Coastguard Worker return nullptr;
466*6777b538SAndroid Build Coastguard Worker Addr address(node->Data()->prev);
467*6777b538SAndroid Build Coastguard Worker if (address.value() == node->address().value())
468*6777b538SAndroid Build Coastguard Worker return nullptr; // Another head? fail it.
469*6777b538SAndroid Build Coastguard Worker prev.reset(new CacheRankingsBlock(backend_->File(address), address));
470*6777b538SAndroid Build Coastguard Worker }
471*6777b538SAndroid Build Coastguard Worker
472*6777b538SAndroid Build Coastguard Worker TrackRankingsBlock(prev.get(), true);
473*6777b538SAndroid Build Coastguard Worker
474*6777b538SAndroid Build Coastguard Worker if (!GetRanking(prev.get()))
475*6777b538SAndroid Build Coastguard Worker return nullptr;
476*6777b538SAndroid Build Coastguard Worker
477*6777b538SAndroid Build Coastguard Worker ConvertToLongLived(prev.get());
478*6777b538SAndroid Build Coastguard Worker if (node && !CheckSingleLink(prev.get(), node))
479*6777b538SAndroid Build Coastguard Worker return nullptr;
480*6777b538SAndroid Build Coastguard Worker
481*6777b538SAndroid Build Coastguard Worker return prev.release();
482*6777b538SAndroid Build Coastguard Worker }
483*6777b538SAndroid Build Coastguard Worker
FreeRankingsBlock(CacheRankingsBlock * node)484*6777b538SAndroid Build Coastguard Worker void Rankings::FreeRankingsBlock(CacheRankingsBlock* node) {
485*6777b538SAndroid Build Coastguard Worker TrackRankingsBlock(node, false);
486*6777b538SAndroid Build Coastguard Worker }
487*6777b538SAndroid Build Coastguard Worker
TrackRankingsBlock(CacheRankingsBlock * node,bool start_tracking)488*6777b538SAndroid Build Coastguard Worker void Rankings::TrackRankingsBlock(CacheRankingsBlock* node,
489*6777b538SAndroid Build Coastguard Worker bool start_tracking) {
490*6777b538SAndroid Build Coastguard Worker if (!node)
491*6777b538SAndroid Build Coastguard Worker return;
492*6777b538SAndroid Build Coastguard Worker
493*6777b538SAndroid Build Coastguard Worker IteratorPair current(node->address().value(), node);
494*6777b538SAndroid Build Coastguard Worker
495*6777b538SAndroid Build Coastguard Worker if (start_tracking)
496*6777b538SAndroid Build Coastguard Worker iterators_.push_back(current);
497*6777b538SAndroid Build Coastguard Worker else
498*6777b538SAndroid Build Coastguard Worker iterators_.remove(current);
499*6777b538SAndroid Build Coastguard Worker }
500*6777b538SAndroid Build Coastguard Worker
SelfCheck()501*6777b538SAndroid Build Coastguard Worker int Rankings::SelfCheck() {
502*6777b538SAndroid Build Coastguard Worker int total = 0;
503*6777b538SAndroid Build Coastguard Worker int error = 0;
504*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < LAST_ELEMENT; i++) {
505*6777b538SAndroid Build Coastguard Worker int partial = CheckList(static_cast<List>(i));
506*6777b538SAndroid Build Coastguard Worker if (partial < 0 && !error)
507*6777b538SAndroid Build Coastguard Worker error = partial;
508*6777b538SAndroid Build Coastguard Worker else if (partial > 0)
509*6777b538SAndroid Build Coastguard Worker total += partial;
510*6777b538SAndroid Build Coastguard Worker }
511*6777b538SAndroid Build Coastguard Worker
512*6777b538SAndroid Build Coastguard Worker return error ? error : total;
513*6777b538SAndroid Build Coastguard Worker }
514*6777b538SAndroid Build Coastguard Worker
SanityCheck(CacheRankingsBlock * node,bool from_list) const515*6777b538SAndroid Build Coastguard Worker bool Rankings::SanityCheck(CacheRankingsBlock* node, bool from_list) const {
516*6777b538SAndroid Build Coastguard Worker if (!node->VerifyHash())
517*6777b538SAndroid Build Coastguard Worker return false;
518*6777b538SAndroid Build Coastguard Worker
519*6777b538SAndroid Build Coastguard Worker const RankingsNode* data = node->Data();
520*6777b538SAndroid Build Coastguard Worker
521*6777b538SAndroid Build Coastguard Worker if ((!data->next && data->prev) || (data->next && !data->prev))
522*6777b538SAndroid Build Coastguard Worker return false;
523*6777b538SAndroid Build Coastguard Worker
524*6777b538SAndroid Build Coastguard Worker // Both pointers on zero is a node out of the list.
525*6777b538SAndroid Build Coastguard Worker if (!data->next && !data->prev && from_list)
526*6777b538SAndroid Build Coastguard Worker return false;
527*6777b538SAndroid Build Coastguard Worker
528*6777b538SAndroid Build Coastguard Worker List list = NO_USE; // Initialize it to something.
529*6777b538SAndroid Build Coastguard Worker if ((node->address().value() == data->prev) && !IsHead(data->prev, &list))
530*6777b538SAndroid Build Coastguard Worker return false;
531*6777b538SAndroid Build Coastguard Worker
532*6777b538SAndroid Build Coastguard Worker if ((node->address().value() == data->next) && !IsTail(data->next, &list))
533*6777b538SAndroid Build Coastguard Worker return false;
534*6777b538SAndroid Build Coastguard Worker
535*6777b538SAndroid Build Coastguard Worker if (!data->next && !data->prev)
536*6777b538SAndroid Build Coastguard Worker return true;
537*6777b538SAndroid Build Coastguard Worker
538*6777b538SAndroid Build Coastguard Worker Addr next_addr(data->next);
539*6777b538SAndroid Build Coastguard Worker Addr prev_addr(data->prev);
540*6777b538SAndroid Build Coastguard Worker if (!next_addr.SanityCheck() || next_addr.file_type() != RANKINGS ||
541*6777b538SAndroid Build Coastguard Worker !prev_addr.SanityCheck() || prev_addr.file_type() != RANKINGS)
542*6777b538SAndroid Build Coastguard Worker return false;
543*6777b538SAndroid Build Coastguard Worker
544*6777b538SAndroid Build Coastguard Worker return true;
545*6777b538SAndroid Build Coastguard Worker }
546*6777b538SAndroid Build Coastguard Worker
DataSanityCheck(CacheRankingsBlock * node,bool from_list) const547*6777b538SAndroid Build Coastguard Worker bool Rankings::DataSanityCheck(CacheRankingsBlock* node, bool from_list) const {
548*6777b538SAndroid Build Coastguard Worker const RankingsNode* data = node->Data();
549*6777b538SAndroid Build Coastguard Worker if (!data->contents)
550*6777b538SAndroid Build Coastguard Worker return false;
551*6777b538SAndroid Build Coastguard Worker
552*6777b538SAndroid Build Coastguard Worker // It may have never been inserted.
553*6777b538SAndroid Build Coastguard Worker if (from_list && (!data->last_used || !data->last_modified))
554*6777b538SAndroid Build Coastguard Worker return false;
555*6777b538SAndroid Build Coastguard Worker
556*6777b538SAndroid Build Coastguard Worker return true;
557*6777b538SAndroid Build Coastguard Worker }
558*6777b538SAndroid Build Coastguard Worker
SetContents(CacheRankingsBlock * node,CacheAddr address)559*6777b538SAndroid Build Coastguard Worker void Rankings::SetContents(CacheRankingsBlock* node, CacheAddr address) {
560*6777b538SAndroid Build Coastguard Worker node->Data()->contents = address;
561*6777b538SAndroid Build Coastguard Worker node->Store();
562*6777b538SAndroid Build Coastguard Worker }
563*6777b538SAndroid Build Coastguard Worker
ReadHeads()564*6777b538SAndroid Build Coastguard Worker void Rankings::ReadHeads() {
565*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < LAST_ELEMENT; i++)
566*6777b538SAndroid Build Coastguard Worker heads_[i] = Addr(control_data_->heads[i]);
567*6777b538SAndroid Build Coastguard Worker }
568*6777b538SAndroid Build Coastguard Worker
ReadTails()569*6777b538SAndroid Build Coastguard Worker void Rankings::ReadTails() {
570*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < LAST_ELEMENT; i++)
571*6777b538SAndroid Build Coastguard Worker tails_[i] = Addr(control_data_->tails[i]);
572*6777b538SAndroid Build Coastguard Worker }
573*6777b538SAndroid Build Coastguard Worker
WriteHead(List list)574*6777b538SAndroid Build Coastguard Worker void Rankings::WriteHead(List list) {
575*6777b538SAndroid Build Coastguard Worker control_data_->heads[list] = heads_[list].value();
576*6777b538SAndroid Build Coastguard Worker }
577*6777b538SAndroid Build Coastguard Worker
WriteTail(List list)578*6777b538SAndroid Build Coastguard Worker void Rankings::WriteTail(List list) {
579*6777b538SAndroid Build Coastguard Worker control_data_->tails[list] = tails_[list].value();
580*6777b538SAndroid Build Coastguard Worker }
581*6777b538SAndroid Build Coastguard Worker
GetRanking(CacheRankingsBlock * rankings)582*6777b538SAndroid Build Coastguard Worker bool Rankings::GetRanking(CacheRankingsBlock* rankings) {
583*6777b538SAndroid Build Coastguard Worker if (!rankings->address().is_initialized())
584*6777b538SAndroid Build Coastguard Worker return false;
585*6777b538SAndroid Build Coastguard Worker
586*6777b538SAndroid Build Coastguard Worker if (!rankings->Load())
587*6777b538SAndroid Build Coastguard Worker return false;
588*6777b538SAndroid Build Coastguard Worker
589*6777b538SAndroid Build Coastguard Worker if (!SanityCheck(rankings, true)) {
590*6777b538SAndroid Build Coastguard Worker backend_->CriticalError(ERR_INVALID_LINKS);
591*6777b538SAndroid Build Coastguard Worker return false;
592*6777b538SAndroid Build Coastguard Worker }
593*6777b538SAndroid Build Coastguard Worker
594*6777b538SAndroid Build Coastguard Worker backend_->OnEvent(Stats::OPEN_RANKINGS);
595*6777b538SAndroid Build Coastguard Worker
596*6777b538SAndroid Build Coastguard Worker // Note that if the cache is in read_only mode, open entries are not marked
597*6777b538SAndroid Build Coastguard Worker // as dirty, except when an entry is doomed. We have to look for open entries.
598*6777b538SAndroid Build Coastguard Worker if (!backend_->read_only() && !rankings->Data()->dirty)
599*6777b538SAndroid Build Coastguard Worker return true;
600*6777b538SAndroid Build Coastguard Worker
601*6777b538SAndroid Build Coastguard Worker EntryImpl* entry = backend_->GetOpenEntry(rankings);
602*6777b538SAndroid Build Coastguard Worker if (!entry) {
603*6777b538SAndroid Build Coastguard Worker if (backend_->read_only())
604*6777b538SAndroid Build Coastguard Worker return true;
605*6777b538SAndroid Build Coastguard Worker
606*6777b538SAndroid Build Coastguard Worker // We cannot trust this entry, but we cannot initiate a cleanup from this
607*6777b538SAndroid Build Coastguard Worker // point (we may be in the middle of a cleanup already). The entry will be
608*6777b538SAndroid Build Coastguard Worker // deleted when detected from a regular open/create path.
609*6777b538SAndroid Build Coastguard Worker rankings->Data()->dirty = backend_->GetCurrentEntryId() - 1;
610*6777b538SAndroid Build Coastguard Worker if (!rankings->Data()->dirty)
611*6777b538SAndroid Build Coastguard Worker rankings->Data()->dirty--;
612*6777b538SAndroid Build Coastguard Worker return true;
613*6777b538SAndroid Build Coastguard Worker }
614*6777b538SAndroid Build Coastguard Worker
615*6777b538SAndroid Build Coastguard Worker // Note that we should not leave this module without deleting rankings first.
616*6777b538SAndroid Build Coastguard Worker rankings->SetData(entry->rankings()->Data());
617*6777b538SAndroid Build Coastguard Worker
618*6777b538SAndroid Build Coastguard Worker return true;
619*6777b538SAndroid Build Coastguard Worker }
620*6777b538SAndroid Build Coastguard Worker
ConvertToLongLived(CacheRankingsBlock * rankings)621*6777b538SAndroid Build Coastguard Worker void Rankings::ConvertToLongLived(CacheRankingsBlock* rankings) {
622*6777b538SAndroid Build Coastguard Worker if (rankings->own_data())
623*6777b538SAndroid Build Coastguard Worker return;
624*6777b538SAndroid Build Coastguard Worker
625*6777b538SAndroid Build Coastguard Worker // We cannot return a shared node because we are not keeping a reference
626*6777b538SAndroid Build Coastguard Worker // to the entry that owns the buffer. Make this node a copy of the one that
627*6777b538SAndroid Build Coastguard Worker // we have, and let the iterator logic update it when the entry changes.
628*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock temp(nullptr, Addr(0));
629*6777b538SAndroid Build Coastguard Worker *temp.Data() = *rankings->Data();
630*6777b538SAndroid Build Coastguard Worker rankings->StopSharingData();
631*6777b538SAndroid Build Coastguard Worker *rankings->Data() = *temp.Data();
632*6777b538SAndroid Build Coastguard Worker }
633*6777b538SAndroid Build Coastguard Worker
CompleteTransaction()634*6777b538SAndroid Build Coastguard Worker void Rankings::CompleteTransaction() {
635*6777b538SAndroid Build Coastguard Worker Addr node_addr(static_cast<CacheAddr>(control_data_->transaction));
636*6777b538SAndroid Build Coastguard Worker if (!node_addr.is_initialized() || node_addr.is_separate_file()) {
637*6777b538SAndroid Build Coastguard Worker NOTREACHED();
638*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Invalid rankings info.";
639*6777b538SAndroid Build Coastguard Worker return;
640*6777b538SAndroid Build Coastguard Worker }
641*6777b538SAndroid Build Coastguard Worker
642*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock node(backend_->File(node_addr), node_addr);
643*6777b538SAndroid Build Coastguard Worker if (!node.Load())
644*6777b538SAndroid Build Coastguard Worker return;
645*6777b538SAndroid Build Coastguard Worker
646*6777b538SAndroid Build Coastguard Worker node.Store();
647*6777b538SAndroid Build Coastguard Worker
648*6777b538SAndroid Build Coastguard Worker // We want to leave the node inside the list. The entry must me marked as
649*6777b538SAndroid Build Coastguard Worker // dirty, and will be removed later. Otherwise, we'll get assertions when
650*6777b538SAndroid Build Coastguard Worker // attempting to remove the dirty entry.
651*6777b538SAndroid Build Coastguard Worker if (INSERT == control_data_->operation) {
652*6777b538SAndroid Build Coastguard Worker FinishInsert(&node);
653*6777b538SAndroid Build Coastguard Worker } else if (REMOVE == control_data_->operation) {
654*6777b538SAndroid Build Coastguard Worker RevertRemove(&node);
655*6777b538SAndroid Build Coastguard Worker } else {
656*6777b538SAndroid Build Coastguard Worker NOTREACHED();
657*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Invalid operation to recover.";
658*6777b538SAndroid Build Coastguard Worker }
659*6777b538SAndroid Build Coastguard Worker }
660*6777b538SAndroid Build Coastguard Worker
FinishInsert(CacheRankingsBlock * node)661*6777b538SAndroid Build Coastguard Worker void Rankings::FinishInsert(CacheRankingsBlock* node) {
662*6777b538SAndroid Build Coastguard Worker control_data_->transaction = 0;
663*6777b538SAndroid Build Coastguard Worker control_data_->operation = 0;
664*6777b538SAndroid Build Coastguard Worker Addr& my_head = heads_[control_data_->operation_list];
665*6777b538SAndroid Build Coastguard Worker Addr& my_tail = tails_[control_data_->operation_list];
666*6777b538SAndroid Build Coastguard Worker if (my_head.value() != node->address().value()) {
667*6777b538SAndroid Build Coastguard Worker if (my_tail.value() == node->address().value()) {
668*6777b538SAndroid Build Coastguard Worker // This part will be skipped by the logic of Insert.
669*6777b538SAndroid Build Coastguard Worker node->Data()->next = my_tail.value();
670*6777b538SAndroid Build Coastguard Worker }
671*6777b538SAndroid Build Coastguard Worker
672*6777b538SAndroid Build Coastguard Worker Insert(node, true, static_cast<List>(control_data_->operation_list));
673*6777b538SAndroid Build Coastguard Worker }
674*6777b538SAndroid Build Coastguard Worker
675*6777b538SAndroid Build Coastguard Worker // Tell the backend about this entry.
676*6777b538SAndroid Build Coastguard Worker backend_->RecoveredEntry(node);
677*6777b538SAndroid Build Coastguard Worker }
678*6777b538SAndroid Build Coastguard Worker
RevertRemove(CacheRankingsBlock * node)679*6777b538SAndroid Build Coastguard Worker void Rankings::RevertRemove(CacheRankingsBlock* node) {
680*6777b538SAndroid Build Coastguard Worker Addr next_addr(node->Data()->next);
681*6777b538SAndroid Build Coastguard Worker Addr prev_addr(node->Data()->prev);
682*6777b538SAndroid Build Coastguard Worker if (!next_addr.is_initialized() || !prev_addr.is_initialized()) {
683*6777b538SAndroid Build Coastguard Worker // The operation actually finished. Nothing to do.
684*6777b538SAndroid Build Coastguard Worker control_data_->transaction = 0;
685*6777b538SAndroid Build Coastguard Worker return;
686*6777b538SAndroid Build Coastguard Worker }
687*6777b538SAndroid Build Coastguard Worker if (next_addr.is_separate_file() || prev_addr.is_separate_file()) {
688*6777b538SAndroid Build Coastguard Worker NOTREACHED();
689*6777b538SAndroid Build Coastguard Worker LOG(WARNING) << "Invalid rankings info.";
690*6777b538SAndroid Build Coastguard Worker control_data_->transaction = 0;
691*6777b538SAndroid Build Coastguard Worker return;
692*6777b538SAndroid Build Coastguard Worker }
693*6777b538SAndroid Build Coastguard Worker
694*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock next(backend_->File(next_addr), next_addr);
695*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr);
696*6777b538SAndroid Build Coastguard Worker if (!next.Load() || !prev.Load())
697*6777b538SAndroid Build Coastguard Worker return;
698*6777b538SAndroid Build Coastguard Worker
699*6777b538SAndroid Build Coastguard Worker CacheAddr node_value = node->address().value();
700*6777b538SAndroid Build Coastguard Worker DCHECK(prev.Data()->next == node_value ||
701*6777b538SAndroid Build Coastguard Worker prev.Data()->next == prev_addr.value() ||
702*6777b538SAndroid Build Coastguard Worker prev.Data()->next == next.address().value());
703*6777b538SAndroid Build Coastguard Worker DCHECK(next.Data()->prev == node_value ||
704*6777b538SAndroid Build Coastguard Worker next.Data()->prev == next_addr.value() ||
705*6777b538SAndroid Build Coastguard Worker next.Data()->prev == prev.address().value());
706*6777b538SAndroid Build Coastguard Worker
707*6777b538SAndroid Build Coastguard Worker if (node_value != prev_addr.value())
708*6777b538SAndroid Build Coastguard Worker prev.Data()->next = node_value;
709*6777b538SAndroid Build Coastguard Worker if (node_value != next_addr.value())
710*6777b538SAndroid Build Coastguard Worker next.Data()->prev = node_value;
711*6777b538SAndroid Build Coastguard Worker
712*6777b538SAndroid Build Coastguard Worker List my_list = static_cast<List>(control_data_->operation_list);
713*6777b538SAndroid Build Coastguard Worker Addr& my_head = heads_[my_list];
714*6777b538SAndroid Build Coastguard Worker Addr& my_tail = tails_[my_list];
715*6777b538SAndroid Build Coastguard Worker if (!my_head.is_initialized() || !my_tail.is_initialized()) {
716*6777b538SAndroid Build Coastguard Worker my_head.set_value(node_value);
717*6777b538SAndroid Build Coastguard Worker my_tail.set_value(node_value);
718*6777b538SAndroid Build Coastguard Worker WriteHead(my_list);
719*6777b538SAndroid Build Coastguard Worker WriteTail(my_list);
720*6777b538SAndroid Build Coastguard Worker } else if (my_head.value() == next.address().value()) {
721*6777b538SAndroid Build Coastguard Worker my_head.set_value(node_value);
722*6777b538SAndroid Build Coastguard Worker prev.Data()->next = next.address().value();
723*6777b538SAndroid Build Coastguard Worker WriteHead(my_list);
724*6777b538SAndroid Build Coastguard Worker } else if (my_tail.value() == prev.address().value()) {
725*6777b538SAndroid Build Coastguard Worker my_tail.set_value(node_value);
726*6777b538SAndroid Build Coastguard Worker next.Data()->prev = prev.address().value();
727*6777b538SAndroid Build Coastguard Worker WriteTail(my_list);
728*6777b538SAndroid Build Coastguard Worker }
729*6777b538SAndroid Build Coastguard Worker
730*6777b538SAndroid Build Coastguard Worker next.Store();
731*6777b538SAndroid Build Coastguard Worker prev.Store();
732*6777b538SAndroid Build Coastguard Worker control_data_->transaction = 0;
733*6777b538SAndroid Build Coastguard Worker control_data_->operation = 0;
734*6777b538SAndroid Build Coastguard Worker backend_->FlushIndex();
735*6777b538SAndroid Build Coastguard Worker }
736*6777b538SAndroid Build Coastguard Worker
CheckLinks(CacheRankingsBlock * node,CacheRankingsBlock * prev,CacheRankingsBlock * next,List * list)737*6777b538SAndroid Build Coastguard Worker bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev,
738*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock* next, List* list) {
739*6777b538SAndroid Build Coastguard Worker CacheAddr node_addr = node->address().value();
740*6777b538SAndroid Build Coastguard Worker if (prev->Data()->next == node_addr &&
741*6777b538SAndroid Build Coastguard Worker next->Data()->prev == node_addr) {
742*6777b538SAndroid Build Coastguard Worker // A regular linked node.
743*6777b538SAndroid Build Coastguard Worker return true;
744*6777b538SAndroid Build Coastguard Worker }
745*6777b538SAndroid Build Coastguard Worker
746*6777b538SAndroid Build Coastguard Worker if (node_addr != prev->address().value() &&
747*6777b538SAndroid Build Coastguard Worker node_addr != next->address().value() &&
748*6777b538SAndroid Build Coastguard Worker prev->Data()->next == next->address().value() &&
749*6777b538SAndroid Build Coastguard Worker next->Data()->prev == prev->address().value()) {
750*6777b538SAndroid Build Coastguard Worker // The list is actually ok, node is wrong.
751*6777b538SAndroid Build Coastguard Worker node->Data()->next = 0;
752*6777b538SAndroid Build Coastguard Worker node->Data()->prev = 0;
753*6777b538SAndroid Build Coastguard Worker node->Store();
754*6777b538SAndroid Build Coastguard Worker return false;
755*6777b538SAndroid Build Coastguard Worker }
756*6777b538SAndroid Build Coastguard Worker
757*6777b538SAndroid Build Coastguard Worker if (prev->Data()->next == node_addr ||
758*6777b538SAndroid Build Coastguard Worker next->Data()->prev == node_addr) {
759*6777b538SAndroid Build Coastguard Worker // Only one link is weird, lets double check.
760*6777b538SAndroid Build Coastguard Worker if (prev->Data()->next != node_addr && IsHead(node_addr, list))
761*6777b538SAndroid Build Coastguard Worker return true;
762*6777b538SAndroid Build Coastguard Worker
763*6777b538SAndroid Build Coastguard Worker if (next->Data()->prev != node_addr && IsTail(node_addr, list))
764*6777b538SAndroid Build Coastguard Worker return true;
765*6777b538SAndroid Build Coastguard Worker }
766*6777b538SAndroid Build Coastguard Worker
767*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Inconsistent LRU.";
768*6777b538SAndroid Build Coastguard Worker STRESS_NOTREACHED();
769*6777b538SAndroid Build Coastguard Worker
770*6777b538SAndroid Build Coastguard Worker backend_->CriticalError(ERR_INVALID_LINKS);
771*6777b538SAndroid Build Coastguard Worker return false;
772*6777b538SAndroid Build Coastguard Worker }
773*6777b538SAndroid Build Coastguard Worker
CheckSingleLink(CacheRankingsBlock * prev,CacheRankingsBlock * next)774*6777b538SAndroid Build Coastguard Worker bool Rankings::CheckSingleLink(CacheRankingsBlock* prev,
775*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock* next) {
776*6777b538SAndroid Build Coastguard Worker if (prev->Data()->next != next->address().value() ||
777*6777b538SAndroid Build Coastguard Worker next->Data()->prev != prev->address().value()) {
778*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Inconsistent LRU.";
779*6777b538SAndroid Build Coastguard Worker
780*6777b538SAndroid Build Coastguard Worker backend_->CriticalError(ERR_INVALID_LINKS);
781*6777b538SAndroid Build Coastguard Worker return false;
782*6777b538SAndroid Build Coastguard Worker }
783*6777b538SAndroid Build Coastguard Worker
784*6777b538SAndroid Build Coastguard Worker return true;
785*6777b538SAndroid Build Coastguard Worker }
786*6777b538SAndroid Build Coastguard Worker
CheckList(List list)787*6777b538SAndroid Build Coastguard Worker int Rankings::CheckList(List list) {
788*6777b538SAndroid Build Coastguard Worker Addr last1, last2;
789*6777b538SAndroid Build Coastguard Worker int head_items;
790*6777b538SAndroid Build Coastguard Worker int rv = CheckListSection(list, last1, last2, true, // Head to tail.
791*6777b538SAndroid Build Coastguard Worker &last1, &last2, &head_items);
792*6777b538SAndroid Build Coastguard Worker if (rv == ERR_NO_ERROR)
793*6777b538SAndroid Build Coastguard Worker return head_items;
794*6777b538SAndroid Build Coastguard Worker
795*6777b538SAndroid Build Coastguard Worker return rv;
796*6777b538SAndroid Build Coastguard Worker }
797*6777b538SAndroid Build Coastguard Worker
798*6777b538SAndroid Build Coastguard Worker // Note that the returned error codes assume a forward walk (from head to tail)
799*6777b538SAndroid Build Coastguard Worker // so they have to be adjusted accordingly by the caller. We use two stop values
800*6777b538SAndroid Build Coastguard Worker // to be able to detect a corrupt node at the end that is not linked going back.
CheckListSection(List list,Addr end1,Addr end2,bool forward,Addr * last,Addr * second_last,int * num_items)801*6777b538SAndroid Build Coastguard Worker int Rankings::CheckListSection(List list, Addr end1, Addr end2, bool forward,
802*6777b538SAndroid Build Coastguard Worker Addr* last, Addr* second_last, int* num_items) {
803*6777b538SAndroid Build Coastguard Worker Addr current = forward ? heads_[list] : tails_[list];
804*6777b538SAndroid Build Coastguard Worker *last = *second_last = current;
805*6777b538SAndroid Build Coastguard Worker *num_items = 0;
806*6777b538SAndroid Build Coastguard Worker if (!current.is_initialized())
807*6777b538SAndroid Build Coastguard Worker return ERR_NO_ERROR;
808*6777b538SAndroid Build Coastguard Worker
809*6777b538SAndroid Build Coastguard Worker if (!current.SanityCheckForRankings())
810*6777b538SAndroid Build Coastguard Worker return ERR_INVALID_HEAD;
811*6777b538SAndroid Build Coastguard Worker
812*6777b538SAndroid Build Coastguard Worker std::unique_ptr<CacheRankingsBlock> node;
813*6777b538SAndroid Build Coastguard Worker Addr prev_addr(current);
814*6777b538SAndroid Build Coastguard Worker do {
815*6777b538SAndroid Build Coastguard Worker node =
816*6777b538SAndroid Build Coastguard Worker std::make_unique<CacheRankingsBlock>(backend_->File(current), current);
817*6777b538SAndroid Build Coastguard Worker node->Load();
818*6777b538SAndroid Build Coastguard Worker if (!SanityCheck(node.get(), true))
819*6777b538SAndroid Build Coastguard Worker return ERR_INVALID_ENTRY;
820*6777b538SAndroid Build Coastguard Worker
821*6777b538SAndroid Build Coastguard Worker CacheAddr next = forward ? node->Data()->next : node->Data()->prev;
822*6777b538SAndroid Build Coastguard Worker CacheAddr prev = forward ? node->Data()->prev : node->Data()->next;
823*6777b538SAndroid Build Coastguard Worker
824*6777b538SAndroid Build Coastguard Worker if (prev != prev_addr.value())
825*6777b538SAndroid Build Coastguard Worker return ERR_INVALID_PREV;
826*6777b538SAndroid Build Coastguard Worker
827*6777b538SAndroid Build Coastguard Worker Addr next_addr(next);
828*6777b538SAndroid Build Coastguard Worker if (!next_addr.SanityCheckForRankings())
829*6777b538SAndroid Build Coastguard Worker return ERR_INVALID_NEXT;
830*6777b538SAndroid Build Coastguard Worker
831*6777b538SAndroid Build Coastguard Worker prev_addr = current;
832*6777b538SAndroid Build Coastguard Worker current = next_addr;
833*6777b538SAndroid Build Coastguard Worker *second_last = *last;
834*6777b538SAndroid Build Coastguard Worker *last = current;
835*6777b538SAndroid Build Coastguard Worker (*num_items)++;
836*6777b538SAndroid Build Coastguard Worker
837*6777b538SAndroid Build Coastguard Worker if (next_addr == prev_addr) {
838*6777b538SAndroid Build Coastguard Worker if (next_addr == (forward ? tails_[list] : heads_[list]))
839*6777b538SAndroid Build Coastguard Worker return ERR_NO_ERROR;
840*6777b538SAndroid Build Coastguard Worker return ERR_INVALID_TAIL;
841*6777b538SAndroid Build Coastguard Worker }
842*6777b538SAndroid Build Coastguard Worker } while (current != end1 && current != end2);
843*6777b538SAndroid Build Coastguard Worker return ERR_NO_ERROR;
844*6777b538SAndroid Build Coastguard Worker }
845*6777b538SAndroid Build Coastguard Worker
IsHead(CacheAddr addr,List * list) const846*6777b538SAndroid Build Coastguard Worker bool Rankings::IsHead(CacheAddr addr, List* list) const {
847*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < LAST_ELEMENT; i++) {
848*6777b538SAndroid Build Coastguard Worker if (addr == heads_[i].value()) {
849*6777b538SAndroid Build Coastguard Worker *list = static_cast<List>(i);
850*6777b538SAndroid Build Coastguard Worker return true;
851*6777b538SAndroid Build Coastguard Worker }
852*6777b538SAndroid Build Coastguard Worker }
853*6777b538SAndroid Build Coastguard Worker return false;
854*6777b538SAndroid Build Coastguard Worker }
855*6777b538SAndroid Build Coastguard Worker
IsTail(CacheAddr addr,List * list) const856*6777b538SAndroid Build Coastguard Worker bool Rankings::IsTail(CacheAddr addr, List* list) const {
857*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < LAST_ELEMENT; i++) {
858*6777b538SAndroid Build Coastguard Worker if (addr == tails_[i].value()) {
859*6777b538SAndroid Build Coastguard Worker *list = static_cast<List>(i);
860*6777b538SAndroid Build Coastguard Worker return true;
861*6777b538SAndroid Build Coastguard Worker }
862*6777b538SAndroid Build Coastguard Worker }
863*6777b538SAndroid Build Coastguard Worker return false;
864*6777b538SAndroid Build Coastguard Worker }
865*6777b538SAndroid Build Coastguard Worker
866*6777b538SAndroid Build Coastguard Worker // We expect to have just a few iterators at any given time, maybe two or three,
867*6777b538SAndroid Build Coastguard Worker // But we could have more than one pointing at the same mode. We walk the list
868*6777b538SAndroid Build Coastguard Worker // of cache iterators and update all that are pointing to the given node.
UpdateIterators(CacheRankingsBlock * node)869*6777b538SAndroid Build Coastguard Worker void Rankings::UpdateIterators(CacheRankingsBlock* node) {
870*6777b538SAndroid Build Coastguard Worker CacheAddr address = node->address().value();
871*6777b538SAndroid Build Coastguard Worker for (auto& iterator : iterators_) {
872*6777b538SAndroid Build Coastguard Worker if (iterator.first == address && iterator.second->HasData()) {
873*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock* other = iterator.second;
874*6777b538SAndroid Build Coastguard Worker if (other != node)
875*6777b538SAndroid Build Coastguard Worker *other->Data() = *node->Data();
876*6777b538SAndroid Build Coastguard Worker }
877*6777b538SAndroid Build Coastguard Worker }
878*6777b538SAndroid Build Coastguard Worker }
879*6777b538SAndroid Build Coastguard Worker
UpdateIteratorsForRemoved(CacheAddr address,CacheRankingsBlock * next)880*6777b538SAndroid Build Coastguard Worker void Rankings::UpdateIteratorsForRemoved(CacheAddr address,
881*6777b538SAndroid Build Coastguard Worker CacheRankingsBlock* next) {
882*6777b538SAndroid Build Coastguard Worker CacheAddr next_addr = next->address().value();
883*6777b538SAndroid Build Coastguard Worker for (auto& iterator : iterators_) {
884*6777b538SAndroid Build Coastguard Worker if (iterator.first == address) {
885*6777b538SAndroid Build Coastguard Worker iterator.first = next_addr;
886*6777b538SAndroid Build Coastguard Worker iterator.second->CopyFrom(next);
887*6777b538SAndroid Build Coastguard Worker }
888*6777b538SAndroid Build Coastguard Worker }
889*6777b538SAndroid Build Coastguard Worker }
890*6777b538SAndroid Build Coastguard Worker
IncrementCounter(List list)891*6777b538SAndroid Build Coastguard Worker void Rankings::IncrementCounter(List list) {
892*6777b538SAndroid Build Coastguard Worker if (!count_lists_)
893*6777b538SAndroid Build Coastguard Worker return;
894*6777b538SAndroid Build Coastguard Worker
895*6777b538SAndroid Build Coastguard Worker DCHECK(control_data_->sizes[list] < std::numeric_limits<int32_t>::max());
896*6777b538SAndroid Build Coastguard Worker if (control_data_->sizes[list] < std::numeric_limits<int32_t>::max())
897*6777b538SAndroid Build Coastguard Worker control_data_->sizes[list]++;
898*6777b538SAndroid Build Coastguard Worker }
899*6777b538SAndroid Build Coastguard Worker
DecrementCounter(List list)900*6777b538SAndroid Build Coastguard Worker void Rankings::DecrementCounter(List list) {
901*6777b538SAndroid Build Coastguard Worker if (!count_lists_)
902*6777b538SAndroid Build Coastguard Worker return;
903*6777b538SAndroid Build Coastguard Worker
904*6777b538SAndroid Build Coastguard Worker DCHECK(control_data_->sizes[list] > 0);
905*6777b538SAndroid Build Coastguard Worker if (control_data_->sizes[list] > 0)
906*6777b538SAndroid Build Coastguard Worker control_data_->sizes[list]--;
907*6777b538SAndroid Build Coastguard Worker }
908*6777b538SAndroid Build Coastguard Worker
909*6777b538SAndroid Build Coastguard Worker } // namespace disk_cache
910