Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(664)

Side by Side Diff: net/disk_cache/rankings.cc

Issue 14141: Disk cache: remove the hard coded list from rankings.cc... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/disk_cache/rankings.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/disk_cache/rankings.h" 5 #include "net/disk_cache/rankings.h"
6 6
7 #include "base/histogram.h" 7 #include "base/histogram.h"
8 #include "net/disk_cache/backend_impl.h" 8 #include "net/disk_cache/backend_impl.h"
9 #include "net/disk_cache/entry_impl.h" 9 #include "net/disk_cache/entry_impl.h"
10 #include "net/disk_cache/errors.h" 10 #include "net/disk_cache/errors.h"
11 11
12 using base::Time; 12 using base::Time;
13 13
14 // This is used by crash_cache.exe to generate unit test files. 14 // This is used by crash_cache.exe to generate unit test files.
15 disk_cache::RankCrashes g_rankings_crash = disk_cache::NO_CRASH; 15 disk_cache::RankCrashes g_rankings_crash = disk_cache::NO_CRASH;
16 16
17 namespace { 17 namespace {
18 18
19 enum Lists {
20 NO_USE = 0, // List of entries that have not been reused.
21 LOW_USE, // List of entries with low reuse.
22 HIGH_USE, // List of entries with high reuse.
23 DELETED, // List of recently deleted or doomed entries.
24 LAST_ELEMENT
25 };
26
27 enum Operation { 19 enum Operation {
28 INSERT = 1, 20 INSERT = 1,
29 REMOVE 21 REMOVE
30 }; 22 };
31 23
32 // This class provides a simple lock for the LRU list of rankings. Whenever an 24 // This class provides a simple lock for the LRU list of rankings. Whenever an
33 // entry is to be inserted or removed from the list, a transaction object should 25 // entry is to be inserted or removed from the list, a transaction object should
34 // be created to keep track of the operation. If the process crashes before 26 // be created to keep track of the operation. If the process crashes before
35 // finishing the operation, the transaction record (stored as part of the user 27 // finishing the operation, the transaction record (stored as part of the user
36 // data on the file header) can be used to finish the operation. 28 // data on the file header) can be used to finish the operation.
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 155
164 bool Rankings::Init(BackendImpl* backend) { 156 bool Rankings::Init(BackendImpl* backend) {
165 DCHECK(!init_); 157 DCHECK(!init_);
166 if (init_) 158 if (init_)
167 return false; 159 return false;
168 160
169 backend_ = backend; 161 backend_ = backend;
170 162
171 control_data_ = backend_->GetLruData(); 163 control_data_ = backend_->GetLruData();
172 164
173 head_ = ReadHead(); 165 ReadHeads();
174 tail_ = ReadTail(); 166 ReadTails();
175 167
176 if (control_data_->transaction) 168 if (control_data_->transaction)
177 CompleteTransaction(); 169 CompleteTransaction();
178 170
179 init_ = true; 171 init_ = true;
180 return true; 172 return true;
181 } 173 }
182 174
183 void Rankings::Reset() { 175 void Rankings::Reset() {
184 init_ = false; 176 init_ = false;
185 head_.set_value(0); 177 for (int i = 0; i < LAST_ELEMENT; i++) {
186 tail_.set_value(0); 178 heads_[i].set_value(0);
179 tails_[i].set_value(0);
180 }
187 control_data_ = NULL; 181 control_data_ = NULL;
188 } 182 }
189 183
190 bool Rankings::GetRanking(CacheRankingsBlock* rankings) { 184 bool Rankings::GetRanking(CacheRankingsBlock* rankings) {
191 Time start = Time::Now(); 185 Time start = Time::Now();
192 if (!rankings->address().is_initialized()) 186 if (!rankings->address().is_initialized())
193 return false; 187 return false;
194 188
195 if (!rankings->Load()) 189 if (!rankings->Load())
196 return false; 190 return false;
(...skipping 19 matching lines...) Expand all
216 return true; 210 return true;
217 } 211 }
218 212
219 EntryImpl* cache_entry = 213 EntryImpl* cache_entry =
220 reinterpret_cast<EntryImpl*>(rankings->Data()->pointer); 214 reinterpret_cast<EntryImpl*>(rankings->Data()->pointer);
221 rankings->SetData(cache_entry->rankings()->Data()); 215 rankings->SetData(cache_entry->rankings()->Data());
222 UMA_HISTOGRAM_TIMES(L"DiskCache.GetRankings", Time::Now() - start); 216 UMA_HISTOGRAM_TIMES(L"DiskCache.GetRankings", Time::Now() - start);
223 return true; 217 return true;
224 } 218 }
225 219
226 void Rankings::Insert(CacheRankingsBlock* node, bool modified) { 220 void Rankings::Insert(CacheRankingsBlock* node, bool modified, List list) {
227 Trace("Insert 0x%x", node->address().value()); 221 Trace("Insert 0x%x", node->address().value());
228 DCHECK(node->HasData()); 222 DCHECK(node->HasData());
229 Transaction lock(control_data_, node->address(), INSERT, NO_USE); 223 Addr& my_head = heads_[list];
230 CacheRankingsBlock head(backend_->File(head_), head_); 224 Addr& my_tail = tails_[list];
231 if (head_.is_initialized()) { 225 Transaction lock(control_data_, node->address(), INSERT, list);
226 CacheRankingsBlock head(backend_->File(my_head), my_head);
227 if (my_head.is_initialized()) {
232 if (!GetRanking(&head)) 228 if (!GetRanking(&head))
233 return; 229 return;
234 230
235 if (head.Data()->prev != head_.value() && // Normal path. 231 if (head.Data()->prev != my_head.value() && // Normal path.
236 head.Data()->prev != node->address().value()) { // FinishInsert(). 232 head.Data()->prev != node->address().value()) { // FinishInsert().
237 backend_->CriticalError(ERR_INVALID_LINKS); 233 backend_->CriticalError(ERR_INVALID_LINKS);
238 return; 234 return;
239 } 235 }
240 236
241 head.Data()->prev = node->address().value(); 237 head.Data()->prev = node->address().value();
242 head.Store(); 238 head.Store();
243 GenerateCrash(ON_INSERT_1); 239 GenerateCrash(ON_INSERT_1);
244 UpdateIterators(&head); 240 UpdateIterators(&head);
245 } 241 }
246 242
247 node->Data()->next = head_.value(); 243 node->Data()->next = my_head.value();
248 node->Data()->prev = node->address().value(); 244 node->Data()->prev = node->address().value();
249 head_.set_value(node->address().value()); 245 my_head.set_value(node->address().value());
250 246
251 if (!tail_.is_initialized() || tail_.value() == node->address().value()) { 247 if (!my_tail.is_initialized() || my_tail.value() == node->address().value()) {
252 tail_.set_value(node->address().value()); 248 my_tail.set_value(node->address().value());
253 node->Data()->next = tail_.value(); 249 node->Data()->next = my_tail.value();
254 WriteTail(); 250 WriteTail(list);
255 GenerateCrash(ON_INSERT_2); 251 GenerateCrash(ON_INSERT_2);
256 } 252 }
257 253
258 Time now = Time::Now(); 254 Time now = Time::Now();
259 node->Data()->last_used = now.ToInternalValue(); 255 node->Data()->last_used = now.ToInternalValue();
260 if (modified) 256 if (modified)
261 node->Data()->last_modified = now.ToInternalValue(); 257 node->Data()->last_modified = now.ToInternalValue();
262 node->Store(); 258 node->Store();
263 GenerateCrash(ON_INSERT_3); 259 GenerateCrash(ON_INSERT_3);
264 260
265 // The last thing to do is move our head to point to a node already stored. 261 // The last thing to do is move our head to point to a node already stored.
266 WriteHead(); 262 WriteHead(list);
267 GenerateCrash(ON_INSERT_4); 263 GenerateCrash(ON_INSERT_4);
268 } 264 }
269 265
270 // If a, b and r are elements on the list, and we want to remove r, the possible 266 // If a, b and r are elements on the list, and we want to remove r, the possible
271 // states for the objects if a crash happens are (where y(x, z) means for object 267 // states for the objects if a crash happens are (where y(x, z) means for object
272 // y, prev is x and next is z): 268 // y, prev is x and next is z):
273 // A. One element: 269 // A. One element:
274 // 1. r(r, r), head(r), tail(r) initial state 270 // 1. r(r, r), head(r), tail(r) initial state
275 // 2. r(r, r), head(0), tail(r) WriteHead() 271 // 2. r(r, r), head(0), tail(r) WriteHead()
276 // 3. r(r, r), head(0), tail(0) WriteTail() 272 // 3. r(r, r), head(0), tail(0) WriteTail()
277 // 4. r(0, 0), head(0), tail(0) next.Store() 273 // 4. r(0, 0), head(0), tail(0) next.Store()
278 // 274 //
279 // B. Remove a random element: 275 // B. Remove a random element:
280 // 1. a(x, r), r(a, b), b(r, y), head(x), tail(y) initial state 276 // 1. a(x, r), r(a, b), b(r, y), head(x), tail(y) initial state
281 // 2. a(x, r), r(a, b), b(a, y), head(x), tail(y) next.Store() 277 // 2. a(x, r), r(a, b), b(a, y), head(x), tail(y) next.Store()
282 // 3. a(x, b), r(a, b), b(a, y), head(x), tail(y) prev.Store() 278 // 3. a(x, b), r(a, b), b(a, y), head(x), tail(y) prev.Store()
283 // 4. a(x, b), r(0, 0), b(a, y), head(x), tail(y) node.Store() 279 // 4. a(x, b), r(0, 0), b(a, y), head(x), tail(y) node.Store()
284 // 280 //
285 // C. Remove head: 281 // C. Remove head:
286 // 1. r(r, b), b(r, y), head(r), tail(y) initial state 282 // 1. r(r, b), b(r, y), head(r), tail(y) initial state
287 // 2. r(r, b), b(r, y), head(b), tail(y) WriteHead() 283 // 2. r(r, b), b(r, y), head(b), tail(y) WriteHead()
288 // 3. r(r, b), b(b, y), head(b), tail(y) next.Store() 284 // 3. r(r, b), b(b, y), head(b), tail(y) next.Store()
289 // 4. r(0, 0), b(b, y), head(b), tail(y) prev.Store() 285 // 4. r(0, 0), b(b, y), head(b), tail(y) prev.Store()
290 // 286 //
291 // D. Remove tail: 287 // D. Remove tail:
292 // 1. a(x, r), r(a, r), head(x), tail(r) initial state 288 // 1. a(x, r), r(a, r), head(x), tail(r) initial state
293 // 2. a(x, r), r(a, r), head(x), tail(a) WriteTail() 289 // 2. a(x, r), r(a, r), head(x), tail(a) WriteTail()
294 // 3. a(x, a), r(a, r), head(x), tail(a) prev.Store() 290 // 3. a(x, a), r(a, r), head(x), tail(a) prev.Store()
295 // 4. a(x, a), r(0, 0), head(x), tail(a) next.Store() 291 // 4. a(x, a), r(0, 0), head(x), tail(a) next.Store()
296 void Rankings::Remove(CacheRankingsBlock* node) { 292 void Rankings::Remove(CacheRankingsBlock* node, List list) {
297 Trace("Remove 0x%x (0x%x 0x%x)", node->address().value(), node->Data()->next, 293 Trace("Remove 0x%x (0x%x 0x%x)", node->address().value(), node->Data()->next,
298 node->Data()->prev); 294 node->Data()->prev);
299 DCHECK(node->HasData()); 295 DCHECK(node->HasData());
300 Addr next_addr(node->Data()->next); 296 Addr next_addr(node->Data()->next);
301 Addr prev_addr(node->Data()->prev); 297 Addr prev_addr(node->Data()->prev);
302 if (!next_addr.is_initialized() || next_addr.is_separate_file() || 298 if (!next_addr.is_initialized() || next_addr.is_separate_file() ||
303 !prev_addr.is_initialized() || prev_addr.is_separate_file()) { 299 !prev_addr.is_initialized() || prev_addr.is_separate_file()) {
304 LOG(WARNING) << "Invalid rankings info."; 300 LOG(WARNING) << "Invalid rankings info.";
305 return; 301 return;
306 } 302 }
307 303
308 CacheRankingsBlock next(backend_->File(next_addr), next_addr); 304 CacheRankingsBlock next(backend_->File(next_addr), next_addr);
309 CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr); 305 CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr);
310 if (!GetRanking(&next) || !GetRanking(&prev)) 306 if (!GetRanking(&next) || !GetRanking(&prev))
311 return; 307 return;
312 308
313 if (!CheckLinks(node, &prev, &next)) 309 if (!CheckLinks(node, &prev, &next, list))
314 return; 310 return;
315 311
316 Transaction lock(control_data_, node->address(), REMOVE, NO_USE); 312 Transaction lock(control_data_, node->address(), REMOVE, list);
317 prev.Data()->next = next.address().value(); 313 prev.Data()->next = next.address().value();
318 next.Data()->prev = prev.address().value(); 314 next.Data()->prev = prev.address().value();
319 GenerateCrash(ON_REMOVE_1); 315 GenerateCrash(ON_REMOVE_1);
320 316
321 CacheAddr node_value = node->address().value(); 317 CacheAddr node_value = node->address().value();
322 if (node_value == head_.value() || node_value == tail_.value()) { 318 Addr& my_head = heads_[list];
323 if (head_.value() == tail_.value()) { 319 Addr& my_tail = tails_[list];
324 head_.set_value(0); 320 if (node_value == my_head.value() || node_value == my_tail.value()) {
325 tail_.set_value(0); 321 if (my_head.value() == my_tail.value()) {
322 my_head.set_value(0);
323 my_tail.set_value(0);
326 324
327 WriteHead(); 325 WriteHead(list);
328 GenerateCrash(ON_REMOVE_2); 326 GenerateCrash(ON_REMOVE_2);
329 WriteTail(); 327 WriteTail(list);
330 GenerateCrash(ON_REMOVE_3); 328 GenerateCrash(ON_REMOVE_3);
331 } else if (node_value == head_.value()) { 329 } else if (node_value == my_head.value()) {
332 head_.set_value(next.address().value()); 330 my_head.set_value(next.address().value());
333 next.Data()->prev = next.address().value(); 331 next.Data()->prev = next.address().value();
334 332
335 WriteHead(); 333 WriteHead(list);
336 GenerateCrash(ON_REMOVE_4); 334 GenerateCrash(ON_REMOVE_4);
337 } else if (node_value == tail_.value()) { 335 } else if (node_value == my_tail.value()) {
338 tail_.set_value(prev.address().value()); 336 my_tail.set_value(prev.address().value());
339 prev.Data()->next = prev.address().value(); 337 prev.Data()->next = prev.address().value();
340 338
341 WriteTail(); 339 WriteTail(list);
342 GenerateCrash(ON_REMOVE_5); 340 GenerateCrash(ON_REMOVE_5);
343 341
344 // Store the new tail to make sure we can undo the operation if we crash. 342 // Store the new tail to make sure we can undo the operation if we crash.
345 prev.Store(); 343 prev.Store();
346 GenerateCrash(ON_REMOVE_6); 344 GenerateCrash(ON_REMOVE_6);
347 } 345 }
348 } 346 }
349 347
350 // Nodes out of the list can be identified by invalid pointers. 348 // Nodes out of the list can be identified by invalid pointers.
351 node->Data()->next = 0; 349 node->Data()->next = 0;
352 node->Data()->prev = 0; 350 node->Data()->prev = 0;
353 351
354 // The last thing to get to disk is the node itself, so before that there is 352 // The last thing to get to disk is the node itself, so before that there is
355 // enough info to recover. 353 // enough info to recover.
356 next.Store(); 354 next.Store();
357 GenerateCrash(ON_REMOVE_7); 355 GenerateCrash(ON_REMOVE_7);
358 prev.Store(); 356 prev.Store();
359 GenerateCrash(ON_REMOVE_8); 357 GenerateCrash(ON_REMOVE_8);
360 node->Store(); 358 node->Store();
361 UpdateIterators(&next); 359 UpdateIterators(&next);
362 UpdateIterators(&prev); 360 UpdateIterators(&prev);
363 } 361 }
364 362
365 // A crash in between Remove and Insert will lead to a dirty entry not on the 363 // A crash in between Remove and Insert will lead to a dirty entry not on the
366 // list. We want to avoid that case as much as we can (as while waiting for IO), 364 // list. We want to avoid that case as much as we can (as while waiting for IO),
367 // but the net effect is just an assert on debug when attempting to remove the 365 // but the net effect is just an assert on debug when attempting to remove the
368 // entry. Otherwise we'll need reentrant transactions, which is an overkill. 366 // entry. Otherwise we'll need reentrant transactions, which is an overkill.
369 void Rankings::UpdateRank(CacheRankingsBlock* node, bool modified) { 367 void Rankings::UpdateRank(CacheRankingsBlock* node, bool modified, List list) {
370 Time start = Time::Now(); 368 Time start = Time::Now();
371 Remove(node); 369 Remove(node, list);
372 Insert(node, modified); 370 Insert(node, modified, list);
373 UMA_HISTOGRAM_TIMES(L"DiskCache.UpdateRank", Time::Now() - start); 371 UMA_HISTOGRAM_TIMES(L"DiskCache.UpdateRank", Time::Now() - start);
374 } 372 }
375 373
376 void Rankings::CompleteTransaction() { 374 void Rankings::CompleteTransaction() {
377 Addr node_addr(static_cast<CacheAddr>(control_data_->transaction)); 375 Addr node_addr(static_cast<CacheAddr>(control_data_->transaction));
378 if (!node_addr.is_initialized() || node_addr.is_separate_file()) { 376 if (!node_addr.is_initialized() || node_addr.is_separate_file()) {
379 NOTREACHED(); 377 NOTREACHED();
380 LOG(ERROR) << "Invalid rankings info."; 378 LOG(ERROR) << "Invalid rankings info.";
381 return; 379 return;
382 } 380 }
383 381
384 Trace("CompleteTransaction 0x%x", node_addr.value()); 382 Trace("CompleteTransaction 0x%x", node_addr.value());
385 383
386 CacheRankingsBlock node(backend_->File(node_addr), node_addr); 384 CacheRankingsBlock node(backend_->File(node_addr), node_addr);
387 if (!node.Load()) 385 if (!node.Load())
388 return; 386 return;
389 387
390 node.Data()->pointer = NULL; 388 node.Data()->pointer = NULL;
391 node.Store(); 389 node.Store();
392 390
391 Addr& my_head = heads_[control_data_->operation_list];
392 Addr& my_tail = tails_[control_data_->operation_list];
393
393 // We want to leave the node inside the list. The entry must me marked as 394 // We want to leave the node inside the list. The entry must me marked as
394 // dirty, and will be removed later. Otherwise, we'll get assertions when 395 // dirty, and will be removed later. Otherwise, we'll get assertions when
395 // attempting to remove the dirty entry. 396 // attempting to remove the dirty entry.
396 if (INSERT == control_data_->operation) { 397 if (INSERT == control_data_->operation) {
397 Trace("FinishInsert h:0x%x t:0x%x", head_.value(), tail_.value()); 398 Trace("FinishInsert h:0x%x t:0x%x", my_head.value(), my_tail.value());
398 FinishInsert(&node); 399 FinishInsert(&node);
399 } else if (REMOVE == control_data_->operation) { 400 } else if (REMOVE == control_data_->operation) {
400 Trace("RevertRemove h:0x%x t:0x%x", head_.value(), tail_.value()); 401 Trace("RevertRemove h:0x%x t:0x%x", my_head.value(), my_tail.value());
401 RevertRemove(&node); 402 RevertRemove(&node);
402 } else { 403 } else {
403 NOTREACHED(); 404 NOTREACHED();
404 LOG(ERROR) << "Invalid operation to recover."; 405 LOG(ERROR) << "Invalid operation to recover.";
405 } 406 }
406 } 407 }
407 408
408 void Rankings::FinishInsert(CacheRankingsBlock* node) { 409 void Rankings::FinishInsert(CacheRankingsBlock* node) {
409 control_data_->transaction = 0; 410 control_data_->transaction = 0;
410 control_data_->operation = 0; 411 control_data_->operation = 0;
411 if (head_.value() != node->address().value()) { 412 Addr& my_head = heads_[control_data_->operation_list];
412 if (tail_.value() == node->address().value()) { 413 Addr& my_tail = tails_[control_data_->operation_list];
414 if (my_head.value() != node->address().value()) {
415 if (my_tail.value() == node->address().value()) {
413 // This part will be skipped by the logic of Insert. 416 // This part will be skipped by the logic of Insert.
414 node->Data()->next = tail_.value(); 417 node->Data()->next = my_tail.value();
415 } 418 }
416 419
417 Insert(node, true); 420 Insert(node, true, static_cast<List>(control_data_->operation_list));
418 } 421 }
419 422
420 // Tell the backend about this entry. 423 // Tell the backend about this entry.
421 backend_->RecoveredEntry(node); 424 backend_->RecoveredEntry(node);
422 } 425 }
423 426
424 void Rankings::RevertRemove(CacheRankingsBlock* node) { 427 void Rankings::RevertRemove(CacheRankingsBlock* node) {
425 Addr next_addr(node->Data()->next); 428 Addr next_addr(node->Data()->next);
426 Addr prev_addr(node->Data()->prev); 429 Addr prev_addr(node->Data()->prev);
427 if (!next_addr.is_initialized() || !prev_addr.is_initialized()) { 430 if (!next_addr.is_initialized() || !prev_addr.is_initialized()) {
(...skipping 19 matching lines...) Expand all
447 prev.Data()->next == next.address().value()); 450 prev.Data()->next == next.address().value());
448 DCHECK(next.Data()->prev == node_value || 451 DCHECK(next.Data()->prev == node_value ||
449 next.Data()->prev == next_addr.value() || 452 next.Data()->prev == next_addr.value() ||
450 next.Data()->prev == prev.address().value()); 453 next.Data()->prev == prev.address().value());
451 454
452 if (node_value != prev_addr.value()) 455 if (node_value != prev_addr.value())
453 prev.Data()->next = node_value; 456 prev.Data()->next = node_value;
454 if (node_value != next_addr.value()) 457 if (node_value != next_addr.value())
455 next.Data()->prev = node_value; 458 next.Data()->prev = node_value;
456 459
457 if (!head_.is_initialized() || !tail_.is_initialized()) { 460 List my_list = static_cast<List>(control_data_->operation_list);
458 head_.set_value(node_value); 461 Addr& my_head = heads_[my_list];
459 tail_.set_value(node_value); 462 Addr& my_tail = tails_[my_list];
460 WriteHead(); 463 if (!my_head.is_initialized() || !my_tail.is_initialized()) {
461 WriteTail(); 464 my_head.set_value(node_value);
462 } else if (head_.value() == next.address().value()) { 465 my_tail.set_value(node_value);
463 head_.set_value(node_value); 466 WriteHead(my_list);
467 WriteTail(my_list);
468 } else if (my_head.value() == next.address().value()) {
469 my_head.set_value(node_value);
464 prev.Data()->next = next.address().value(); 470 prev.Data()->next = next.address().value();
465 WriteHead(); 471 WriteHead(my_list);
466 } else if (tail_.value() == prev.address().value()) { 472 } else if (my_tail.value() == prev.address().value()) {
467 tail_.set_value(node_value); 473 my_tail.set_value(node_value);
468 next.Data()->prev = prev.address().value(); 474 next.Data()->prev = prev.address().value();
469 WriteTail(); 475 WriteTail(my_list);
470 } 476 }
471 477
472 next.Store(); 478 next.Store();
473 prev.Store(); 479 prev.Store();
474 control_data_->transaction = 0; 480 control_data_->transaction = 0;
475 control_data_->operation = 0; 481 control_data_->operation = 0;
476 } 482 }
477 483
478 CacheRankingsBlock* Rankings::GetNext(CacheRankingsBlock* node) { 484 CacheRankingsBlock* Rankings::GetNext(CacheRankingsBlock* node, List list) {
479 ScopedRankingsBlock next(this); 485 ScopedRankingsBlock next(this);
480 if (!node) { 486 if (!node) {
481 if (!head_.is_initialized()) 487 Addr& my_head = heads_[list];
488 if (!my_head.is_initialized())
482 return NULL; 489 return NULL;
483 next.reset(new CacheRankingsBlock(backend_->File(head_), head_)); 490 next.reset(new CacheRankingsBlock(backend_->File(my_head), my_head));
484 } else { 491 } else {
485 if (!tail_.is_initialized()) 492 Addr& my_tail = tails_[list];
493 if (!my_tail.is_initialized())
486 return NULL; 494 return NULL;
487 if (tail_.value() == node->address().value()) 495 if (my_tail.value() == node->address().value())
488 return NULL; 496 return NULL;
489 Addr address(node->Data()->next); 497 Addr address(node->Data()->next);
490 next.reset(new CacheRankingsBlock(backend_->File(address), address)); 498 next.reset(new CacheRankingsBlock(backend_->File(address), address));
491 } 499 }
492 500
493 TrackRankingsBlock(next.get(), true); 501 TrackRankingsBlock(next.get(), true);
494 502
495 if (!GetRanking(next.get())) 503 if (!GetRanking(next.get()))
496 return NULL; 504 return NULL;
497 505
498 if (node && !CheckSingleLink(node, next.get())) 506 if (node && !CheckSingleLink(node, next.get()))
499 return NULL; 507 return NULL;
500 508
501 return next.release(); 509 return next.release();
502 } 510 }
503 511
504 CacheRankingsBlock* Rankings::GetPrev(CacheRankingsBlock* node) { 512 CacheRankingsBlock* Rankings::GetPrev(CacheRankingsBlock* node, List list) {
505 ScopedRankingsBlock prev(this); 513 ScopedRankingsBlock prev(this);
506 if (!node) { 514 if (!node) {
507 if (!tail_.is_initialized()) 515 Addr& my_tail = tails_[list];
516 if (!my_tail.is_initialized())
508 return NULL; 517 return NULL;
509 prev.reset(new CacheRankingsBlock(backend_->File(tail_), tail_)); 518 prev.reset(new CacheRankingsBlock(backend_->File(my_tail), my_tail));
510 } else { 519 } else {
511 if (!head_.is_initialized()) 520 Addr& my_head = heads_[list];
521 if (!my_head.is_initialized())
512 return NULL; 522 return NULL;
513 if (head_.value() == node->address().value()) 523 if (my_head.value() == node->address().value())
514 return NULL; 524 return NULL;
515 Addr address(node->Data()->prev); 525 Addr address(node->Data()->prev);
516 prev.reset(new CacheRankingsBlock(backend_->File(address), address)); 526 prev.reset(new CacheRankingsBlock(backend_->File(address), address));
517 } 527 }
518 528
519 TrackRankingsBlock(prev.get(), true); 529 TrackRankingsBlock(prev.get(), true);
520 530
521 if (!GetRanking(prev.get())) 531 if (!GetRanking(prev.get()))
522 return NULL; 532 return NULL;
523 533
524 if (node && !CheckSingleLink(prev.get(), node)) 534 if (node && !CheckSingleLink(prev.get(), node))
525 return NULL; 535 return NULL;
526 536
527 return prev.release(); 537 return prev.release();
528 } 538 }
529 539
530 void Rankings::FreeRankingsBlock(CacheRankingsBlock* node) { 540 void Rankings::FreeRankingsBlock(CacheRankingsBlock* node) {
531 TrackRankingsBlock(node, false); 541 TrackRankingsBlock(node, false);
532 } 542 }
533 543
534 int Rankings::SelfCheck() { 544 int Rankings::SelfCheck() {
535 if (!head_.is_initialized()) { 545 int total = 0;
536 if (!tail_.is_initialized()) 546 for (int i = 0; i < LAST_ELEMENT; i++) {
537 return 0; 547 int partial = CheckList(static_cast<List>(i));
538 return ERR_INVALID_TAIL; 548 if (partial < 0)
549 return partial;
550 total += partial;
539 } 551 }
540 if (!tail_.is_initialized()) 552 return total;
541 return ERR_INVALID_HEAD;
542
543 if (tail_.is_separate_file())
544 return ERR_INVALID_TAIL;
545
546 if (head_.is_separate_file())
547 return ERR_INVALID_HEAD;
548
549 int num_items = 0;
550 Addr address(head_.value());
551 Addr prev(head_.value());
552 scoped_ptr<CacheRankingsBlock> node;
553 do {
554 node.reset(new CacheRankingsBlock(backend_->File(address), address));
555 node->Load();
556 if (node->Data()->prev != prev.value())
557 return ERR_INVALID_PREV;
558 if (!CheckEntry(node.get()))
559 return ERR_INVALID_ENTRY;
560
561 prev.set_value(address.value());
562 address.set_value(node->Data()->next);
563 if (!address.is_initialized() || address.is_separate_file())
564 return ERR_INVALID_NEXT;
565
566 num_items++;
567 } while (node->address().value() != address.value());
568 return num_items;
569 } 553 }
570 554
571 bool Rankings::SanityCheck(CacheRankingsBlock* node, bool from_list) { 555 bool Rankings::SanityCheck(CacheRankingsBlock* node, bool from_list) {
572 const RankingsNode* data = node->Data(); 556 const RankingsNode* data = node->Data();
573 if (!data->contents) 557 if (!data->contents)
574 return false; 558 return false;
575 559
576 // It may have never been inserted. 560 // It may have never been inserted.
577 if (from_list && (!data->last_used || !data->last_modified)) 561 if (from_list && (!data->last_used || !data->last_modified))
578 return false; 562 return false;
579 563
580 if ((!data->next && data->prev) || (data->next && !data->prev)) 564 if ((!data->next && data->prev) || (data->next && !data->prev))
581 return false; 565 return false;
582 566
583 // Both pointers on zero is a node out of the list. 567 // Both pointers on zero is a node out of the list.
584 if (!data->next && !data->prev && from_list) 568 if (!data->next && !data->prev && from_list)
585 return false; 569 return false;
586 570
587 if ((node->address().value() == data->prev) && (head_.value() != data->prev)) 571 if ((node->address().value() == data->prev) && !IsHead(data->prev))
588 return false; 572 return false;
589 573
590 if ((node->address().value() == data->next) && (tail_.value() != data->next)) 574 if ((node->address().value() == data->next) && !IsTail(data->next))
591 return false; 575 return false;
592 576
593 return true; 577 return true;
594 } 578 }
595 579
596 Addr Rankings::ReadHead() { 580 void Rankings::ReadHeads() {
597 return Addr(control_data_->heads[NO_USE]); 581 for (int i = 0; i < LAST_ELEMENT; i++)
582 heads_[i] = Addr(control_data_->heads[i]);
598 } 583 }
599 584
600 Addr Rankings::ReadTail() { 585 void Rankings::ReadTails() {
601 return Addr(control_data_->tails[NO_USE]); 586 for (int i = 0; i < LAST_ELEMENT; i++)
587 tails_[i] = Addr(control_data_->tails[i]);
602 } 588 }
603 589
604 void Rankings::WriteHead() { 590 void Rankings::WriteHead(List list) {
605 control_data_->heads[NO_USE] = head_.value(); 591 control_data_->heads[list] = heads_[list].value();
606 } 592 }
607 593
608 void Rankings::WriteTail() { 594 void Rankings::WriteTail(List list) {
609 control_data_->tails[NO_USE] = tail_.value(); 595 control_data_->tails[list] = tails_[list].value();
610 } 596 }
611 597
612 bool Rankings::CheckEntry(CacheRankingsBlock* rankings) { 598 bool Rankings::CheckEntry(CacheRankingsBlock* rankings) {
613 if (!rankings->Data()->pointer) 599 if (!rankings->Data()->pointer)
614 return true; 600 return true;
615 601
616 // If this entry is not dirty, it is a serious problem. 602 // If this entry is not dirty, it is a serious problem.
617 return backend_->GetCurrentEntryId() != rankings->Data()->dirty; 603 return backend_->GetCurrentEntryId() != rankings->Data()->dirty;
618 } 604 }
619 605
620 bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev, 606 bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev,
621 CacheRankingsBlock* next) { 607 CacheRankingsBlock* next, List list) {
622 if ((prev->Data()->next != node->address().value() && 608 if ((prev->Data()->next != node->address().value() &&
623 head_.value() != node->address().value()) || 609 heads_[list].value() != node->address().value()) ||
624 (next->Data()->prev != node->address().value() && 610 (next->Data()->prev != node->address().value() &&
625 tail_.value() != node->address().value())) { 611 tails_[list].value() != node->address().value())) {
626 LOG(ERROR) << "Inconsistent LRU."; 612 LOG(ERROR) << "Inconsistent LRU.";
627 613
628 if (prev->Data()->next == next->address().value() && 614 if (prev->Data()->next == next->address().value() &&
629 next->Data()->prev == prev->address().value()) { 615 next->Data()->prev == prev->address().value()) {
630 // The list is actually ok, node is wrong. 616 // The list is actually ok, node is wrong.
631 node->Data()->next = 0; 617 node->Data()->next = 0;
632 node->Data()->prev = 0; 618 node->Data()->prev = 0;
633 node->Store(); 619 node->Store();
634 return false; 620 return false;
635 } 621 }
(...skipping 10 matching lines...) Expand all
646 next->Data()->prev != prev->address().value()) { 632 next->Data()->prev != prev->address().value()) {
647 LOG(ERROR) << "Inconsistent LRU."; 633 LOG(ERROR) << "Inconsistent LRU.";
648 634
649 backend_->CriticalError(ERR_INVALID_LINKS); 635 backend_->CriticalError(ERR_INVALID_LINKS);
650 return false; 636 return false;
651 } 637 }
652 638
653 return true; 639 return true;
654 } 640 }
655 641
642 int Rankings::CheckList(List list) {
643 Addr& my_head = heads_[list];
644 Addr& my_tail = tails_[list];
645 if (!my_head.is_initialized()) {
646 if (!my_tail.is_initialized())
647 return 0;
648 // If there is no head, having a tail is an error.
649 return ERR_INVALID_TAIL;
650 }
651 // If there is no tail, having a head is an error.
652 if (!my_tail.is_initialized())
653 return ERR_INVALID_HEAD;
654
655 if (my_tail.is_separate_file())
656 return ERR_INVALID_TAIL;
657
658 if (my_head.is_separate_file())
659 return ERR_INVALID_HEAD;
660
661 int num_items = 0;
662 Addr address(my_head.value());
663 Addr prev(my_head.value());
664 scoped_ptr<CacheRankingsBlock> node;
665 do {
666 node.reset(new CacheRankingsBlock(backend_->File(address), address));
667 node->Load();
668 if (node->Data()->prev != prev.value())
669 return ERR_INVALID_PREV;
670 if (!CheckEntry(node.get()))
671 return ERR_INVALID_ENTRY;
672
673 prev.set_value(address.value());
674 address.set_value(node->Data()->next);
675 if (!address.is_initialized() || address.is_separate_file())
676 return ERR_INVALID_NEXT;
677
678 num_items++;
679 } while (node->address().value() != address.value());
680 return num_items;
681 }
682
683 bool Rankings::IsHead(CacheAddr addr) {
684 for (int i = 0; i < LAST_ELEMENT; i++)
685 if (addr == heads_[i].value())
686 return true;
687 return false;
688 }
689
690 bool Rankings::IsTail(CacheAddr addr) {
691 for (int i = 0; i < LAST_ELEMENT; i++)
692 if (addr == tails_[i].value())
693 return true;
694 return false;
695 }
696
656 void Rankings::TrackRankingsBlock(CacheRankingsBlock* node, 697 void Rankings::TrackRankingsBlock(CacheRankingsBlock* node,
657 bool start_tracking) { 698 bool start_tracking) {
658 if (!node) 699 if (!node)
659 return; 700 return;
660 701
661 IteratorPair current(node->address().value(), node); 702 IteratorPair current(node->address().value(), node);
662 703
663 if (start_tracking) 704 if (start_tracking)
664 iterators_.push_back(current); 705 iterators_.push_back(current);
665 else 706 else
666 iterators_.remove(current); 707 iterators_.remove(current);
667 } 708 }
668 709
669 // We expect to have just a few iterators at any given time, maybe two or three, 710 // We expect to have just a few iterators at any given time, maybe two or three,
670 // But we could have more than one pointing at the same mode. We walk the list 711 // But we could have more than one pointing at the same mode. We walk the list
671 // of cache iterators and update all that are pointing to the given node. 712 // of cache iterators and update all that are pointing to the given node.
672 void Rankings::UpdateIterators(CacheRankingsBlock* node) { 713 void Rankings::UpdateIterators(CacheRankingsBlock* node) {
673 CacheAddr address = node->address().value(); 714 CacheAddr address = node->address().value();
674 for (IteratorList::iterator it = iterators_.begin(); it != iterators_.end(); 715 for (IteratorList::iterator it = iterators_.begin(); it != iterators_.end();
675 ++it) { 716 ++it) {
676 if (it->first == address) { 717 if (it->first == address) {
677 CacheRankingsBlock* other = it->second; 718 CacheRankingsBlock* other = it->second;
678 other->Data()->next = node->Data()->next; 719 other->Data()->next = node->Data()->next;
679 other->Data()->prev = node->Data()->prev; 720 other->Data()->prev = node->Data()->prev;
680 } 721 }
681 } 722 }
682 } 723 }
683 724
684 } // namespace disk_cache 725 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/rankings.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698