summaryrefslogtreecommitdiffstats
path: root/net/disk_cache
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-20 23:15:10 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-20 23:15:10 +0000
commit4739f709cff67fc2237f1f72fb55e8c87c09f647 (patch)
tree2254b67fb3cf31f625991f9026f329ada455d2a3 /net/disk_cache
parent1ce036139aba74ac80a94100c315d56a4eabcae2 (diff)
downloadchromium_src-4739f709cff67fc2237f1f72fb55e8c87c09f647.zip
chromium_src-4739f709cff67fc2237f1f72fb55e8c87c09f647.tar.gz
chromium_src-4739f709cff67fc2237f1f72fb55e8c87c09f647.tar.bz2
Disk cache: Remove all non essential synchronization from the
cache destructor. The default setting for unit tests is still to perform full synchronization so we make sure that all work is performed, and that there are no leaks. However, when not running unit tests, all in progress operations are simply dropped on the flor, so they should result in dirty entries for the next run. BUG=74623 TEST=net_unittests Review URL: https://chromiumcodereview.appspot.com/9702059 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127826 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/disk_cache')
-rw-r--r--net/disk_cache/backend_impl.cc18
-rw-r--r--net/disk_cache/backend_impl.h7
-rw-r--r--net/disk_cache/backend_unittest.cc87
-rw-r--r--net/disk_cache/entry_impl.cc84
-rw-r--r--net/disk_cache/entry_impl.h10
-rw-r--r--net/disk_cache/file.h5
-rw-r--r--net/disk_cache/file_posix.cc12
-rw-r--r--net/disk_cache/file_win.cc7
-rw-r--r--net/disk_cache/in_flight_backend_io.cc57
-rw-r--r--net/disk_cache/in_flight_backend_io.h18
-rw-r--r--net/disk_cache/in_flight_io.cc29
-rw-r--r--net/disk_cache/in_flight_io.h17
-rw-r--r--net/disk_cache/sparse_control.cc8
-rw-r--r--net/disk_cache/storage_block-inl.h6
-rw-r--r--net/disk_cache/storage_block.h5
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();