| Index: net/disk_cache/simple/simple_index.cc
|
| diff --git a/net/disk_cache/simple/simple_index.cc b/net/disk_cache/simple/simple_index.cc
|
| deleted file mode 100644
|
| index 6eb60bd57abbb9e3a08b3627461520deea15d188..0000000000000000000000000000000000000000
|
| --- a/net/disk_cache/simple/simple_index.cc
|
| +++ /dev/null
|
| @@ -1,480 +0,0 @@
|
| -// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/disk_cache/simple/simple_index.h"
|
| -
|
| -#include <algorithm>
|
| -#include <limits>
|
| -#include <string>
|
| -#include <utility>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/files/file_enumerator.h"
|
| -#include "base/files/file_util.h"
|
| -#include "base/logging.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/metrics/field_trial.h"
|
| -#include "base/numerics/safe_conversions.h"
|
| -#include "base/pickle.h"
|
| -#include "base/strings/string_number_conversions.h"
|
| -#include "base/strings/string_tokenizer.h"
|
| -#include "base/task_runner.h"
|
| -#include "base/threading/worker_pool.h"
|
| -#include "base/time/time.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/disk_cache/simple/simple_entry_format.h"
|
| -#include "net/disk_cache/simple/simple_histogram_macros.h"
|
| -#include "net/disk_cache/simple/simple_index_delegate.h"
|
| -#include "net/disk_cache/simple/simple_index_file.h"
|
| -#include "net/disk_cache/simple/simple_synchronous_entry.h"
|
| -#include "net/disk_cache/simple/simple_util.h"
|
| -
|
| -#if defined(OS_POSIX)
|
| -#include <sys/stat.h>
|
| -#include <sys/time.h>
|
| -#endif
|
| -
|
| -namespace {
|
| -
|
| -// How many milliseconds we delay writing the index to disk since the last cache
|
| -// operation has happened.
|
| -const int kWriteToDiskDelayMSecs = 20000;
|
| -const int kWriteToDiskOnBackgroundDelayMSecs = 100;
|
| -
|
| -// Divides the cache space into this amount of parts to evict when only one part
|
| -// is left.
|
| -const uint32 kEvictionMarginDivisor = 20;
|
| -
|
| -const uint32 kBytesInKb = 1024;
|
| -
|
| -// Utility class used for timestamp comparisons in entry metadata while sorting.
|
| -class CompareHashesForTimestamp {
|
| - typedef disk_cache::SimpleIndex SimpleIndex;
|
| - typedef disk_cache::SimpleIndex::EntrySet EntrySet;
|
| - public:
|
| - explicit CompareHashesForTimestamp(const EntrySet& set);
|
| -
|
| - bool operator()(uint64 hash1, uint64 hash2);
|
| - private:
|
| - const EntrySet& entry_set_;
|
| -};
|
| -
|
| -CompareHashesForTimestamp::CompareHashesForTimestamp(const EntrySet& set)
|
| - : entry_set_(set) {
|
| -}
|
| -
|
| -bool CompareHashesForTimestamp::operator()(uint64 hash1, uint64 hash2) {
|
| - EntrySet::const_iterator it1 = entry_set_.find(hash1);
|
| - DCHECK(it1 != entry_set_.end());
|
| - EntrySet::const_iterator it2 = entry_set_.find(hash2);
|
| - DCHECK(it2 != entry_set_.end());
|
| - return it1->second.GetLastUsedTime() < it2->second.GetLastUsedTime();
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace disk_cache {
|
| -
|
| -EntryMetadata::EntryMetadata()
|
| - : last_used_time_seconds_since_epoch_(0),
|
| - entry_size_(0) {
|
| -}
|
| -
|
| -EntryMetadata::EntryMetadata(base::Time last_used_time, uint64 entry_size)
|
| - : last_used_time_seconds_since_epoch_(0),
|
| - entry_size_(base::checked_cast<int32>(entry_size)) {
|
| - SetLastUsedTime(last_used_time);
|
| -}
|
| -
|
| -base::Time EntryMetadata::GetLastUsedTime() const {
|
| - // Preserve nullity.
|
| - if (last_used_time_seconds_since_epoch_ == 0)
|
| - return base::Time();
|
| -
|
| - return base::Time::UnixEpoch() +
|
| - base::TimeDelta::FromSeconds(last_used_time_seconds_since_epoch_);
|
| -}
|
| -
|
| -void EntryMetadata::SetLastUsedTime(const base::Time& last_used_time) {
|
| - // Preserve nullity.
|
| - if (last_used_time.is_null()) {
|
| - last_used_time_seconds_since_epoch_ = 0;
|
| - return;
|
| - }
|
| -
|
| - last_used_time_seconds_since_epoch_ = base::checked_cast<uint32>(
|
| - (last_used_time - base::Time::UnixEpoch()).InSeconds());
|
| - // Avoid accidental nullity.
|
| - if (last_used_time_seconds_since_epoch_ == 0)
|
| - last_used_time_seconds_since_epoch_ = 1;
|
| -}
|
| -
|
| -uint64 EntryMetadata::GetEntrySize() const {
|
| - return entry_size_;
|
| -}
|
| -
|
| -void EntryMetadata::SetEntrySize(uint64 entry_size) {
|
| - entry_size_ = base::checked_cast<int32>(entry_size);
|
| -}
|
| -
|
| -void EntryMetadata::Serialize(Pickle* pickle) const {
|
| - DCHECK(pickle);
|
| - int64 internal_last_used_time = GetLastUsedTime().ToInternalValue();
|
| - pickle->WriteInt64(internal_last_used_time);
|
| - pickle->WriteUInt64(entry_size_);
|
| -}
|
| -
|
| -bool EntryMetadata::Deserialize(PickleIterator* it) {
|
| - DCHECK(it);
|
| - int64 tmp_last_used_time;
|
| - uint64 tmp_entry_size;
|
| - if (!it->ReadInt64(&tmp_last_used_time) || !it->ReadUInt64(&tmp_entry_size) ||
|
| - tmp_entry_size > static_cast<uint64>(std::numeric_limits<int32>::max()))
|
| - return false;
|
| - SetLastUsedTime(base::Time::FromInternalValue(tmp_last_used_time));
|
| - entry_size_ = static_cast<int32>(tmp_entry_size);
|
| - return true;
|
| -}
|
| -
|
| -SimpleIndex::SimpleIndex(
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& io_thread,
|
| - SimpleIndexDelegate* delegate,
|
| - net::CacheType cache_type,
|
| - scoped_ptr<SimpleIndexFile> index_file)
|
| - : delegate_(delegate),
|
| - cache_type_(cache_type),
|
| - cache_size_(0),
|
| - max_size_(0),
|
| - high_watermark_(0),
|
| - low_watermark_(0),
|
| - eviction_in_progress_(false),
|
| - initialized_(false),
|
| - index_file_(index_file.Pass()),
|
| - io_thread_(io_thread),
|
| - // Creating the callback once so it is reused every time
|
| - // write_to_disk_timer_.Start() is called.
|
| - write_to_disk_cb_(base::Bind(&SimpleIndex::WriteToDisk, AsWeakPtr())),
|
| - app_on_background_(false) {
|
| -}
|
| -
|
| -SimpleIndex::~SimpleIndex() {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| -
|
| - // Fail all callbacks waiting for the index to come up.
|
| - for (CallbackList::iterator it = to_run_when_initialized_.begin(),
|
| - end = to_run_when_initialized_.end(); it != end; ++it) {
|
| - it->Run(net::ERR_ABORTED);
|
| - }
|
| -}
|
| -
|
| -void SimpleIndex::Initialize(base::Time cache_mtime) {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| -
|
| -#if defined(OS_ANDROID)
|
| - if (base::android::IsVMInitialized()) {
|
| - app_status_listener_.reset(new base::android::ApplicationStatusListener(
|
| - base::Bind(&SimpleIndex::OnApplicationStateChange, AsWeakPtr())));
|
| - }
|
| -#endif
|
| -
|
| - SimpleIndexLoadResult* load_result = new SimpleIndexLoadResult();
|
| - scoped_ptr<SimpleIndexLoadResult> load_result_scoped(load_result);
|
| - base::Closure reply = base::Bind(
|
| - &SimpleIndex::MergeInitializingSet,
|
| - AsWeakPtr(),
|
| - base::Passed(&load_result_scoped));
|
| - index_file_->LoadIndexEntries(cache_mtime, reply, load_result);
|
| -}
|
| -
|
| -void SimpleIndex::SetMaxSize(uint64 max_bytes) {
|
| - // Zero size means use the default.
|
| - if (max_bytes) {
|
| - max_size_ = max_bytes;
|
| - high_watermark_ = max_size_ - max_size_ / kEvictionMarginDivisor;
|
| - low_watermark_ = max_size_ - 2 * (max_size_ / kEvictionMarginDivisor);
|
| - }
|
| -}
|
| -
|
| -int SimpleIndex::ExecuteWhenReady(const net::CompletionCallback& task) {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - if (initialized_)
|
| - io_thread_->PostTask(FROM_HERE, base::Bind(task, net::OK));
|
| - else
|
| - to_run_when_initialized_.push_back(task);
|
| - return net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -scoped_ptr<SimpleIndex::HashList> SimpleIndex::GetEntriesBetween(
|
| - base::Time initial_time, base::Time end_time) {
|
| - DCHECK_EQ(true, initialized_);
|
| -
|
| - if (!initial_time.is_null())
|
| - initial_time -= EntryMetadata::GetLowerEpsilonForTimeComparisons();
|
| - if (end_time.is_null())
|
| - end_time = base::Time::Max();
|
| - else
|
| - end_time += EntryMetadata::GetUpperEpsilonForTimeComparisons();
|
| - const base::Time extended_end_time =
|
| - end_time.is_null() ? base::Time::Max() : end_time;
|
| - DCHECK(extended_end_time >= initial_time);
|
| - scoped_ptr<HashList> ret_hashes(new HashList());
|
| - for (EntrySet::iterator it = entries_set_.begin(), end = entries_set_.end();
|
| - it != end; ++it) {
|
| - EntryMetadata& metadata = it->second;
|
| - base::Time entry_time = metadata.GetLastUsedTime();
|
| - if (initial_time <= entry_time && entry_time < extended_end_time)
|
| - ret_hashes->push_back(it->first);
|
| - }
|
| - return ret_hashes.Pass();
|
| -}
|
| -
|
| -scoped_ptr<SimpleIndex::HashList> SimpleIndex::GetAllHashes() {
|
| - return GetEntriesBetween(base::Time(), base::Time());
|
| -}
|
| -
|
| -int32 SimpleIndex::GetEntryCount() const {
|
| - // TODO(pasko): return a meaningful initial estimate before initialized.
|
| - return entries_set_.size();
|
| -}
|
| -
|
| -void SimpleIndex::Insert(uint64 entry_hash) {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - // Upon insert we don't know yet the size of the entry.
|
| - // It will be updated later when the SimpleEntryImpl finishes opening or
|
| - // creating the new entry, and then UpdateEntrySize will be called.
|
| - InsertInEntrySet(
|
| - entry_hash, EntryMetadata(base::Time::Now(), 0), &entries_set_);
|
| - if (!initialized_)
|
| - removed_entries_.erase(entry_hash);
|
| - PostponeWritingToDisk();
|
| -}
|
| -
|
| -void SimpleIndex::Remove(uint64 entry_hash) {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - EntrySet::iterator it = entries_set_.find(entry_hash);
|
| - if (it != entries_set_.end()) {
|
| - UpdateEntryIteratorSize(&it, 0);
|
| - entries_set_.erase(it);
|
| - }
|
| -
|
| - if (!initialized_)
|
| - removed_entries_.insert(entry_hash);
|
| - PostponeWritingToDisk();
|
| -}
|
| -
|
| -bool SimpleIndex::Has(uint64 hash) const {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - // If not initialized, always return true, forcing it to go to the disk.
|
| - return !initialized_ || entries_set_.count(hash) > 0;
|
| -}
|
| -
|
| -bool SimpleIndex::UseIfExists(uint64 entry_hash) {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - // Always update the last used time, even if it is during initialization.
|
| - // It will be merged later.
|
| - EntrySet::iterator it = entries_set_.find(entry_hash);
|
| - if (it == entries_set_.end())
|
| - // If not initialized, always return true, forcing it to go to the disk.
|
| - return !initialized_;
|
| - it->second.SetLastUsedTime(base::Time::Now());
|
| - PostponeWritingToDisk();
|
| - return true;
|
| -}
|
| -
|
| -void SimpleIndex::StartEvictionIfNeeded() {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - if (eviction_in_progress_ || cache_size_ <= high_watermark_)
|
| - return;
|
| - // Take all live key hashes from the index and sort them by time.
|
| - eviction_in_progress_ = true;
|
| - eviction_start_time_ = base::TimeTicks::Now();
|
| - SIMPLE_CACHE_UMA(
|
| - MEMORY_KB, "Eviction.CacheSizeOnStart2", cache_type_,
|
| - static_cast<base::HistogramBase::Sample>(cache_size_ / kBytesInKb));
|
| - SIMPLE_CACHE_UMA(
|
| - MEMORY_KB, "Eviction.MaxCacheSizeOnStart2", cache_type_,
|
| - static_cast<base::HistogramBase::Sample>(max_size_ / kBytesInKb));
|
| - std::vector<uint64> entry_hashes;
|
| - entry_hashes.reserve(entries_set_.size());
|
| - for (EntrySet::const_iterator it = entries_set_.begin(),
|
| - end = entries_set_.end(); it != end; ++it) {
|
| - entry_hashes.push_back(it->first);
|
| - }
|
| - std::sort(entry_hashes.begin(), entry_hashes.end(),
|
| - CompareHashesForTimestamp(entries_set_));
|
| -
|
| - // Remove as many entries from the index to get below |low_watermark_|.
|
| - std::vector<uint64>::iterator it = entry_hashes.begin();
|
| - uint64 evicted_so_far_size = 0;
|
| - while (evicted_so_far_size < cache_size_ - low_watermark_) {
|
| - DCHECK(it != entry_hashes.end());
|
| - EntrySet::iterator found_meta = entries_set_.find(*it);
|
| - DCHECK(found_meta != entries_set_.end());
|
| - evicted_so_far_size += found_meta->second.GetEntrySize();
|
| - ++it;
|
| - }
|
| -
|
| - // Take out the rest of hashes from the eviction list.
|
| - entry_hashes.erase(it, entry_hashes.end());
|
| - SIMPLE_CACHE_UMA(COUNTS,
|
| - "Eviction.EntryCount", cache_type_, entry_hashes.size());
|
| - SIMPLE_CACHE_UMA(TIMES,
|
| - "Eviction.TimeToSelectEntries", cache_type_,
|
| - base::TimeTicks::Now() - eviction_start_time_);
|
| - SIMPLE_CACHE_UMA(
|
| - MEMORY_KB, "Eviction.SizeOfEvicted2", cache_type_,
|
| - static_cast<base::HistogramBase::Sample>(
|
| - evicted_so_far_size / kBytesInKb));
|
| -
|
| - delegate_->DoomEntries(&entry_hashes, base::Bind(&SimpleIndex::EvictionDone,
|
| - AsWeakPtr()));
|
| -}
|
| -
|
| -bool SimpleIndex::UpdateEntrySize(uint64 entry_hash, int64 entry_size) {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - EntrySet::iterator it = entries_set_.find(entry_hash);
|
| - if (it == entries_set_.end())
|
| - return false;
|
| -
|
| - UpdateEntryIteratorSize(&it, entry_size);
|
| - PostponeWritingToDisk();
|
| - StartEvictionIfNeeded();
|
| - return true;
|
| -}
|
| -
|
| -void SimpleIndex::EvictionDone(int result) {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| -
|
| - // Ignore the result of eviction. We did our best.
|
| - eviction_in_progress_ = false;
|
| - SIMPLE_CACHE_UMA(BOOLEAN, "Eviction.Result", cache_type_, result == net::OK);
|
| - SIMPLE_CACHE_UMA(TIMES,
|
| - "Eviction.TimeToDone", cache_type_,
|
| - base::TimeTicks::Now() - eviction_start_time_);
|
| - SIMPLE_CACHE_UMA(
|
| - MEMORY_KB, "Eviction.SizeWhenDone2", cache_type_,
|
| - static_cast<base::HistogramBase::Sample>(cache_size_ / kBytesInKb));
|
| -}
|
| -
|
| -// static
|
| -void SimpleIndex::InsertInEntrySet(
|
| - uint64 entry_hash,
|
| - const disk_cache::EntryMetadata& entry_metadata,
|
| - EntrySet* entry_set) {
|
| - DCHECK(entry_set);
|
| - entry_set->insert(std::make_pair(entry_hash, entry_metadata));
|
| -}
|
| -
|
| -void SimpleIndex::PostponeWritingToDisk() {
|
| - if (!initialized_)
|
| - return;
|
| - const int delay = app_on_background_ ? kWriteToDiskOnBackgroundDelayMSecs
|
| - : kWriteToDiskDelayMSecs;
|
| - // If the timer is already active, Start() will just Reset it, postponing it.
|
| - write_to_disk_timer_.Start(
|
| - FROM_HERE, base::TimeDelta::FromMilliseconds(delay), write_to_disk_cb_);
|
| -}
|
| -
|
| -void SimpleIndex::UpdateEntryIteratorSize(EntrySet::iterator* it,
|
| - int64 entry_size) {
|
| - // Update the total cache size with the new entry size.
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - DCHECK_GE(cache_size_, (*it)->second.GetEntrySize());
|
| - cache_size_ -= (*it)->second.GetEntrySize();
|
| - cache_size_ += entry_size;
|
| - (*it)->second.SetEntrySize(entry_size);
|
| -}
|
| -
|
| -void SimpleIndex::MergeInitializingSet(
|
| - scoped_ptr<SimpleIndexLoadResult> load_result) {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - DCHECK(load_result->did_load);
|
| -
|
| - EntrySet* index_file_entries = &load_result->entries;
|
| -
|
| - for (base::hash_set<uint64>::const_iterator it = removed_entries_.begin();
|
| - it != removed_entries_.end(); ++it) {
|
| - index_file_entries->erase(*it);
|
| - }
|
| - removed_entries_.clear();
|
| -
|
| - for (EntrySet::const_iterator it = entries_set_.begin();
|
| - it != entries_set_.end(); ++it) {
|
| - const uint64 entry_hash = it->first;
|
| - std::pair<EntrySet::iterator, bool> insert_result =
|
| - index_file_entries->insert(EntrySet::value_type(entry_hash,
|
| - EntryMetadata()));
|
| - EntrySet::iterator& possibly_inserted_entry = insert_result.first;
|
| - possibly_inserted_entry->second = it->second;
|
| - }
|
| -
|
| - uint64 merged_cache_size = 0;
|
| - for (EntrySet::iterator it = index_file_entries->begin();
|
| - it != index_file_entries->end(); ++it) {
|
| - merged_cache_size += it->second.GetEntrySize();
|
| - }
|
| -
|
| - entries_set_.swap(*index_file_entries);
|
| - cache_size_ = merged_cache_size;
|
| - initialized_ = true;
|
| -
|
| - // The actual IO is asynchronous, so calling WriteToDisk() shouldn't slow the
|
| - // merge down much.
|
| - if (load_result->flush_required)
|
| - WriteToDisk();
|
| -
|
| - SIMPLE_CACHE_UMA(CUSTOM_COUNTS,
|
| - "IndexInitializationWaiters", cache_type_,
|
| - to_run_when_initialized_.size(), 0, 100, 20);
|
| - // Run all callbacks waiting for the index to come up.
|
| - for (CallbackList::iterator it = to_run_when_initialized_.begin(),
|
| - end = to_run_when_initialized_.end(); it != end; ++it) {
|
| - io_thread_->PostTask(FROM_HERE, base::Bind((*it), net::OK));
|
| - }
|
| - to_run_when_initialized_.clear();
|
| -}
|
| -
|
| -#if defined(OS_ANDROID)
|
| -void SimpleIndex::OnApplicationStateChange(
|
| - base::android::ApplicationState state) {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - // For more info about android activities, see:
|
| - // developer.android.com/training/basics/activity-lifecycle/pausing.html
|
| - if (state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
|
| - app_on_background_ = false;
|
| - } else if (state ==
|
| - base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES) {
|
| - app_on_background_ = true;
|
| - WriteToDisk();
|
| - }
|
| -}
|
| -#endif
|
| -
|
| -void SimpleIndex::WriteToDisk() {
|
| - DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - if (!initialized_)
|
| - return;
|
| - SIMPLE_CACHE_UMA(CUSTOM_COUNTS,
|
| - "IndexNumEntriesOnWrite", cache_type_,
|
| - entries_set_.size(), 0, 100000, 50);
|
| - const base::TimeTicks start = base::TimeTicks::Now();
|
| - if (!last_write_to_disk_.is_null()) {
|
| - if (app_on_background_) {
|
| - SIMPLE_CACHE_UMA(MEDIUM_TIMES,
|
| - "IndexWriteInterval.Background", cache_type_,
|
| - start - last_write_to_disk_);
|
| - } else {
|
| - SIMPLE_CACHE_UMA(MEDIUM_TIMES,
|
| - "IndexWriteInterval.Foreground", cache_type_,
|
| - start - last_write_to_disk_);
|
| - }
|
| - }
|
| - last_write_to_disk_ = start;
|
| -
|
| - index_file_->WriteToDisk(entries_set_, cache_size_,
|
| - start, app_on_background_, base::Closure());
|
| -}
|
| -
|
| -} // namespace disk_cache
|
|
|