diff options
Diffstat (limited to 'net/disk_cache')
-rw-r--r-- | net/disk_cache/backend_impl.cc | 18 | ||||
-rw-r--r-- | net/disk_cache/backend_impl.h | 7 | ||||
-rw-r--r-- | net/disk_cache/backend_unittest.cc | 87 | ||||
-rw-r--r-- | net/disk_cache/entry_impl.cc | 84 | ||||
-rw-r--r-- | net/disk_cache/entry_impl.h | 10 | ||||
-rw-r--r-- | net/disk_cache/file.h | 5 | ||||
-rw-r--r-- | net/disk_cache/file_posix.cc | 12 | ||||
-rw-r--r-- | net/disk_cache/file_win.cc | 7 | ||||
-rw-r--r-- | net/disk_cache/in_flight_backend_io.cc | 57 | ||||
-rw-r--r-- | net/disk_cache/in_flight_backend_io.h | 18 | ||||
-rw-r--r-- | net/disk_cache/in_flight_io.cc | 29 | ||||
-rw-r--r-- | net/disk_cache/in_flight_io.h | 17 | ||||
-rw-r--r-- | net/disk_cache/sparse_control.cc | 8 | ||||
-rw-r--r-- | net/disk_cache/storage_block-inl.h | 6 | ||||
-rw-r--r-- | net/disk_cache/storage_block.h | 5 |
15 files changed, 297 insertions, 73 deletions
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc index 170b03d..7f36741 100644 --- a/net/disk_cache/backend_impl.cc +++ b/net/disk_cache/backend_impl.cc @@ -352,7 +352,15 @@ BackendImpl::BackendImpl(const FilePath& path, } BackendImpl::~BackendImpl() { - background_queue_.WaitForPendingIO(); + if (user_flags_ & kNoRandom) { + // This is a unit test, so we want to be strict about not leaking entries + // and completing all the work. + background_queue_.WaitForPendingIO(); + } else { + // This is most likely not a test, so we want to do as little work as + // possible at this time, at the price of leaving dirty entries behind. + background_queue_.DropPendingIO(); + } if (background_queue_.BackgroundIsCurrentThread()) { // Unit tests may use the same thread for everything. @@ -496,10 +504,12 @@ void BackendImpl::CleanupCache() { if (data_) data_->header.crash = 0; - File::WaitForPendingIO(&num_pending_io_); if (user_flags_ & kNoRandom) { // This is a net_unittest, verify that we are not 'leaking' entries. + File::WaitForPendingIO(&num_pending_io_); DCHECK(!num_refs_); + } else { + File::DropPendingIO(); } } block_files_.CloseFiles(); @@ -826,6 +836,10 @@ MappedFile* BackendImpl::File(Addr address) { return block_files_.GetFile(address); } +base::WeakPtr<InFlightBackendIO> BackendImpl::GetBackgroundQueue() { + return background_queue_.GetWeakPtr(); +} + bool BackendImpl::CreateExternalFile(Addr* address) { int file_number = data_->header.last_file + 1; Addr file_address(0); diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h index 53c8893..cc822d5 100644 --- a/net/disk_cache/backend_impl.h +++ b/net/disk_cache/backend_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -100,9 +100,8 @@ class NET_EXPORT_PRIVATE BackendImpl : public Backend { // Returns the actual file used to store a given (non-external) address. MappedFile* File(Addr address); - InFlightBackendIO* background_queue() { - return &background_queue_; - } + // Returns a weak pointer to the background queue. + base::WeakPtr<InFlightBackendIO> GetBackgroundQueue(); // Creates an external storage file. bool CreateExternalFile(Addr* address); diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc index 4bc5955..ea617fd 100644 --- a/net/disk_cache/backend_unittest.cc +++ b/net/disk_cache/backend_unittest.cc @@ -35,6 +35,9 @@ class DiskCacheBackendTest : public DiskCacheTestWithCache { protected: void BackendBasics(); void BackendKeying(); + void BackendShutdownWithPendingFileIO(bool fast); + void BackendShutdownWithPendingIO(bool fast); + void BackendShutdownWithPendingCreate(bool fast); void BackendSetSize(); void BackendLoad(); void BackendChain(); @@ -275,7 +278,7 @@ TEST_F(DiskCacheBackendTest, ExternalFiles) { } // Tests that we deal with file-level pending operations at destruction time. -TEST_F(DiskCacheTest, ShutdownWithPendingIO) { +void DiskCacheBackendTest::BackendShutdownWithPendingFileIO(bool fast) { net::TestCompletionCallback cb; { @@ -285,8 +288,11 @@ TEST_F(DiskCacheTest, ShutdownWithPendingIO) { base::Thread::Options(MessageLoop::TYPE_IO, 0))); disk_cache::Backend* cache; + uint32 flags = disk_cache::kNoBuffering; + if (!fast) + flags |= disk_cache::kNoRandom; int rv = disk_cache::BackendImpl::CreateBackend( - cache_path_, false, 0, net::DISK_CACHE, disk_cache::kNoRandom, + cache_path_, false, 0, net::DISK_CACHE, flags, base::MessageLoopProxy::current(), NULL, &cache, cb.callback()); ASSERT_EQ(net::OK, cb.GetResult(rv)); @@ -319,15 +325,30 @@ TEST_F(DiskCacheTest, ShutdownWithPendingIO) { delete cache; if (rv == net::ERR_IO_PENDING) { - EXPECT_TRUE(cb.have_result()); + if (fast) + EXPECT_FALSE(cb.have_result()); + else + EXPECT_TRUE(cb.have_result()); } } MessageLoop::current()->RunAllPending(); } +TEST_F(DiskCacheBackendTest, ShutdownWithPendingFileIO) { + BackendShutdownWithPendingFileIO(false); +} + +// We'll be leaking from this test. +TEST_F(DiskCacheBackendTest, ShutdownWithPendingFileIO_Fast) { + // The integrity test sets kNoRandom so there's a version mismatch if we don't + // force new eviction. + SetNewEviction(); + BackendShutdownWithPendingFileIO(true); +} + // Tests that we deal with background-thread pending operations. -TEST_F(DiskCacheTest, ShutdownWithPendingIO2) { +void DiskCacheBackendTest::BackendShutdownWithPendingIO(bool fast) { net::TestCompletionCallback cb; { @@ -337,8 +358,11 @@ TEST_F(DiskCacheTest, ShutdownWithPendingIO2) { base::Thread::Options(MessageLoop::TYPE_IO, 0))); disk_cache::Backend* cache; + uint32 flags = disk_cache::kNoBuffering; + if (!fast) + flags |= disk_cache::kNoRandom; int rv = disk_cache::BackendImpl::CreateBackend( - cache_path_, false, 0, net::DISK_CACHE, disk_cache::kNoRandom, + cache_path_, false, 0, net::DISK_CACHE, flags, cache_thread.message_loop_proxy(), NULL, &cache, cb.callback()); ASSERT_EQ(net::OK, cb.GetResult(rv)); @@ -362,6 +386,59 @@ TEST_F(DiskCacheTest, ShutdownWithPendingIO2) { MessageLoop::current()->RunAllPending(); } +TEST_F(DiskCacheBackendTest, ShutdownWithPendingIO) { + BackendShutdownWithPendingIO(false); +} + +// We'll be leaking from this test. +TEST_F(DiskCacheBackendTest, ShutdownWithPendingIO_Fast) { + // The integrity test sets kNoRandom so there's a version mismatch if we don't + // force new eviction. + SetNewEviction(); + BackendShutdownWithPendingIO(true); +} + +// Tests that we deal with create-type pending operations. +void DiskCacheBackendTest::BackendShutdownWithPendingCreate(bool fast) { + net::TestCompletionCallback cb; + + { + ASSERT_TRUE(CleanupCacheDir()); + base::Thread cache_thread("CacheThread"); + ASSERT_TRUE(cache_thread.StartWithOptions( + base::Thread::Options(MessageLoop::TYPE_IO, 0))); + + disk_cache::Backend* cache; + disk_cache::BackendFlags flags = + fast ? disk_cache::kNone : disk_cache::kNoRandom; + int rv = disk_cache::BackendImpl::CreateBackend( + cache_path_, false, 0, net::DISK_CACHE, flags, + cache_thread.message_loop_proxy(), NULL, &cache, cb.callback()); + ASSERT_EQ(net::OK, cb.GetResult(rv)); + + disk_cache::Entry* entry; + rv = cache->CreateEntry("some key", &entry, cb.callback()); + ASSERT_EQ(net::ERR_IO_PENDING, rv); + + delete cache; + EXPECT_FALSE(cb.have_result()); + } + + MessageLoop::current()->RunAllPending(); +} + +TEST_F(DiskCacheBackendTest, ShutdownWithPendingCreate) { + BackendShutdownWithPendingCreate(false); +} + +// We'll be leaking an entry from this test. +TEST_F(DiskCacheBackendTest, ShutdownWithPendingCreate_Fast) { + // The integrity test sets kNoRandom so there's a version mismatch if we don't + // force new eviction. + SetNewEviction(); + BackendShutdownWithPendingCreate(true); +} + TEST_F(DiskCacheTest, TruncatedIndex) { ASSERT_TRUE(CleanupCacheDir()); FilePath index = cache_path_.AppendASCII("index"); diff --git a/net/disk_cache/entry_impl.cc b/net/disk_cache/entry_impl.cc index 1718370..d0e5856 100644 --- a/net/disk_cache/entry_impl.cc +++ b/net/disk_cache/entry_impl.cc @@ -292,8 +292,9 @@ bool EntryImpl::UserBuffer::GrowBuffer(int required, int limit) { // ------------------------------------------------------------------------ EntryImpl::EntryImpl(BackendImpl* backend, Addr address, bool read_only) - : entry_(NULL, Addr(0)), node_(NULL, Addr(0)), backend_(backend), - doomed_(false), read_only_(read_only), dirty_(false) { + : entry_(NULL, Addr(0)), node_(NULL, Addr(0)), + backend_(backend->GetWeakPtr()), doomed_(false), read_only_(read_only), + dirty_(false) { entry_.LazyInit(backend->File(address), address); for (int i = 0; i < kNumStreams; i++) { unreported_size_[i] = 0; @@ -301,7 +302,7 @@ EntryImpl::EntryImpl(BackendImpl* backend, Addr address, bool read_only) } void EntryImpl::DoomImpl() { - if (doomed_) + if (doomed_ || !backend_) return; SetPointerForInvalidEntry(backend_->GetCurrentEntryId()); @@ -678,7 +679,13 @@ void EntryImpl::IncrementIoCount() { } void EntryImpl::DecrementIoCount() { - backend_->DecrementIoCount(); + if (backend_) + backend_->DecrementIoCount(); +} + +void EntryImpl::OnEntryCreated(BackendImpl* backend) { + // Just grab a reference to the backround queue. + background_queue_ = backend->GetBackgroundQueue(); } void EntryImpl::SetTimes(base::Time last_used, base::Time last_modified) { @@ -688,6 +695,9 @@ void EntryImpl::SetTimes(base::Time last_used, base::Time last_modified) { } void EntryImpl::ReportIOTime(Operation op, const base::TimeTicks& start) { + if (!backend_) + return; + int group = backend_->GetSizeGroup(); switch (op) { case kRead: @@ -744,11 +754,13 @@ int EntryImpl::NumBlocksForEntry(int key_size) { // ------------------------------------------------------------------------ void EntryImpl::Doom() { - backend_->background_queue()->DoomEntryImpl(this); + if (background_queue_) + background_queue_->DoomEntryImpl(this); } void EntryImpl::Close() { - backend_->background_queue()->CloseEntryImpl(this); + if (background_queue_) + background_queue_->CloseEntryImpl(this); } std::string EntryImpl::GetKey() const { @@ -817,8 +829,10 @@ int EntryImpl::ReadData(int index, int offset, net::IOBuffer* buf, int buf_len, if (buf_len < 0) return net::ERR_INVALID_ARGUMENT; - backend_->background_queue()->ReadData(this, index, offset, buf, buf_len, - callback); + if (!background_queue_) + return net::ERR_UNEXPECTED; + + background_queue_->ReadData(this, index, offset, buf, buf_len, callback); return net::ERR_IO_PENDING; } @@ -835,8 +849,11 @@ int EntryImpl::WriteData( if (offset < 0 || buf_len < 0) return net::ERR_INVALID_ARGUMENT; - backend_->background_queue()->WriteData(this, index, offset, buf, buf_len, - truncate, callback); + if (!background_queue_) + return net::ERR_UNEXPECTED; + + background_queue_->WriteData(this, index, offset, buf, buf_len, truncate, + callback); return net::ERR_IO_PENDING; } @@ -845,8 +862,10 @@ int EntryImpl::ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len, if (callback.is_null()) return ReadSparseDataImpl(offset, buf, buf_len, callback); - backend_->background_queue()->ReadSparseData(this, offset, buf, buf_len, - callback); + if (!background_queue_) + return net::ERR_UNEXPECTED; + + background_queue_->ReadSparseData(this, offset, buf, buf_len, callback); return net::ERR_IO_PENDING; } @@ -855,15 +874,19 @@ int EntryImpl::WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len, if (callback.is_null()) return WriteSparseDataImpl(offset, buf, buf_len, callback); - backend_->background_queue()->WriteSparseData(this, offset, buf, buf_len, - callback); + if (!background_queue_) + return net::ERR_UNEXPECTED; + + background_queue_->WriteSparseData(this, offset, buf, buf_len, callback); return net::ERR_IO_PENDING; } int EntryImpl::GetAvailableRange(int64 offset, int len, int64* start, const net::CompletionCallback& callback) { - backend_->background_queue()->GetAvailableRange(this, offset, len, start, - callback); + if (!background_queue_) + return net::ERR_UNEXPECTED; + + background_queue_->GetAvailableRange(this, offset, len, start, callback); return net::ERR_IO_PENDING; } @@ -877,14 +900,18 @@ bool EntryImpl::CouldBeSparse() const { } void EntryImpl::CancelSparseIO() { - backend_->background_queue()->CancelSparseIO(this); + if (background_queue_) + background_queue_->CancelSparseIO(this); } int EntryImpl::ReadyForSparseIO(const net::CompletionCallback& callback) { if (!sparse_.get()) return net::OK; - backend_->background_queue()->ReadyForSparseIO(this, callback); + if (!background_queue_) + return net::ERR_UNEXPECTED; + + background_queue_->ReadyForSparseIO(this, callback); return net::ERR_IO_PENDING; } @@ -895,6 +922,11 @@ int EntryImpl::ReadyForSparseIO(const net::CompletionCallback& callback) { // data related to a previous cache entry because the range was not fully // written before). EntryImpl::~EntryImpl() { + if (!backend_) { + entry_.clear_modified(); + node_.clear_modified(); + return; + } Log("~EntryImpl in"); // Save the sparse info to disk. This will generate IO for this entry and @@ -958,6 +990,9 @@ int EntryImpl::InternalReadData( if (buf_len < 0) return net::ERR_INVALID_ARGUMENT; + if (!backend_) + return net::ERR_UNEXPECTED; + TimeTicks start = TimeTicks::Now(); if (offset + buf_len > entry_size) @@ -1035,6 +1070,9 @@ int EntryImpl::InternalWriteData( if (offset < 0 || buf_len < 0) return net::ERR_INVALID_ARGUMENT; + if (!backend_) + return net::ERR_UNEXPECTED; + int max_file_size = backend_->MaxFileSize(); // offset or buf_len could be negative numbers. @@ -1140,6 +1178,8 @@ bool EntryImpl::CreateDataBlock(int index, int size) { bool EntryImpl::CreateBlock(int size, Addr* address) { DCHECK(!address->is_initialized()); + if (!backend_) + return false; FileType file_type = Addr::RequiredFileType(size); if (EXTERNAL == file_type) { @@ -1164,6 +1204,7 @@ bool EntryImpl::CreateBlock(int size, Addr* address) { // important that the entry doesn't keep a reference to this address, or we'll // end up deleting the contents of |address| once again. void EntryImpl::DeleteData(Addr address, int index) { + DCHECK(backend_); if (!address.is_initialized()) return; if (address.is_separate_file()) { @@ -1181,6 +1222,9 @@ void EntryImpl::DeleteData(Addr address, int index) { } void EntryImpl::UpdateRank(bool modified) { + if (!backend_) + return; + if (!doomed_) { // Everything is handled by the backend. backend_->UpdateRank(this, modified); @@ -1195,6 +1239,9 @@ void EntryImpl::UpdateRank(bool modified) { } File* EntryImpl::GetBackingFile(Addr address, int index) { + if (!backend_) + return NULL; + File* file; if (address.is_separate_file()) file = GetExternalFile(address, index); @@ -1466,6 +1513,7 @@ uint32 EntryImpl::GetEntryFlags() { } void EntryImpl::GetData(int index, char** buffer, Addr* address) { + DCHECK(backend_); if (user_buffers_[index].get() && user_buffers_[index]->Size() && !user_buffers_[index]->Start()) { // The data is already in memory, just copy it and we're done. diff --git a/net/disk_cache/entry_impl.h b/net/disk_cache/entry_impl.h index 3083b23..8296200 100644 --- a/net/disk_cache/entry_impl.h +++ b/net/disk_cache/entry_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -15,6 +15,7 @@ namespace disk_cache { class BackendImpl; +class InFlightBackendIO; class SparseControl; // This class implements the Entry interface. An object of this @@ -121,6 +122,10 @@ class NET_EXPORT_PRIVATE EntryImpl void IncrementIoCount(); void DecrementIoCount(); + // This entry is being returned to the user. It is always called from the + // primary thread (not the dedicated cache thread). + void OnEntryCreated(BackendImpl* backend); + // Set the access times for this entry. This method provides support for // the upgrade tool. void SetTimes(base::Time last_used, base::Time last_modified); @@ -254,7 +259,8 @@ class NET_EXPORT_PRIVATE EntryImpl CacheEntryBlock entry_; // Key related information for this entry. CacheRankingsBlock node_; // Rankings related information for this entry. - BackendImpl* backend_; // Back pointer to the cache. + base::WeakPtr<BackendImpl> backend_; // Back pointer to the cache. + base::WeakPtr<InFlightBackendIO> background_queue_; // In-progress queue. scoped_ptr<UserBuffer> user_buffers_[kNumStreams]; // Stores user data. // Files to store external user data and key. scoped_refptr<File> files_[kNumStreams + 1]; diff --git a/net/disk_cache/file.h b/net/disk_cache/file.h index dc50133..3617e0c 100644 --- a/net/disk_cache/file.h +++ b/net/disk_cache/file.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -68,6 +68,9 @@ class NET_EXPORT_PRIVATE File : public base::RefCounted<File> { // Blocks until |num_pending_io| IO operations complete. static void WaitForPendingIO(int* num_pending_io); + // Drops current pending operations without waiting for them to complete. + static void DropPendingIO(); + protected: virtual ~File(); diff --git a/net/disk_cache/file_posix.cc b/net/disk_cache/file_posix.cc index 39c5159..e03d955 100644 --- a/net/disk_cache/file_posix.cc +++ b/net/disk_cache/file_posix.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -97,7 +97,7 @@ void FileBackgroundIO::Read() { } else { result_ = net::ERR_CACHE_READ_FAILURE; } - controller_->OnIOComplete(this); + NotifyController(); } // Runs on a worker thread. @@ -105,7 +105,7 @@ void FileBackgroundIO::Write() { bool rv = file_->Write(buf_, buf_len_, offset_); result_ = rv ? static_cast<int>(buf_len_) : net::ERR_CACHE_WRITE_FAILURE; - controller_->OnIOComplete(this); + NotifyController(); } // --------------------------------------------------------------------------- @@ -282,6 +282,12 @@ void File::WaitForPendingIO(int* num_pending_io) { DeleteFileInFlightIO(); } +// Static. +void File::DropPendingIO() { + GetFileInFlightIO()->DropPendingIO(); + DeleteFileInFlightIO(); +} + File::~File() { if (IsValid()) base::ClosePlatformFile(platform_file_); diff --git a/net/disk_cache/file_win.cc b/net/disk_cache/file_win.cc index d12f82c8..071b4ef 100644 --- a/net/disk_cache/file_win.cc +++ b/net/disk_cache/file_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -264,4 +264,9 @@ void File::WaitForPendingIO(int* num_pending_io) { } } +// Static. +void File::DropPendingIO() { + // Nothing to do here. +} + } // namespace disk_cache diff --git a/net/disk_cache/in_flight_backend_io.cc b/net/disk_cache/in_flight_backend_io.cc index 0e5e969..e9fbd73 100644 --- a/net/disk_cache/in_flight_backend_io.cc +++ b/net/disk_cache/in_flight_backend_io.cc @@ -42,7 +42,23 @@ void BackendIO::OnIOComplete(int result) { DCHECK(IsEntryOperation()); DCHECK_NE(result, net::ERR_IO_PENDING); result_ = result; - controller_->OnIOComplete(this); + NotifyController(); +} + +// Runs on the primary thread. +void BackendIO::OnDone(bool cancel) { + if (IsEntryOperation()) { + CACHE_UMA(TIMES, "TotalIOTime", 0, ElapsedTime()); + } + + if (!ReturnsEntry()) + return; + + if (result() == net::OK) { + static_cast<EntryImpl*>(*entry_ptr_)->OnEntryCreated(backend_); + if (cancel) + (*entry_ptr_)->Close(); + } } bool BackendIO::IsEntryOperation() { @@ -54,10 +70,6 @@ void BackendIO::ReferenceEntry() { entry_->AddRef(); } -base::TimeDelta BackendIO::ElapsedTime() const { - return base::TimeTicks::Now() - start_time_; -} - void BackendIO::Init() { operation_ = OP_INIT; } @@ -196,6 +208,15 @@ void BackendIO::ReadyForSparseIO(EntryImpl* entry) { BackendIO::~BackendIO() {} +bool BackendIO::ReturnsEntry() { + return (operation_ == OP_OPEN || operation_ == OP_CREATE || + operation_ == OP_OPEN_NEXT || operation_ == OP_OPEN_PREV); +} + +base::TimeDelta BackendIO::ElapsedTime() const { + return base::TimeTicks::Now() - start_time_; +} + // Runs on the background thread. void BackendIO::ExecuteBackendOperation() { switch (operation_) { @@ -254,7 +275,7 @@ void BackendIO::ExecuteBackendOperation() { result_ = net::ERR_UNEXPECTED; } DCHECK_NE(net::ERR_IO_PENDING, result_); - controller_->OnIOComplete(this); + NotifyController(); } // Runs on the background thread. @@ -263,23 +284,23 @@ void BackendIO::ExecuteEntryOperation() { case OP_READ: result_ = entry_->ReadDataImpl( index_, offset_, buf_, buf_len_, - base::Bind(&BackendIO::OnIOComplete, base::Unretained(this))); + base::Bind(&BackendIO::OnIOComplete, this)); break; case OP_WRITE: result_ = entry_->WriteDataImpl( index_, offset_, buf_, buf_len_, - base::Bind(&BackendIO::OnIOComplete, base::Unretained(this)), + base::Bind(&BackendIO::OnIOComplete, this), truncate_); break; case OP_READ_SPARSE: result_ = entry_->ReadSparseDataImpl( offset64_, buf_, buf_len_, - base::Bind(&BackendIO::OnIOComplete, base::Unretained(this))); + base::Bind(&BackendIO::OnIOComplete, this)); break; case OP_WRITE_SPARSE: result_ = entry_->WriteSparseDataImpl( offset64_, buf_, buf_len_, - base::Bind(&BackendIO::OnIOComplete, base::Unretained(this))); + base::Bind(&BackendIO::OnIOComplete, this)); break; case OP_GET_RANGE: result_ = entry_->GetAvailableRangeImpl(offset64_, buf_len_, start_); @@ -290,20 +311,21 @@ void BackendIO::ExecuteEntryOperation() { break; case OP_IS_READY: result_ = entry_->ReadyForSparseIOImpl( - base::Bind(&BackendIO::OnIOComplete, base::Unretained(this))); + base::Bind(&BackendIO::OnIOComplete, this)); break; default: NOTREACHED() << "Invalid Operation"; result_ = net::ERR_UNEXPECTED; } if (result_ != net::ERR_IO_PENDING) - controller_->OnIOComplete(this); + NotifyController(); } InFlightBackendIO::InFlightBackendIO(BackendImpl* backend, base::MessageLoopProxy* background_thread) : backend_(backend), - background_thread_(background_thread) { + background_thread_(background_thread), + ALLOW_THIS_IN_INITIALIZER_LIST(ptr_factory_(this)) { } InFlightBackendIO::~InFlightBackendIO() { @@ -475,10 +497,7 @@ void InFlightBackendIO::WaitForPendingIO() { void InFlightBackendIO::OnOperationComplete(BackgroundIO* operation, bool cancel) { BackendIO* op = static_cast<BackendIO*>(operation); - - if (op->IsEntryOperation()) { - CACHE_UMA(TIMES, "TotalIOTime", 0, op->ElapsedTime()); - } + op->OnDone(cancel); if (!op->callback().is_null() && (!cancel || op->IsEntryOperation())) op->callback().Run(op->result()); @@ -490,4 +509,8 @@ void InFlightBackendIO::PostOperation(BackendIO* operation) { OnOperationPosted(operation); } +base::WeakPtr<InFlightBackendIO> InFlightBackendIO::GetWeakPtr() { + return ptr_factory_.GetWeakPtr(); +} + } // namespace diff --git a/net/disk_cache/in_flight_backend_io.h b/net/disk_cache/in_flight_backend_io.h index 4e6f904..0e2eec6 100644 --- a/net/disk_cache/in_flight_backend_io.h +++ b/net/disk_cache/in_flight_backend_io.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -34,6 +34,10 @@ class BackendIO : public BackgroundIO { // Callback implementation. void OnIOComplete(int result); + // Called when we are finishing this operation. If |cancel| is true, the user + // callback will not be invoked. + void OnDone(bool cancel); + // Returns true if this operation is directed to an entry (vs. the backend). bool IsEntryOperation(); @@ -42,9 +46,6 @@ class BackendIO : public BackgroundIO { // Grabs an extra reference of entry_. void ReferenceEntry(); - // Returns the time that has passed since the operation was created. - base::TimeDelta ElapsedTime() const; - // The operations we proxy: void Init(); void OpenEntry(const std::string& key, Entry** entry); @@ -109,6 +110,12 @@ class BackendIO : public BackgroundIO { virtual ~BackendIO(); + // Returns true if this operation returns an entry. + bool ReturnsEntry(); + + // Returns the time that has passed since the operation was created. + base::TimeDelta ElapsedTime() const; + void ExecuteBackendOperation(); void ExecuteEntryOperation(); @@ -196,6 +203,8 @@ class InFlightBackendIO : public InFlightIO { return background_thread_->BelongsToCurrentThread(); } + base::WeakPtr<InFlightBackendIO> GetWeakPtr(); + protected: virtual void OnOperationComplete(BackgroundIO* operation, bool cancel) OVERRIDE; @@ -205,6 +214,7 @@ class InFlightBackendIO : public InFlightIO { BackendImpl* backend_; scoped_refptr<base::MessageLoopProxy> background_thread_; + base::WeakPtrFactory<InFlightBackendIO> ptr_factory_; DISALLOW_COPY_AND_ASSIGN(InFlightBackendIO); }; diff --git a/net/disk_cache/in_flight_io.cc b/net/disk_cache/in_flight_io.cc index 0f5185f..636cb4f 100644 --- a/net/disk_cache/in_flight_io.cc +++ b/net/disk_cache/in_flight_io.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -11,7 +11,7 @@ namespace disk_cache { BackgroundIO::BackgroundIO(InFlightIO* controller) - : controller_(controller), result_(-1), io_completed_(true, false) { + : result_(-1), io_completed_(true, false), controller_(controller) { } // Runs on the primary thread. @@ -21,15 +21,13 @@ void BackgroundIO::OnIOSignalled() { } void BackgroundIO::Cancel() { + // controller_ may be in use from the background thread at this time. + base::AutoLock lock(controller_lock_); DCHECK(controller_); controller_ = NULL; } -BackgroundIO::~BackgroundIO() {} - -// Runs on the background thread. -void BackgroundIO::NotifyController() { - controller_->OnIOComplete(this); +BackgroundIO::~BackgroundIO() { } // --------------------------------------------------------------------------- @@ -42,6 +40,13 @@ InFlightIO::InFlightIO() InFlightIO::~InFlightIO() { } +// Runs on the background thread. +void BackgroundIO::NotifyController() { + base::AutoLock lock(controller_lock_); + if (controller_) + controller_->OnIOComplete(this); +} + void InFlightIO::WaitForPendingIO() { while (!io_list_.empty()) { // Block the current thread until all pending IO completes. @@ -50,6 +55,16 @@ void InFlightIO::WaitForPendingIO() { } } +void InFlightIO::DropPendingIO() { + while (!io_list_.empty()) { + IOList::iterator it = io_list_.begin(); + BackgroundIO* operation = *it; + operation->Cancel(); + DCHECK(io_list_.find(operation) != io_list_.end()); + io_list_.erase(make_scoped_refptr(operation)); + } +} + // Runs on a background thread. void InFlightIO::OnIOComplete(BackgroundIO* operation) { #ifndef NDEBUG diff --git a/net/disk_cache/in_flight_io.h b/net/disk_cache/in_flight_io.h index a361cbd..c007cb9 100644 --- a/net/disk_cache/in_flight_io.h +++ b/net/disk_cache/in_flight_io.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -9,6 +9,7 @@ #include <set> #include "base/message_loop_proxy.h" +#include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" namespace disk_cache { @@ -48,18 +49,19 @@ class BackgroundIO : public base::RefCountedThreadSafe<BackgroundIO> { protected: virtual ~BackgroundIO(); - InFlightIO* controller_; // The controller that tracks all operations. + // Notifies the controller about the end of the operation, from the background + // thread. + void NotifyController(); + int result_; // Final operation result. private: friend class base::RefCountedThreadSafe<BackgroundIO>; - // Notifies the controller about the end of the operation, from the background - // thread. - void NotifyController(); - // An event to signal when the operation completes. base::WaitableEvent io_completed_; + InFlightIO* controller_; // The controller that tracks all operations. + base::Lock controller_lock_; // A lock protecting clearing of controller_. DISALLOW_COPY_AND_ASSIGN(BackgroundIO); }; @@ -95,6 +97,9 @@ class InFlightIO { // complete. void WaitForPendingIO(); + // Drops current pending operations without waiting for them to complete. + void DropPendingIO(); + // Called on a background thread when |operation| completes. void OnIOComplete(BackgroundIO* operation); diff --git a/net/disk_cache/sparse_control.cc b/net/disk_cache/sparse_control.cc index ee558ba..a45ba1f 100644 --- a/net/disk_cache/sparse_control.cc +++ b/net/disk_cache/sparse_control.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -442,6 +442,9 @@ bool SparseControl::OpenChild() { if (!ChildPresent()) return ContinueWithoutChild(key); + if (!entry_->backend_) + return false; + child_ = entry_->backend_->OpenEntryImpl(key); if (!child_) return ContinueWithoutChild(key); @@ -514,6 +517,9 @@ bool SparseControl::ContinueWithoutChild(const std::string& key) { if (kGetRangeOperation == operation_) return true; + if (!entry_->backend_) + return false; + child_ = entry_->backend_->CreateEntryImpl(key); if (!child_) { child_ = NULL; diff --git a/net/disk_cache/storage_block-inl.h b/net/disk_cache/storage_block-inl.h index 614b143..388aa24 100644 --- a/net/disk_cache/storage_block-inl.h +++ b/net/disk_cache/storage_block-inl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -89,6 +89,10 @@ template<typename T> void StorageBlock<T>::set_modified() { modified_ = true; } +template<typename T> void StorageBlock<T>::clear_modified() { + modified_ = false; +} + template<typename T> T* StorageBlock<T>::Data() { if (!data_) AllocateData(); diff --git a/net/disk_cache/storage_block.h b/net/disk_cache/storage_block.h index 2cf3c3a..f32c0fc 100644 --- a/net/disk_cache/storage_block.h +++ b/net/disk_cache/storage_block.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -55,6 +55,9 @@ class StorageBlock : public FileBlock { // Sets the object to lazily save the in-memory data on destruction. void set_modified(); + // Forgets that the data was modified, so it's not lazily saved. + void clear_modified(); + // Gets a pointer to the internal storage (allocates storage if needed). T* Data(); |