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

Unified Diff: net/disk_cache/simple/simple_backend_impl.cc

Issue 15563005: **STILLBAKING** Switch SimpleCache to SequencedWorkerPool. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
index 009076fd822193f50020986b8a75cee4e7abafbc..32580575a8081d38ab239976aa76e47adaa1b72a 100644
--- a/net/disk_cache/simple/simple_backend_impl.cc
+++ b/net/disk_cache/simple/simple_backend_impl.cc
@@ -24,7 +24,8 @@
using base::Closure;
using base::FilePath;
using base::MessageLoopProxy;
-using base::SingleThreadTaskRunner;
+using base::SequencedWorkerPool;
+using base::TaskRunner;
using base::Time;
using base::WorkerPool;
using file_util::DirectoryExists;
@@ -32,6 +33,12 @@ using file_util::CreateDirectory;
namespace {
+// Max thread pool size.
+const int kMaxThreads = 50;
Randy Smith (Not in Mondays) 2013/05/21 21:15:30 Yikes. There's a real, and reasonably high memory
+
+// Prefix given to all threads to aid in debugging.
+const char kThreadNamePrefix[] = "SimpleCache";
+
// Cache size when all other size heuristics failed.
const uint64 kDefaultCacheSize = 80 * 1024 * 1024;
@@ -119,6 +126,17 @@ void CallCompletionCallback(const net::CompletionCallback& callback,
callback.Run(*result);
}
+// Creates a task runner which will serialize operations on an ActiveEntry.
+// Must be called on the |inactive_entry_task_runner_| to correctly serialize
+// with pending mass doom operations.
+void CreateTaskRunnerForEntry(SequencedWorkerPool* sequenced_worker_pool,
+ scoped_refptr<TaskRunner>* out_task_runner) {
+ *out_task_runner =
+ sequenced_worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ sequenced_worker_pool->GetSequenceToken(),
+ SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+}
+
void RecordIndexLoad(base::TimeTicks constructed_since, int result) {
const base::TimeDelta creation_to_index = base::TimeTicks::Now() -
constructed_since;
@@ -143,13 +161,20 @@ SimpleBackendImpl::SimpleBackendImpl(
MessageLoopProxy::current(), // io_thread
path)),
cache_thread_(cache_thread),
- orig_max_size_(max_bytes) {
+ orig_max_size_(max_bytes),
+ worker_pool_(new base::SequencedWorkerPool(kMaxThreads,
+ kThreadNamePrefix)),
+ inactive_entry_task_runner_(
+ worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
+ worker_pool_->GetSequenceToken(),
+ SequencedWorkerPool::SKIP_ON_SHUTDOWN)) {
index_->ExecuteWhenReady(base::Bind(&RecordIndexLoad,
base::TimeTicks::Now()));
}
SimpleBackendImpl::~SimpleBackendImpl() {
index_->WriteToDisk();
+ worker_pool_->Shutdown();
}
int SimpleBackendImpl::Init(const CompletionCallback& completion_callback) {
@@ -176,9 +201,17 @@ int SimpleBackendImpl::GetMaxFileSize() const {
return index_->max_size() / kMaxFileRatio;
}
-void SimpleBackendImpl::OnDeactivated(const SimpleEntryImpl* entry) {
- DCHECK_LT(0U, active_entries_.count(entry->entry_hash()));
- active_entries_.erase(entry->entry_hash());
+void SimpleBackendImpl::DeactivateEntry(uint64 entry_hash) {
+ DCHECK_NE(0U, active_entries_.count(entry_hash));
+ active_entries_[entry_hash].entry = NULL;
+}
+
+void SimpleBackendImpl::ClosedEntry(uint64 entry_hash) {
+ DCHECK_NE(0U, active_entries_.count(entry_hash));
+ EntryMap::iterator it = active_entries_.find(entry_hash);
+ ActiveEntry& active_entry = it->second;
+ if (!active_entry.entry)
+ active_entries_.erase(it);
}
net::CacheType SimpleBackendImpl::GetCacheType() const {
@@ -233,8 +266,8 @@ void SimpleBackendImpl::IndexReadyForDoom(Time initial_time,
EntryMap::iterator it = active_entries_.find(entry_hash);
if (it == active_entries_.end())
continue;
- SimpleEntryImpl* entry = it->second;
- entry->Doom();
+ if (SimpleEntryImpl* entry = it->second.entry)
+ entry->Doom();
(*removed_key_hashes)[i] = removed_key_hashes->back();
removed_key_hashes->resize(removed_key_hashes->size() - 1);
@@ -284,6 +317,75 @@ void SimpleBackendImpl::OnExternalCacheHit(const std::string& key) {
index_->UseIfExists(key);
}
+// private:
+
+// A simple task runner which either calls through to an underlying TaskRunner,
+// or if none is provided, enqueues tasks to run when a TaskRunner is finally
+// given.
+class SimpleBackendImpl::ProxyTaskRunner : public TaskRunner {
pasko 2013/05/21 16:00:01 A more self-descriptive name would be: BarrierTask
Randy Smith (Not in Mondays) 2013/05/21 21:15:30 nit: I think helper classes are supposed to be at
+ public:
+ ProxyTaskRunner() {
+ }
+
+ void SetTaskRunner(
+ scoped_ptr<scoped_refptr<base::TaskRunner> > in_task_runner) {
+ DCHECK(!task_runner_);
+
+ task_runner_.swap(*in_task_runner);
+ while (!tasks_.empty()) {
+ task_runner_->PostTask(tasks_.front().first, tasks_.front().second);
+ tasks_.pop();
+ }
+ }
+
+ bool IsEmpty() const {
+ return !task_runner_ && tasks_.empty();
+ }
+
+ // From TaskRunner:
+ virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const Closure& task,
+ base::TimeDelta delay) OVERRIDE {
+ if (task_runner_)
+ return task_runner_->PostDelayedTask(from_here, task, delay);
+ tasks_.push(std::make_pair(from_here, task));
+ return true;
+ }
+
+ virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
+ if (task_runner_)
+ return task_runner_->RunsTasksOnCurrentThread();
+ return false;
+ }
+
+ private:
+ virtual ~ProxyTaskRunner() {
+ }
+
+ std::queue<std::pair<tracked_objects::Location, Closure> > tasks_;
+ scoped_refptr<TaskRunner> task_runner_;
+};
+
+SimpleBackendImpl::ActiveEntry::ActiveEntry()
+ : task_runner(new SimpleBackendImpl::ProxyTaskRunner()),
+ entry(NULL) {
+}
+
+SimpleBackendImpl::ActiveEntry::ActiveEntry(const ActiveEntry& other)
+ : task_runner(other.task_runner),
+ entry(other.entry) {
+}
+
+SimpleBackendImpl::ActiveEntry::~ActiveEntry() {
+}
+
+SimpleBackendImpl::ActiveEntry& SimpleBackendImpl::ActiveEntry::operator=(
+ const ActiveEntry& other) {
+ task_runner = other.task_runner;
+ entry = other.entry;
+ return *this;
+}
+
void SimpleBackendImpl::InitializeIndex(
const CompletionCallback& callback, uint64 suggested_max_size, int result) {
if (result == net::OK) {
@@ -295,7 +397,7 @@ void SimpleBackendImpl::InitializeIndex(
// static
void SimpleBackendImpl::ProvideDirectorySuggestBetterCacheSize(
- SingleThreadTaskRunner* io_thread,
+ base::SingleThreadTaskRunner* io_thread,
const base::FilePath& path,
const InitializeIndexCallback& initialize_index_callback,
uint64 suggested_max_size) {
@@ -325,25 +427,38 @@ scoped_refptr<SimpleEntryImpl> SimpleBackendImpl::CreateOrFindActiveEntry(
const std::string& key) {
const uint64 entry_hash = simple_util::GetEntryHashKey(key);
- std::pair<EntryMap::iterator, bool> insert_result =
- active_entries_.insert(std::make_pair(entry_hash,
- base::WeakPtr<SimpleEntryImpl>()));
+ std::pair<EntryMap::iterator, bool> insert_result = active_entries_.insert(
+ std::make_pair(entry_hash, ActiveEntry()));
EntryMap::iterator& it = insert_result.first;
- if (insert_result.second)
- DCHECK(!it->second);
- if (!it->second) {
- SimpleEntryImpl* entry = new SimpleEntryImpl(this, path_, key, entry_hash);
- it->second = entry->AsWeakPtr();
+ ActiveEntry& active_entry = it->second;
+
+ if (insert_result.second) {
+ // If this is a new ActiveEntry, we have to asynchronously construct a new
+ // task_runner for it.
+ scoped_ptr<scoped_refptr<base::TaskRunner> >
+ out_task_runner(new scoped_refptr<base::TaskRunner>());
+ inactive_entry_task_runner_->PostTaskAndReply(
pasko 2013/05/21 16:00:01 Why do we have to serialize token creation via a w
gavinp 2013/05/21 16:55:02 What if a mass doom operation is running right now
pasko-google - do not use 2013/05/21 17:25:47 something around the lines of SimpleEntryImpl::Ope
Randy Smith (Not in Mondays) 2013/05/21 21:15:30 What are the performance costs of doing a mass doo
+ FROM_HERE,
+ base::Bind(&CreateTaskRunnerForEntry, worker_pool_,
+ out_task_runner.get()),
+ base::Bind(&ProxyTaskRunner::SetTaskRunner, active_entry.task_runner,
+ base::Passed(&out_task_runner)));
}
- DCHECK(it->second);
+
+ if (!active_entry.entry) {
+ active_entry.entry = new SimpleEntryImpl(this, active_entry.task_runner,
+ path_, key, entry_hash);
+ }
+
// 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();
+ if (key != active_entry.entry->key()) {
+ active_entry.entry->Doom();
DCHECK_EQ(0U, active_entries_.count(entry_hash));
return CreateOrFindActiveEntry(key);
}
- return make_scoped_refptr(it->second.get());
+
+ return make_scoped_refptr(active_entry.entry);
}
} // namespace disk_cache

Powered by Google App Engine
This is Rietveld 408576698