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

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

Issue 14130015: Support overlapping operations on the SimpleEntryImpl. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase again Created 7 years, 8 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
« no previous file with comments | « net/disk_cache/simple/simple_entry_impl.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/disk_cache/simple/simple_entry_impl.cc
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc
index 541fa346a25155cb4608fdbd2187973dce4a6871..4fa31adb26e38ed8ede677fab3afc45e69d75a7b 100644
--- a/net/disk_cache/simple/simple_entry_impl.cc
+++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -105,7 +105,11 @@ void SimpleEntryImpl::Doom() {
void SimpleEntryImpl::Close() {
DCHECK(io_thread_checker_.CalledOnValidThread());
- Release(); // Balanced in CreationOperationCompleted().
+ // Postpone close operation.
+ // Push the close operation to the end of the line. This way we run all
+ // operations before we are able close.
+ pending_operations_.push(base::Bind(&SimpleEntryImpl::CloseInternal, this));
+ RunNextOperationIfNeeded();
}
std::string SimpleEntryImpl::GetKey() const {
@@ -134,26 +138,21 @@ int SimpleEntryImpl::ReadData(int index,
int buf_len,
const CompletionCallback& callback) {
DCHECK(io_thread_checker_.CalledOnValidThread());
- // TODO(gavinp): Add support for overlapping reads. The net::HttpCache does
- // make overlapping read requests when multiple transactions access the same
- // entry as read only. This might make calling SimpleSynchronousEntry::Close()
- // correctly more tricky (see SimpleEntryImpl::EntryOperationComplete).
- if (synchronous_entry_in_use_by_worker_) {
- NOTIMPLEMENTED();
- CHECK(false);
- }
- synchronous_entry_in_use_by_worker_ = true;
- if (index_)
- index_->UseIfExists(key_);
- SynchronousOperationCallback sync_operation_callback =
- base::Bind(&SimpleEntryImpl::EntryOperationComplete,
- this, callback);
- WorkerPool::PostTask(FROM_HERE,
- base::Bind(&SimpleSynchronousEntry::ReadData,
- base::Unretained(synchronous_entry_),
- index, offset, make_scoped_refptr(buf),
- buf_len, sync_operation_callback),
- true);
+ if (index < 0 || index >= kSimpleEntryFileCount || buf_len < 0)
+ return net::ERR_INVALID_ARGUMENT;
+ if (offset >= data_size_[index] || offset < 0 || !buf_len)
+ return 0;
+ // TODO(felipeg): Optimization: Add support for truly parallel read
+ // operations.
+ pending_operations_.push(
+ base::Bind(&SimpleEntryImpl::ReadDataInternal,
+ this,
+ index,
+ offset,
+ make_scoped_refptr(buf),
+ buf_len,
+ callback));
+ RunNextOperationIfNeeded();
return net::ERR_IO_PENDING;
}
@@ -164,22 +163,20 @@ int SimpleEntryImpl::WriteData(int index,
const CompletionCallback& callback,
bool truncate) {
DCHECK(io_thread_checker_.CalledOnValidThread());
- if (synchronous_entry_in_use_by_worker_) {
- NOTIMPLEMENTED();
- CHECK(false);
- }
- synchronous_entry_in_use_by_worker_ = true;
- if (index_)
- index_->UseIfExists(key_);
- SynchronousOperationCallback sync_operation_callback =
- base::Bind(&SimpleEntryImpl::EntryOperationComplete,
- this, callback);
- WorkerPool::PostTask(FROM_HERE,
- base::Bind(&SimpleSynchronousEntry::WriteData,
- base::Unretained(synchronous_entry_),
- index, offset, make_scoped_refptr(buf),
- buf_len, sync_operation_callback, truncate),
- true);
+ if (index < 0 || index >= kSimpleEntryFileCount || offset < 0 || buf_len < 0)
+ return net::ERR_INVALID_ARGUMENT;
+ pending_operations_.push(
+ base::Bind(&SimpleEntryImpl::WriteDataInternal,
+ this,
+ index,
+ offset,
+ make_scoped_refptr(buf),
+ buf_len,
+ callback,
+ truncate));
+ RunNextOperationIfNeeded();
+ // TODO(felipeg): Optimization: Add support for optimistic writes, quickly
+ // returning net::OK here.
return net::ERR_IO_PENDING;
}
@@ -235,27 +232,86 @@ int SimpleEntryImpl::ReadyForSparseIO(const CompletionCallback& callback) {
SimpleEntryImpl::SimpleEntryImpl(SimpleIndex* index,
const FilePath& path,
const std::string& key)
- : constructor_thread_(MessageLoopProxy::current()),
- index_(index->AsWeakPtr()),
- path_(path),
- key_(key),
- synchronous_entry_(NULL),
- synchronous_entry_in_use_by_worker_(false) {
+ : index_(index->AsWeakPtr()),
+ path_(path),
+ key_(key),
+ synchronous_entry_(NULL),
+ operation_running_(false) {
}
SimpleEntryImpl::~SimpleEntryImpl() {
- if (synchronous_entry_) {
- base::Closure close_sync_entry =
- base::Bind(&SimpleSynchronousEntry::Close,
- base::Unretained(synchronous_entry_));
- // We aren't guaranteed to be able to run IO on our constructor thread, but
- // we are also not guaranteed to be allowed to run WorkerPool::PostTask on
- // our other threads.
- if (constructor_thread_->BelongsToCurrentThread())
- WorkerPool::PostTask(FROM_HERE, close_sync_entry, true);
- else
- close_sync_entry.Run();
- }
+ DCHECK_EQ(0U, pending_operations_.size());
+ DCHECK(!operation_running_);
+}
+
+bool SimpleEntryImpl::RunNextOperationIfNeeded() {
+ DCHECK(io_thread_checker_.CalledOnValidThread());
+ if (pending_operations_.size() <= 0 || operation_running_)
+ return false;
+ base::Closure operation = pending_operations_.front();
+ pending_operations_.pop();
+ operation.Run();
+ return true;
+}
+
+void SimpleEntryImpl::CloseInternal() {
+ DCHECK(io_thread_checker_.CalledOnValidThread());
+ DCHECK(pending_operations_.size() == 0);
gavinp 2013/04/19 05:51:39 Oops.
+ DCHECK(!operation_running_);
+ DCHECK(synchronous_entry_);
+ WorkerPool::PostTask(FROM_HERE,
+ base::Bind(&SimpleSynchronousEntry::Close,
+ base::Unretained(synchronous_entry_)),
+ true);
+ // Entry::Close() is expected to delete this entry. See disk_cache.h for
+ // details.
+ Release(); // Balanced in CreationOperationCompleted().
+}
+
+void SimpleEntryImpl::ReadDataInternal(int index,
+ int offset,
+ scoped_refptr<net::IOBuffer> buf,
+ int buf_len,
+ const CompletionCallback& callback) {
+ DCHECK(io_thread_checker_.CalledOnValidThread());
+ DCHECK(!operation_running_);
+ operation_running_ = true;
+ if (index_)
+ index_->UseIfExists(key_);
+ SynchronousOperationCallback sync_operation_callback =
+ base::Bind(&SimpleEntryImpl::EntryOperationComplete,
+ this, callback);
+ WorkerPool::PostTask(FROM_HERE,
+ base::Bind(&SimpleSynchronousEntry::ReadData,
+ base::Unretained(synchronous_entry_),
+ index, offset, buf,
+ buf_len, sync_operation_callback),
+ true);
+}
+
+void SimpleEntryImpl::WriteDataInternal(int index,
+ int offset,
+ scoped_refptr<net::IOBuffer> buf,
+ int buf_len,
+ const CompletionCallback& callback,
+ bool truncate) {
+ DCHECK(io_thread_checker_.CalledOnValidThread());
+ DCHECK(!operation_running_);
+ operation_running_ = true;
+ if (index_)
+ index_->UseIfExists(key_);
+
+ // TODO(felipeg): When adding support for optimistic writes we need to set
+ // data_size_[index] = buf_len here.
+ SynchronousOperationCallback sync_operation_callback =
+ base::Bind(&SimpleEntryImpl::EntryOperationComplete,
+ this, callback);
+ WorkerPool::PostTask(FROM_HERE,
+ base::Bind(&SimpleSynchronousEntry::WriteData,
+ base::Unretained(synchronous_entry_),
+ index, offset, buf,
+ buf_len, sync_operation_callback, truncate),
+ true);
}
void SimpleEntryImpl::CreationOperationComplete(
@@ -275,7 +331,7 @@ void SimpleEntryImpl::CreationOperationComplete(
// The Backend interface requires us to return |this|, and keep the Entry
// alive until Entry::Close(). Adding a reference to self will keep |this|
// alive after the scope of the Callback calling us is destroyed.
- AddRef(); // Balanced in Close().
+ AddRef(); // Balanced in CloseInternal().
synchronous_entry_ = sync_entry;
SetSynchronousData();
if (index_)
@@ -289,8 +345,9 @@ void SimpleEntryImpl::EntryOperationComplete(
int result) {
DCHECK(io_thread_checker_.CalledOnValidThread());
DCHECK(synchronous_entry_);
- DCHECK(synchronous_entry_in_use_by_worker_);
- synchronous_entry_in_use_by_worker_ = false;
+ DCHECK(operation_running_);
+
+ operation_running_ = false;
SetSynchronousData();
if (index_) {
if (result >= 0) {
@@ -301,11 +358,12 @@ void SimpleEntryImpl::EntryOperationComplete(
}
}
completion_callback.Run(result);
+ RunNextOperationIfNeeded();
}
void SimpleEntryImpl::SetSynchronousData() {
DCHECK(io_thread_checker_.CalledOnValidThread());
- DCHECK(!synchronous_entry_in_use_by_worker_);
+ DCHECK(!operation_running_);
// TODO(felipeg): These copies to avoid data races are not optimal. While
// adding an IO thread index (for fast misses etc...), we can store this data
// in that structure. This also solves problems with last_used() on ext4
« no previous file with comments | « net/disk_cache/simple/simple_entry_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698