diff options
Diffstat (limited to 'net/disk_cache')
| -rw-r--r-- | net/disk_cache/backend_impl.cc | 20 | ||||
| -rw-r--r-- | net/disk_cache/backend_impl.h | 3 | ||||
| -rw-r--r-- | net/disk_cache/backend_unittest.cc | 28 | ||||
| -rw-r--r-- | net/disk_cache/disk_cache_perftest.cc | 8 | ||||
| -rw-r--r-- | net/disk_cache/entry_impl.cc | 32 | ||||
| -rw-r--r-- | net/disk_cache/entry_unittest.cc | 191 | ||||
| -rw-r--r-- | net/disk_cache/file_posix.cc | 14 | ||||
| -rw-r--r-- | net/disk_cache/in_flight_backend_io.cc | 131 | ||||
| -rw-r--r-- | net/disk_cache/in_flight_backend_io.h | 21 | ||||
| -rw-r--r-- | net/disk_cache/in_flight_io.cc | 4 | ||||
| -rw-r--r-- | net/disk_cache/mem_entry_impl.cc | 8 | ||||
| -rw-r--r-- | net/disk_cache/sparse_control.cc | 24 | ||||
| -rw-r--r-- | net/disk_cache/stats_histogram.cc | 8 | ||||
| -rw-r--r-- | net/disk_cache/stats_histogram.h | 1 | ||||
| -rw-r--r-- | net/disk_cache/stress_cache.cc | 6 |
15 files changed, 311 insertions, 188 deletions
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc index 0709238..6162a77 100644 --- a/net/disk_cache/backend_impl.cc +++ b/net/disk_cache/backend_impl.cc @@ -13,6 +13,7 @@ #include "base/string_util.h" #include "base/stringprintf.h" #include "base/sys_info.h" +#include "base/thread_restrictions.h" #include "base/time.h" #include "base/timer.h" #include "base/worker_pool.h" @@ -115,6 +116,10 @@ FilePath GetTempCacheName(const FilePath& path, const std::string& name) { // Moves the cache files to a new folder and creates a task to delete them. bool DelayedCacheCleanup(const FilePath& full_path) { + // GetTempCacheName() and MoveCache() use synchronous file + // operations. + base::ThreadRestrictions::ScopedAllowIO allow_io; + FilePath current_path = full_path.StripTrailingSeparators(); FilePath path = current_path.DirName(); @@ -169,13 +174,13 @@ bool SetFieldTrialInfo(int size_group) { // Field trials involve static objects so we have to do this only once. first = false; - scoped_refptr<base::FieldTrial> trial1 = - new base::FieldTrial("CacheSize", 10); + scoped_refptr<base::FieldTrial> trial1( + new base::FieldTrial("CacheSize", 10)); std::string group1 = base::StringPrintf("CacheSizeGroup_%d", size_group); trial1->AppendGroup(group1, base::FieldTrial::kAllRemainingProbability); - scoped_refptr<base::FieldTrial> trial2 = - new base::FieldTrial("CacheThrottle", 100); + scoped_refptr<base::FieldTrial> trial2( + new base::FieldTrial("CacheThrottle", 100)); int group2a = trial2->AppendGroup("CacheThrottle_On", 10); // 10 % in. trial2->AppendGroup("CacheThrottle_Off", 10); // 10 % control. @@ -1310,6 +1315,13 @@ int BackendImpl::RunTaskForTest(Task* task, CompletionCallback* callback) { return net::ERR_IO_PENDING; } +void BackendImpl::ThrottleRequestsForTest(bool throttle) { + if (throttle) + background_queue_.StartQueingOperations(); + else + background_queue_.StopQueingOperations(); +} + int BackendImpl::SelfCheck() { if (!init_) { LOG(ERROR) << "Init failed"; diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h index a8880d1..05e5016 100644 --- a/net/disk_cache/backend_impl.h +++ b/net/disk_cache/backend_impl.h @@ -249,6 +249,9 @@ class BackendImpl : public Backend { // deleted after it runs. int RunTaskForTest(Task* task, CompletionCallback* callback); + // Starts or stops throttling requests. + void ThrottleRequestsForTest(bool throttle); + // Peforms a simple self-check, and returns the number of dirty items // or an error code (negative value). int SelfCheck(); diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc index adfc95c..4298456 100644 --- a/net/disk_cache/backend_unittest.cc +++ b/net/disk_cache/backend_unittest.cc @@ -230,7 +230,7 @@ TEST_F(DiskCacheBackendTest, ExternalFiles) { FilePath filename = GetCacheFilePath().AppendASCII("f_000001"); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer1->data(), kSize, false); ASSERT_EQ(kSize, file_util::WriteFile(filename, buffer1->data(), kSize)); @@ -241,7 +241,7 @@ TEST_F(DiskCacheBackendTest, ExternalFiles) { entry->Close(); // And verify that the first file is still there. - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); ASSERT_EQ(kSize, file_util::ReadFile(filename, buffer2->data(), kSize)); EXPECT_EQ(0, memcmp(buffer1->data(), buffer2->data(), kSize)); } @@ -269,7 +269,7 @@ TEST_F(DiskCacheTest, ShutdownWithPendingIO) { ASSERT_EQ(net::OK, cb.GetResult(rv)); const int kSize = 25000; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, false); for (int i = 0; i < 10 * 1024 * 1024; i += 64 * 1024) { @@ -319,7 +319,7 @@ TEST_F(DiskCacheTest, ShutdownWithPendingIO2) { ASSERT_EQ(net::OK, cb.GetResult(rv)); const int kSize = 25000; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, false); rv = entry->WriteData(0, 0, buffer, kSize, &cb, false); @@ -366,7 +366,7 @@ void DiskCacheBackendTest::BackendSetSize() { disk_cache::Entry* entry; ASSERT_EQ(net::OK, CreateEntry(first, &entry)); - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(cache_size); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(cache_size)); memset(buffer->data(), 0, cache_size); EXPECT_EQ(cache_size / 10, WriteData(entry, 0, 0, buffer, cache_size / 10, false)) << "normal file"; @@ -497,7 +497,7 @@ void DiskCacheBackendTest::BackendValidEntry() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); memset(buffer1->data(), 0, kSize); base::strlcpy(buffer1->data(), "And the data to save", kSize); EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer1, kSize, false)); @@ -506,7 +506,7 @@ void DiskCacheBackendTest::BackendValidEntry() { ASSERT_EQ(net::OK, OpenEntry(key, &entry)); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); memset(buffer2->data(), 0, kSize); EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer2, kSize)); entry->Close(); @@ -535,7 +535,7 @@ void DiskCacheBackendTest::BackendInvalidEntry() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 0, kSize); base::strlcpy(buffer->data(), "And the data to save", kSize); EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false)); @@ -579,7 +579,7 @@ void DiskCacheBackendTest::BackendInvalidEntryRead() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 0, kSize); base::strlcpy(buffer->data(), "And the data to save", kSize); EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false)); @@ -697,7 +697,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry() { disk_cache::Entry* entry; ASSERT_EQ(net::OK, CreateEntry(first, &entry)); - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 0, kSize); EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false)); @@ -748,7 +748,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry2() { SetMaxSize(kSize * 40); InitCache(); - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 0, kSize); disk_cache::Entry* entry; @@ -940,7 +940,7 @@ void DiskCacheBackendTest::BackendInvalidEntryEnumeration() { ASSERT_EQ(net::OK, CreateEntry(key, &entry1)); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); memset(buffer1->data(), 0, kSize); base::strlcpy(buffer1->data(), "And the data to save", kSize); EXPECT_EQ(kSize, WriteData(entry1, 0, 0, buffer1, kSize, false)); @@ -1574,7 +1574,7 @@ void DiskCacheBackendTest::BackendDisable4() { ASSERT_EQ(net::OK, CreateEntry(key3, &entry3)); const int kBufSize = 20000; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kBufSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kBufSize)); memset(buf->data(), 0, kBufSize); EXPECT_EQ(100, WriteData(entry2, 0, 0, buf, 100, false)); EXPECT_EQ(kBufSize, WriteData(entry3, 0, 0, buf, kBufSize, false)); @@ -1840,7 +1840,7 @@ TEST_F(DiskCacheBackendTest, TotalBuffersSize1) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 200; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, true); for (int i = 0; i < 10; i++) { diff --git a/net/disk_cache/disk_cache_perftest.cc b/net/disk_cache/disk_cache_perftest.cc index 1f1514d..c86955f 100644 --- a/net/disk_cache/disk_cache_perftest.cc +++ b/net/disk_cache/disk_cache_perftest.cc @@ -44,8 +44,8 @@ const int kMaxSize = 16 * 1024 - 1; int TimeWrite(int num_entries, disk_cache::Backend* cache, TestEntries* entries) { const int kSize1 = 200; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kMaxSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kMaxSize)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kMaxSize, false); @@ -95,8 +95,8 @@ int TimeWrite(int num_entries, disk_cache::Backend* cache, int TimeRead(int num_entries, disk_cache::Backend* cache, const TestEntries& entries, bool cold) { const int kSize1 = 200; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kMaxSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kMaxSize)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kMaxSize, false); diff --git a/net/disk_cache/entry_impl.cc b/net/disk_cache/entry_impl.cc index 7fabbe5..ce59270 100644 --- a/net/disk_cache/entry_impl.cc +++ b/net/disk_cache/entry_impl.cc @@ -148,6 +148,7 @@ bool EntryImpl::UserBuffer::PreWrite(int offset, int len) { void EntryImpl::UserBuffer::Truncate(int offset) { DCHECK_GE(offset, 0); DCHECK_GE(offset, offset_); + DVLOG(3) << "Buffer truncate at " << offset << " current " << offset_; offset -= offset_; if (Size() >= offset) @@ -159,6 +160,7 @@ void EntryImpl::UserBuffer::Write(int offset, net::IOBuffer* buf, int len) { DCHECK_GE(len, 0); DCHECK_GE(offset + len, 0); DCHECK_GE(offset, offset_); + DVLOG(3) << "Buffer write at " << offset << " current " << offset_; if (!Size() && offset > kMaxBlockSize) offset_ = offset; @@ -268,6 +270,8 @@ bool EntryImpl::UserBuffer::GrowBuffer(int required, int limit) { if (!grow_allowed_) return false; + DVLOG(3) << "Buffer grow to " << required; + buffer_.reserve(required); return true; } @@ -480,6 +484,7 @@ void EntryImpl::DoomImpl() { int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(node_.Data()->dirty || read_only_); + DVLOG(2) << "Read from " << index << " at " << offset << " : " << buf_len; if (index < 0 || index >= kNumStreams) return net::ERR_INVALID_ARGUMENT; @@ -500,8 +505,8 @@ int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf, backend_->OnEvent(Stats::READ_DATA); backend_->OnRead(buf_len); - // We need the current size in disk. - int eof = entry_size - unreported_size_[index]; + Addr address(entry_.Data()->data_addr[index]); + int eof = address.is_initialized() ? entry_size : 0; if (user_buffers_[index].get() && user_buffers_[index]->PreRead(eof, offset, &buf_len)) { // Complete the operation locally. @@ -510,7 +515,7 @@ int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf, return buf_len; } - Addr address(entry_.Data()->data_addr[index]); + address.set_value(entry_.Data()->data_addr[index]); DCHECK(address.is_initialized()); if (!address.is_initialized()) return net::ERR_FAILED; @@ -548,6 +553,7 @@ int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback, bool truncate) { DCHECK(node_.Data()->dirty || read_only_); + DVLOG(2) << "Write to " << index << " at " << offset << " : " << buf_len; if (index < 0 || index >= kNumStreams) return net::ERR_INVALID_ARGUMENT; @@ -1142,14 +1148,20 @@ bool EntryImpl::ImportSeparateFile(int index, int new_size) { bool EntryImpl::PrepareBuffer(int index, int offset, int buf_len) { DCHECK(user_buffers_[index].get()); - if (offset > user_buffers_[index]->End()) { - // We are about to extend the buffer (with zeros), so make sure that we are - // not overwriting anything. + if ((user_buffers_[index]->End() && offset > user_buffers_[index]->End()) || + offset > entry_.Data()->data_size[index]) { + // We are about to extend the buffer or the file (with zeros), so make sure + // that we are not overwriting anything. Addr address(entry_.Data()->data_addr[index]); if (address.is_initialized() && address.is_separate_file()) { - int eof = entry_.Data()->data_size[index]; - if (eof > user_buffers_[index]->Start() && !Flush(index, 0)) + if (!Flush(index, 0)) return false; + // There is an actual file already, and we don't want to keep track of + // its length so we let this operation go straight to disk. + // The only case when a buffer is allowed to extend the file (as in fill + // with zeros before the start) is when there is no file yet to extend. + user_buffers_[index].reset(); + return true; } } @@ -1158,7 +1170,8 @@ bool EntryImpl::PrepareBuffer(int index, int offset, int buf_len) { return false; // Lets try again. - if (!user_buffers_[index]->PreWrite(offset, buf_len)) { + if (offset > user_buffers_[index]->End() || + !user_buffers_[index]->PreWrite(offset, buf_len)) { // We cannot complete the operation with a buffer. DCHECK(!user_buffers_[index]->Size()); DCHECK(!user_buffers_[index]->Start()); @@ -1172,6 +1185,7 @@ bool EntryImpl::Flush(int index, int min_len) { Addr address(entry_.Data()->data_addr[index]); DCHECK(user_buffers_[index].get()); DCHECK(!address.is_initialized() || address.is_separate_file()); + DVLOG(3) << "Flush"; int size = std::max(entry_.Data()->data_size[index], min_len); if (size && !address.is_initialized() && !CreateDataBlock(index, size)) diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc index c4dc705..bea940c 100644 --- a/net/disk_cache/entry_unittest.cc +++ b/net/disk_cache/entry_unittest.cc @@ -76,7 +76,7 @@ class InternalSyncIOTask : public SyncIOTask { // This part of the test runs on the background thread. void DiskCacheEntryTest::InternalSyncIOBackground(disk_cache::Entry* entry) { const int kSize1 = 10; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); CacheTestFillBuffer(buffer1->data(), kSize1, false); EXPECT_EQ(0, entry->ReadData(0, 0, buffer1, kSize1, NULL)); base::strlcpy(buffer1->data(), "the data", kSize1); @@ -87,8 +87,8 @@ void DiskCacheEntryTest::InternalSyncIOBackground(disk_cache::Entry* entry) { const int kSize2 = 5000; const int kSize3 = 10000; - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); - scoped_refptr<net::IOBuffer> buffer3 = new net::IOBuffer(kSize3); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); + scoped_refptr<net::IOBuffer> buffer3(new net::IOBuffer(kSize3)); memset(buffer3->data(), 0, kSize3); CacheTestFillBuffer(buffer2->data(), kSize2, false); base::strlcpy(buffer2->data(), "The really big data goes here", kSize2); @@ -179,9 +179,9 @@ void DiskCacheEntryTest::InternalAsyncIO() { const int kSize1 = 10; const int kSize2 = 5000; const int kSize3 = 10000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); - scoped_refptr<net::IOBuffer> buffer3 = new net::IOBuffer(kSize3); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); + scoped_refptr<net::IOBuffer> buffer3(new net::IOBuffer(kSize3)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kSize2, false); CacheTestFillBuffer(buffer3->data(), kSize3, false); @@ -298,8 +298,8 @@ class ExternalSyncIOTask : public SyncIOTask { void DiskCacheEntryTest::ExternalSyncIOBackground(disk_cache::Entry* entry) { const int kSize1 = 17000; const int kSize2 = 25000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kSize2, false); base::strlcpy(buffer1->data(), "the data", kSize1); @@ -383,9 +383,9 @@ void DiskCacheEntryTest::ExternalAsyncIO() { const int kSize1 = 17000; const int kSize2 = 25000; const int kSize3 = 25000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); - scoped_refptr<net::IOBuffer> buffer3 = new net::IOBuffer(kSize3); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); + scoped_refptr<net::IOBuffer> buffer3(new net::IOBuffer(kSize3)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kSize2, false); CacheTestFillBuffer(buffer3->data(), kSize3, false); @@ -475,14 +475,83 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyExternalAsyncIO) { ExternalAsyncIO(); } +TEST_F(DiskCacheEntryTest, RequestThrottling) { + SetDirectMode(); + InitCache(); + disk_cache::Entry* entry = NULL; + ASSERT_EQ(net::OK, CreateEntry("the first key", &entry)); + ASSERT_TRUE(NULL != entry); + + // Let's verify that each IO goes to the right callback object. + CallbackTest cb(true); + + g_cache_tests_error = false; + g_cache_tests_received = 0; + + MessageLoopHelper helper; + + const int kSize = 200; + scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + CacheTestFillBuffer(buffer->data(), kSize, false); + + int expected = 0; + // Start with no throttling. + for (; expected < 10; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + // And now with full throttling. + cache_impl_->ThrottleRequestsForTest(true); + for (; expected < 20; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + for (; expected < 30; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + // We have 9 queued requests, lets dispatch them all at once. + cache_impl_->ThrottleRequestsForTest(false); + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + cache_impl_->ThrottleRequestsForTest(true); + for (; expected < 40; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + + // We can close the entry and keep receiving notifications. + entry->Close(); + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + ASSERT_EQ(net::OK, OpenEntry("the first key", &entry)); + for (; expected < 50; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + + // ... and even close the cache. + entry->Close(); + delete cache_impl_; + cache_ = cache_impl_ = NULL; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + EXPECT_FALSE(g_cache_tests_error); + EXPECT_EQ(expected, g_cache_tests_received); +} + void DiskCacheEntryTest::StreamAccess() { disk_cache::Entry* entry = NULL; ASSERT_EQ(net::OK, CreateEntry("the first key", &entry)); ASSERT_TRUE(NULL != entry); const int kBufferSize = 1024; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kBufferSize); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kBufferSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kBufferSize)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kBufferSize)); const int kNumStreams = 3; for (int i = 0; i < kNumStreams; i++) { @@ -579,7 +648,7 @@ void DiskCacheEntryTest::GetTimes() { Time t3 = Time::Now(); EXPECT_TRUE(t3 > t2); const int kSize = 200; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer, kSize)); if (type_ == net::APP_CACHE) { EXPECT_TRUE(entry->GetLastUsed() < t2); @@ -614,8 +683,8 @@ void DiskCacheEntryTest::GrowData() { ASSERT_EQ(net::OK, CreateEntry(key1, &entry)); const int kSize = 20000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer1->data(), kSize, false); memset(buffer2->data(), 0, kSize); @@ -699,8 +768,8 @@ void DiskCacheEntryTest::TruncateData() { const int kSize1 = 20000; const int kSize2 = 20000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); CacheTestFillBuffer(buffer1->data(), kSize1, false); memset(buffer2->data(), 0, kSize2); @@ -755,11 +824,6 @@ void DiskCacheEntryTest::TruncateData() { TEST_F(DiskCacheEntryTest, TruncateData) { InitCache(); TruncateData(); - - // We generate asynchronous IO that is not really tracked until completion - // so we just wait here before running the next test. - MessageLoopHelper helper; - helper.WaitUntilCacheIoFinished(1); } TEST_F(DiskCacheEntryTest, TruncateDataNoBuffer) { @@ -767,11 +831,6 @@ TEST_F(DiskCacheEntryTest, TruncateDataNoBuffer) { InitCache(); cache_impl_->SetFlags(disk_cache::kNoBuffering); TruncateData(); - - // We generate asynchronous IO that is not really tracked until completion - // so we just wait here before running the next test. - MessageLoopHelper helper; - helper.WaitUntilCacheIoFinished(1); } TEST_F(DiskCacheEntryTest, MemoryOnlyTruncateData) { @@ -801,7 +860,7 @@ void DiskCacheEntryTest::ZeroLengthIO() { // Lets verify the actual content. const int kSize = 20; const char zeros[kSize] = {}; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, false); EXPECT_EQ(kSize, ReadData(entry, 0, 500, buffer, kSize)); @@ -843,8 +902,8 @@ void DiskCacheEntryTest::Buffering() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 200; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer1->data(), kSize, true); CacheTestFillBuffer(buffer2->data(), kSize, true); @@ -900,6 +959,16 @@ void DiskCacheEntryTest::Buffering() { EXPECT_EQ(100, ReadData(entry, 1, 23100, buffer2, kSize)); EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + 100, 100)); + // Extend the file again and read before without closing the entry. + EXPECT_EQ(kSize, WriteData(entry, 1, 25000, buffer1, kSize, false)); + EXPECT_EQ(kSize, WriteData(entry, 1, 45000, buffer1, kSize, false)); + CacheTestFillBuffer(buffer2->data(), kSize, true); + EXPECT_EQ(kSize, ReadData(entry, 1, 25000, buffer2, kSize)); + EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize)); + CacheTestFillBuffer(buffer2->data(), kSize, true); + EXPECT_EQ(kSize, ReadData(entry, 1, 45000, buffer2, kSize)); + EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize)); + entry->Close(); } @@ -924,8 +993,8 @@ void DiskCacheEntryTest::SizeChanges() { const int kSize = 200; const char zeros[kSize] = {}; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer1->data(), kSize, true); CacheTestFillBuffer(buffer2->data(), kSize, true); @@ -943,7 +1012,7 @@ void DiskCacheEntryTest::SizeChanges() { EXPECT_TRUE(!memcmp(buffer2->data(), zeros, kSize)); // Read at the end of the old file size. - EXPECT_EQ(35, ReadData(entry, 1, 23000 + kSize - 35, buffer2, kSize)); + EXPECT_EQ(kSize, ReadData(entry, 1, 23000 + kSize - 35, buffer2, kSize)); EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + kSize - 35, 35)); // Read slightly before the last write. @@ -1013,7 +1082,7 @@ void DiskCacheEntryTest::ReuseEntry(int size) { std::string key2("the second key"); ASSERT_EQ(net::OK, CreateEntry(key2, &entry)); - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(size); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(size)); CacheTestFillBuffer(buffer->data(), size, false); for (int i = 0; i < 15; i++) { @@ -1067,9 +1136,9 @@ void DiskCacheEntryTest::InvalidData() { const int kSize1 = 20000; const int kSize2 = 20000; const int kSize3 = 20000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); - scoped_refptr<net::IOBuffer> buffer3 = new net::IOBuffer(kSize3); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); + scoped_refptr<net::IOBuffer> buffer3(new net::IOBuffer(kSize3)); CacheTestFillBuffer(buffer1->data(), kSize1, false); memset(buffer2->data(), 0, kSize2); @@ -1149,7 +1218,7 @@ TEST_F(DiskCacheEntryTest, ReadWriteDestroyBuffer) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 200; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, false); TestCompletionCallback cb; @@ -1179,7 +1248,7 @@ void DiskCacheEntryTest::DoomNormalEntry() { entry->Close(); const int kSize = 20000; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, true); buffer->data()[19999] = '\0'; @@ -1220,8 +1289,8 @@ void DiskCacheEntryTest::DoomedEntry() { const int kSize1 = 2000; const int kSize2 = 2000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); CacheTestFillBuffer(buffer1->data(), kSize1, false); memset(buffer2->data(), 0, kSize2); @@ -1254,7 +1323,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyEnumerationWithSparseEntries) { InitCache(); const int kSize = 4096; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); std::string key("the first key"); @@ -1308,7 +1377,7 @@ void VerifyContentSparseIO(disk_cache::Entry* entry, int64 offset, char* buffer, int size) { TestCompletionCallback cb; - scoped_refptr<net::IOBuffer> buf_1 = new net::IOBuffer(size); + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(size)); memset(buf_1->data(), 0, size); int ret = entry->ReadSparseData(offset, buf_1, size, &cb); EXPECT_EQ(size, cb.GetResult(ret)); @@ -1322,8 +1391,8 @@ void DiskCacheEntryTest::BasicSparseIO() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 2048; - scoped_refptr<net::IOBuffer> buf_1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buf_2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf_1->data(), kSize, false); // Write at offset 0. @@ -1363,8 +1432,8 @@ void DiskCacheEntryTest::HugeSparseIO() { // Write 1.2 MB so that we cover multiple entries. const int kSize = 1200 * 1024; - scoped_refptr<net::IOBuffer> buf_1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buf_2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf_1->data(), kSize, false); // Write at offset 0x20F0000 (33 MB - 64 KB). @@ -1394,7 +1463,7 @@ void DiskCacheEntryTest::GetAvailableRange() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 16 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); // Write at offset 0x20F0000 (33 MB - 64 KB), and 0x20F4400 (33 MB - 47 KB). @@ -1456,7 +1525,7 @@ void DiskCacheEntryTest::CouldBeSparse() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 16 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); // Write at offset 0x20F0000 (33 MB - 64 KB). @@ -1502,8 +1571,8 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedSparseIO) { InitCache(); const int kSize = 8192; - scoped_refptr<net::IOBuffer> buf_1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buf_2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf_1->data(), kSize, false); std::string key("the first key"); @@ -1512,8 +1581,8 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedSparseIO) { // This loop writes back to back starting from offset 0 and 9000. for (int i = 0; i < kSize; i += 1024) { - scoped_refptr<net::WrappedIOBuffer> buf_3 = - new net::WrappedIOBuffer(buf_1->data() + i); + scoped_refptr<net::WrappedIOBuffer> buf_3( + new net::WrappedIOBuffer(buf_1->data() + i)); VerifySparseIO(entry, i, buf_3, 1024, buf_2); VerifySparseIO(entry, 9000 + i, buf_3, 1024, buf_2); } @@ -1533,7 +1602,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedGetAvailableRange) { InitCache(); const int kSize = 8192; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); disk_cache::Entry* entry; @@ -1594,7 +1663,7 @@ void DiskCacheEntryTest::DoomSparseEntry() { ASSERT_EQ(net::OK, CreateEntry(key2, &entry2)); const int kSize = 4 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); int64 offset = 1024; @@ -1681,7 +1750,7 @@ TEST_F(DiskCacheEntryTest, DoomSparseEntry2) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 4 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); int64 offset = 1024; @@ -1711,7 +1780,7 @@ void DiskCacheEntryTest::PartialSparseEntry() { // of a sparse entry, at least to write a big range without leaving holes. const int kSize = 4 * 1024; const int kSmallSize = 128; - scoped_refptr<net::IOBuffer> buf1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf1(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf1->data(), kSize, false); // The first write is just to extend the entry. The third write occupies @@ -1723,7 +1792,7 @@ void DiskCacheEntryTest::PartialSparseEntry() { entry->Close(); ASSERT_EQ(net::OK, OpenEntry(key, &entry)); - scoped_refptr<net::IOBuffer> buf2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf2(new net::IOBuffer(kSize)); memset(buf2->data(), 0, kSize); EXPECT_EQ(0, ReadSparseData(entry, 8000, buf2, kSize)); @@ -1805,7 +1874,7 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 4 * 1024; - scoped_refptr<net::IOBuffer> buf1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf1(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf1->data(), kSize, false); const int k1Meg = 1024 * 1024; @@ -1856,7 +1925,7 @@ TEST_F(DiskCacheEntryTest, CancelSparseIO) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 40 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); // This will open and write two "real" entries. diff --git a/net/disk_cache/file_posix.cc b/net/disk_cache/file_posix.cc index 9d810c7..a8d74ae 100644 --- a/net/disk_cache/file_posix.cc +++ b/net/disk_cache/file_posix.cc @@ -182,9 +182,9 @@ void BackgroundIO::OnIOSignalled() { void InFlightIO::PostRead(disk_cache::File *file, void* buf, size_t buf_len, size_t offset, disk_cache::FileIOCallback *callback) { - scoped_refptr<BackgroundIO> operation = - new BackgroundIO(file, buf, buf_len, offset, callback, this); - io_list_.insert(operation.get()); + scoped_refptr<BackgroundIO> operation( + new BackgroundIO(file, buf, buf_len, offset, callback, this)); + io_list_.insert(operation); file->AddRef(); // Balanced on InvokeCallback() if (!callback_thread_) @@ -198,9 +198,9 @@ void InFlightIO::PostRead(disk_cache::File *file, void* buf, size_t buf_len, void InFlightIO::PostWrite(disk_cache::File* file, const void* buf, size_t buf_len, size_t offset, disk_cache::FileIOCallback* callback) { - scoped_refptr<BackgroundIO> operation = - new BackgroundIO(file, buf, buf_len, offset, callback, this); - io_list_.insert(operation.get()); + scoped_refptr<BackgroundIO> operation( + new BackgroundIO(file, buf, buf_len, offset, callback, this)); + io_list_.insert(operation); file->AddRef(); // Balanced on InvokeCallback() if (!callback_thread_) @@ -241,7 +241,7 @@ void InFlightIO::InvokeCallback(BackgroundIO* operation, bool cancel_task) { // Release the references acquired in PostRead / PostWrite. operation->file()->Release(); - io_list_.erase(operation); + io_list_.erase(make_scoped_refptr(operation)); callback->OnFileIOComplete(bytes); } diff --git a/net/disk_cache/in_flight_backend_io.cc b/net/disk_cache/in_flight_backend_io.cc index fe53829..d83bd10 100644 --- a/net/disk_cache/in_flight_backend_io.cc +++ b/net/disk_cache/in_flight_backend_io.cc @@ -42,8 +42,9 @@ bool BackendIO::IsEntryOperation() { return operation_ > OP_MAX_BACKEND; } -void BackendIO::ReleaseEntry() { - entry_ = NULL; +// Runs on the background thread. +void BackendIO::ReferenceEntry() { + entry_->AddRef(); } base::TimeDelta BackendIO::ElapsedTime() const { @@ -274,6 +275,8 @@ void BackendIO::ExecuteEntryOperation() { NOTREACHED() << "Invalid Operation"; result_ = net::ERR_UNEXPECTED; } + // We added a reference to protect the queued operation. + entry_->Release(); if (result_ != net::ERR_IO_PENDING) controller_->OnIOComplete(this); } @@ -291,34 +294,34 @@ InFlightBackendIO::~InFlightBackendIO() { } void InFlightBackendIO::Init(CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->Init(); QueueOperation(operation); } void InFlightBackendIO::OpenEntry(const std::string& key, Entry** entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->OpenEntry(key, entry); QueueOperation(operation); } void InFlightBackendIO::CreateEntry(const std::string& key, Entry** entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->CreateEntry(key, entry); QueueOperation(operation); } void InFlightBackendIO::DoomEntry(const std::string& key, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->DoomEntry(key); QueueOperation(operation); } void InFlightBackendIO::DoomAllEntries(CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->DoomAllEntries(); QueueOperation(operation); } @@ -326,58 +329,58 @@ void InFlightBackendIO::DoomAllEntries(CompletionCallback* callback) { void InFlightBackendIO::DoomEntriesBetween(const base::Time initial_time, const base::Time end_time, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->DoomEntriesBetween(initial_time, end_time); QueueOperation(operation); } void InFlightBackendIO::DoomEntriesSince(const base::Time initial_time, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->DoomEntriesSince(initial_time); QueueOperation(operation); } void InFlightBackendIO::OpenNextEntry(void** iter, Entry** next_entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->OpenNextEntry(iter, next_entry); QueueOperation(operation); } void InFlightBackendIO::OpenPrevEntry(void** iter, Entry** prev_entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->OpenPrevEntry(iter, prev_entry); QueueOperation(operation); } void InFlightBackendIO::EndEnumeration(void* iterator) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, NULL); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, NULL)); operation->EndEnumeration(iterator); QueueOperation(operation); } void InFlightBackendIO::CloseEntryImpl(EntryImpl* entry) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, NULL); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, NULL)); operation->CloseEntryImpl(entry); QueueOperation(operation); } void InFlightBackendIO::DoomEntryImpl(EntryImpl* entry) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, NULL); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, NULL)); operation->DoomEntryImpl(entry); QueueOperation(operation); } void InFlightBackendIO::FlushQueue(net::CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->FlushQueue(); QueueOperation(operation); } void InFlightBackendIO::RunTask(Task* task, net::CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->RunTask(task); QueueOperation(operation); } @@ -385,7 +388,7 @@ void InFlightBackendIO::RunTask(Task* task, net::CompletionCallback* callback) { void InFlightBackendIO::ReadData(EntryImpl* entry, int index, int offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->ReadData(entry, index, offset, buf, buf_len); QueueOperation(operation); } @@ -394,7 +397,7 @@ void InFlightBackendIO::WriteData(EntryImpl* entry, int index, int offset, net::IOBuffer* buf, int buf_len, bool truncate, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->WriteData(entry, index, offset, buf, buf_len, truncate); QueueOperation(operation); } @@ -402,7 +405,7 @@ void InFlightBackendIO::WriteData(EntryImpl* entry, int index, int offset, void InFlightBackendIO::ReadSparseData(EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->ReadSparseData(entry, offset, buf, buf_len); QueueOperation(operation); } @@ -410,7 +413,7 @@ void InFlightBackendIO::ReadSparseData(EntryImpl* entry, int64 offset, void InFlightBackendIO::WriteSparseData(EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->WriteSparseData(entry, offset, buf, buf_len); QueueOperation(operation); } @@ -418,28 +421,25 @@ void InFlightBackendIO::WriteSparseData(EntryImpl* entry, int64 offset, void InFlightBackendIO::GetAvailableRange(EntryImpl* entry, int64 offset, int len, int64* start, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->GetAvailableRange(entry, offset, len, start); QueueOperation(operation); } void InFlightBackendIO::CancelSparseIO(EntryImpl* entry) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, NULL); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, NULL)); operation->CancelSparseIO(entry); QueueOperation(operation); } void InFlightBackendIO::ReadyForSparseIO(EntryImpl* entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->ReadyForSparseIO(entry); QueueOperation(operation); } void InFlightBackendIO::WaitForPendingIO() { - // We clear the list first so that we don't post more operations after this - // point. - pending_ops_.clear(); InFlightIO::WaitForPendingIO(); } @@ -455,45 +455,51 @@ void InFlightBackendIO::OnOperationComplete(BackgroundIO* operation, bool cancel) { BackendIO* op = static_cast<BackendIO*>(operation); - if (!op->IsEntryOperation() && !pending_ops_.empty()) { - // Process the next request. Note that invoking the callback may result - // in the backend destruction (and with it this object), so we should deal - // with the next operation before invoking the callback. - PostQueuedOperation(&pending_ops_); - } - if (op->IsEntryOperation()) { backend_->OnOperationCompleted(op->ElapsedTime()); - if (!pending_entry_ops_.empty()) { - PostQueuedOperation(&pending_entry_ops_); - - // If we are not throttling requests anymore, dispatch the whole queue. - if (!queue_entry_ops_) { + if (!pending_ops_.empty() && RemoveFirstQueuedOperation(op)) { + // Process the next request. Note that invoking the callback may result + // in the backend destruction (and with it this object), so we should deal + // with the next operation before invoking the callback. + if (queue_entry_ops_) { + PostQueuedOperation(); + } else { + // If we are not throttling requests anymore, dispatch the whole queue. CACHE_UMA(COUNTS_10000, "FinalQueuedOperations", 0, - pending_entry_ops_.size()); - while (!pending_entry_ops_.empty()) - PostQueuedOperation(&pending_entry_ops_); + pending_ops_.size()); + PostAllQueuedOperations(); } } } if (op->callback() && (!cancel || op->IsEntryOperation())) op->callback()->Run(op->result()); - - if (cancel) - op->ReleaseEntry(); } void InFlightBackendIO::QueueOperation(BackendIO* operation) { if (!operation->IsEntryOperation()) - return QueueOperationToList(operation, &pending_ops_); + return PostOperation(operation); - if (!queue_entry_ops_) + // We have to protect the entry from deletion while it is on the queue. + // If the caller closes the entry right after writing to it, and the write is + // waiting on the queue, we could end up deleting the entry before the write + // operation is actually posted. Sending a task to reference the entry we make + // sure that there is an extra reference before the caller can post a task to + // release its reference. + background_thread_->PostTask(FROM_HERE, + NewRunnableMethod(operation, &BackendIO::ReferenceEntry)); + + bool empty_list = pending_ops_.empty(); + if (!queue_entry_ops_ && empty_list) return PostOperation(operation); - CACHE_UMA(COUNTS_10000, "QueuedOperations", 0, pending_entry_ops_.size()); + CACHE_UMA(COUNTS_10000, "QueuedOperations", 0, pending_ops_.size()); - QueueOperationToList(operation, &pending_entry_ops_); + // We keep the operation that we are executing in the list so that we know + // when it completes. + pending_ops_.push_back(operation); + if (empty_list) + PostOperation(operation); } void InFlightBackendIO::PostOperation(BackendIO* operation) { @@ -502,18 +508,31 @@ void InFlightBackendIO::PostOperation(BackendIO* operation) { OnOperationPosted(operation); } -void InFlightBackendIO::PostQueuedOperation(OperationList* from_list) { - scoped_refptr<BackendIO> next_op = from_list->front(); - from_list->pop_front(); +void InFlightBackendIO::PostQueuedOperation() { + if (pending_ops_.empty()) + return; + + // Keep it in the list until it's done. + scoped_refptr<BackendIO> next_op = pending_ops_.front(); PostOperation(next_op); } -void InFlightBackendIO::QueueOperationToList(BackendIO* operation, - OperationList* list) { - if (list->empty()) - return PostOperation(operation); +void InFlightBackendIO::PostAllQueuedOperations() { + for (OperationList::iterator it = pending_ops_.begin(); + it != pending_ops_.end(); ++it) { + PostOperation(*it); + } + pending_ops_.clear(); +} + +bool InFlightBackendIO::RemoveFirstQueuedOperation(BackendIO* operation) { + DCHECK(!pending_ops_.empty()); + scoped_refptr<BackendIO> next_op = pending_ops_.front(); + if (operation != next_op) + return false; - list->push_back(operation); + pending_ops_.pop_front(); + return true; } } // namespace diff --git a/net/disk_cache/in_flight_backend_io.h b/net/disk_cache/in_flight_backend_io.h index 5eba131..ca239dd 100644 --- a/net/disk_cache/in_flight_backend_io.h +++ b/net/disk_cache/in_flight_backend_io.h @@ -37,7 +37,8 @@ class BackendIO : public BackgroundIO { net::CompletionCallback* callback() { return callback_; } - void ReleaseEntry(); + // Grabs an extra reference of entry_. + void ReferenceEntry(); // Returns the time that has passed since the operation was created. base::TimeDelta ElapsedTime() const; @@ -72,12 +73,10 @@ class BackendIO : public BackgroundIO { private: // There are two types of operations to proxy: regular backend operations are - // queued so that we don't have more than one operation going on at the same - // time (for instance opening an entry and creating the same entry). On the - // other hand, operations targeted to a given entry can be long lived and - // support multiple simultaneous users (multiple reads or writes to the same - // entry), so they are not queued, just posted to the worker thread as they - // come. + // executed sequentially (queued by the message loop). On the other hand, + // operations targeted to a given entry can be long lived and support multiple + // simultaneous users (multiple reads or writes to the same entry), and they + // are subject to throttling, so we keep an explicit queue. enum Operation { OP_NONE = 0, OP_INIT, @@ -200,13 +199,13 @@ class InFlightBackendIO : public InFlightIO { typedef std::list<scoped_refptr<BackendIO> > OperationList; void QueueOperation(BackendIO* operation); void PostOperation(BackendIO* operation); - void PostQueuedOperation(OperationList* from_list); - void QueueOperationToList(BackendIO* operation, OperationList* list); + void PostQueuedOperation(); + void PostAllQueuedOperations(); + bool RemoveFirstQueuedOperation(BackendIO* operation); BackendImpl* backend_; scoped_refptr<base::MessageLoopProxy> background_thread_; - OperationList pending_ops_; // The list of operations to be posted. - OperationList pending_entry_ops_; // Entry (async) operations to be posted. + OperationList pending_ops_; // Entry (async) operations to be posted. bool queue_entry_ops_; // True if we are queuing entry (async) operations. DISALLOW_COPY_AND_ASSIGN(InFlightBackendIO); diff --git a/net/disk_cache/in_flight_io.cc b/net/disk_cache/in_flight_io.cc index 5c859af..ba24d61 100644 --- a/net/disk_cache/in_flight_io.cc +++ b/net/disk_cache/in_flight_io.cc @@ -74,14 +74,14 @@ void InFlightIO::InvokeCallback(BackgroundIO* operation, bool cancel_task) { // Make sure that we remove the operation from the list before invoking the // callback (so that a subsequent cancel does not invoke the callback again). DCHECK(io_list_.find(operation) != io_list_.end()); - io_list_.erase(operation); + io_list_.erase(make_scoped_refptr(operation)); OnOperationComplete(operation, cancel_task); } // Runs on the primary thread. void InFlightIO::OnOperationPosted(BackgroundIO* operation) { DCHECK(callback_thread_->BelongsToCurrentThread()); - io_list_.insert(operation); + io_list_.insert(make_scoped_refptr(operation)); } } // namespace disk_cache diff --git a/net/disk_cache/mem_entry_impl.cc b/net/disk_cache/mem_entry_impl.cc index 8d8bb4c..a9e599c 100644 --- a/net/disk_cache/mem_entry_impl.cc +++ b/net/disk_cache/mem_entry_impl.cc @@ -172,8 +172,8 @@ int MemEntryImpl::ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len, return net::ERR_INVALID_ARGUMENT; // We will keep using this buffer and adjust the offset in this buffer. - scoped_refptr<net::DrainableIOBuffer> io_buf = - new net::DrainableIOBuffer(buf, buf_len); + scoped_refptr<net::DrainableIOBuffer> io_buf( + new net::DrainableIOBuffer(buf, buf_len)); // Iterate until we have read enough. while (io_buf->BytesRemaining()) { @@ -218,8 +218,8 @@ int MemEntryImpl::WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len, if (offset < 0 || buf_len < 0) return net::ERR_INVALID_ARGUMENT; - scoped_refptr<net::DrainableIOBuffer> io_buf = - new net::DrainableIOBuffer(buf, buf_len); + scoped_refptr<net::DrainableIOBuffer> io_buf( + new net::DrainableIOBuffer(buf, buf_len)); // This loop walks through child entries continuously starting from |offset| // and writes blocks of data (of maximum size kMaxSparseEntrySize) into each diff --git a/net/disk_cache/sparse_control.cc b/net/disk_cache/sparse_control.cc index e94a1bc..32f44ab 100644 --- a/net/disk_cache/sparse_control.cc +++ b/net/disk_cache/sparse_control.cc @@ -319,8 +319,8 @@ int SparseControl::CreateSparseEntry() { children_map_.Resize(kNumSparseBits, true); // Save the header. The bitmap is saved in the destructor. - scoped_refptr<net::IOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_)); + scoped_refptr<net::IOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_))); int rv = entry_->WriteData(kSparseIndex, 0, buf, sizeof(sparse_header_), NULL, false); @@ -349,8 +349,8 @@ int SparseControl::OpenSparseEntry(int data_len) { if (map_len > kMaxMapSize || map_len % 4) return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; - scoped_refptr<net::IOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_)); + scoped_refptr<net::IOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_))); // Read header. int rv = entry_->ReadData(kSparseIndex, 0, buf, sizeof(sparse_header_), NULL); @@ -402,8 +402,8 @@ bool SparseControl::OpenChild() { static_cast<int>(sizeof(child_data_))) return KillChildAndContinue(key, false); - scoped_refptr<net::WrappedIOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_)); + scoped_refptr<net::WrappedIOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_))); // Read signature. int rv = child_->ReadData(kSparseIndex, 0, buf, sizeof(child_data_), NULL); @@ -425,8 +425,8 @@ bool SparseControl::OpenChild() { } void SparseControl::CloseChild() { - scoped_refptr<net::WrappedIOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_)); + scoped_refptr<net::WrappedIOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_))); // Save the allocation bitmap before closing the child entry. int rv = child_->WriteData(kSparseIndex, 0, buf, sizeof(child_data_), @@ -492,8 +492,8 @@ void SparseControl::SetChildBit(bool value) { } void SparseControl::WriteSparseData() { - scoped_refptr<net::IOBuffer> buf = new net::WrappedIOBuffer( - reinterpret_cast<const char*>(children_map_.GetMap())); + scoped_refptr<net::IOBuffer> buf(new net::WrappedIOBuffer( + reinterpret_cast<const char*>(children_map_.GetMap()))); int len = children_map_.ArraySize() * 4; int rv = entry_->WriteData(kSparseIndex, sizeof(sparse_header_), buf, len, @@ -597,8 +597,8 @@ void SparseControl::InitChildData() { memset(&child_data_, 0, sizeof(child_data_)); child_data_.header = sparse_header_; - scoped_refptr<net::WrappedIOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_)); + scoped_refptr<net::WrappedIOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_))); int rv = child_->WriteData(kSparseIndex, 0, buf, sizeof(child_data_), NULL, false); diff --git a/net/disk_cache/stats_histogram.cc b/net/disk_cache/stats_histogram.cc index 06ed1b3..366a7e1 100644 --- a/net/disk_cache/stats_histogram.cc +++ b/net/disk_cache/stats_histogram.cc @@ -42,7 +42,7 @@ scoped_refptr<StatsHistogram> StatsHistogram::StatsHistogramFactoryGet( Histogram* temp_histogram = histogram.get(); StatsHistogram* temp_stats_histogram = static_cast<StatsHistogram*>(temp_histogram); - scoped_refptr<StatsHistogram> return_histogram = temp_stats_histogram; + scoped_refptr<StatsHistogram> return_histogram(temp_stats_histogram); return return_histogram; } @@ -86,4 +86,10 @@ void StatsHistogram::SnapshotSample(SampleSet* sample) const { mutable_me->ClearFlags(kUmaTargetedHistogramFlag); } +Histogram::Inconsistencies StatsHistogram::FindCorruption( + const SampleSet& snapshot) const { + return NO_INCONSISTENCIES; // This class won't monitor inconsistencies. +} + + } // namespace disk_cache diff --git a/net/disk_cache/stats_histogram.h b/net/disk_cache/stats_histogram.h index cbd8f03..499784c 100644 --- a/net/disk_cache/stats_histogram.h +++ b/net/disk_cache/stats_histogram.h @@ -44,6 +44,7 @@ class StatsHistogram : public base::Histogram { virtual Sample ranges(size_t i) const; virtual size_t bucket_count() const; virtual void SnapshotSample(SampleSet* sample) const; + virtual Inconsistencies FindCorruption(const SampleSet& snapshot) const; private: bool init_; diff --git a/net/disk_cache/stress_cache.cc b/net/disk_cache/stress_cache.cc index 98dcbe1..ae2f981 100644 --- a/net/disk_cache/stress_cache.cc +++ b/net/disk_cache/stress_cache.cc @@ -27,7 +27,7 @@ #include "base/at_exit.h" #include "base/command_line.h" -#include "base/debug_util.h" +#include "base/debug/debugger.h" #include "base/file_path.h" #include "base/logging.h" #include "base/message_loop.h" @@ -130,7 +130,7 @@ void StressTheCache(int iteration) { } const int kSize = 4000; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 'k', kSize); for (int i = 0;; i++) { @@ -213,7 +213,7 @@ bool StartCrashThread() { void CrashHandler(const std::string& str) { g_crashing = true; - DebugUtil::BreakDebugger(); + base::debug::BreakDebugger(); } // ----------------------------------------------------------------------- |
