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

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

Issue 12880: Disk cache: Add support for an extra data stream for each cache entry.... (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
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 const int kHeadIndex = 0; 19 enum Lists {
20 const int kTailIndex = 1; 20 NO_USE = 0, // List of entries that have not been reused.
21 const int kTransactionIndex = 2; 21 LOW_USE, // List of entries with low reuse.
22 const int kOperationIndex = 3; 22 HIGH_USE, // List of entries with high reuse.
23 DELETED, // List of recently deleted or doomed entries.
24 LAST_ELEMENT
25 };
23 26
24 enum Operation { 27 enum Operation {
25 INSERT = 1, 28 INSERT = 1,
26 REMOVE 29 REMOVE
27 }; 30 };
28 31
29 // This class provides a simple lock for the LRU list of rankings. Whenever an 32 // This class provides a simple lock for the LRU list of rankings. Whenever an
30 // entry is to be inserted or removed from the list, a transaction object should 33 // entry is to be inserted or removed from the list, a transaction object should
31 // be created to keep track of the operation. If the process crashes before 34 // be created to keep track of the operation. If the process crashes before
32 // finishing the operation, the transaction record (stored as part of the user 35 // finishing the operation, the transaction record (stored as part of the user
33 // data on the file header) can be used to finish the operation. 36 // data on the file header) can be used to finish the operation.
34 class Transaction { 37 class Transaction {
35 public: 38 public:
36 // addr is the cache addres of the node being inserted or removed. We want to 39 // addr is the cache addres of the node being inserted or removed. We want to
37 // avoid having the compiler doing optimizations on when to read or write 40 // avoid having the compiler doing optimizations on when to read or write
38 // from user_data because it is the basis of the crash detection. Maybe 41 // from user_data because it is the basis of the crash detection. Maybe
39 // volatile is not enough for that, but it should be a good hint. 42 // volatile is not enough for that, but it should be a good hint.
40 Transaction(volatile int32* user_data, disk_cache::Addr addr, Operation op); 43 Transaction(volatile disk_cache::LruData* data, disk_cache::Addr addr,
44 Operation op, int list);
41 ~Transaction(); 45 ~Transaction();
42 private: 46 private:
43 volatile int32* user_data_; 47 volatile disk_cache::LruData* data_;
44 DISALLOW_EVIL_CONSTRUCTORS(Transaction); 48 DISALLOW_COPY_AND_ASSIGN(Transaction);
45 }; 49 };
46 50
47 Transaction::Transaction(volatile int32* user_data, disk_cache::Addr addr, 51 Transaction::Transaction(volatile disk_cache::LruData* data,
48 Operation op) : user_data_(user_data) { 52 disk_cache::Addr addr, Operation op, int list)
49 DCHECK(!user_data_[kTransactionIndex]); 53 : data_(data) {
54 DCHECK(!data_->transaction);
50 DCHECK(addr.is_initialized()); 55 DCHECK(addr.is_initialized());
51 user_data_[kOperationIndex] = op; 56 data_->operation = op;
52 user_data_[kTransactionIndex] = static_cast<int32>(addr.value()); 57 data_->operation_list = list;
58 data_->transaction = addr.value();
53 } 59 }
54 60
55 Transaction::~Transaction() { 61 Transaction::~Transaction() {
56 DCHECK(user_data_[kTransactionIndex]); 62 DCHECK(data_->transaction);
57 user_data_[kTransactionIndex] = 0; 63 data_->transaction = 0;
58 user_data_[kOperationIndex] = 0; 64 data_->operation = 0;
65 data_->operation_list = 0;
59 } 66 }
60 67
61 // Code locations that can generate crashes. 68 // Code locations that can generate crashes.
62 enum CrashLocation { 69 enum CrashLocation {
63 ON_INSERT_1, ON_INSERT_2, ON_INSERT_3, ON_INSERT_4, ON_REMOVE_1, ON_REMOVE_2, 70 ON_INSERT_1, ON_INSERT_2, ON_INSERT_3, ON_INSERT_4, ON_REMOVE_1, ON_REMOVE_2,
64 ON_REMOVE_3, ON_REMOVE_4, ON_REMOVE_5, ON_REMOVE_6, ON_REMOVE_7, ON_REMOVE_8 71 ON_REMOVE_3, ON_REMOVE_4, ON_REMOVE_5, ON_REMOVE_6, ON_REMOVE_7, ON_REMOVE_8
65 }; 72 };
66 73
67 // Generates a crash on debug builds, acording to the value of g_rankings_crash. 74 // Generates a crash on debug builds, acording to the value of g_rankings_crash.
68 // This used by crash_cache.exe to generate unit-test files. 75 // This used by crash_cache.exe to generate unit-test files.
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 } // namespace 160 } // namespace
154 161
155 namespace disk_cache { 162 namespace disk_cache {
156 163
157 bool Rankings::Init(BackendImpl* backend) { 164 bool Rankings::Init(BackendImpl* backend) {
158 DCHECK(!init_); 165 DCHECK(!init_);
159 if (init_) 166 if (init_)
160 return false; 167 return false;
161 168
162 backend_ = backend; 169 backend_ = backend;
163 MappedFile* file = backend_->File(Addr(RANKINGS, 0, 0, 0));
164 170
165 header_ = reinterpret_cast<BlockFileHeader*>(file->buffer()); 171 control_data_ = backend_->GetLruData();
166 172
167 head_ = ReadHead(); 173 head_ = ReadHead();
168 tail_ = ReadTail(); 174 tail_ = ReadTail();
169 175
170 if (header_->user[kTransactionIndex]) 176 if (control_data_->transaction)
171 CompleteTransaction(); 177 CompleteTransaction();
172 178
173 init_ = true; 179 init_ = true;
174 return true; 180 return true;
175 } 181 }
176 182
177 void Rankings::Reset() { 183 void Rankings::Reset() {
178 init_ = false; 184 init_ = false;
179 head_.set_value(0); 185 head_.set_value(0);
180 tail_.set_value(0); 186 tail_.set_value(0);
181 header_ = NULL; 187 control_data_ = NULL;
182 } 188 }
183 189
184 bool Rankings::GetRanking(CacheRankingsBlock* rankings) { 190 bool Rankings::GetRanking(CacheRankingsBlock* rankings) {
185 Time start = Time::Now(); 191 Time start = Time::Now();
186 if (!rankings->address().is_initialized()) 192 if (!rankings->address().is_initialized())
187 return false; 193 return false;
188 194
189 if (!rankings->Load()) 195 if (!rankings->Load())
190 return false; 196 return false;
191 197
(...skipping 21 matching lines...) Expand all
213 EntryImpl* cache_entry = 219 EntryImpl* cache_entry =
214 reinterpret_cast<EntryImpl*>(rankings->Data()->pointer); 220 reinterpret_cast<EntryImpl*>(rankings->Data()->pointer);
215 rankings->SetData(cache_entry->rankings()->Data()); 221 rankings->SetData(cache_entry->rankings()->Data());
216 UMA_HISTOGRAM_TIMES(L"DiskCache.GetRankings", Time::Now() - start); 222 UMA_HISTOGRAM_TIMES(L"DiskCache.GetRankings", Time::Now() - start);
217 return true; 223 return true;
218 } 224 }
219 225
220 void Rankings::Insert(CacheRankingsBlock* node, bool modified) { 226 void Rankings::Insert(CacheRankingsBlock* node, bool modified) {
221 Trace("Insert 0x%x", node->address().value()); 227 Trace("Insert 0x%x", node->address().value());
222 DCHECK(node->HasData()); 228 DCHECK(node->HasData());
223 Transaction lock(header_->user, node->address(), INSERT); 229 Transaction lock(control_data_, node->address(), INSERT, NO_USE);
224 CacheRankingsBlock head(backend_->File(head_), head_); 230 CacheRankingsBlock head(backend_->File(head_), head_);
225 if (head_.is_initialized()) { 231 if (head_.is_initialized()) {
226 if (!GetRanking(&head)) 232 if (!GetRanking(&head))
227 return; 233 return;
228 234
229 if (head.Data()->prev != head_.value() && // Normal path. 235 if (head.Data()->prev != head_.value() && // Normal path.
230 head.Data()->prev != node->address().value()) { // FinishInsert(). 236 head.Data()->prev != node->address().value()) { // FinishInsert().
231 backend_->CriticalError(ERR_INVALID_LINKS); 237 backend_->CriticalError(ERR_INVALID_LINKS);
232 return; 238 return;
233 } 239 }
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 } 306 }
301 307
302 CacheRankingsBlock next(backend_->File(next_addr), next_addr); 308 CacheRankingsBlock next(backend_->File(next_addr), next_addr);
303 CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr); 309 CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr);
304 if (!GetRanking(&next) || !GetRanking(&prev)) 310 if (!GetRanking(&next) || !GetRanking(&prev))
305 return; 311 return;
306 312
307 if (!CheckLinks(node, &prev, &next)) 313 if (!CheckLinks(node, &prev, &next))
308 return; 314 return;
309 315
310 Transaction lock(header_->user, node->address(), REMOVE); 316 Transaction lock(control_data_, node->address(), REMOVE, NO_USE);
311 prev.Data()->next = next.address().value(); 317 prev.Data()->next = next.address().value();
312 next.Data()->prev = prev.address().value(); 318 next.Data()->prev = prev.address().value();
313 GenerateCrash(ON_REMOVE_1); 319 GenerateCrash(ON_REMOVE_1);
314 320
315 CacheAddr node_value = node->address().value(); 321 CacheAddr node_value = node->address().value();
316 if (node_value == head_.value() || node_value == tail_.value()) { 322 if (node_value == head_.value() || node_value == tail_.value()) {
317 if (head_.value() == tail_.value()) { 323 if (head_.value() == tail_.value()) {
318 head_.set_value(0); 324 head_.set_value(0);
319 tail_.set_value(0); 325 tail_.set_value(0);
320 326
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 // but the net effect is just an assert on debug when attempting to remove the 367 // but the net effect is just an assert on debug when attempting to remove the
362 // entry. Otherwise we'll need reentrant transactions, which is an overkill. 368 // entry. Otherwise we'll need reentrant transactions, which is an overkill.
363 void Rankings::UpdateRank(CacheRankingsBlock* node, bool modified) { 369 void Rankings::UpdateRank(CacheRankingsBlock* node, bool modified) {
364 Time start = Time::Now(); 370 Time start = Time::Now();
365 Remove(node); 371 Remove(node);
366 Insert(node, modified); 372 Insert(node, modified);
367 UMA_HISTOGRAM_TIMES(L"DiskCache.UpdateRank", Time::Now() - start); 373 UMA_HISTOGRAM_TIMES(L"DiskCache.UpdateRank", Time::Now() - start);
368 } 374 }
369 375
370 void Rankings::CompleteTransaction() { 376 void Rankings::CompleteTransaction() {
371 Addr node_addr(static_cast<CacheAddr>(header_->user[kTransactionIndex])); 377 Addr node_addr(static_cast<CacheAddr>(control_data_->transaction));
372 if (!node_addr.is_initialized() || node_addr.is_separate_file()) { 378 if (!node_addr.is_initialized() || node_addr.is_separate_file()) {
373 NOTREACHED(); 379 NOTREACHED();
374 LOG(ERROR) << "Invalid rankings info."; 380 LOG(ERROR) << "Invalid rankings info.";
375 return; 381 return;
376 } 382 }
377 383
378 Trace("CompleteTransaction 0x%x", node_addr.value()); 384 Trace("CompleteTransaction 0x%x", node_addr.value());
379 385
380 CacheRankingsBlock node(backend_->File(node_addr), node_addr); 386 CacheRankingsBlock node(backend_->File(node_addr), node_addr);
381 if (!node.Load()) 387 if (!node.Load())
382 return; 388 return;
383 389
384 node.Data()->pointer = NULL; 390 node.Data()->pointer = NULL;
385 node.Store(); 391 node.Store();
386 392
387 // We want to leave the node inside the list. The entry must me marked as 393 // We want to leave the node inside the list. The entry must me marked as
388 // dirty, and will be removed later. Otherwise, we'll get assertions when 394 // dirty, and will be removed later. Otherwise, we'll get assertions when
389 // attempting to remove the dirty entry. 395 // attempting to remove the dirty entry.
390 if (INSERT == header_->user[kOperationIndex]) { 396 if (INSERT == control_data_->operation) {
391 Trace("FinishInsert h:0x%x t:0x%x", head_.value(), tail_.value()); 397 Trace("FinishInsert h:0x%x t:0x%x", head_.value(), tail_.value());
392 FinishInsert(&node); 398 FinishInsert(&node);
393 } else if (REMOVE == header_->user[kOperationIndex]) { 399 } else if (REMOVE == control_data_->operation) {
394 Trace("RevertRemove h:0x%x t:0x%x", head_.value(), tail_.value()); 400 Trace("RevertRemove h:0x%x t:0x%x", head_.value(), tail_.value());
395 RevertRemove(&node); 401 RevertRemove(&node);
396 } else { 402 } else {
397 NOTREACHED(); 403 NOTREACHED();
398 LOG(ERROR) << "Invalid operation to recover."; 404 LOG(ERROR) << "Invalid operation to recover.";
399 } 405 }
400 } 406 }
401 407
402 void Rankings::FinishInsert(CacheRankingsBlock* node) { 408 void Rankings::FinishInsert(CacheRankingsBlock* node) {
403 header_->user[kTransactionIndex] = 0; 409 control_data_->transaction = 0;
404 header_->user[kOperationIndex] = 0; 410 control_data_->operation = 0;
405 if (head_.value() != node->address().value()) { 411 if (head_.value() != node->address().value()) {
406 if (tail_.value() == node->address().value()) { 412 if (tail_.value() == node->address().value()) {
407 // This part will be skipped by the logic of Insert. 413 // This part will be skipped by the logic of Insert.
408 node->Data()->next = tail_.value(); 414 node->Data()->next = tail_.value();
409 } 415 }
410 416
411 Insert(node, true); 417 Insert(node, true);
412 } 418 }
413 419
414 // Tell the backend about this entry. 420 // Tell the backend about this entry.
415 backend_->RecoveredEntry(node); 421 backend_->RecoveredEntry(node);
416 } 422 }
417 423
418 void Rankings::RevertRemove(CacheRankingsBlock* node) { 424 void Rankings::RevertRemove(CacheRankingsBlock* node) {
419 Addr next_addr(node->Data()->next); 425 Addr next_addr(node->Data()->next);
420 Addr prev_addr(node->Data()->prev); 426 Addr prev_addr(node->Data()->prev);
421 if (!next_addr.is_initialized() || !prev_addr.is_initialized()) { 427 if (!next_addr.is_initialized() || !prev_addr.is_initialized()) {
422 // The operation actually finished. Nothing to do. 428 // The operation actually finished. Nothing to do.
423 header_->user[kTransactionIndex] = 0; 429 control_data_->transaction = 0;
424 return; 430 return;
425 } 431 }
426 if (next_addr.is_separate_file() || prev_addr.is_separate_file()) { 432 if (next_addr.is_separate_file() || prev_addr.is_separate_file()) {
427 NOTREACHED(); 433 NOTREACHED();
428 LOG(WARNING) << "Invalid rankings info."; 434 LOG(WARNING) << "Invalid rankings info.";
429 header_->user[kTransactionIndex] = 0; 435 control_data_->transaction = 0;
430 return; 436 return;
431 } 437 }
432 438
433 CacheRankingsBlock next(backend_->File(next_addr), next_addr); 439 CacheRankingsBlock next(backend_->File(next_addr), next_addr);
434 CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr); 440 CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr);
435 if (!next.Load() || !prev.Load()) 441 if (!next.Load() || !prev.Load())
436 return; 442 return;
437 443
438 CacheAddr node_value = node->address().value(); 444 CacheAddr node_value = node->address().value();
439 DCHECK(prev.Data()->next == node_value || 445 DCHECK(prev.Data()->next == node_value ||
(...skipping 18 matching lines...) Expand all
458 prev.Data()->next = next.address().value(); 464 prev.Data()->next = next.address().value();
459 WriteHead(); 465 WriteHead();
460 } else if (tail_.value() == prev.address().value()) { 466 } else if (tail_.value() == prev.address().value()) {
461 tail_.set_value(node_value); 467 tail_.set_value(node_value);
462 next.Data()->prev = prev.address().value(); 468 next.Data()->prev = prev.address().value();
463 WriteTail(); 469 WriteTail();
464 } 470 }
465 471
466 next.Store(); 472 next.Store();
467 prev.Store(); 473 prev.Store();
468 header_->user[kTransactionIndex] = 0; 474 control_data_->transaction = 0;
469 header_->user[kOperationIndex] = 0; 475 control_data_->operation = 0;
470 } 476 }
471 477
472 CacheRankingsBlock* Rankings::GetNext(CacheRankingsBlock* node) { 478 CacheRankingsBlock* Rankings::GetNext(CacheRankingsBlock* node) {
473 ScopedRankingsBlock next(this); 479 ScopedRankingsBlock next(this);
474 if (!node) { 480 if (!node) {
475 if (!head_.is_initialized()) 481 if (!head_.is_initialized())
476 return NULL; 482 return NULL;
477 next.reset(new CacheRankingsBlock(backend_->File(head_), head_)); 483 next.reset(new CacheRankingsBlock(backend_->File(head_), head_));
478 } else { 484 } else {
479 if (!tail_.is_initialized()) 485 if (!tail_.is_initialized())
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 if ((node->address().value() == data->prev) && (head_.value() != data->prev)) 587 if ((node->address().value() == data->prev) && (head_.value() != data->prev))
582 return false; 588 return false;
583 589
584 if ((node->address().value() == data->next) && (tail_.value() != data->next)) 590 if ((node->address().value() == data->next) && (tail_.value() != data->next))
585 return false; 591 return false;
586 592
587 return true; 593 return true;
588 } 594 }
589 595
590 Addr Rankings::ReadHead() { 596 Addr Rankings::ReadHead() {
591 CacheAddr head = static_cast<CacheAddr>(header_->user[kHeadIndex]); 597 return Addr(control_data_->heads[NO_USE]);
592 return Addr(head);
593 } 598 }
594 599
595 Addr Rankings::ReadTail() { 600 Addr Rankings::ReadTail() {
596 CacheAddr tail = static_cast<CacheAddr>(header_->user[kTailIndex]); 601 return Addr(control_data_->tails[NO_USE]);
597 return Addr(tail);
598 } 602 }
599 603
600 void Rankings::WriteHead() { 604 void Rankings::WriteHead() {
601 header_->user[kHeadIndex] = static_cast<int32>(head_.value()); 605 control_data_->heads[NO_USE] = head_.value();
602 } 606 }
603 607
604 void Rankings::WriteTail() { 608 void Rankings::WriteTail() {
605 header_->user[kTailIndex] = static_cast<int32>(tail_.value()); 609 control_data_->tails[NO_USE] = tail_.value();
606 } 610 }
607 611
608 bool Rankings::CheckEntry(CacheRankingsBlock* rankings) { 612 bool Rankings::CheckEntry(CacheRankingsBlock* rankings) {
609 if (!rankings->Data()->pointer) 613 if (!rankings->Data()->pointer)
610 return true; 614 return true;
611 615
612 // If this entry is not dirty, it is a serious problem. 616 // If this entry is not dirty, it is a serious problem.
613 return backend_->GetCurrentEntryId() != rankings->Data()->dirty; 617 return backend_->GetCurrentEntryId() != rankings->Data()->dirty;
614 } 618 }
615 619
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 ++it) { 675 ++it) {
672 if (it->first == address) { 676 if (it->first == address) {
673 CacheRankingsBlock* other = it->second; 677 CacheRankingsBlock* other = it->second;
674 other->Data()->next = node->Data()->next; 678 other->Data()->next = node->Data()->next;
675 other->Data()->prev = node->Data()->prev; 679 other->Data()->prev = node->Data()->prev;
676 } 680 }
677 } 681 }
678 } 682 }
679 683
680 } // namespace disk_cache 684 } // namespace disk_cache
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698