Chromium Code Reviews| 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..f9fea2a9662f08554e46c636507907c4060400f4 100644 |
| --- a/net/disk_cache/simple/simple_entry_impl.cc |
| +++ b/net/disk_cache/simple/simple_entry_impl.cc |
| @@ -87,7 +87,28 @@ int SimpleEntryImpl::DoomEntry(WeakPtr<SimpleIndex> index, |
| } |
| void SimpleEntryImpl::Doom() { |
|
gavinp
2013/04/17 08:12:35
I think doom is one of the only operations that al
felipeg
2013/04/17 10:06:43
Done.
|
| + LOG(INFO) << " DOOM " << key_; |
| DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + if (synchronous_entry_in_use_by_worker_) { |
| + // Postpone doom operation. |
| + operations_.push( |
| + base::Bind(&SimpleEntryImpl::DoomInternal, |
| + weak_ptr_factory_.GetWeakPtr())); |
| + return; |
| + } |
| + DCHECK(operations_.size() == 0); |
| + DCHECK(!synchronous_entry_in_use_by_worker_); |
| + |
| + DoomInternal(); |
| + // TODO(felipeg): Maybe we should have a flag is_doomed_ and do some DCHECKS |
| + // around the code, to see if we dont call read in a doomed entry. |
|
gavinp
2013/04/17 08:12:35
I believe it's correct and valid to Read/Write in
felipeg
2013/04/17 10:06:43
Done.
|
| + RunNextOperationIfNeeded(); |
| +} |
| + |
| +void SimpleEntryImpl::DoomInternal() { |
| + LOG(INFO) << " DOOM " << key_; |
| + DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + DCHECK(!synchronous_entry_in_use_by_worker_); |
| #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 |
| @@ -100,13 +121,26 @@ void SimpleEntryImpl::Doom() { |
| } |
| void SimpleEntryImpl::Close() { |
| + LOG(INFO) << " CLOSE " << key_; |
| 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 (synchronous_entry_in_use_by_worker_) { |
| + LOG(INFO) << " CLOSE " << key_; |
| + // 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; |
| } |
| + LOG(INFO) << " CLOSE " << key_; |
| + DCHECK(operations_.size() == 0); |
| + DCHECK(!synchronous_entry_in_use_by_worker_); |
| + |
| + 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; |
| @@ -132,20 +166,49 @@ int32 SimpleEntryImpl::GetDataSize(int index) const { |
| return data_size_[index]; |
| } |
| + |
| + |
| int SimpleEntryImpl::ReadData(int index, |
| int offset, |
| net::IOBuffer* buf, |
| int buf_len, |
| const CompletionCallback& callback) { |
| + LOG(INFO) << " READ " << key_; |
| 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); |
| + if (synchronous_entry_in_use_by_worker_ && !read_only_operation_) { |
| + // Postpone read operation. |
| + operations_.push( |
| + base::Bind(&SimpleEntryImpl::ReadDataInternal, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + index, |
| + offset, |
| + make_scoped_refptr(buf), |
| + buf_len, |
| + callback)); |
| + return net::ERR_IO_PENDING; |
| } |
| + DCHECK(operations_.size() == 0); |
| + ReadDataInternal(index, |
| + offset, |
| + make_scoped_refptr(buf), |
| + buf_len, |
| + callback); |
| + return net::ERR_IO_PENDING; |
| +} |
| + |
| +void SimpleEntryImpl::ReadDataInternal(int index, |
| + int offset, |
| + scoped_refptr<net::IOBuffer> buf, |
| + int buf_len, |
| + const CompletionCallback& callback) { |
| + LOG(INFO) << " READ " << key_; |
| + DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + DCHECK(!synchronous_entry_in_use_by_worker_); |
| + read_only_operation_ = true; |
| synchronous_entry_in_use_by_worker_ = true; |
| if (index_) |
| index_->UseIfExists(key_); |
| @@ -156,10 +219,14 @@ int SimpleEntryImpl::ReadData(int index, |
| WorkerPool::PostTask(FROM_HERE, |
| base::Bind(&SimpleSynchronousEntry::ReadData, |
| base::Unretained(synchronous_entry_), |
| - index, offset, make_scoped_refptr(buf), |
| + index, offset, buf, |
|
gavinp
2013/04/17 08:17:14
This is really dangerous, calling with the naked b
gavinp
2013/04/17 09:40:16
Boy this stuff is subtle.
I was wrong: I failed t
|
| buf_len, sync_operation_callback), |
| true); |
| - return net::ERR_IO_PENDING; |
| +} |
| + |
| +// TODO(felipeg): Maybe in case of failure from a write operation, we could try |
| +// to invalidate all operations in the queue of the current entry. |
| +static void WriteDataNoOp(int noop) { |
| } |
| int SimpleEntryImpl::WriteData(int index, |
|
gavinp
2013/04/17 09:23:56
I think ReadData / WriteData can be made a lot sim
felipeg
2013/04/17 10:06:43
Done.
|
| @@ -168,14 +235,56 @@ int SimpleEntryImpl::WriteData(int index, |
| int buf_len, |
| const CompletionCallback& callback, |
| bool truncate) { |
| + LOG(INFO) << " WRITE " << key_ << " buf " << buf << " buf_len " << buf_len << " truncate " << truncate; |
| DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + |
| if (synchronous_entry_in_use_by_worker_) { |
| - NOTIMPLEMENTED(); |
| - CHECK(false); |
| + LOG(INFO) << " WRITE " << key_; |
| + // Postpone write operation. |
| + operations_.push( |
| + base::Bind(&SimpleEntryImpl::WriteDataInternal, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + index, |
| + offset, |
| + make_scoped_refptr(buf), |
| + buf_len, |
| + callback, |
| + truncate)); |
| + // When writting, if there is already a pending operation, we have to return |
| + // pending. |
| + return net::ERR_IO_PENDING; |
| } |
| + LOG(INFO) << " WRITE " << key_; |
| + DCHECK(operations_.size() == 0); |
| + WriteDataInternal(index, |
| + offset, |
| + make_scoped_refptr(buf), |
| + buf_len, |
| + //callback, |
| + base::Bind(&WriteDataNoOp), |
| + truncate); |
| + //return net::ERR_IO_PENDING; |
| + // Pretend everything goes fine, and make HTTP Cache Transaction happy. |
| + return buf_len; |
| +} |
| + |
| +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(!synchronous_entry_in_use_by_worker_); |
| + read_only_operation_ = false; |
| synchronous_entry_in_use_by_worker_ = true; |
| if (index_) |
| index_->UseIfExists(key_); |
| + |
| + // TODO(felipeg): last_used_ last_modified_ |
| + |
| + data_size_[index] = buf_len; |
| + |
| SynchronousOperationCallback sync_operation_callback = |
| base::Bind(&SimpleEntryImpl::EntryOperationComplete, |
| index_, callback, weak_ptr_factory_.GetWeakPtr(), |
| @@ -183,10 +292,10 @@ int SimpleEntryImpl::WriteData(int index, |
| WorkerPool::PostTask(FROM_HERE, |
| base::Bind(&SimpleSynchronousEntry::WriteData, |
| base::Unretained(synchronous_entry_), |
| - index, offset, make_scoped_refptr(buf), |
| + index, offset, buf, |
| buf_len, sync_operation_callback, truncate), |
| true); |
| - return net::ERR_IO_PENDING; |
| + LOG(INFO) << " WRITE " << key_; |
| } |
| int SimpleEntryImpl::ReadSparseData(int64 offset, |
| @@ -246,6 +355,7 @@ SimpleEntryImpl::SimpleEntryImpl( |
| key_(synchronous_entry->key()), |
| synchronous_entry_(synchronous_entry), |
| synchronous_entry_in_use_by_worker_(false), |
| + read_only_operation_(false), |
| index_(index) { |
| DCHECK(synchronous_entry); |
| SetSynchronousData(); |
| @@ -291,10 +401,21 @@ void SimpleEntryImpl::EntryOperationComplete( |
| } |
| if (entry) { |
| + if (entry->read_only_operation_) |
| + LOG(INFO) << " READ EntryOperationComplete " << entry->key(); |
| + else |
| + LOG(INFO) << " WRITE EntryOperationComplete " << entry->key(); |
| DCHECK(entry->synchronous_entry_in_use_by_worker_); |
| + entry->read_only_operation_ = false; |
| entry->synchronous_entry_in_use_by_worker_ = false; |
| entry->SetSynchronousData(); |
| + |
| + entry->RunNextOperationIfNeeded(); |
| + |
| + completion_callback.Run(result); |
| } else { |
| + |
| + LOG(INFO) << " EntryOperationComplete " << entry->key(); |
| // |entry| must have had Close() called while this operation was in flight. |
| // Since the simple cache now only supports one pending entry operation in |
| // flight at a time, it's safe to now call Close() on |sync_entry|. |
| @@ -302,8 +423,23 @@ void SimpleEntryImpl::EntryOperationComplete( |
| base::Bind(&SimpleSynchronousEntry::Close, |
| base::Unretained(sync_entry)), |
| true); |
| + |
| + completion_callback.Run(result); |
| } |
| - completion_callback.Run(result); |
| +} |
| + |
| +void SimpleEntryImpl::RunNextOperationIfNeeded() { |
| + LOG(INFO) << " RunNextOperationIfNeeded " << key_; |
| + DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + if (operations_.size() <= 0) |
| + return; |
| + base::Closure operation = operations_.front(); |
| + operations_.pop(); |
| + |
| + LOG(INFO) << " operation.Run " << key_; |
| + // TODO(felipeg): maybe we should post task. But it could shuffle even more |
| + // the order of new operations in this entry. |
|
gavinp
2013/04/17 08:17:14
The callers should be totally insensitive to the o
felipeg
2013/04/17 10:06:43
No post is better because when debugging our minds
|
| + operation.Run(); |
| } |
| void SimpleEntryImpl::SetSynchronousData() { |