xref: /aosp_15_r20/external/cronet/net/disk_cache/blockfile/rankings.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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