| Index: net/disk_cache/simple/simple_backend_impl.cc
|
| diff --git a/net/disk_cache/simple/simple_backend_impl.cc b/net/disk_cache/simple/simple_backend_impl.cc
|
| deleted file mode 100644
|
| index 6c43eeb9d6e0b439d577d1d0aff79b0dd39d5654..0000000000000000000000000000000000000000
|
| --- a/net/disk_cache/simple/simple_backend_impl.cc
|
| +++ /dev/null
|
| @@ -1,732 +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_backend_impl.h"
|
| -
|
| -#include <algorithm>
|
| -#include <cstdlib>
|
| -#include <functional>
|
| -
|
| -#if defined(OS_POSIX)
|
| -#include <sys/resource.h>
|
| -#endif
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/callback.h"
|
| -#include "base/files/file_util.h"
|
| -#include "base/location.h"
|
| -#include "base/metrics/field_trial.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "base/metrics/sparse_histogram.h"
|
| -#include "base/single_thread_task_runner.h"
|
| -#include "base/sys_info.h"
|
| -#include "base/task_runner_util.h"
|
| -#include "base/thread_task_runner_handle.h"
|
| -#include "base/threading/sequenced_worker_pool.h"
|
| -#include "base/time/time.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/disk_cache/cache_util.h"
|
| -#include "net/disk_cache/simple/simple_entry_format.h"
|
| -#include "net/disk_cache/simple/simple_entry_impl.h"
|
| -#include "net/disk_cache/simple/simple_histogram_macros.h"
|
| -#include "net/disk_cache/simple/simple_index.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"
|
| -#include "net/disk_cache/simple/simple_version_upgrade.h"
|
| -
|
| -using base::Callback;
|
| -using base::Closure;
|
| -using base::FilePath;
|
| -using base::SequencedWorkerPool;
|
| -using base::Time;
|
| -using base::DirectoryExists;
|
| -using base::CreateDirectory;
|
| -
|
| -namespace disk_cache {
|
| -
|
| -namespace {
|
| -
|
| -// Maximum number of concurrent worker pool threads, which also is the limit
|
| -// on concurrent IO (as we use one thread per IO request).
|
| -const size_t kMaxWorkerThreads = 5U;
|
| -
|
| -const char kThreadNamePrefix[] = "SimpleCache";
|
| -
|
| -// Maximum fraction of the cache that one entry can consume.
|
| -const int kMaxFileRatio = 8;
|
| -
|
| -// A global sequenced worker pool to use for launching all tasks.
|
| -SequencedWorkerPool* g_sequenced_worker_pool = NULL;
|
| -
|
| -void MaybeCreateSequencedWorkerPool() {
|
| - if (!g_sequenced_worker_pool) {
|
| - g_sequenced_worker_pool =
|
| - new SequencedWorkerPool(kMaxWorkerThreads, kThreadNamePrefix);
|
| - g_sequenced_worker_pool->AddRef(); // Leak it.
|
| - }
|
| -}
|
| -
|
| -bool g_fd_limit_histogram_has_been_populated = false;
|
| -
|
| -void MaybeHistogramFdLimit(net::CacheType cache_type) {
|
| - if (g_fd_limit_histogram_has_been_populated)
|
| - return;
|
| -
|
| - // Used in histograms; add new entries at end.
|
| - enum FdLimitStatus {
|
| - FD_LIMIT_STATUS_UNSUPPORTED = 0,
|
| - FD_LIMIT_STATUS_FAILED = 1,
|
| - FD_LIMIT_STATUS_SUCCEEDED = 2,
|
| - FD_LIMIT_STATUS_MAX = 3
|
| - };
|
| - FdLimitStatus fd_limit_status = FD_LIMIT_STATUS_UNSUPPORTED;
|
| - int soft_fd_limit = 0;
|
| - int hard_fd_limit = 0;
|
| -
|
| -#if defined(OS_POSIX)
|
| - struct rlimit nofile;
|
| - if (!getrlimit(RLIMIT_NOFILE, &nofile)) {
|
| - soft_fd_limit = nofile.rlim_cur;
|
| - hard_fd_limit = nofile.rlim_max;
|
| - fd_limit_status = FD_LIMIT_STATUS_SUCCEEDED;
|
| - } else {
|
| - fd_limit_status = FD_LIMIT_STATUS_FAILED;
|
| - }
|
| -#endif
|
| -
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "FileDescriptorLimitStatus", cache_type,
|
| - fd_limit_status, FD_LIMIT_STATUS_MAX);
|
| - if (fd_limit_status == FD_LIMIT_STATUS_SUCCEEDED) {
|
| - SIMPLE_CACHE_UMA(SPARSE_SLOWLY,
|
| - "FileDescriptorLimitSoft", cache_type, soft_fd_limit);
|
| - SIMPLE_CACHE_UMA(SPARSE_SLOWLY,
|
| - "FileDescriptorLimitHard", cache_type, hard_fd_limit);
|
| - }
|
| -
|
| - g_fd_limit_histogram_has_been_populated = true;
|
| -}
|
| -
|
| -// Detects if the files in the cache directory match the current disk cache
|
| -// backend type and version. If the directory contains no cache, occupies it
|
| -// with the fresh structure.
|
| -bool FileStructureConsistent(const base::FilePath& path) {
|
| - if (!base::PathExists(path) && !base::CreateDirectory(path)) {
|
| - LOG(ERROR) << "Failed to create directory: " << path.LossyDisplayName();
|
| - return false;
|
| - }
|
| - return disk_cache::UpgradeSimpleCacheOnDisk(path);
|
| -}
|
| -
|
| -// A context used by a BarrierCompletionCallback to track state.
|
| -struct BarrierContext {
|
| - BarrierContext(int expected)
|
| - : expected(expected),
|
| - count(0),
|
| - had_error(false) {}
|
| -
|
| - const int expected;
|
| - int count;
|
| - bool had_error;
|
| -};
|
| -
|
| -void BarrierCompletionCallbackImpl(
|
| - BarrierContext* context,
|
| - const net::CompletionCallback& final_callback,
|
| - int result) {
|
| - DCHECK_GT(context->expected, context->count);
|
| - if (context->had_error)
|
| - return;
|
| - if (result != net::OK) {
|
| - context->had_error = true;
|
| - final_callback.Run(result);
|
| - return;
|
| - }
|
| - ++context->count;
|
| - if (context->count == context->expected)
|
| - final_callback.Run(net::OK);
|
| -}
|
| -
|
| -// A barrier completion callback is a net::CompletionCallback that waits for
|
| -// |count| successful results before invoking |final_callback|. In the case of
|
| -// an error, the first error is passed to |final_callback| and all others
|
| -// are ignored.
|
| -net::CompletionCallback MakeBarrierCompletionCallback(
|
| - int count,
|
| - const net::CompletionCallback& final_callback) {
|
| - BarrierContext* context = new BarrierContext(count);
|
| - return base::Bind(&BarrierCompletionCallbackImpl,
|
| - base::Owned(context), final_callback);
|
| -}
|
| -
|
| -// A short bindable thunk that ensures a completion callback is always called
|
| -// after running an operation asynchronously.
|
| -void RunOperationAndCallback(
|
| - const Callback<int(const net::CompletionCallback&)>& operation,
|
| - const net::CompletionCallback& operation_callback) {
|
| - const int operation_result = operation.Run(operation_callback);
|
| - if (operation_result != net::ERR_IO_PENDING)
|
| - operation_callback.Run(operation_result);
|
| -}
|
| -
|
| -void RecordIndexLoad(net::CacheType cache_type,
|
| - base::TimeTicks constructed_since,
|
| - int result) {
|
| - const base::TimeDelta creation_to_index = base::TimeTicks::Now() -
|
| - constructed_since;
|
| - if (result == net::OK) {
|
| - SIMPLE_CACHE_UMA(TIMES, "CreationToIndex", cache_type, creation_to_index);
|
| - } else {
|
| - SIMPLE_CACHE_UMA(TIMES,
|
| - "CreationToIndexFail", cache_type, creation_to_index);
|
| - }
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -class SimpleBackendImpl::ActiveEntryProxy
|
| - : public SimpleEntryImpl::ActiveEntryProxy {
|
| - public:
|
| - ~ActiveEntryProxy() override {
|
| - if (backend_) {
|
| - DCHECK_EQ(1U, backend_->active_entries_.count(entry_hash_));
|
| - backend_->active_entries_.erase(entry_hash_);
|
| - }
|
| - }
|
| -
|
| - static scoped_ptr<SimpleEntryImpl::ActiveEntryProxy> Create(
|
| - int64 entry_hash,
|
| - SimpleBackendImpl* backend) {
|
| - scoped_ptr<SimpleEntryImpl::ActiveEntryProxy>
|
| - proxy(new ActiveEntryProxy(entry_hash, backend));
|
| - return proxy.Pass();
|
| - }
|
| -
|
| - private:
|
| - ActiveEntryProxy(uint64 entry_hash,
|
| - SimpleBackendImpl* backend)
|
| - : entry_hash_(entry_hash),
|
| - backend_(backend->AsWeakPtr()) {}
|
| -
|
| - uint64 entry_hash_;
|
| - base::WeakPtr<SimpleBackendImpl> backend_;
|
| -};
|
| -
|
| -SimpleBackendImpl::SimpleBackendImpl(
|
| - const FilePath& path,
|
| - int max_bytes,
|
| - net::CacheType cache_type,
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
|
| - net::NetLog* net_log)
|
| - : path_(path),
|
| - cache_type_(cache_type),
|
| - cache_thread_(cache_thread),
|
| - orig_max_size_(max_bytes),
|
| - entry_operations_mode_(cache_type == net::DISK_CACHE ?
|
| - SimpleEntryImpl::OPTIMISTIC_OPERATIONS :
|
| - SimpleEntryImpl::NON_OPTIMISTIC_OPERATIONS),
|
| - net_log_(net_log) {
|
| - MaybeHistogramFdLimit(cache_type_);
|
| -}
|
| -
|
| -SimpleBackendImpl::~SimpleBackendImpl() {
|
| - index_->WriteToDisk();
|
| -}
|
| -
|
| -int SimpleBackendImpl::Init(const CompletionCallback& completion_callback) {
|
| - MaybeCreateSequencedWorkerPool();
|
| -
|
| - worker_pool_ = g_sequenced_worker_pool->GetTaskRunnerWithShutdownBehavior(
|
| - SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
|
| -
|
| - index_.reset(new SimpleIndex(
|
| - base::ThreadTaskRunnerHandle::Get(),
|
| - this,
|
| - cache_type_,
|
| - make_scoped_ptr(new SimpleIndexFile(
|
| - cache_thread_, worker_pool_.get(), cache_type_, path_))));
|
| - index_->ExecuteWhenReady(
|
| - base::Bind(&RecordIndexLoad, cache_type_, base::TimeTicks::Now()));
|
| -
|
| - PostTaskAndReplyWithResult(
|
| - cache_thread_.get(),
|
| - FROM_HERE,
|
| - base::Bind(
|
| - &SimpleBackendImpl::InitCacheStructureOnDisk, path_, orig_max_size_),
|
| - base::Bind(&SimpleBackendImpl::InitializeIndex,
|
| - AsWeakPtr(),
|
| - completion_callback));
|
| - return net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -bool SimpleBackendImpl::SetMaxSize(int max_bytes) {
|
| - if (max_bytes < 0)
|
| - return false;
|
| - orig_max_size_ = max_bytes;
|
| - index_->SetMaxSize(max_bytes);
|
| - return true;
|
| -}
|
| -
|
| -int SimpleBackendImpl::GetMaxFileSize() const {
|
| - return static_cast<int>(index_->max_size() / kMaxFileRatio);
|
| -}
|
| -
|
| -void SimpleBackendImpl::OnDoomStart(uint64 entry_hash) {
|
| - DCHECK_EQ(0u, entries_pending_doom_.count(entry_hash));
|
| - entries_pending_doom_.insert(
|
| - std::make_pair(entry_hash, std::vector<Closure>()));
|
| -}
|
| -
|
| -void SimpleBackendImpl::OnDoomComplete(uint64 entry_hash) {
|
| - DCHECK_EQ(1u, entries_pending_doom_.count(entry_hash));
|
| - base::hash_map<uint64, std::vector<Closure> >::iterator it =
|
| - entries_pending_doom_.find(entry_hash);
|
| - std::vector<Closure> to_run_closures;
|
| - to_run_closures.swap(it->second);
|
| - entries_pending_doom_.erase(it);
|
| -
|
| - std::for_each(to_run_closures.begin(), to_run_closures.end(),
|
| - std::mem_fun_ref(&Closure::Run));
|
| -}
|
| -
|
| -void SimpleBackendImpl::DoomEntries(std::vector<uint64>* entry_hashes,
|
| - const net::CompletionCallback& callback) {
|
| - scoped_ptr<std::vector<uint64> >
|
| - mass_doom_entry_hashes(new std::vector<uint64>());
|
| - mass_doom_entry_hashes->swap(*entry_hashes);
|
| -
|
| - std::vector<uint64> to_doom_individually_hashes;
|
| -
|
| - // For each of the entry hashes, there are two cases:
|
| - // 1. The entry is either open or pending doom, and so it should be doomed
|
| - // individually to avoid flakes.
|
| - // 2. The entry is not in use at all, so we can call
|
| - // SimpleSynchronousEntry::DoomEntrySet and delete the files en masse.
|
| - for (int i = mass_doom_entry_hashes->size() - 1; i >= 0; --i) {
|
| - const uint64 entry_hash = (*mass_doom_entry_hashes)[i];
|
| - DCHECK(active_entries_.count(entry_hash) == 0 ||
|
| - entries_pending_doom_.count(entry_hash) == 0);
|
| - if (!active_entries_.count(entry_hash) &&
|
| - !entries_pending_doom_.count(entry_hash)) {
|
| - continue;
|
| - }
|
| -
|
| - to_doom_individually_hashes.push_back(entry_hash);
|
| -
|
| - (*mass_doom_entry_hashes)[i] = mass_doom_entry_hashes->back();
|
| - mass_doom_entry_hashes->resize(mass_doom_entry_hashes->size() - 1);
|
| - }
|
| -
|
| - net::CompletionCallback barrier_callback =
|
| - MakeBarrierCompletionCallback(to_doom_individually_hashes.size() + 1,
|
| - callback);
|
| - for (std::vector<uint64>::const_iterator
|
| - it = to_doom_individually_hashes.begin(),
|
| - end = to_doom_individually_hashes.end(); it != end; ++it) {
|
| - const int doom_result = DoomEntryFromHash(*it, barrier_callback);
|
| - DCHECK_EQ(net::ERR_IO_PENDING, doom_result);
|
| - index_->Remove(*it);
|
| - }
|
| -
|
| - for (std::vector<uint64>::const_iterator it = mass_doom_entry_hashes->begin(),
|
| - end = mass_doom_entry_hashes->end();
|
| - it != end; ++it) {
|
| - index_->Remove(*it);
|
| - OnDoomStart(*it);
|
| - }
|
| -
|
| - // Taking this pointer here avoids undefined behaviour from calling
|
| - // base::Passed before mass_doom_entry_hashes.get().
|
| - std::vector<uint64>* mass_doom_entry_hashes_ptr =
|
| - mass_doom_entry_hashes.get();
|
| - PostTaskAndReplyWithResult(worker_pool_.get(),
|
| - FROM_HERE,
|
| - base::Bind(&SimpleSynchronousEntry::DoomEntrySet,
|
| - mass_doom_entry_hashes_ptr,
|
| - path_),
|
| - base::Bind(&SimpleBackendImpl::DoomEntriesComplete,
|
| - AsWeakPtr(),
|
| - base::Passed(&mass_doom_entry_hashes),
|
| - barrier_callback));
|
| -}
|
| -
|
| -net::CacheType SimpleBackendImpl::GetCacheType() const {
|
| - return net::DISK_CACHE;
|
| -}
|
| -
|
| -int32 SimpleBackendImpl::GetEntryCount() const {
|
| - // TODO(pasko): Use directory file count when index is not ready.
|
| - return index_->GetEntryCount();
|
| -}
|
| -
|
| -int SimpleBackendImpl::OpenEntry(const std::string& key,
|
| - Entry** entry,
|
| - const CompletionCallback& callback) {
|
| - const uint64 entry_hash = simple_util::GetEntryHashKey(key);
|
| -
|
| - // TODO(gavinp): Factor out this (not quite completely) repetitive code
|
| - // block from OpenEntry/CreateEntry/DoomEntry.
|
| - base::hash_map<uint64, std::vector<Closure> >::iterator it =
|
| - entries_pending_doom_.find(entry_hash);
|
| - if (it != entries_pending_doom_.end()) {
|
| - Callback<int(const net::CompletionCallback&)> operation =
|
| - base::Bind(&SimpleBackendImpl::OpenEntry,
|
| - base::Unretained(this), key, entry);
|
| - it->second.push_back(base::Bind(&RunOperationAndCallback,
|
| - operation, callback));
|
| - return net::ERR_IO_PENDING;
|
| - }
|
| - scoped_refptr<SimpleEntryImpl> simple_entry =
|
| - CreateOrFindActiveEntry(entry_hash, key);
|
| - CompletionCallback backend_callback =
|
| - base::Bind(&SimpleBackendImpl::OnEntryOpenedFromKey,
|
| - AsWeakPtr(),
|
| - key,
|
| - entry,
|
| - simple_entry,
|
| - callback);
|
| - return simple_entry->OpenEntry(entry, backend_callback);
|
| -}
|
| -
|
| -int SimpleBackendImpl::CreateEntry(const std::string& key,
|
| - Entry** entry,
|
| - const CompletionCallback& callback) {
|
| - DCHECK_LT(0u, key.size());
|
| - const uint64 entry_hash = simple_util::GetEntryHashKey(key);
|
| -
|
| - base::hash_map<uint64, std::vector<Closure> >::iterator it =
|
| - entries_pending_doom_.find(entry_hash);
|
| - if (it != entries_pending_doom_.end()) {
|
| - Callback<int(const net::CompletionCallback&)> operation =
|
| - base::Bind(&SimpleBackendImpl::CreateEntry,
|
| - base::Unretained(this), key, entry);
|
| - it->second.push_back(base::Bind(&RunOperationAndCallback,
|
| - operation, callback));
|
| - return net::ERR_IO_PENDING;
|
| - }
|
| - scoped_refptr<SimpleEntryImpl> simple_entry =
|
| - CreateOrFindActiveEntry(entry_hash, key);
|
| - return simple_entry->CreateEntry(entry, callback);
|
| -}
|
| -
|
| -int SimpleBackendImpl::DoomEntry(const std::string& key,
|
| - const net::CompletionCallback& callback) {
|
| - const uint64 entry_hash = simple_util::GetEntryHashKey(key);
|
| -
|
| - base::hash_map<uint64, std::vector<Closure> >::iterator it =
|
| - entries_pending_doom_.find(entry_hash);
|
| - if (it != entries_pending_doom_.end()) {
|
| - Callback<int(const net::CompletionCallback&)> operation =
|
| - base::Bind(&SimpleBackendImpl::DoomEntry, base::Unretained(this), key);
|
| - it->second.push_back(base::Bind(&RunOperationAndCallback,
|
| - operation, callback));
|
| - return net::ERR_IO_PENDING;
|
| - }
|
| - scoped_refptr<SimpleEntryImpl> simple_entry =
|
| - CreateOrFindActiveEntry(entry_hash, key);
|
| - return simple_entry->DoomEntry(callback);
|
| -}
|
| -
|
| -int SimpleBackendImpl::DoomAllEntries(const CompletionCallback& callback) {
|
| - return DoomEntriesBetween(Time(), Time(), callback);
|
| -}
|
| -
|
| -void SimpleBackendImpl::IndexReadyForDoom(Time initial_time,
|
| - Time end_time,
|
| - const CompletionCallback& callback,
|
| - int result) {
|
| - if (result != net::OK) {
|
| - callback.Run(result);
|
| - return;
|
| - }
|
| - scoped_ptr<std::vector<uint64> > removed_key_hashes(
|
| - index_->GetEntriesBetween(initial_time, end_time).release());
|
| - DoomEntries(removed_key_hashes.get(), callback);
|
| -}
|
| -
|
| -int SimpleBackendImpl::DoomEntriesBetween(
|
| - const Time initial_time,
|
| - const Time end_time,
|
| - const CompletionCallback& callback) {
|
| - return index_->ExecuteWhenReady(
|
| - base::Bind(&SimpleBackendImpl::IndexReadyForDoom, AsWeakPtr(),
|
| - initial_time, end_time, callback));
|
| -}
|
| -
|
| -int SimpleBackendImpl::DoomEntriesSince(
|
| - const Time initial_time,
|
| - const CompletionCallback& callback) {
|
| - return DoomEntriesBetween(initial_time, Time(), callback);
|
| -}
|
| -
|
| -class SimpleBackendImpl::SimpleIterator final : public Iterator {
|
| - public:
|
| - explicit SimpleIterator(base::WeakPtr<SimpleBackendImpl> backend)
|
| - : backend_(backend),
|
| - weak_factory_(this) {
|
| - }
|
| -
|
| - // From Backend::Iterator:
|
| - int OpenNextEntry(Entry** next_entry,
|
| - const CompletionCallback& callback) override {
|
| - CompletionCallback open_next_entry_impl =
|
| - base::Bind(&SimpleIterator::OpenNextEntryImpl,
|
| - weak_factory_.GetWeakPtr(), next_entry, callback);
|
| - return backend_->index_->ExecuteWhenReady(open_next_entry_impl);
|
| - }
|
| -
|
| - void OpenNextEntryImpl(Entry** next_entry,
|
| - const CompletionCallback& callback,
|
| - int index_initialization_error_code) {
|
| - if (!backend_) {
|
| - callback.Run(net::ERR_FAILED);
|
| - return;
|
| - }
|
| - if (index_initialization_error_code != net::OK) {
|
| - callback.Run(index_initialization_error_code);
|
| - return;
|
| - }
|
| - if (!hashes_to_enumerate_)
|
| - hashes_to_enumerate_ = backend_->index()->GetAllHashes().Pass();
|
| -
|
| - while (!hashes_to_enumerate_->empty()) {
|
| - uint64 entry_hash = hashes_to_enumerate_->back();
|
| - hashes_to_enumerate_->pop_back();
|
| - if (backend_->index()->Has(entry_hash)) {
|
| - *next_entry = NULL;
|
| - CompletionCallback continue_iteration = base::Bind(
|
| - &SimpleIterator::CheckIterationReturnValue,
|
| - weak_factory_.GetWeakPtr(),
|
| - next_entry,
|
| - callback);
|
| - int error_code_open = backend_->OpenEntryFromHash(entry_hash,
|
| - next_entry,
|
| - continue_iteration);
|
| - if (error_code_open == net::ERR_IO_PENDING)
|
| - return;
|
| - if (error_code_open != net::ERR_FAILED) {
|
| - callback.Run(error_code_open);
|
| - return;
|
| - }
|
| - }
|
| - }
|
| - callback.Run(net::ERR_FAILED);
|
| - }
|
| -
|
| - void CheckIterationReturnValue(Entry** entry,
|
| - const CompletionCallback& callback,
|
| - int error_code) {
|
| - if (error_code == net::ERR_FAILED) {
|
| - OpenNextEntry(entry, callback);
|
| - return;
|
| - }
|
| - callback.Run(error_code);
|
| - }
|
| -
|
| - private:
|
| - base::WeakPtr<SimpleBackendImpl> backend_;
|
| - scoped_ptr<std::vector<uint64> > hashes_to_enumerate_;
|
| - base::WeakPtrFactory<SimpleIterator> weak_factory_;
|
| -};
|
| -
|
| -scoped_ptr<Backend::Iterator> SimpleBackendImpl::CreateIterator() {
|
| - return scoped_ptr<Iterator>(new SimpleIterator(AsWeakPtr()));
|
| -}
|
| -
|
| -void SimpleBackendImpl::GetStats(
|
| - std::vector<std::pair<std::string, std::string> >* stats) {
|
| - std::pair<std::string, std::string> item;
|
| - item.first = "Cache type";
|
| - item.second = "Simple Cache";
|
| - stats->push_back(item);
|
| -}
|
| -
|
| -void SimpleBackendImpl::OnExternalCacheHit(const std::string& key) {
|
| - index_->UseIfExists(simple_util::GetEntryHashKey(key));
|
| -}
|
| -
|
| -void SimpleBackendImpl::InitializeIndex(const CompletionCallback& callback,
|
| - const DiskStatResult& result) {
|
| - if (result.net_error == net::OK) {
|
| - index_->SetMaxSize(result.max_size);
|
| - index_->Initialize(result.cache_dir_mtime);
|
| - }
|
| - callback.Run(result.net_error);
|
| -}
|
| -
|
| -SimpleBackendImpl::DiskStatResult SimpleBackendImpl::InitCacheStructureOnDisk(
|
| - const base::FilePath& path,
|
| - uint64 suggested_max_size) {
|
| - DiskStatResult result;
|
| - result.max_size = suggested_max_size;
|
| - result.net_error = net::OK;
|
| - if (!FileStructureConsistent(path)) {
|
| - LOG(ERROR) << "Simple Cache Backend: wrong file structure on disk: "
|
| - << path.LossyDisplayName();
|
| - result.net_error = net::ERR_FAILED;
|
| - } else {
|
| - bool mtime_result =
|
| - disk_cache::simple_util::GetMTime(path, &result.cache_dir_mtime);
|
| - DCHECK(mtime_result);
|
| - if (!result.max_size) {
|
| - int64 available = base::SysInfo::AmountOfFreeDiskSpace(path);
|
| - result.max_size = disk_cache::PreferredCacheSize(available);
|
| - }
|
| - DCHECK(result.max_size);
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -scoped_refptr<SimpleEntryImpl> SimpleBackendImpl::CreateOrFindActiveEntry(
|
| - const uint64 entry_hash,
|
| - const std::string& key) {
|
| - DCHECK_EQ(entry_hash, simple_util::GetEntryHashKey(key));
|
| - std::pair<EntryMap::iterator, bool> insert_result =
|
| - active_entries_.insert(EntryMap::value_type(entry_hash, NULL));
|
| - EntryMap::iterator& it = insert_result.first;
|
| - const bool did_insert = insert_result.second;
|
| - if (did_insert) {
|
| - SimpleEntryImpl* entry = it->second =
|
| - new SimpleEntryImpl(cache_type_, path_, entry_hash,
|
| - entry_operations_mode_,this, net_log_);
|
| - entry->SetKey(key);
|
| - entry->SetActiveEntryProxy(ActiveEntryProxy::Create(entry_hash, this));
|
| - }
|
| - DCHECK(it->second);
|
| - // It's possible, but unlikely, that we have an entry hash collision with a
|
| - // currently active entry.
|
| - if (key != it->second->key()) {
|
| - it->second->Doom();
|
| - DCHECK_EQ(0U, active_entries_.count(entry_hash));
|
| - return CreateOrFindActiveEntry(entry_hash, key);
|
| - }
|
| - return make_scoped_refptr(it->second);
|
| -}
|
| -
|
| -int SimpleBackendImpl::OpenEntryFromHash(uint64 entry_hash,
|
| - Entry** entry,
|
| - const CompletionCallback& callback) {
|
| - base::hash_map<uint64, std::vector<Closure> >::iterator it =
|
| - entries_pending_doom_.find(entry_hash);
|
| - if (it != entries_pending_doom_.end()) {
|
| - Callback<int(const net::CompletionCallback&)> operation =
|
| - base::Bind(&SimpleBackendImpl::OpenEntryFromHash,
|
| - base::Unretained(this), entry_hash, entry);
|
| - it->second.push_back(base::Bind(&RunOperationAndCallback,
|
| - operation, callback));
|
| - return net::ERR_IO_PENDING;
|
| - }
|
| -
|
| - EntryMap::iterator has_active = active_entries_.find(entry_hash);
|
| - if (has_active != active_entries_.end()) {
|
| - return OpenEntry(has_active->second->key(), entry, callback);
|
| - }
|
| -
|
| - scoped_refptr<SimpleEntryImpl> simple_entry = new SimpleEntryImpl(
|
| - cache_type_, path_, entry_hash, entry_operations_mode_, this, net_log_);
|
| - CompletionCallback backend_callback =
|
| - base::Bind(&SimpleBackendImpl::OnEntryOpenedFromHash,
|
| - AsWeakPtr(), entry_hash, entry, simple_entry, callback);
|
| - return simple_entry->OpenEntry(entry, backend_callback);
|
| -}
|
| -
|
| -int SimpleBackendImpl::DoomEntryFromHash(uint64 entry_hash,
|
| - const CompletionCallback& callback) {
|
| - Entry** entry = new Entry*();
|
| - scoped_ptr<Entry*> scoped_entry(entry);
|
| -
|
| - base::hash_map<uint64, std::vector<Closure> >::iterator pending_it =
|
| - entries_pending_doom_.find(entry_hash);
|
| - if (pending_it != entries_pending_doom_.end()) {
|
| - Callback<int(const net::CompletionCallback&)> operation =
|
| - base::Bind(&SimpleBackendImpl::DoomEntryFromHash,
|
| - base::Unretained(this), entry_hash);
|
| - pending_it->second.push_back(base::Bind(&RunOperationAndCallback,
|
| - operation, callback));
|
| - return net::ERR_IO_PENDING;
|
| - }
|
| -
|
| - EntryMap::iterator active_it = active_entries_.find(entry_hash);
|
| - if (active_it != active_entries_.end())
|
| - return active_it->second->DoomEntry(callback);
|
| -
|
| - // There's no pending dooms, nor any open entry. We can make a trivial
|
| - // call to DoomEntries() to delete this entry.
|
| - std::vector<uint64> entry_hash_vector;
|
| - entry_hash_vector.push_back(entry_hash);
|
| - DoomEntries(&entry_hash_vector, callback);
|
| - return net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -void SimpleBackendImpl::OnEntryOpenedFromHash(
|
| - uint64 hash,
|
| - Entry** entry,
|
| - const scoped_refptr<SimpleEntryImpl>& simple_entry,
|
| - const CompletionCallback& callback,
|
| - int error_code) {
|
| - if (error_code != net::OK) {
|
| - callback.Run(error_code);
|
| - return;
|
| - }
|
| - DCHECK(*entry);
|
| - std::pair<EntryMap::iterator, bool> insert_result =
|
| - active_entries_.insert(EntryMap::value_type(hash, simple_entry.get()));
|
| - EntryMap::iterator& it = insert_result.first;
|
| - const bool did_insert = insert_result.second;
|
| - if (did_insert) {
|
| - // There was no active entry corresponding to this hash. We've already put
|
| - // the entry opened from hash in the |active_entries_|. We now provide the
|
| - // proxy object to the entry.
|
| - it->second->SetActiveEntryProxy(ActiveEntryProxy::Create(hash, this));
|
| - callback.Run(net::OK);
|
| - } else {
|
| - // The entry was made active while we waiting for the open from hash to
|
| - // finish. The entry created from hash needs to be closed, and the one
|
| - // in |active_entries_| can be returned to the caller.
|
| - simple_entry->Close();
|
| - it->second->OpenEntry(entry, callback);
|
| - }
|
| -}
|
| -
|
| -void SimpleBackendImpl::OnEntryOpenedFromKey(
|
| - const std::string key,
|
| - Entry** entry,
|
| - const scoped_refptr<SimpleEntryImpl>& simple_entry,
|
| - const CompletionCallback& callback,
|
| - int error_code) {
|
| - int final_code = error_code;
|
| - if (final_code == net::OK) {
|
| - bool key_matches = key.compare(simple_entry->key()) == 0;
|
| - if (!key_matches) {
|
| - // TODO(clamy): Add a unit test to check this code path.
|
| - DLOG(WARNING) << "Key mismatch on open.";
|
| - simple_entry->Doom();
|
| - simple_entry->Close();
|
| - final_code = net::ERR_FAILED;
|
| - } else {
|
| - DCHECK_EQ(simple_entry->entry_hash(), simple_util::GetEntryHashKey(key));
|
| - }
|
| - SIMPLE_CACHE_UMA(BOOLEAN, "KeyMatchedOnOpen", cache_type_, key_matches);
|
| - }
|
| - callback.Run(final_code);
|
| -}
|
| -
|
| -void SimpleBackendImpl::DoomEntriesComplete(
|
| - scoped_ptr<std::vector<uint64> > entry_hashes,
|
| - const net::CompletionCallback& callback,
|
| - int result) {
|
| - std::for_each(
|
| - entry_hashes->begin(), entry_hashes->end(),
|
| - std::bind1st(std::mem_fun(&SimpleBackendImpl::OnDoomComplete),
|
| - this));
|
| - callback.Run(result);
|
| -}
|
| -
|
| -void SimpleBackendImpl::FlushWorkerPoolForTesting() {
|
| - if (g_sequenced_worker_pool)
|
| - g_sequenced_worker_pool->FlushForTesting();
|
| -}
|
| -
|
| -} // namespace disk_cache
|
|
|