| OLD | NEW | 
|     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/backend_impl.h" |     5 #include "net/disk_cache/backend_impl.h" | 
|     6  |     6  | 
|     7 #include "base/file_util.h" |     7 #include "base/file_util.h" | 
|     8 #include "base/histogram.h" |     8 #include "base/histogram.h" | 
|     9 #include "base/message_loop.h" |     9 #include "base/message_loop.h" | 
|    10 #include "base/string_util.h" |    10 #include "base/string_util.h" | 
|    11 #include "base/sys_info.h" |    11 #include "base/sys_info.h" | 
|    12 #include "base/timer.h" |    12 #include "base/timer.h" | 
|    13 #include "base/worker_pool.h" |    13 #include "base/worker_pool.h" | 
|    14 #include "net/disk_cache/cache_util.h" |    14 #include "net/disk_cache/cache_util.h" | 
|    15 #include "net/disk_cache/entry_impl.h" |    15 #include "net/disk_cache/entry_impl.h" | 
|    16 #include "net/disk_cache/errors.h" |    16 #include "net/disk_cache/errors.h" | 
|    17 #include "net/disk_cache/hash.h" |    17 #include "net/disk_cache/hash.h" | 
|    18 #include "net/disk_cache/file.h" |    18 #include "net/disk_cache/file.h" | 
|    19  |    19  | 
 |    20 // Uncomment this to use the new eviction algorithm. | 
 |    21 // #define USE_NEW_EVICTION | 
 |    22  | 
|    20 using base::Time; |    23 using base::Time; | 
|    21 using base::TimeDelta; |    24 using base::TimeDelta; | 
|    22  |    25  | 
|    23 namespace { |    26 namespace { | 
|    24  |    27  | 
|    25 const wchar_t* kIndexName = L"index"; |    28 const wchar_t* kIndexName = L"index"; | 
|    26 const int kMaxOldFolders = 100; |    29 const int kMaxOldFolders = 100; | 
|    27  |    30  | 
|    28 // Seems like ~240 MB correspond to less than 50k entries for 99% of the people. |    31 // Seems like ~240 MB correspond to less than 50k entries for 99% of the people. | 
|    29 const int k64kEntriesStore = 240 * 1000 * 1000; |    32 const int k64kEntriesStore = 240 * 1000 * 1000; | 
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   177   return NULL; |   180   return NULL; | 
|   178 } |   181 } | 
|   179  |   182  | 
|   180 // ------------------------------------------------------------------------ |   183 // ------------------------------------------------------------------------ | 
|   181  |   184  | 
|   182 bool BackendImpl::Init() { |   185 bool BackendImpl::Init() { | 
|   183   DCHECK(!init_); |   186   DCHECK(!init_); | 
|   184   if (init_) |   187   if (init_) | 
|   185     return false; |   188     return false; | 
|   186  |   189  | 
 |   190 #ifdef USE_NEW_EVICTION | 
 |   191   new_eviction_ = true; | 
 |   192 #endif | 
 |   193  | 
|   187   bool create_files = false; |   194   bool create_files = false; | 
|   188   if (!InitBackingStore(&create_files)) { |   195   if (!InitBackingStore(&create_files)) { | 
|   189     ReportError(ERR_STORAGE_ERROR); |   196     ReportError(ERR_STORAGE_ERROR); | 
|   190     return false; |   197     return false; | 
|   191   } |   198   } | 
|   192  |   199  | 
|   193   num_refs_ = num_pending_io_ = max_refs_ = 0; |   200   num_refs_ = num_pending_io_ = max_refs_ = 0; | 
|   194  |   201  | 
|   195   if (!restarted_) { |   202   if (!restarted_) { | 
|   196     // Create a recurrent timer of 30 secs. |   203     // Create a recurrent timer of 30 secs. | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
|   224   } |   231   } | 
|   225  |   232  | 
|   226   if (!block_files_.Init(create_files)) |   233   if (!block_files_.Init(create_files)) | 
|   227     return false; |   234     return false; | 
|   228  |   235  | 
|   229   // stats_ and rankings_ may end up calling back to us so we better be enabled. |   236   // stats_ and rankings_ may end up calling back to us so we better be enabled. | 
|   230   disabled_ = false; |   237   disabled_ = false; | 
|   231   if (!stats_.Init(this, &data_->header.stats)) |   238   if (!stats_.Init(this, &data_->header.stats)) | 
|   232     return false; |   239     return false; | 
|   233  |   240  | 
|   234   disabled_ = !rankings_.Init(this); |   241   disabled_ = !rankings_.Init(this, new_eviction_); | 
|   235   eviction_.Init(this); |   242   eviction_.Init(this); | 
|   236  |   243  | 
|   237   return !disabled_; |   244   return !disabled_; | 
|   238 } |   245 } | 
|   239  |   246  | 
|   240 BackendImpl::~BackendImpl() { |   247 BackendImpl::~BackendImpl() { | 
|   241   Trace("Backend destructor"); |   248   Trace("Backend destructor"); | 
|   242   if (!init_) |   249   if (!init_) | 
|   243     return; |   250     return; | 
|   244  |   251  | 
|   245   if (data_) |   252   if (data_) | 
|   246     data_->header.crash = 0; |   253     data_->header.crash = 0; | 
|   247  |   254  | 
|   248   timer_.Stop(); |   255   timer_.Stop(); | 
|   249  |   256  | 
|   250   WaitForPendingIO(&num_pending_io_); |   257   WaitForPendingIO(&num_pending_io_); | 
|   251   DCHECK(!num_refs_); |   258   DCHECK(!num_refs_); | 
|   252 } |   259 } | 
|   253  |   260  | 
|   254 // ------------------------------------------------------------------------ |   261 // ------------------------------------------------------------------------ | 
|   255  |   262  | 
|   256 int32 BackendImpl::GetEntryCount() const { |   263 int32 BackendImpl::GetEntryCount() const { | 
|   257   if (!index_) |   264   if (!index_) | 
|   258     return 0; |   265     return 0; | 
|   259   return data_->header.num_entries; |   266   // num_entries includes entries already evicted. | 
 |   267   int32 not_deleted = data_->header.num_entries - | 
 |   268                       data_->header.lru.sizes[Rankings::DELETED]; | 
 |   269  | 
 |   270   if (not_deleted < 0) { | 
 |   271     NOTREACHED(); | 
 |   272     not_deleted = 0; | 
 |   273   } | 
 |   274  | 
 |   275   return not_deleted; | 
|   260 } |   276 } | 
|   261  |   277  | 
|   262 bool BackendImpl::OpenEntry(const std::string& key, Entry** entry) { |   278 bool BackendImpl::OpenEntry(const std::string& key, Entry** entry) { | 
|   263   if (disabled_) |   279   if (disabled_) | 
|   264     return false; |   280     return false; | 
|   265  |   281  | 
|   266   Time start = Time::Now(); |   282   Time start = Time::Now(); | 
|   267   uint32 hash = Hash(key); |   283   uint32 hash = Hash(key); | 
|   268  |   284  | 
|   269   EntryImpl* cache_entry = MatchEntry(key, hash, false); |   285   EntryImpl* cache_entry = MatchEntry(key, hash, false); | 
|   270   if (!cache_entry) { |   286   if (!cache_entry) { | 
|   271     stats_.OnEvent(Stats::OPEN_MISS); |   287     stats_.OnEvent(Stats::OPEN_MISS); | 
|   272     return false; |   288     return false; | 
|   273   } |   289   } | 
|   274  |   290  | 
 |   291   if (ENTRY_NORMAL != cache_entry->entry()->Data()->state) { | 
 |   292     // The entry was already evicted. | 
 |   293     cache_entry->Release(); | 
 |   294     stats_.OnEvent(Stats::OPEN_MISS); | 
 |   295     return false; | 
 |   296   } | 
 |   297  | 
|   275   eviction_.OnOpenEntry(cache_entry); |   298   eviction_.OnOpenEntry(cache_entry); | 
|   276   DCHECK(entry); |   299   DCHECK(entry); | 
|   277   *entry = cache_entry; |   300   *entry = cache_entry; | 
|   278  |   301  | 
|   279   UMA_HISTOGRAM_TIMES("DiskCache.OpenTime", Time::Now() - start); |   302   UMA_HISTOGRAM_TIMES("DiskCache.OpenTime", Time::Now() - start); | 
|   280   stats_.OnEvent(Stats::OPEN_HIT); |   303   stats_.OnEvent(Stats::OPEN_HIT); | 
|   281   return true; |   304   return true; | 
|   282 } |   305 } | 
|   283  |   306  | 
|   284 bool BackendImpl::CreateEntry(const std::string& key, Entry** entry) { |   307 bool BackendImpl::CreateEntry(const std::string& key, Entry** entry) { | 
|   285   if (disabled_ || key.empty()) |   308   if (disabled_ || key.empty()) | 
|   286     return false; |   309     return false; | 
|   287  |   310  | 
 |   311   DCHECK(entry); | 
 |   312   *entry = NULL; | 
 |   313  | 
|   288   Time start = Time::Now(); |   314   Time start = Time::Now(); | 
|   289   uint32 hash = Hash(key); |   315   uint32 hash = Hash(key); | 
|   290  |   316  | 
|   291   scoped_refptr<EntryImpl> parent; |   317   scoped_refptr<EntryImpl> parent; | 
|   292   Addr entry_address(data_->table[hash & mask_]); |   318   Addr entry_address(data_->table[hash & mask_]); | 
|   293   if (entry_address.is_initialized()) { |   319   if (entry_address.is_initialized()) { | 
 |   320     // We have an entry already. It could be the one we are looking for, or just | 
 |   321     // a hash conflict. | 
 |   322     EntryImpl* old_entry = MatchEntry(key, hash, false); | 
 |   323     if (old_entry) | 
 |   324       return ResurrectEntry(old_entry, entry); | 
 |   325  | 
|   294     EntryImpl* parent_entry = MatchEntry(key, hash, true); |   326     EntryImpl* parent_entry = MatchEntry(key, hash, true); | 
|   295     if (!parent_entry) { |   327     if (!parent_entry) { | 
|   296       stats_.OnEvent(Stats::CREATE_MISS); |   328       NOTREACHED(); | 
|   297       Trace("create entry miss "); |  | 
|   298       return false; |   329       return false; | 
|   299     } |   330     } | 
|   300     parent.swap(&parent_entry); |   331     parent.swap(&parent_entry); | 
|   301   } |   332   } | 
|   302  |   333  | 
|   303   int num_blocks; |   334   int num_blocks; | 
|   304   size_t key1_len = sizeof(EntryStore) - offsetof(EntryStore, key); |   335   size_t key1_len = sizeof(EntryStore) - offsetof(EntryStore, key); | 
|   305   if (key.size() < key1_len || |   336   if (key.size() < key1_len || | 
|   306       key.size() > static_cast<size_t>(kMaxInternalKeyLength)) |   337       key.size() > static_cast<size_t>(kMaxInternalKeyLength)) | 
|   307     num_blocks = 1; |   338     num_blocks = 1; | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
|   332     stats_.OnEvent(Stats::CREATE_ERROR); |   363     stats_.OnEvent(Stats::CREATE_ERROR); | 
|   333     return false; |   364     return false; | 
|   334   } |   365   } | 
|   335  |   366  | 
|   336   if (parent.get()) |   367   if (parent.get()) | 
|   337     parent->SetNextAddress(entry_address); |   368     parent->SetNextAddress(entry_address); | 
|   338  |   369  | 
|   339   block_files_.GetFile(entry_address)->Store(cache_entry->entry()); |   370   block_files_.GetFile(entry_address)->Store(cache_entry->entry()); | 
|   340   block_files_.GetFile(node_address)->Store(cache_entry->rankings()); |   371   block_files_.GetFile(node_address)->Store(cache_entry->rankings()); | 
|   341  |   372  | 
|   342   data_->header.num_entries++; |   373   IncreaseNumEntries(); | 
|   343   DCHECK(data_->header.num_entries > 0); |  | 
|   344   eviction_.OnCreateEntry(cache_entry); |   374   eviction_.OnCreateEntry(cache_entry); | 
|   345   if (!parent.get()) |   375   if (!parent.get()) | 
|   346     data_->table[hash & mask_] = entry_address.value(); |   376     data_->table[hash & mask_] = entry_address.value(); | 
|   347  |   377  | 
|   348   DCHECK(entry); |  | 
|   349   *entry = NULL; |  | 
|   350   cache_entry.swap(reinterpret_cast<EntryImpl**>(entry)); |   378   cache_entry.swap(reinterpret_cast<EntryImpl**>(entry)); | 
|   351  |   379  | 
|   352   UMA_HISTOGRAM_TIMES("DiskCache.CreateTime", Time::Now() - start); |   380   UMA_HISTOGRAM_TIMES("DiskCache.CreateTime", Time::Now() - start); | 
|   353   stats_.OnEvent(Stats::CREATE_HIT); |   381   stats_.OnEvent(Stats::CREATE_HIT); | 
|   354   Trace("create entry hit "); |   382   Trace("create entry hit "); | 
|   355   return true; |   383   return true; | 
|   356 } |   384 } | 
|   357  |   385  | 
|   358 bool BackendImpl::DoomEntry(const std::string& key) { |   386 bool BackendImpl::DoomEntry(const std::string& key) { | 
|   359   if (disabled_) |   387   if (disabled_) | 
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   444     entry->Close(); |   472     entry->Close(); | 
|   445     EndEnumeration(&iter);  // Dooming the entry invalidates the iterator. |   473     EndEnumeration(&iter);  // Dooming the entry invalidates the iterator. | 
|   446   } |   474   } | 
|   447 } |   475 } | 
|   448  |   476  | 
|   449 bool BackendImpl::OpenNextEntry(void** iter, Entry** next_entry) { |   477 bool BackendImpl::OpenNextEntry(void** iter, Entry** next_entry) { | 
|   450   return OpenFollowingEntry(true, iter, next_entry); |   478   return OpenFollowingEntry(true, iter, next_entry); | 
|   451 } |   479 } | 
|   452  |   480  | 
|   453 void BackendImpl::EndEnumeration(void** iter) { |   481 void BackendImpl::EndEnumeration(void** iter) { | 
|   454   Rankings::ScopedRankingsBlock rankings(&rankings_, |   482   scoped_ptr<Rankings::Iterator> iterator( | 
|   455       reinterpret_cast<CacheRankingsBlock*>(*iter)); |   483       reinterpret_cast<Rankings::Iterator*>(*iter)); | 
|   456   *iter = NULL; |   484   *iter = NULL; | 
|   457 } |   485 } | 
|   458  |   486  | 
|   459 void BackendImpl::GetStats(StatsItems* stats) { |   487 void BackendImpl::GetStats(StatsItems* stats) { | 
|   460   if (disabled_) |   488   if (disabled_) | 
|   461     return; |   489     return; | 
|   462  |   490  | 
|   463   std::pair<std::string, std::string> item; |   491   std::pair<std::string, std::string> item; | 
|   464  |   492  | 
|   465   item.first = "Entries"; |   493   item.first = "Entries"; | 
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   593   eviction_.OnDoomEntry(entry); |   621   eviction_.OnDoomEntry(entry); | 
|   594   entry->InternalDoom(); |   622   entry->InternalDoom(); | 
|   595  |   623  | 
|   596   if (parent_entry) { |   624   if (parent_entry) { | 
|   597     parent_entry->SetNextAddress(Addr(child)); |   625     parent_entry->SetNextAddress(Addr(child)); | 
|   598     parent_entry->Release(); |   626     parent_entry->Release(); | 
|   599   } else { |   627   } else { | 
|   600     data_->table[hash & mask_] = child; |   628     data_->table[hash & mask_] = child; | 
|   601   } |   629   } | 
|   602  |   630  | 
|   603   data_->header.num_entries--; |   631   if (!new_eviction_) { | 
|   604   DCHECK(data_->header.num_entries >= 0); |   632     DecreaseNumEntries(); | 
 |   633   } | 
 |   634  | 
|   605   stats_.OnEvent(Stats::DOOM_ENTRY); |   635   stats_.OnEvent(Stats::DOOM_ENTRY); | 
|   606 } |   636 } | 
|   607  |   637  | 
 |   638 // An entry may be linked on the DELETED list for a while after being doomed. | 
 |   639 // This function is called when we want to remove it. | 
 |   640 void BackendImpl::RemoveEntry(EntryImpl* entry) { | 
 |   641   if (!new_eviction_) | 
 |   642     return; | 
 |   643  | 
 |   644   DCHECK(ENTRY_DOOMED == entry->entry()->Data()->state); | 
 |   645  | 
 |   646   Trace("Remove entry 0x%p", entry); | 
 |   647   eviction_.OnDestroyEntry(entry); | 
 |   648   DecreaseNumEntries(); | 
 |   649 } | 
 |   650  | 
|   608 void BackendImpl::CacheEntryDestroyed() { |   651 void BackendImpl::CacheEntryDestroyed() { | 
|   609   DecreaseNumRefs(); |   652   DecreaseNumRefs(); | 
|   610 } |   653 } | 
|   611  |   654  | 
|   612 int32 BackendImpl::GetCurrentEntryId() { |   655 int32 BackendImpl::GetCurrentEntryId() { | 
|   613   return data_->header.this_id; |   656   return data_->header.this_id; | 
|   614 } |   657 } | 
|   615  |   658  | 
|   616 int BackendImpl::MaxFileSize() const { |   659 int BackendImpl::MaxFileSize() const { | 
|   617   return max_size_ / 8; |   660   return max_size_ / 8; | 
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   735 // ------------------------------------------------------------------------ |   778 // ------------------------------------------------------------------------ | 
|   736  |   779  | 
|   737 // We just created a new file so we're going to write the header and set the |   780 // We just created a new file so we're going to write the header and set the | 
|   738 // file length to include the hash table (zero filled). |   781 // file length to include the hash table (zero filled). | 
|   739 bool BackendImpl::CreateBackingStore(disk_cache::File* file) { |   782 bool BackendImpl::CreateBackingStore(disk_cache::File* file) { | 
|   740   AdjustMaxCacheSize(0); |   783   AdjustMaxCacheSize(0); | 
|   741  |   784  | 
|   742   IndexHeader header; |   785   IndexHeader header; | 
|   743   header.table_len = DesiredIndexTableLen(max_size_); |   786   header.table_len = DesiredIndexTableLen(max_size_); | 
|   744  |   787  | 
 |   788   // We need file version 2.1 for the new eviction algorithm. | 
 |   789   if (new_eviction_) | 
 |   790     header.version = 0x20001; | 
 |   791  | 
|   745   if (!file->Write(&header, sizeof(header), 0)) |   792   if (!file->Write(&header, sizeof(header), 0)) | 
|   746     return false; |   793     return false; | 
|   747  |   794  | 
|   748   return file->SetLength(GetIndexSize(header.table_len)); |   795   return file->SetLength(GetIndexSize(header.table_len)); | 
|   749 } |   796 } | 
|   750  |   797  | 
|   751 bool BackendImpl::InitBackingStore(bool* file_created) { |   798 bool BackendImpl::InitBackingStore(bool* file_created) { | 
|   752   file_util::CreateDirectory(path_); |   799   file_util::CreateDirectory(path_); | 
|   753  |   800  | 
|   754   std::wstring index_name(path_); |   801   std::wstring index_name(path_); | 
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   955  |  1002  | 
|   956   return find_parent ? parent_entry : cache_entry; |  1003   return find_parent ? parent_entry : cache_entry; | 
|   957 } |  1004 } | 
|   958  |  1005  | 
|   959 // This is the actual implementation for OpenNextEntry and OpenPrevEntry. |  1006 // This is the actual implementation for OpenNextEntry and OpenPrevEntry. | 
|   960 bool BackendImpl::OpenFollowingEntry(bool forward, void** iter, |  1007 bool BackendImpl::OpenFollowingEntry(bool forward, void** iter, | 
|   961                                      Entry** next_entry) { |  1008                                      Entry** next_entry) { | 
|   962   if (disabled_) |  1009   if (disabled_) | 
|   963     return false; |  1010     return false; | 
|   964  |  1011  | 
|   965   Rankings::ScopedRankingsBlock rankings(&rankings_, |  1012   DCHECK(iter); | 
|   966       reinterpret_cast<CacheRankingsBlock*>(*iter)); |  1013   DCHECK(next_entry); | 
|   967   CacheRankingsBlock* next_block = forward ? |  | 
|   968       rankings_.GetNext(rankings.get(), Rankings::NO_USE) : |  | 
|   969       rankings_.GetPrev(rankings.get(), Rankings::NO_USE); |  | 
|   970   Rankings::ScopedRankingsBlock next(&rankings_, next_block); |  | 
|   971   *next_entry = NULL; |  1014   *next_entry = NULL; | 
 |  1015  | 
 |  1016   const int kListsToSearch = 3; | 
 |  1017   scoped_refptr<EntryImpl> entries[kListsToSearch]; | 
 |  1018   scoped_ptr<Rankings::Iterator> iterator( | 
 |  1019       reinterpret_cast<Rankings::Iterator*>(*iter)); | 
|   972   *iter = NULL; |  1020   *iter = NULL; | 
|   973   if (!next.get()) |  1021  | 
 |  1022   if (!iterator.get()) { | 
 |  1023     iterator.reset(new Rankings::Iterator(&rankings_)); | 
 |  1024     bool ret = false; | 
 |  1025  | 
 |  1026     // Get an entry from each list. | 
 |  1027     for (int i = 0; i < kListsToSearch; i++) { | 
 |  1028       EntryImpl* temp = NULL; | 
 |  1029       ret |= OpenFollowingEntryFromList(forward, static_cast<Rankings::List>(i), | 
 |  1030                                         &iterator->nodes[i], &temp); | 
 |  1031       entries[i].swap(&temp);  // The entry was already addref'd. | 
 |  1032     } | 
 |  1033     if (!ret) | 
 |  1034       return false; | 
 |  1035   } else { | 
 |  1036     // Get the next entry from the last list, and the actual entries for the | 
 |  1037     // elements on the other lists. | 
 |  1038     for (int i = 0; i < kListsToSearch; i++) { | 
 |  1039       EntryImpl* temp = NULL; | 
 |  1040       if (iterator->list == i) { | 
 |  1041           OpenFollowingEntryFromList(forward, iterator->list, | 
 |  1042                                      &iterator->nodes[i], &temp); | 
 |  1043       } else { | 
 |  1044         temp = GetEnumeratedEntry(iterator->nodes[i]); | 
 |  1045       } | 
 |  1046  | 
 |  1047       entries[i].swap(&temp);  // The entry was already addref'd. | 
 |  1048     } | 
 |  1049   } | 
 |  1050  | 
 |  1051   int newest = -1; | 
 |  1052   int oldest = -1; | 
 |  1053   Time access_times[kListsToSearch]; | 
 |  1054   for (int i = 0; i < kListsToSearch; i++) { | 
 |  1055     if (entries[i].get()) { | 
 |  1056       access_times[i] = entries[i]->GetLastUsed(); | 
 |  1057       if (newest < 0) { | 
 |  1058         DCHECK(oldest < 0); | 
 |  1059         newest = oldest = i; | 
 |  1060         continue; | 
 |  1061       } | 
 |  1062       if (access_times[i] > access_times[newest]) | 
 |  1063         newest = i; | 
 |  1064       if (access_times[i] < access_times[oldest]) | 
 |  1065         oldest = i; | 
 |  1066     } | 
 |  1067   } | 
 |  1068  | 
 |  1069   if (newest < 0 || oldest < 0) | 
|   974     return false; |  1070     return false; | 
|   975  |  1071  | 
|   976   scoped_refptr<EntryImpl> entry; |  1072   if (forward) { | 
|   977   if (next->Data()->pointer) { |  1073     entries[newest].swap(reinterpret_cast<EntryImpl**>(next_entry)); | 
|   978     entry = reinterpret_cast<EntryImpl*>(next->Data()->pointer); |  1074     iterator->list = static_cast<Rankings::List>(newest); | 
|   979   } else { |  1075   } else { | 
|   980     bool dirty; |  1076     entries[oldest].swap(reinterpret_cast<EntryImpl**>(next_entry)); | 
|   981     EntryImpl* temp = NULL; |  1077     iterator->list = static_cast<Rankings::List>(oldest); | 
|   982     if (NewEntry(Addr(next->Data()->contents), &temp, &dirty)) |  | 
|   983       return false; |  | 
|   984     entry.swap(&temp); |  | 
|   985  |  | 
|   986     if (dirty) { |  | 
|   987       // We cannot trust this entry. Call MatchEntry to go through the regular |  | 
|   988       // path and take the appropriate action. |  | 
|   989       std::string key = entry->GetKey(); |  | 
|   990       uint32 hash = entry->GetHash(); |  | 
|   991       entry = NULL;  // Release the entry. |  | 
|   992       temp = MatchEntry(key, hash, false); |  | 
|   993       if (temp) |  | 
|   994         temp->Release(); |  | 
|   995  |  | 
|   996       return false; |  | 
|   997     } |  | 
|   998  |  | 
|   999     entry.swap(&temp); |  | 
|  1000     temp = EntryImpl::Update(temp);  // Update returns an adref'd entry. |  | 
|  1001     entry.swap(&temp); |  | 
|  1002     if (!entry.get()) |  | 
|  1003       return false; |  | 
|  1004   } |  1078   } | 
|  1005  |  1079  | 
|  1006   entry.swap(reinterpret_cast<EntryImpl**>(next_entry)); |  1080   *iter = iterator.release(); | 
|  1007   *iter = next.release(); |  | 
|  1008   return true; |  1081   return true; | 
|  1009 } |  1082 } | 
|  1010  |  1083  | 
 |  1084 bool BackendImpl::OpenFollowingEntryFromList(bool forward, Rankings::List list, | 
 |  1085                                              CacheRankingsBlock** from_entry, | 
 |  1086                                              EntryImpl** next_entry) { | 
 |  1087   if (disabled_) | 
 |  1088     return false; | 
 |  1089  | 
 |  1090   if (!new_eviction_ && Rankings::NO_USE != list) | 
 |  1091     return false; | 
 |  1092  | 
 |  1093   Rankings::ScopedRankingsBlock rankings(&rankings_, *from_entry); | 
 |  1094   CacheRankingsBlock* next_block = forward ? | 
 |  1095       rankings_.GetNext(rankings.get(), list) : | 
 |  1096       rankings_.GetPrev(rankings.get(), list); | 
 |  1097   Rankings::ScopedRankingsBlock next(&rankings_, next_block); | 
 |  1098   *from_entry = NULL; | 
 |  1099  | 
 |  1100   *next_entry = GetEnumeratedEntry(next.get()); | 
 |  1101   if (!*next_entry) | 
 |  1102     return false; | 
 |  1103  | 
 |  1104   *from_entry = next.release(); | 
 |  1105   return true; | 
 |  1106 } | 
 |  1107  | 
 |  1108 EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next) { | 
 |  1109   if (!next) | 
 |  1110     return NULL; | 
 |  1111  | 
 |  1112   scoped_refptr<EntryImpl> entry; | 
 |  1113   EntryImpl* temp = NULL; | 
 |  1114  | 
 |  1115   if (next->Data()->pointer) { | 
 |  1116     entry = reinterpret_cast<EntryImpl*>(next->Data()->pointer); | 
 |  1117     entry.swap(&temp); | 
 |  1118     return temp; | 
 |  1119   } | 
 |  1120  | 
 |  1121   bool dirty; | 
 |  1122   if (NewEntry(Addr(next->Data()->contents), &temp, &dirty)) | 
 |  1123     return NULL; | 
 |  1124   entry.swap(&temp); | 
 |  1125  | 
 |  1126   if (dirty) { | 
 |  1127     // We cannot trust this entry. Call MatchEntry to go through the regular | 
 |  1128     // path and take the appropriate action. | 
 |  1129     std::string key = entry->GetKey(); | 
 |  1130     uint32 hash = entry->GetHash(); | 
 |  1131     entry = NULL;  // Release the entry. | 
 |  1132     temp = MatchEntry(key, hash, false); | 
 |  1133     if (temp) | 
 |  1134       temp->Release(); | 
 |  1135  | 
 |  1136     return NULL; | 
 |  1137   } | 
 |  1138  | 
 |  1139   entry.swap(&temp); | 
 |  1140   return EntryImpl::Update(temp);  // Update returns an adref'd entry. | 
 |  1141 } | 
 |  1142  | 
 |  1143 bool BackendImpl::ResurrectEntry(EntryImpl* deleted_entry, Entry** entry) { | 
 |  1144   if (ENTRY_NORMAL == deleted_entry->entry()->Data()->state) { | 
 |  1145     deleted_entry->Release(); | 
 |  1146     stats_.OnEvent(Stats::CREATE_MISS); | 
 |  1147     Trace("create entry miss "); | 
 |  1148     return false; | 
 |  1149   } | 
 |  1150  | 
 |  1151   // We are attempting to create an entry and found out that the entry was | 
 |  1152   // previously deleted. | 
 |  1153  | 
 |  1154   eviction_.OnCreateEntry(deleted_entry); | 
 |  1155   *entry = deleted_entry; | 
 |  1156  | 
 |  1157   stats_.OnEvent(Stats::CREATE_HIT); | 
 |  1158   Trace("Resurrect entry hit "); | 
 |  1159   return true; | 
 |  1160 } | 
 |  1161  | 
|  1011 void BackendImpl::DestroyInvalidEntry(Addr address, EntryImpl* entry) { |  1162 void BackendImpl::DestroyInvalidEntry(Addr address, EntryImpl* entry) { | 
|  1012   LOG(WARNING) << "Destroying invalid entry."; |  1163   LOG(WARNING) << "Destroying invalid entry."; | 
|  1013   Trace("Destroying invalid entry 0x%p", entry); |  1164   Trace("Destroying invalid entry 0x%p", entry); | 
|  1014  |  1165  | 
|  1015   entry->SetPointerForInvalidEntry(GetCurrentEntryId()); |  1166   entry->SetPointerForInvalidEntry(GetCurrentEntryId()); | 
|  1016  |  1167  | 
|  1017   eviction_.OnDoomEntry(entry); |  1168   eviction_.OnDoomEntry(entry); | 
|  1018   entry->InternalDoom(); |  1169   entry->InternalDoom(); | 
|  1019  |  1170  | 
|  1020   data_->header.num_entries--; |  1171   if (!new_eviction_) | 
|  1021   DCHECK(data_->header.num_entries >= 0); |  1172     DecreaseNumEntries(); | 
|  1022   stats_.OnEvent(Stats::INVALID_ENTRY); |  1173   stats_.OnEvent(Stats::INVALID_ENTRY); | 
|  1023 } |  1174 } | 
|  1024  |  1175  | 
|  1025 void BackendImpl::AddStorageSize(int32 bytes) { |  1176 void BackendImpl::AddStorageSize(int32 bytes) { | 
|  1026   data_->header.num_bytes += bytes; |  1177   data_->header.num_bytes += bytes; | 
|  1027   DCHECK(data_->header.num_bytes >= 0); |  1178   DCHECK(data_->header.num_bytes >= 0); | 
|  1028  |  1179  | 
|  1029   if (data_->header.num_bytes > max_size_) |  1180   if (data_->header.num_bytes > max_size_) | 
|  1030     eviction_.TrimCache(false); |  1181     eviction_.TrimCache(false); | 
|  1031 } |  1182 } | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
|  1042 } |  1193 } | 
|  1043  |  1194  | 
|  1044 void BackendImpl::DecreaseNumRefs() { |  1195 void BackendImpl::DecreaseNumRefs() { | 
|  1045   DCHECK(num_refs_); |  1196   DCHECK(num_refs_); | 
|  1046   num_refs_--; |  1197   num_refs_--; | 
|  1047  |  1198  | 
|  1048   if (!num_refs_ && disabled_) |  1199   if (!num_refs_ && disabled_) | 
|  1049     RestartCache(); |  1200     RestartCache(); | 
|  1050 } |  1201 } | 
|  1051  |  1202  | 
 |  1203 void BackendImpl::IncreaseNumEntries() { | 
 |  1204   data_->header.num_entries++; | 
 |  1205   DCHECK(data_->header.num_entries > 0); | 
 |  1206 } | 
 |  1207  | 
 |  1208 void BackendImpl::DecreaseNumEntries() { | 
 |  1209   data_->header.num_entries--; | 
 |  1210   if (data_->header.num_entries < 0) { | 
 |  1211     NOTREACHED(); | 
 |  1212     data_->header.num_entries = 0; | 
 |  1213   } | 
 |  1214 } | 
 |  1215  | 
|  1052 void BackendImpl::LogStats() { |  1216 void BackendImpl::LogStats() { | 
|  1053   StatsItems stats; |  1217   StatsItems stats; | 
|  1054   GetStats(&stats); |  1218   GetStats(&stats); | 
|  1055  |  1219  | 
|  1056   for (size_t index = 0; index < stats.size(); index++) { |  1220   for (size_t index = 0; index < stats.size(); index++) { | 
|  1057     LOG(INFO) << stats[index].first << ": " << stats[index].second; |  1221     LOG(INFO) << stats[index].first << ": " << stats[index].second; | 
|  1058   } |  1222   } | 
|  1059 } |  1223 } | 
|  1060  |  1224  | 
 |  1225 void BackendImpl::UpgradeTo2_1() { | 
 |  1226   // 2.1 is basically the same as 2.0, except that new fields are actually | 
 |  1227   // updated by the new eviction algorithm. | 
 |  1228   DCHECK(0x20000 == data_->header.version); | 
 |  1229   data_->header.version = 0x20001; | 
 |  1230   data_->header.lru.sizes[Rankings::NO_USE] = data_->header.num_entries; | 
 |  1231 } | 
 |  1232  | 
|  1061 bool BackendImpl::CheckIndex() { |  1233 bool BackendImpl::CheckIndex() { | 
|  1062   if (!data_) { |  1234   if (!data_) { | 
|  1063     LOG(ERROR) << "Unable to map Index file"; |  1235     LOG(ERROR) << "Unable to map Index file"; | 
|  1064     return false; |  1236     return false; | 
|  1065   } |  1237   } | 
|  1066  |  1238  | 
|  1067   size_t current_size = index_->GetLength(); |  1239   size_t current_size = index_->GetLength(); | 
|  1068   if (current_size < sizeof(Index)) { |  1240   if (current_size < sizeof(Index)) { | 
|  1069     LOG(ERROR) << "Corrupt Index file"; |  1241     LOG(ERROR) << "Corrupt Index file"; | 
|  1070     return false; |  1242     return false; | 
|  1071   } |  1243   } | 
|  1072  |  1244  | 
|  1073   if (kIndexMagic != data_->header.magic || |  1245   if (new_eviction_) { | 
|  1074       kCurrentVersion != data_->header.version) { |  1246     // We support versions 2.0 and 2.1, upgrading 2.0 to 2.1. | 
|  1075     LOG(ERROR) << "Invalid file version or magic"; |  1247     if (kIndexMagic != data_->header.magic || | 
|  1076     return false; |  1248         kCurrentVersion >> 16 != data_->header.version >> 16) { | 
 |  1249       LOG(ERROR) << "Invalid file version or magic"; | 
 |  1250       return false; | 
 |  1251     } | 
 |  1252     if (kCurrentVersion == data_->header.version) { | 
 |  1253       // We need file version 2.1 for the new eviction algorithm. | 
 |  1254       UpgradeTo2_1(); | 
 |  1255     } | 
 |  1256   } else { | 
 |  1257     if (kIndexMagic != data_->header.magic || | 
 |  1258         kCurrentVersion != data_->header.version) { | 
 |  1259       LOG(ERROR) << "Invalid file version or magic"; | 
 |  1260       return false; | 
 |  1261     } | 
|  1077   } |  1262   } | 
|  1078  |  1263  | 
|  1079   if (!data_->header.table_len) { |  1264   if (!data_->header.table_len) { | 
|  1080     LOG(ERROR) << "Invalid table size"; |  1265     LOG(ERROR) << "Invalid table size"; | 
|  1081     return false; |  1266     return false; | 
|  1082   } |  1267   } | 
|  1083  |  1268  | 
|  1084   if (current_size < GetIndexSize(data_->header.table_len) || |  1269   if (current_size < GetIndexSize(data_->header.table_len) || | 
|  1085       data_->header.table_len & (kBaseTableLen - 1)) { |  1270       data_->header.table_len & (kBaseTableLen - 1)) { | 
|  1086     LOG(ERROR) << "Corrupt Index file"; |  1271     LOG(ERROR) << "Corrupt Index file"; | 
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1153  |  1338  | 
|  1154   return num_dirty; |  1339   return num_dirty; | 
|  1155 } |  1340 } | 
|  1156  |  1341  | 
|  1157 bool BackendImpl::CheckEntry(EntryImpl* cache_entry) { |  1342 bool BackendImpl::CheckEntry(EntryImpl* cache_entry) { | 
|  1158   RankingsNode* rankings = cache_entry->rankings()->Data(); |  1343   RankingsNode* rankings = cache_entry->rankings()->Data(); | 
|  1159   return !rankings->pointer; |  1344   return !rankings->pointer; | 
|  1160 } |  1345 } | 
|  1161  |  1346  | 
|  1162 }  // namespace disk_cache |  1347 }  // namespace disk_cache | 
| OLD | NEW |