summaryrefslogtreecommitdiffstats
path: root/net/disk_cache
diff options
context:
space:
mode:
Diffstat (limited to 'net/disk_cache')
-rw-r--r--net/disk_cache/backend_impl.cc20
-rw-r--r--net/disk_cache/backend_impl.h3
-rw-r--r--net/disk_cache/backend_unittest.cc28
-rw-r--r--net/disk_cache/disk_cache_perftest.cc8
-rw-r--r--net/disk_cache/entry_impl.cc32
-rw-r--r--net/disk_cache/entry_unittest.cc191
-rw-r--r--net/disk_cache/file_posix.cc14
-rw-r--r--net/disk_cache/in_flight_backend_io.cc131
-rw-r--r--net/disk_cache/in_flight_backend_io.h21
-rw-r--r--net/disk_cache/in_flight_io.cc4
-rw-r--r--net/disk_cache/mem_entry_impl.cc8
-rw-r--r--net/disk_cache/sparse_control.cc24
-rw-r--r--net/disk_cache/stats_histogram.cc8
-rw-r--r--net/disk_cache/stats_histogram.h1
-rw-r--r--net/disk_cache/stress_cache.cc6
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();
}
// -----------------------------------------------------------------------