| 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 1917a88715091ac1a37be9dae3b8fd104b6f4edf..6a15dd03de784d2643ec729238c58f92b90ca837 100644
|
| --- a/net/disk_cache/simple/simple_entry_impl.cc
|
| +++ b/net/disk_cache/simple/simple_entry_impl.cc
|
| @@ -88,6 +88,7 @@ int SimpleEntryImpl::DoomEntry(WeakPtr<SimpleIndex> index,
|
|
|
| void SimpleEntryImpl::Doom() {
|
| DCHECK(io_thread_checker_.CalledOnValidThread());
|
| + DCHECK(!operation_running_);
|
| #if defined(OS_POSIX)
|
| // This call to static SimpleEntryImpl::DoomEntry() will just erase the
|
| // underlying files. On POSIX, this is fine; the files are still open on the
|
| @@ -101,12 +102,22 @@ void SimpleEntryImpl::Doom() {
|
|
|
| void SimpleEntryImpl::Close() {
|
| DCHECK(io_thread_checker_.CalledOnValidThread());
|
| - if (!synchronous_entry_in_use_by_worker_) {
|
| - WorkerPool::PostTask(FROM_HERE,
|
| - base::Bind(&SimpleSynchronousEntry::Close,
|
| - base::Unretained(synchronous_entry_)),
|
| - true);
|
| + if (operation_running_) {
|
| + // Postpone close operation.
|
| + // Push the close operation to the end of the line. This way we run all
|
| + // operations before we are able close.
|
| + operations_.push(
|
| + base::Bind(&SimpleEntryImpl::Close,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + return;
|
| }
|
| + DCHECK(operations_.size() == 0);
|
| + DCHECK(!operation_running_);
|
| +
|
| + WorkerPool::PostTask(FROM_HERE,
|
| + base::Bind(&SimpleSynchronousEntry::Close,
|
| + base::Unretained(synchronous_entry_)),
|
| + true);
|
| // Entry::Close() is expected to release this entry. See disk_cache.h for
|
| // details.
|
| delete this;
|
| @@ -138,27 +149,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,
|
| - index_, callback, weak_ptr_factory_.GetWeakPtr(),
|
| - synchronous_entry_);
|
| - 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.
|
| + operations_.push(
|
| + base::Bind(&SimpleEntryImpl::ReadDataInternal,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + index,
|
| + offset,
|
| + make_scoped_refptr(buf),
|
| + buf_len,
|
| + callback));
|
| + RunNextOperationIfNeeded();
|
| return net::ERR_IO_PENDING;
|
| }
|
|
|
| @@ -169,23 +174,22 @@ 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,
|
| - index_, callback, weak_ptr_factory_.GetWeakPtr(),
|
| - synchronous_entry_);
|
| - 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;
|
| +
|
| + operations_.push(
|
| + base::Bind(&SimpleEntryImpl::WriteDataInternal,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + 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;
|
| }
|
|
|
| @@ -245,7 +249,7 @@ SimpleEntryImpl::SimpleEntryImpl(
|
| path_(synchronous_entry->path()),
|
| key_(synchronous_entry->key()),
|
| synchronous_entry_(synchronous_entry),
|
| - synchronous_entry_in_use_by_worker_(false),
|
| + operation_running_(false),
|
| index_(index) {
|
| DCHECK(synchronous_entry);
|
| SetSynchronousData();
|
| @@ -255,6 +259,66 @@ SimpleEntryImpl::~SimpleEntryImpl() {
|
| DCHECK(io_thread_checker_.CalledOnValidThread());
|
| }
|
|
|
| +bool SimpleEntryImpl::RunNextOperationIfNeeded() {
|
| + DCHECK(io_thread_checker_.CalledOnValidThread());
|
| + if (operations_.size() <= 0 || operation_running_)
|
| + return false;
|
| + base::Closure operation = operations_.front();
|
| + operations_.pop();
|
| + operation.Run();
|
| + return true;
|
| +}
|
| +
|
| +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,
|
| + index_, callback, weak_ptr_factory_.GetWeakPtr(),
|
| + synchronous_entry_);
|
| + 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_);
|
| +
|
| + last_used_ = base::Time::Now();
|
| + last_modified_ = base::Time::Now();
|
| + data_size_[index] = buf_len;
|
| +
|
| + SynchronousOperationCallback sync_operation_callback =
|
| + base::Bind(&SimpleEntryImpl::EntryOperationComplete,
|
| + index_, callback, weak_ptr_factory_.GetWeakPtr(),
|
| + synchronous_entry_);
|
| + WorkerPool::PostTask(FROM_HERE,
|
| + base::Bind(&SimpleSynchronousEntry::WriteData,
|
| + base::Unretained(synchronous_entry_),
|
| + index, offset, buf,
|
| + buf_len, sync_operation_callback, truncate),
|
| + true);
|
| +}
|
| +
|
| // static
|
| void SimpleEntryImpl::CreationOperationComplete(
|
| WeakPtr<SimpleIndex> index,
|
| @@ -291,9 +355,10 @@ void SimpleEntryImpl::EntryOperationComplete(
|
| }
|
|
|
| if (entry) {
|
| - DCHECK(entry->synchronous_entry_in_use_by_worker_);
|
| - entry->synchronous_entry_in_use_by_worker_ = false;
|
| + DCHECK(entry->operation_running_);
|
| + entry->operation_running_ = false;
|
| entry->SetSynchronousData();
|
| + entry->RunNextOperationIfNeeded();
|
| } else {
|
| // |entry| must have had Close() called while this operation was in flight.
|
| // Since the simple cache now only supports one pending entry operation in
|
| @@ -308,7 +373,7 @@ void SimpleEntryImpl::EntryOperationComplete(
|
|
|
| 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
|
|
|