Index: net/disk_cache/v3/eviction_v3.cc |
=================================================================== |
--- net/disk_cache/v3/eviction_v3.cc (revision 232523) |
+++ net/disk_cache/v3/eviction_v3.cc (working copy) |
@@ -26,7 +26,7 @@ |
// size so that we have a chance to see an element again and move it to another |
// list. |
-#include "net/disk_cache/eviction.h" |
+#include "net/disk_cache/v3/eviction_v3.h" |
#include "base/bind.h" |
#include "base/compiler_specific.h" |
@@ -34,13 +34,17 @@ |
#include "base/message_loop/message_loop.h" |
#include "base/strings/string_util.h" |
#include "base/time/time.h" |
-#include "net/disk_cache/backend_impl.h" |
-#include "net/disk_cache/entry_impl.h" |
+#include "net/base/net_errors.h" |
#include "net/disk_cache/experiments.h" |
#include "net/disk_cache/histogram_macros.h" |
#include "net/disk_cache/trace.h" |
+#include "net/disk_cache/v3/backend_impl_v3.h" |
+#include "net/disk_cache/v3/entry_impl_v3.h" |
+#include "net/disk_cache/v3/index_table.h" |
+ |
using base::Time; |
+using base::TimeDelta; |
using base::TimeTicks; |
namespace { |
@@ -61,39 +65,47 @@ |
return current_size > max_size - kCleanUpMargin * 20; |
} |
+Time TimeFromTimestamp(int timestamp, int64 base_time) { |
+ return Time::FromInternalValue(base_time) + TimeDelta::FromSeconds(timestamp); |
+} |
+ |
} // namespace |
namespace disk_cache { |
// The real initialization happens during Init(), init_ is the only member that |
// has to be initialized here. |
-Eviction::Eviction() |
+EvictionV3::EvictionV3() |
: backend_(NULL), |
+ index_(NULL), |
+ header_(NULL), |
init_(false), |
+ cells_to_evict_(NULL), |
ptr_factory_(this) { |
} |
-Eviction::~Eviction() { |
+EvictionV3::~EvictionV3() { |
} |
-void Eviction::Init(BackendImpl* backend) { |
+void EvictionV3::Init(BackendImplV3* backend) { |
// We grab a bunch of info from the backend to make the code a little cleaner |
// when we're actually doing work. |
backend_ = backend; |
- rankings_ = &backend->rankings_; |
- header_ = &backend_->data_->header; |
+ index_ = &backend_->index_; |
+ header_ = index_->header(); |
max_size_ = LowWaterAdjust(backend_->max_size_); |
- index_size_ = backend->mask_ + 1; |
- new_eviction_ = backend->new_eviction_; |
+ index_size_ = 1;//? |
+ lru_ = backend->lru_eviction_; |
first_trim_ = true; |
trimming_ = false; |
delay_trim_ = false; |
trim_delays_ = 0; |
init_ = true; |
test_mode_ = false; |
+ empty_ = false; |
} |
-void Eviction::Stop() { |
+void EvictionV3::Stop() { |
// It is possible for the backend initialization to fail, in which case this |
// object was never initialized... and there is nothing to do. |
if (!init_) |
@@ -101,148 +113,148 @@ |
// We want to stop further evictions, so let's pretend that we are busy from |
// this point on. |
- DCHECK(!trimming_); |
+ DCHECK(!trimming_);//cannot do |
trimming_ = true; |
ptr_factory_.InvalidateWeakPtrs(); |
} |
-void Eviction::TrimCache(bool empty) { |
- if (backend_->disabled_ || trimming_) |
+void EvictionV3::TrimCache() { |
+ if (trimming_) |
return; |
- if (!empty && !ShouldTrim()) |
+ if (!ShouldTrim()) |
return PostDelayedTrim(); |
- if (new_eviction_) |
- return TrimCacheV2(empty); |
- |
Trace("*** Trim Cache ***"); |
trimming_ = true; |
- TimeTicks start = TimeTicks::Now(); |
- Rankings::ScopedRankingsBlock node(rankings_); |
- Rankings::ScopedRankingsBlock next( |
- rankings_, rankings_->GetPrev(node.get(), Rankings::NO_USE)); |
- int deleted_entries = 0; |
- int target_size = empty ? 0 : max_size_; |
- while ((header_->num_bytes > target_size || test_mode_) && next.get()) { |
- // The iterator could be invalidated within EvictEntry(). |
- if (!next->HasData()) |
- break; |
- node.reset(next.release()); |
- next.reset(rankings_->GetPrev(node.get(), Rankings::NO_USE)); |
- if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { |
- // This entry is not being used by anybody. |
- // Do NOT use node as an iterator after this point. |
- rankings_->TrackRankingsBlock(node.get(), false); |
- if (EvictEntry(node.get(), empty, Rankings::NO_USE) && !test_mode_) |
- deleted_entries++; |
- if (!empty && test_mode_) |
- break; |
- } |
- if (!empty && (deleted_entries > 20 || |
- (TimeTicks::Now() - start).InMilliseconds() > 20)) { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&Eviction::TrimCache, ptr_factory_.GetWeakPtr(), false)); |
- break; |
- } |
+ if (!TrimCacheImpl()) { |
+ trimming_ = false; |
+ Trace("*** Trim Cache end ***"); |
} |
+} |
- if (empty) { |
- CACHE_UMA(AGE_MS, "TotalClearTimeV1", 0, start); |
- } else { |
- CACHE_UMA(AGE_MS, "TotalTrimTimeV1", 0, start); |
- } |
- CACHE_UMA(COUNTS, "TrimItemsV1", 0, deleted_entries); |
+int EvictionV3::TrimAllCache(const net::CompletionCallback& callback) { |
+ if (!callback_.is_null()) |
+ return net::ERR_FAILED; |
- trimming_ = false; |
- Trace("*** Trim Cache end ***"); |
- return; |
+ empty_ = true; |
+ trimming_ = true; |
+ Trace("*** Trim All Cache ***"); |
+ |
+ if (!TrimCacheImpl()) |
+ return net::OK; |
+ |
+ callback_ = callback; |
+ return net::ERR_IO_PENDING; |
} |
-void Eviction::OnOpenEntryV2(EntryImpl* entry) { |
- EntryStore* info = entry->entry()->Data(); |
- DCHECK_EQ(ENTRY_NORMAL, info->state); |
+void EvictionV3::OnOpenEntry(EntryImplV3* entry) { |
+ if (lru_) |
+ return; |
- if (info->reuse_count < kint32max) { |
- info->reuse_count++; |
- entry->entry()->set_modified(); |
+ EntryCell cell = index_->FindEntryCell(entry->GetHash(), entry->GetAddress()); |
+ DCHECK_NE(cell.GetGroup(), ENTRY_EVICTED); |
+ int reuse_count = entry->GetReuseCounter(); |
+ if (reuse_count < 256) { |
+ reuse_count++; |
+ entry->SetReuseCounter(reuse_count); |
+ |
// We may need to move this to a new list. |
- if (1 == info->reuse_count) { |
- rankings_->Remove(entry->rankings(), Rankings::NO_USE, true); |
- rankings_->Insert(entry->rankings(), false, Rankings::LOW_USE); |
- entry->entry()->Store(); |
- } else if (kHighUse == info->reuse_count) { |
- rankings_->Remove(entry->rankings(), Rankings::LOW_USE, true); |
- rankings_->Insert(entry->rankings(), false, Rankings::HIGH_USE); |
- entry->entry()->Store(); |
+ if (1 == reuse_count) { |
+ DCHECK_EQ(cell.GetGroup(), ENTRY_NO_USE); |
+ cell.SetGroup(ENTRY_LOW_USE); |
+ } else if (kHighUse == reuse_count) { |
+ DCHECK_EQ(cell.GetGroup(), ENTRY_LOW_USE); |
+ cell.SetGroup(ENTRY_HIGH_USE); |
} |
+ if (reuse_count < 16) { |
+ cell.SetReuse(reuse_count); |
+ index_->Save(&cell); |
+ } |
} |
} |
-void Eviction::OnCreateEntryV2(EntryImpl* entry) { |
- EntryStore* info = entry->entry()->Data(); |
- switch (info->state) { |
- case ENTRY_NORMAL: { |
- DCHECK(!info->reuse_count); |
- DCHECK(!info->refetch_count); |
- break; |
- }; |
- case ENTRY_EVICTED: { |
- if (info->refetch_count < kint32max) |
- info->refetch_count++; |
+void EvictionV3::OnCreateEntry(EntryImplV3* entry) { |
+ EntryCell cell = index_->FindEntryCell(entry->GetHash(), entry->GetAddress()); |
+ DCHECK_EQ(cell.GetGroup(), ENTRY_NO_USE); |
+ DCHECK(!entry->GetReuseCounter()); |
+ DCHECK(!entry->GetRefetchCounter()); |
+} |
- if (info->refetch_count > kHighUse && info->reuse_count < kHighUse) { |
- info->reuse_count = kHighUse; |
- } else { |
- info->reuse_count++; |
- } |
- info->state = ENTRY_NORMAL; |
- entry->entry()->Store(); |
- rankings_->Remove(entry->rankings(), Rankings::DELETED, true); |
- break; |
- }; |
- default: |
- NOTREACHED(); |
+void EvictionV3::OnResurrectEntry(EntryImplV3* entry) { |
+ DCHECK(!lru_); |
+ EntryCell cell = index_->FindEntryCell(entry->GetHash(), entry->GetAddress()); |
+ DCHECK_EQ(cell.GetGroup(), ENTRY_NO_USE); |
+ int reuse_count = entry->GetReuseCounter(); |
+ int refetch_count = entry->GetRefetchCounter(); |
+ |
+ if (refetch_count < 256) { |
+ refetch_count++; |
+ entry->SetRefetchCounter(refetch_count); |
} |
- rankings_->Insert(entry->rankings(), true, GetListForEntryV2(entry)); |
+ if (refetch_count > kHighUse && reuse_count < kHighUse) { |
+ reuse_count = kHighUse; |
+ } else if (reuse_count < 256) { |
+ reuse_count++; |
+ } |
+ entry->SetReuseCounter(reuse_count); |
+ |
+ if (reuse_count >= kHighUse) |
+ cell.SetGroup(ENTRY_HIGH_USE); |
+ else |
+ cell.SetGroup(ENTRY_LOW_USE); |
+ |
+ if (reuse_count < 16) |
+ cell.SetReuse(reuse_count); |
+ |
+ index_->Save(&cell); |
} |
-void Eviction::SetTestMode() { |
+void EvictionV3::OnEvictEntryComplete() { |
+ if (!test_mode_ && TrimCacheImpl()) |
+ return; |
+ |
+ trimming_ = false; |
+ Trace("*** Trim Cache end ***"); |
+ |
+ if (!callback_.is_null()) |
+ callback_.Run(net::OK); |
+} |
+ |
+void EvictionV3::SetTestMode() { |
test_mode_ = true; |
} |
-void Eviction::TrimDeletedList(bool empty) { |
- DCHECK(test_mode_ && new_eviction_); |
+void EvictionV3::TrimDeletedList(bool empty) { |
+ DCHECK(test_mode_ && !lru_); |
TrimDeleted(empty); |
} |
// ----------------------------------------------------------------------- |
-void Eviction::PostDelayedTrim() { |
+void EvictionV3::PostDelayedTrim() { |
// Prevent posting multiple tasks. |
if (delay_trim_) |
return; |
delay_trim_ = true; |
trim_delays_++; |
- base::MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&Eviction::DelayedTrim, ptr_factory_.GetWeakPtr()), |
+ base::MessageLoop::current()->PostDelayedTask(FROM_HERE, |
+ base::Bind(&EvictionV3::DelayedTrim, ptr_factory_.GetWeakPtr()), |
base::TimeDelta::FromMilliseconds(1000)); |
} |
-void Eviction::DelayedTrim() { |
+void EvictionV3::DelayedTrim() { |
delay_trim_ = false; |
if (trim_delays_ < kMaxDelayedTrims && backend_->IsLoaded()) |
return PostDelayedTrim(); |
- TrimCache(false); |
+ TrimCache(); |
} |
-bool Eviction::ShouldTrim() { |
+bool EvictionV3::ShouldTrim() { |
if (!FallingBehind(header_->num_bytes, max_size_) && |
trim_delays_ < kMaxDelayedTrims && backend_->IsLoaded()) { |
return false; |
@@ -253,7 +265,7 @@ |
return true; |
} |
-bool Eviction::ShouldTrimDeleted() { |
+bool EvictionV3::ShouldTrimDeleted() { |
int index_load = header_->num_entries * 100 / index_size_; |
// If the index is not loaded, the deleted list will tend to double the size |
@@ -261,130 +273,113 @@ |
// about the same size. |
int max_length = (index_load < 25) ? header_->num_entries * 2 / 5 : |
header_->num_entries / 4; |
- return (!test_mode_ && header_->lru.sizes[Rankings::DELETED] > max_length); |
+ return false;//(!test_mode_ && header_->lru.sizes[Rankings::DELETED] > max_length); |
} |
-bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty, |
- Rankings::List list) { |
- EntryImpl* entry = backend_->GetEnumeratedEntry(node, list); |
- if (!entry) { |
- Trace("NewEntry failed on Trim 0x%x", node->address().value()); |
- return false; |
+int EvictionV3::EvictEntry(uint32 hash, Addr address) { |
+ if (empty_) { |
+ EntryImplV3* entry = backend_->GetOpenEntry(address); |
+ if (entry) { |
+ entry->Doom(); |
+ entry->Close(); |
+ return net::OK; |
+ } |
} |
- ReportTrimTimes(entry); |
- if (empty || !new_eviction_) { |
- entry->DoomImpl(); |
- } else { |
- entry->DeleteEntryData(false); |
- EntryStore* info = entry->entry()->Data(); |
- DCHECK_EQ(ENTRY_NORMAL, info->state); |
+ if (backend_->EvictEntry(hash, address)) |
+ return net::ERR_IO_PENDING; |
- rankings_->Remove(entry->rankings(), GetListForEntryV2(entry), true); |
- info->state = ENTRY_EVICTED; |
- entry->entry()->Store(); |
- rankings_->Insert(entry->rankings(), true, Rankings::DELETED); |
- } |
- if (!empty) |
- backend_->OnEvent(Stats::TRIM_ENTRY); |
+ return net::ERR_FAILED; |
+} |
- entry->Release(); |
+bool EvictionV3::TrimCacheImpl() { |
+ int target_size = empty_ ? 0 : max_size_; |
- return true; |
-} |
+ if (!cells_to_evict_ || cells_to_evict_->empty()) { |
+ // See if we are done. |
+ if (header_->num_bytes < target_size && !test_mode_) |
+ return false; |
-void Eviction::TrimCacheV2(bool empty) { |
- Trace("*** Trim Cache ***"); |
- trimming_ = true; |
- TimeTicks start = TimeTicks::Now(); |
+ EntryGroup group = ENTRY_RESERVED; |
+ index_->GetOldest(&no_use_cells_, &low_use_cells_, &high_use_cells_); |
- const int kListsToSearch = 3; |
- Rankings::ScopedRankingsBlock next[kListsToSearch]; |
- int list = Rankings::LAST_ELEMENT; |
+ int timestamps[ENTRY_HIGH_USE + 1]; |
+ timestamps[ENTRY_NO_USE] = GetTimestampForGoup(ENTRY_NO_USE); |
+ timestamps[ENTRY_LOW_USE] = GetTimestampForGoup(ENTRY_LOW_USE); |
+ timestamps[ENTRY_HIGH_USE] = GetTimestampForGoup(ENTRY_HIGH_USE); |
- // Get a node from each list. |
- for (int i = 0; i < kListsToSearch; i++) { |
- bool done = false; |
- next[i].set_rankings(rankings_); |
- if (done) |
- continue; |
- next[i].reset(rankings_->GetPrev(NULL, static_cast<Rankings::List>(i))); |
- if (!empty && NodeIsOldEnough(next[i].get(), i)) { |
- list = static_cast<Rankings::List>(i); |
- done = true; |
+ if (CellIsOldEnough(no_use_cells_, 1)) |
+ group = ENTRY_NO_USE; |
+ else if (CellIsOldEnough(low_use_cells_, 2)) |
+ group = ENTRY_LOW_USE; |
+ else if (CellIsOldEnough(high_use_cells_, 4)) |
+ group = ENTRY_HIGH_USE; |
+ else |
+ group = SelectListByLength(); |
+ |
+ if (group == ENTRY_NO_USE) { |
+ cells_to_evict_ = &no_use_cells_; |
+ low_use_cells_.clear(); |
+ high_use_cells_.clear(); |
+ } else if (group == ENTRY_LOW_USE) { |
+ cells_to_evict_ = &low_use_cells_; |
+ no_use_cells_.clear(); |
+ high_use_cells_.clear(); |
+ } else if (group == ENTRY_HIGH_USE) { |
+ cells_to_evict_ = &high_use_cells_; |
+ no_use_cells_.clear(); |
+ low_use_cells_.clear(); |
+ } else { |
+ return false; |
} |
- } |
- // If we are not meeting the time targets lets move on to list length. |
- if (!empty && Rankings::LAST_ELEMENT == list) |
- list = SelectListByLength(next); |
+ if (first_trim_) { |
+ first_trim_ = false; |
+ if (backend_->ShouldReportAgain()) { |
+ int64 base_time = index_->header()->base_time; |
+ CACHE_UMA(AGE, "TrimAge", 0, |
+ TimeFromTimestamp(timestamps[group], base_time)); |
+ ReportListStats(timestamps[ENTRY_NO_USE], timestamps[ENTRY_LOW_USE], |
+ timestamps[ENTRY_HIGH_USE]); |
+ } |
- if (empty) |
- list = 0; |
+ if (!(header_->flags & CACHE_EVICTED)) { |
+ // This is the first entry that we have to evict, generate some noise. |
+ backend_->FirstEviction(); |
+ } |
+ } |
+ |
- Rankings::ScopedRankingsBlock node(rankings_); |
- int deleted_entries = 0; |
- int target_size = empty ? 0 : max_size_; |
+ DCHECK(!cells_to_evict_->empty()); |
+ } |
- for (; list < kListsToSearch; list++) { |
- while ((header_->num_bytes > target_size || test_mode_) && |
- next[list].get()) { |
- // The iterator could be invalidated within EvictEntry(). |
- if (!next[list]->HasData()) |
+ int rv = net::OK; |
+ while (!cells_to_evict_->empty()) { |
+ rv = EvictEntry(cells_to_evict_->back().hash, |
+ cells_to_evict_->back().address); |
+ cells_to_evict_->pop_back(); |
+ if (rv != net::ERR_FAILED) { |
+ if (!empty_) |
+ backend_->OnEvent(Stats::TRIM_ENTRY); |
+ if (rv == net::ERR_IO_PENDING) |
break; |
- node.reset(next[list].release()); |
- next[list].reset(rankings_->GetPrev(node.get(), |
- static_cast<Rankings::List>(list))); |
- if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { |
- // This entry is not being used by anybody. |
- // Do NOT use node as an iterator after this point. |
- rankings_->TrackRankingsBlock(node.get(), false); |
- if (EvictEntry(node.get(), empty, static_cast<Rankings::List>(list))) |
- deleted_entries++; |
- |
- if (!empty && test_mode_) |
- break; |
- } |
- if (!empty && (deleted_entries > 20 || |
- (TimeTicks::Now() - start).InMilliseconds() > 20)) { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&Eviction::TrimCache, ptr_factory_.GetWeakPtr(), false)); |
- break; |
- } |
} |
- if (!empty) |
- list = kListsToSearch; |
} |
- if (empty) { |
- TrimDeleted(true); |
- } else if (ShouldTrimDeleted()) { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&Eviction::TrimDeleted, ptr_factory_.GetWeakPtr(), empty)); |
- } |
+ if (test_mode_ || rv != net::ERR_IO_PENDING) |
+ return false; |
- if (empty) { |
- CACHE_UMA(AGE_MS, "TotalClearTimeV2", 0, start); |
- } else { |
- CACHE_UMA(AGE_MS, "TotalTrimTimeV2", 0, start); |
- } |
- CACHE_UMA(COUNTS, "TrimItemsV2", 0, deleted_entries); |
- |
- Trace("*** Trim Cache end ***"); |
- trimming_ = false; |
- return; |
+ return true; |
} |
// This is a minimal implementation that just discards the oldest nodes. |
// TODO(rvargas): Do something better here. |
-void Eviction::TrimDeleted(bool empty) { |
+void EvictionV3::TrimDeleted(bool empty) { |
Trace("*** Trim Deleted ***"); |
if (backend_->disabled_) |
return; |
- TimeTicks start = TimeTicks::Now(); |
+ /*TimeTicks start = TimeTicks::Now(); |
Rankings::ScopedRankingsBlock node(rankings_); |
Rankings::ScopedRankingsBlock next( |
rankings_, rankings_->GetPrev(node.get(), Rankings::DELETED)); |
@@ -401,102 +396,113 @@ |
} |
if (deleted_entries && !empty && ShouldTrimDeleted()) { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&Eviction::TrimDeleted, ptr_factory_.GetWeakPtr(), false)); |
+ MessageLoop::current()->PostTask(FROM_HERE, |
+ base::Bind(&EvictionV3::TrimDeleted, ptr_factory_.GetWeakPtr(), false)); |
} |
CACHE_UMA(AGE_MS, "TotalTrimDeletedTime", 0, start); |
- CACHE_UMA(COUNTS, "TrimDeletedItems", 0, deleted_entries); |
+ CACHE_UMA(COUNTS, "TrimDeletedItems", 0, deleted_entries);*/ |
Trace("*** Trim Deleted end ***"); |
return; |
} |
-void Eviction::ReportTrimTimes(EntryImpl* entry) { |
- if (first_trim_) { |
- first_trim_ = false; |
- if (backend_->ShouldReportAgain()) { |
- CACHE_UMA(AGE, "TrimAge", 0, entry->GetLastUsed()); |
- ReportListStats(); |
- } |
- |
- if (header_->lru.filled) |
- return; |
- |
- header_->lru.filled = 1; |
- |
- if (header_->create_time) { |
- // This is the first entry that we have to evict, generate some noise. |
- backend_->FirstEviction(); |
- } else { |
- // This is an old file, but we may want more reports from this user so |
- // lets save some create_time. |
- Time::Exploded old = {0}; |
- old.year = 2009; |
- old.month = 3; |
- old.day_of_month = 1; |
- header_->create_time = Time::FromLocalExploded(old).ToInternalValue(); |
- } |
+int EvictionV3::GetTimestampForGoup(int group) { |
+ CellList* cells = NULL; |
+ switch (group) { |
+ case ENTRY_NO_USE: |
+ cells = &no_use_cells_; |
+ break; |
+ case ENTRY_LOW_USE: |
+ cells = &low_use_cells_; |
+ break; |
+ case ENTRY_HIGH_USE: |
+ cells = &high_use_cells_; |
+ break; |
+ default: |
+ NOTREACHED(); |
} |
+ if (cells->empty()) |
+ return 0; |
+ EntryCell cell = index_->FindEntryCell(cells->begin()->hash, |
+ cells->begin()->address); |
+ return cell.GetTimestamp(); |
} |
-bool Eviction::NodeIsOldEnough(CacheRankingsBlock* node, int list) { |
- if (!node) |
+bool EvictionV3::CellIsOldEnough(const CellList& cells, int multiplier) { |
+ if (cells.empty()) |
return false; |
+ if (lru_) |
+ return true; |
+ |
+ EntryCell cell = index_->FindEntryCell(cells.begin()->hash, |
+ cells.begin()->address); |
+ |
+ Time used = Time::FromInternalValue(header_->base_time) + |
+ TimeDelta::FromMinutes(cell.GetTimestamp()); |
+ |
// If possible, we want to keep entries on each list at least kTargetTime |
// hours. Each successive list on the enumeration has 2x the target time of |
// the previous list. |
- Time used = Time::FromInternalValue(node->Data()->last_used); |
- int multiplier = 1 << list; |
- return (Time::Now() - used).InHours() > kTargetTime * multiplier; |
+ return (backend_->GetCurrentTime() - used).InHours() > |
+ kTargetTime * multiplier; |
} |
-int Eviction::SelectListByLength(Rankings::ScopedRankingsBlock* next) { |
- int data_entries = header_->num_entries - |
- header_->lru.sizes[Rankings::DELETED]; |
+EntryGroup EvictionV3::SelectListByLength() { |
+ int data_entries = header_->num_entries - header_->num_evicted_entries; |
+ |
// Start by having each list to be roughly the same size. |
- if (header_->lru.sizes[0] > data_entries / 3) |
- return 0; |
+ if (header_->num_no_use_entries > data_entries / 3) { |
+ DCHECK(!no_use_cells_.empty()); |
+ return ENTRY_NO_USE; |
+ } |
- int list = (header_->lru.sizes[1] > data_entries / 3) ? 1 : 2; |
- |
// Make sure that frequently used items are kept for a minimum time; we know |
// that this entry is not older than its current target, but it must be at |
- // least older than the target for list 0 (kTargetTime), as long as we don't |
- // exhaust list 0. |
- if (!NodeIsOldEnough(next[list].get(), 0) && |
- header_->lru.sizes[0] > data_entries / 10) |
- list = 0; |
+ // least older than the target for unused entries (kTargetTime), as long as we |
+ // don't exhaust that list. |
- return list; |
+ bool could_delete_no_used = header_->num_no_use_entries > data_entries / 10 || |
+ (!no_use_cells_.empty() && empty_); |
+ |
+ if (header_->num_low_use_entries > data_entries / 3 && |
+ (CellIsOldEnough(low_use_cells_, 1) || !could_delete_no_used)) { |
+ DCHECK(!low_use_cells_.empty()); |
+ return ENTRY_LOW_USE; |
+ } |
+ |
+ if (header_->num_high_use_entries > data_entries / 3 && |
+ (CellIsOldEnough(high_use_cells_, 1) || !could_delete_no_used)) { |
+ DCHECK(!high_use_cells_.empty()); |
+ return ENTRY_HIGH_USE; |
+ } |
+ |
+ if (could_delete_no_used) |
+ return ENTRY_NO_USE; |
+ |
+ if (!low_use_cells_.empty() && empty_) |
+ return ENTRY_LOW_USE; |
+ |
+ if (!high_use_cells_.empty() && empty_) |
+ return ENTRY_HIGH_USE; |
+ |
+ return ENTRY_RESERVED; |
} |
-void Eviction::ReportListStats() { |
- if (!new_eviction_) |
+void EvictionV3::ReportListStats(int time1, int time2, int time3) { |
+ if (lru_) |
return; |
- Rankings::ScopedRankingsBlock last1(rankings_, |
- rankings_->GetPrev(NULL, Rankings::NO_USE)); |
- Rankings::ScopedRankingsBlock last2(rankings_, |
- rankings_->GetPrev(NULL, Rankings::LOW_USE)); |
- Rankings::ScopedRankingsBlock last3(rankings_, |
- rankings_->GetPrev(NULL, Rankings::HIGH_USE)); |
- Rankings::ScopedRankingsBlock last4(rankings_, |
- rankings_->GetPrev(NULL, Rankings::DELETED)); |
+ int64 base_time = index_->header()->base_time; |
- if (last1.get()) |
- CACHE_UMA(AGE, "NoUseAge", 0, |
- Time::FromInternalValue(last1.get()->Data()->last_used)); |
- if (last2.get()) |
- CACHE_UMA(AGE, "LowUseAge", 0, |
- Time::FromInternalValue(last2.get()->Data()->last_used)); |
- if (last3.get()) |
- CACHE_UMA(AGE, "HighUseAge", 0, |
- Time::FromInternalValue(last3.get()->Data()->last_used)); |
- if (last4.get()) |
- CACHE_UMA(AGE, "DeletedAge", 0, |
- Time::FromInternalValue(last4.get()->Data()->last_used)); |
+ if (time1) |
+ CACHE_UMA(AGE, "NoUseAge", 0, TimeFromTimestamp(time1, base_time)); |
+ |
+ if (time2) |
+ CACHE_UMA(AGE, "LowUseAge", 0, TimeFromTimestamp(time2, base_time)); |
+ |
+ if (time3) |
+ CACHE_UMA(AGE, "HighUseAge", 0, TimeFromTimestamp(time3, base_time)); |
} |
} // namespace disk_cache |