summaryrefslogtreecommitdiffstats
path: root/net/disk_cache
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-23 18:47:25 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-23 18:47:25 +0000
commite1fcf1482fd306b7e404ed037106801840deda76 (patch)
treed5d26cf73f30a254aecca16dfba4f6f5e9bdba4c /net/disk_cache
parent8e3e066579460f88a19e2e6e091c396f3bd851c3 (diff)
downloadchromium_src-e1fcf1482fd306b7e404ed037106801840deda76.zip
chromium_src-e1fcf1482fd306b7e404ed037106801840deda76.tar.gz
chromium_src-e1fcf1482fd306b7e404ed037106801840deda76.tar.bz2
Disk cache: Extend the internal buffering performed by each entry
to cover external files. We now keep a variable-size buffer and use it even after we know that the data is not going to be stored by a block-file. The backend keeps track of the total memory used by all entries and prevents that value from going over a max value that depends on the total memory available. This CL removes the tests that were checking the synchronous operation of sparse IO because that model is no longer supported by the public API, and this CL would add complexity to them (they fail due to thread safety concerns). BUG=6626 TEST=net_unittests Review URL: http://codereview.chromium.org/3167020 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57082 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/disk_cache')
-rw-r--r--net/disk_cache/backend_impl.cc35
-rw-r--r--net/disk_cache/backend_impl.h15
-rw-r--r--net/disk_cache/backend_unittest.cc163
-rw-r--r--net/disk_cache/disk_cache_test_base.cc33
-rw-r--r--net/disk_cache/disk_cache_test_base.h14
-rw-r--r--net/disk_cache/entry_impl.cc516
-rw-r--r--net/disk_cache/entry_impl.h24
-rw-r--r--net/disk_cache/entry_unittest.cc751
-rw-r--r--net/disk_cache/file.h6
-rw-r--r--net/disk_cache/file_posix.cc33
-rw-r--r--net/disk_cache/file_win.cc32
11 files changed, 1079 insertions, 543 deletions
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc
index a5110c3..2be8d19 100644
--- a/net/disk_cache/backend_impl.cc
+++ b/net/disk_cache/backend_impl.cc
@@ -465,6 +465,7 @@ int BackendImpl::SyncInit() {
entry_count_ = byte_count_ = 0;
if (!restarted_) {
+ buffer_bytes_ = 0;
trace_object_ = TraceObject::GetTraceObject();
// Create a recurrent timer of 30 secs.
int timer_delay = unit_test_ ? 1000 : 30000;
@@ -968,6 +969,22 @@ void BackendImpl::TooMuchStorageRequested(int32 size) {
stats_.ModifyStorageStats(0, size);
}
+bool BackendImpl::IsAllocAllowed(int current_size, int new_size) {
+ DCHECK_GT(new_size, current_size);
+ int to_add = new_size - current_size;
+ if (buffer_bytes_ + to_add > MaxBuffersSize())
+ return false;
+
+ buffer_bytes_ += to_add;
+ HISTOGRAM_COUNTS("DiskCache.BufferBytes", buffer_bytes_ / 10);
+ return true;
+}
+
+void BackendImpl::BufferDeleted(int size) {
+ buffer_bytes_ -= size;
+ DCHECK_GE(size, 0);
+}
+
bool BackendImpl::IsLoaded() const {
CACHE_UMA(COUNTS, "PendingIO", GetSizeGroup(), num_pending_io_);
if (user_flags_ & kNoLoadProtection)
@@ -1865,4 +1882,22 @@ bool BackendImpl::CheckEntry(EntryImpl* cache_entry) {
return !rankings->dummy;
}
+int BackendImpl::MaxBuffersSize() {
+ static int64 total_memory = base::SysInfo::AmountOfPhysicalMemory();
+ static bool done = false;
+
+ if (!done) {
+ const int kMaxBuffersSize = 30 * 1024 * 1024;
+
+ // We want to use up to 2% of the computer's memory.
+ total_memory = total_memory * 2 / 100;
+ if (total_memory > kMaxBuffersSize || total_memory <= 0)
+ total_memory = kMaxBuffersSize;
+
+ done = true;
+ }
+
+ return static_cast<int>(total_memory);
+}
+
} // namespace disk_cache
diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h
index f64f3c8..24af0b4 100644
--- a/net/disk_cache/backend_impl.h
+++ b/net/disk_cache/backend_impl.h
@@ -175,6 +175,17 @@ class BackendImpl : public Backend {
// Logs requests that are denied due to being too big.
void TooMuchStorageRequested(int32 size);
+ // Returns true if a temporary buffer is allowed to be extended.
+ bool IsAllocAllowed(int current_size, int new_size);
+
+ // Tracks the release of |size| bytes by an entry buffer.
+ void BufferDeleted(int size);
+
+ // Only intended for testing the two previous methods.
+ int GetTotalBuffersSize() const {
+ return buffer_bytes_;
+ }
+
// Returns true if this instance seems to be under heavy load.
bool IsLoaded() const;
@@ -314,6 +325,9 @@ class BackendImpl : public Backend {
// Part of the self test. Returns false if the entry is corrupt.
bool CheckEntry(EntryImpl* cache_entry);
+ // Returns the maximum total memory for the memory buffers.
+ int MaxBuffersSize();
+
InFlightBackendIO background_queue_; // The controller of pending operations.
scoped_refptr<MappedFile> index_; // The main cache index.
FilePath path_; // Path to the folder used as backing storage.
@@ -329,6 +343,7 @@ class BackendImpl : public Backend {
int num_pending_io_; // Number of pending IO operations.
int entry_count_; // Number of entries accessed lately.
int byte_count_; // Number of bytes read/written lately.
+ int buffer_bytes_; // Total size of the temporary entries' buffers.
net::CacheType cache_type_;
int uma_report_; // Controls transmision of UMA data.
uint32 user_flags_; // Flags set by the user.
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 7bb27d2..727b29d 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -224,7 +224,7 @@ TEST_F(DiskCacheBackendTest, ExternalFiles) {
// Now let's create a file with the cache.
disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry("key", &entry));
- ASSERT_EQ(0, entry->WriteData(0, 20000, buffer1, 0, NULL, false));
+ ASSERT_EQ(0, WriteData(entry, 0, 20000, buffer1, 0, false));
entry->Close();
// And verify that the first file is still there.
@@ -355,21 +355,21 @@ void DiskCacheBackendTest::BackendSetSize() {
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(cache_size);
memset(buffer->data(), 0, cache_size);
- EXPECT_EQ(cache_size / 10, entry->WriteData(0, 0, buffer, cache_size / 10,
- NULL, false)) << "normal file";
+ EXPECT_EQ(cache_size / 10, WriteData(entry, 0, 0, buffer, cache_size / 10,
+ false)) << "normal file";
- EXPECT_EQ(net::ERR_FAILED, entry->WriteData(1, 0, buffer, cache_size / 5,
- NULL, false)) << "file size above the limit";
+ EXPECT_EQ(net::ERR_FAILED, WriteData(entry, 1, 0, buffer, cache_size / 5,
+ false)) << "file size above the limit";
// By doubling the total size, we make this file cacheable.
SetMaxSize(cache_size * 2);
- EXPECT_EQ(cache_size / 5, entry->WriteData(1, 0, buffer, cache_size / 5,
- NULL, false));
+ EXPECT_EQ(cache_size / 5, WriteData(entry, 1, 0, buffer, cache_size / 5,
+ false));
// Let's fill up the cache!.
SetMaxSize(cache_size * 10);
- EXPECT_EQ(cache_size * 3 / 4, entry->WriteData(0, 0, buffer,
- cache_size * 3 / 4, NULL, false));
+ EXPECT_EQ(cache_size * 3 / 4, WriteData(entry, 0, 0, buffer,
+ cache_size * 3 / 4, false));
entry->Close();
FlushQueueForTest();
@@ -378,13 +378,13 @@ void DiskCacheBackendTest::BackendSetSize() {
// The cache is 95% full.
ASSERT_EQ(net::OK, CreateEntry(second, &entry));
- EXPECT_EQ(cache_size / 10, entry->WriteData(0, 0, buffer, cache_size / 10,
- NULL, false));
+ EXPECT_EQ(cache_size / 10, WriteData(entry, 0, 0, buffer, cache_size / 10,
+ false));
disk_cache::Entry* entry2;
ASSERT_EQ(net::OK, CreateEntry("an extra key", &entry2));
- EXPECT_EQ(cache_size / 10, entry2->WriteData(0, 0, buffer, cache_size / 10,
- NULL, false));
+ EXPECT_EQ(cache_size / 10, WriteData(entry2, 0, 0, buffer, cache_size / 10,
+ false));
entry2->Close(); // This will trigger the cache trim.
EXPECT_NE(net::OK, OpenEntry(first, &entry2));
@@ -472,23 +472,23 @@ void DiskCacheBackendTest::BackendValidEntry() {
InitCache();
std::string key("Some key");
- disk_cache::Entry* entry1;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize = 50;
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, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
- entry1->Close();
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer1, kSize, false));
+ entry->Close();
SimulateCrash();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry1));
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize);
memset(buffer2->data(), 0, kSize);
- EXPECT_EQ(kSize, entry1->ReadData(0, 0, buffer2, kSize, NULL));
- entry1->Close();
+ EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer2, kSize));
+ entry->Close();
EXPECT_STREQ(buffer1->data(), buffer2->data());
}
@@ -510,17 +510,17 @@ void DiskCacheBackendTest::BackendInvalidEntry() {
InitCache();
std::string key("Some key");
- disk_cache::Entry* entry1;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize = 50;
- 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, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
+ 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));
SimulateCrash();
- EXPECT_NE(net::OK, OpenEntry(key, &entry1));
+ EXPECT_NE(net::OK, OpenEntry(key, &entry));
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -548,21 +548,21 @@ void DiskCacheBackendTest::BackendInvalidEntryRead() {
InitCache();
std::string key("Some key");
- disk_cache::Entry* entry1;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize = 50;
- 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, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry1));
- EXPECT_EQ(kSize, entry1->ReadData(0, 0, buffer1, kSize, NULL));
+ 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));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer, kSize));
SimulateCrash();
- EXPECT_NE(net::OK, OpenEntry(key, &entry1));
+ EXPECT_NE(net::OK, OpenEntry(key, &entry));
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -653,13 +653,13 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry() {
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
memset(buffer->data(), 0, kSize);
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
// Simulate a crash.
SimulateCrash();
ASSERT_EQ(net::OK, CreateEntry(second, &entry));
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
EXPECT_EQ(2, cache_->GetEntryCount());
SetMaxSize(kSize);
@@ -703,7 +703,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry2() {
for (int i = 0; i < 32; i++) {
std::string key(StringPrintf("some key %d", i));
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
entry->Close();
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// Note that we are not closing the entries.
@@ -713,7 +713,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry2() {
SimulateCrash();
ASSERT_EQ(net::OK, CreateEntry("Something else", &entry));
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
EXPECT_EQ(33, cache_->GetEntryCount());
SetMaxSize(kSize);
@@ -866,10 +866,10 @@ void DiskCacheBackendTest::BackendInvalidEntryEnumeration() {
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, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry1, 0, 0, buffer1, kSize, false));
entry1->Close();
ASSERT_EQ(net::OK, OpenEntry(key, &entry1));
- EXPECT_EQ(kSize, entry1->ReadData(0, 0, buffer1, kSize, NULL));
+ EXPECT_EQ(kSize, ReadData(entry1, 0, 0, buffer1, kSize));
std::string key2("Another key");
ASSERT_EQ(net::OK, CreateEntry(key2, &entry2));
@@ -1499,8 +1499,8 @@ void DiskCacheBackendTest::BackendDisable4() {
const int kBufSize = 20000;
scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kBufSize);
memset(buf->data(), 0, kBufSize);
- EXPECT_EQ(100, entry2->WriteData(0, 0, buf, 100, NULL, false));
- EXPECT_EQ(kBufSize, entry3->WriteData(0, 0, buf, kBufSize, NULL, false));
+ EXPECT_EQ(100, WriteData(entry2, 0, 0, buf, 100, false));
+ EXPECT_EQ(kBufSize, WriteData(entry3, 0, 0, buf, kBufSize, false));
// This line should disable the cache but not delete it.
EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry4));
@@ -1508,13 +1508,13 @@ void DiskCacheBackendTest::BackendDisable4() {
EXPECT_NE(net::OK, CreateEntry("cache is disabled", &entry4));
- EXPECT_EQ(100, entry2->ReadData(0, 0, buf, 100, NULL));
- EXPECT_EQ(100, entry2->WriteData(0, 0, buf, 100, NULL, false));
- EXPECT_EQ(100, entry2->WriteData(1, 0, buf, 100, NULL, false));
+ EXPECT_EQ(100, ReadData(entry2, 0, 0, buf, 100));
+ EXPECT_EQ(100, WriteData(entry2, 0, 0, buf, 100, false));
+ EXPECT_EQ(100, WriteData(entry2, 1, 0, buf, 100, false));
- EXPECT_EQ(kBufSize, entry3->ReadData(0, 0, buf, kBufSize, NULL));
- EXPECT_EQ(kBufSize, entry3->WriteData(0, 0, buf, kBufSize, NULL, false));
- EXPECT_EQ(kBufSize, entry3->WriteData(1, 0, buf, kBufSize, NULL, false));
+ EXPECT_EQ(kBufSize, ReadData(entry3, 0, 0, buf, kBufSize));
+ EXPECT_EQ(kBufSize, WriteData(entry3, 0, 0, buf, kBufSize, false));
+ EXPECT_EQ(kBufSize, WriteData(entry3, 1, 0, buf, kBufSize, false));
std::string key = entry2->GetKey();
EXPECT_EQ(sizeof(key2) - 1, key.size());
@@ -1747,3 +1747,64 @@ TEST_F(DiskCacheBackendTest, Histograms) {
CACHE_UMA(HOURS, "FillupTime", i, 28);
}
}
+
+// Make sure that we keep the total memory used by the internal buffers under
+// control.
+TEST_F(DiskCacheBackendTest, TotalBuffersSize1) {
+ SetDirectMode();
+ InitCache();
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+
+ const int kSize = 200;
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
+ CacheTestFillBuffer(buffer->data(), kSize, true);
+
+ for (int i = 0; i < 10; i++) {
+ SCOPED_TRACE(i);
+ // Allocate 2MB for this entry.
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, true));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 0, buffer, kSize, true));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 1024 * 1024, buffer, kSize, false));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 1024 * 1024, buffer, kSize, false));
+
+ // Delete one of the buffers and truncate the other.
+ EXPECT_EQ(0, WriteData(entry, 0, 0, buffer, 0, true));
+ EXPECT_EQ(0, WriteData(entry, 1, 10, buffer, 0, true));
+
+ // Delete the second buffer, writing 10 bytes to disk.
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ }
+
+ entry->Close();
+ EXPECT_EQ(0, cache_impl_->GetTotalBuffersSize());
+}
+
+// This test assumes at least 150MB of system memory.
+TEST_F(DiskCacheBackendTest, TotalBuffersSize2) {
+ SetDirectMode();
+ InitCache();
+
+ const int kOneMB = 1024 * 1024;
+ EXPECT_TRUE(cache_impl_->IsAllocAllowed(0, kOneMB));
+ EXPECT_EQ(kOneMB, cache_impl_->GetTotalBuffersSize());
+
+ EXPECT_TRUE(cache_impl_->IsAllocAllowed(0, kOneMB));
+ EXPECT_EQ(kOneMB * 2, cache_impl_->GetTotalBuffersSize());
+
+ EXPECT_TRUE(cache_impl_->IsAllocAllowed(0, kOneMB));
+ EXPECT_EQ(kOneMB * 3, cache_impl_->GetTotalBuffersSize());
+
+ cache_impl_->BufferDeleted(kOneMB);
+ EXPECT_EQ(kOneMB * 2, cache_impl_->GetTotalBuffersSize());
+
+ // Check the upper limit.
+ EXPECT_FALSE(cache_impl_->IsAllocAllowed(0, 30 * kOneMB));
+
+ for (int i = 0; i < 30; i++)
+ cache_impl_->IsAllocAllowed(0, kOneMB); // Ignore the result.
+
+ EXPECT_FALSE(cache_impl_->IsAllocAllowed(0, kOneMB));
+}
diff --git a/net/disk_cache/disk_cache_test_base.cc b/net/disk_cache/disk_cache_test_base.cc
index 0add3c7..9e7d98f6 100644
--- a/net/disk_cache/disk_cache_test_base.cc
+++ b/net/disk_cache/disk_cache_test_base.cc
@@ -4,6 +4,7 @@
#include "net/disk_cache/disk_cache_test_base.h"
+#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/disk_cache/backend_impl.h"
@@ -190,3 +191,35 @@ void DiskCacheTestWithCache::FlushQueueForTest() {
int rv = cache_impl_->FlushQueueForTest(&cb);
EXPECT_EQ(net::OK, cb.GetResult(rv));
}
+
+int DiskCacheTestWithCache::ReadData(disk_cache::Entry* entry, int index,
+ int offset, net::IOBuffer* buf, int len) {
+ TestCompletionCallback cb;
+ int rv = entry->ReadData(index, offset, buf, len, &cb);
+ return cb.GetResult(rv);
+}
+
+
+int DiskCacheTestWithCache::WriteData(disk_cache::Entry* entry, int index,
+ int offset, net::IOBuffer* buf, int len,
+ bool truncate) {
+ TestCompletionCallback cb;
+ int rv = entry->WriteData(index, offset, buf, len, &cb, truncate);
+ return cb.GetResult(rv);
+}
+
+int DiskCacheTestWithCache::ReadSparseData(disk_cache::Entry* entry,
+ int64 offset, net::IOBuffer* buf,
+ int len) {
+ TestCompletionCallback cb;
+ int rv = entry->ReadSparseData(offset, buf, len, &cb);
+ return cb.GetResult(rv);
+}
+
+int DiskCacheTestWithCache::WriteSparseData(disk_cache::Entry* entry,
+ int64 offset,
+ net::IOBuffer* buf, int len) {
+ TestCompletionCallback cb;
+ int rv = entry->WriteSparseData(offset, buf, len, &cb);
+ return cb.GetResult(rv);
+}
diff --git a/net/disk_cache/disk_cache_test_base.h b/net/disk_cache/disk_cache_test_base.h
index 4bcc2cb..a647d97 100644
--- a/net/disk_cache/disk_cache_test_base.h
+++ b/net/disk_cache/disk_cache_test_base.h
@@ -13,6 +13,12 @@
class FilePath;
+namespace net {
+
+class IOBuffer;
+
+} // namespace net
+
namespace disk_cache {
class Backend;
@@ -90,6 +96,14 @@ class DiskCacheTestWithCache : public DiskCacheTest {
int DoomEntriesSince(const base::Time initial_time);
int OpenNextEntry(void** iter, disk_cache::Entry** next_entry);
void FlushQueueForTest();
+ int ReadData(disk_cache::Entry* entry, int index, int offset,
+ net::IOBuffer* buf, int len);
+ int WriteData(disk_cache::Entry* entry, int index, int offset,
+ net::IOBuffer* buf, int len, bool truncate);
+ int ReadSparseData(disk_cache::Entry* entry, int64 offset, net::IOBuffer* buf,
+ int len);
+ int WriteSparseData(disk_cache::Entry* entry, int64 offset,
+ net::IOBuffer* buf, int len);
// cache_ will always have a valid object, regardless of how the cache was
// initialized. The implementation pointers can be NULL.
diff --git a/net/disk_cache/entry_impl.cc b/net/disk_cache/entry_impl.cc
index a017549..8f514b0 100644
--- a/net/disk_cache/entry_impl.cc
+++ b/net/disk_cache/entry_impl.cc
@@ -77,10 +77,215 @@ void ClearInvalidData(char* buffer, int offset, int valid_len) {
memset(buffer + offset + valid_len, 0, end);
}
+const int kMaxBufferSize = 1024 * 1024; // 1 MB.
+
} // namespace
namespace disk_cache {
+// This class handles individual memory buffers that store data before it is
+// sent to disk. The buffer can start at any offset, but if we try to write to
+// anywhere in the first 16KB of the file (kMaxBlockSize), we set the offset to
+// zero. The buffer grows up to a size determined by the backend, to keep the
+// total memory used under control.
+class EntryImpl::UserBuffer {
+ public:
+ explicit UserBuffer(BackendImpl* backend)
+ : backend_(backend->GetWeakPtr()), offset_(0), grow_allowed_(true) {
+ buffer_.reserve(kMaxBlockSize);
+ }
+ ~UserBuffer() {
+ if (backend_)
+ backend_->BufferDeleted(capacity() - kMaxBlockSize);
+ }
+
+ // Returns true if we can handle writing |len| bytes to |offset|.
+ bool PreWrite(int offset, int len);
+
+ // Truncates the buffer to |offset| bytes.
+ void Truncate(int offset);
+
+ // Writes |len| bytes from |buf| at the given |offset|.
+ void Write(int offset, net::IOBuffer* buf, int len);
+
+ // Returns true if we can read |len| bytes from |offset|, given that the
+ // actual file has |eof| bytes stored. Note that the number of bytes to read
+ // may be modified by this method even though it returns false: that means we
+ // should do a smaller read from disk.
+ bool PreRead(int eof, int offset, int* len);
+
+ // Read |len| bytes from |buf| at the given |offset|.
+ int Read(int offset, net::IOBuffer* buf, int len);
+
+ // Prepare this buffer for reuse.
+ void Reset();
+
+ char* Data() { return buffer_.size() ? &buffer_[0] : NULL; }
+ int Size() { return static_cast<int>(buffer_.size()); }
+ int Start() { return offset_; }
+ int End() { return offset_ + Size(); }
+
+ private:
+ int capacity() { return static_cast<int>(buffer_.capacity()); }
+ bool GrowBuffer(int required, int limit);
+
+ base::WeakPtr<BackendImpl> backend_;
+ int offset_;
+ std::vector<char> buffer_;
+ bool grow_allowed_;
+ DISALLOW_COPY_AND_ASSIGN(UserBuffer);
+};
+
+bool EntryImpl::UserBuffer::PreWrite(int offset, int len) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GE(len, 0);
+ DCHECK_GE(offset + len, 0);
+
+ // We don't want to write before our current start.
+ if (offset < offset_)
+ return false;
+
+ // Lets get the common case out of the way.
+ if (offset + len <= capacity())
+ return true;
+
+ // If we are writing to the first 16K (kMaxBlockSize), we want to keep the
+ // buffer offset_ at 0.
+ if (!Size() && offset > kMaxBlockSize)
+ return GrowBuffer(len, kMaxBufferSize);
+
+ int required = offset - offset_ + len;
+ return GrowBuffer(required, kMaxBufferSize * 6 / 5);
+}
+
+void EntryImpl::UserBuffer::Truncate(int offset) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GE(offset, offset_);
+
+ offset -= offset_;
+ if (Size() >= offset)
+ buffer_.resize(offset);
+}
+
+void EntryImpl::UserBuffer::Write(int offset, net::IOBuffer* buf, int len) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GE(len, 0);
+ DCHECK_GE(offset + len, 0);
+ DCHECK_GE(offset, offset_);
+
+ if (!Size() && offset > kMaxBlockSize)
+ offset_ = offset;
+
+ offset -= offset_;
+
+ if (offset > Size())
+ buffer_.resize(offset);
+
+ if (!len)
+ return;
+
+ char* buffer = buf->data();
+ int valid_len = Size() - offset;
+ int copy_len = std::min(valid_len, len);
+ if (copy_len) {
+ memcpy(&buffer_[offset], buffer, copy_len);
+ len -= copy_len;
+ buffer += copy_len;
+ }
+ if (!len)
+ return;
+
+ buffer_.insert(buffer_.end(), buffer, buffer + len);
+}
+
+bool EntryImpl::UserBuffer::PreRead(int eof, int offset, int* len) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GT(*len, 0);
+
+ if (offset < offset_) {
+ // We are reading before this buffer.
+ if (offset >= eof)
+ return true;
+
+ // If the read overlaps with the buffer, change its length so that there is
+ // no overlap.
+ *len = std::min(*len, offset_ - offset);
+ *len = std::min(*len, eof - offset);
+
+ // We should read from disk.
+ return false;
+ }
+
+ if (!Size())
+ return false;
+
+ // See if we can fulfill the first part of the operation.
+ return (offset - offset_ < Size());
+}
+
+int EntryImpl::UserBuffer::Read(int offset, net::IOBuffer* buf, int len) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GT(len, 0);
+ DCHECK(Size() || offset < offset_);
+
+ int clean_bytes = 0;
+ if (offset < offset_) {
+ // We don't have a file so lets fill the first part with 0.
+ clean_bytes = std::min(offset_ - offset, len);
+ memset(buf->data(), 0, clean_bytes);
+ if (len == clean_bytes)
+ return len;
+ offset = offset_;
+ len -= clean_bytes;
+ }
+
+ int start = offset - offset_;
+ int available = Size() - start;
+ DCHECK_GE(start, 0);
+ DCHECK_GE(available, 0);
+ len = std::min(len, available);
+ memcpy(buf->data() + clean_bytes, &buffer_[start], len);
+ return len + clean_bytes;
+}
+
+void EntryImpl::UserBuffer::Reset() {
+ if (!grow_allowed_) {
+ if (backend_)
+ backend_->BufferDeleted(capacity() - kMaxBlockSize);
+ grow_allowed_ = true;
+ std::vector<char> tmp;
+ buffer_.swap(tmp);
+ }
+ offset_ = 0;
+ buffer_.clear();
+}
+
+bool EntryImpl::UserBuffer::GrowBuffer(int required, int limit) {
+ DCHECK_GE(required, 0);
+ int current_size = capacity();
+ if (required <= current_size)
+ return true;
+
+ if (required > limit)
+ return false;
+
+ if (!backend_)
+ return false;
+
+ int to_add = std::max(required - current_size, kMaxBlockSize * 4);
+ to_add = std::max(current_size, to_add);
+ required = std::min(current_size + to_add, limit);
+
+ grow_allowed_ = backend_->IsAllocAllowed(current_size, required);
+ if (!grow_allowed_)
+ return false;
+
+ buffer_.reserve(required);
+ return true;
+}
+
+// ------------------------------------------------------------------------
+
EntryImpl::EntryImpl(BackendImpl* backend, Addr address)
: entry_(NULL, Addr(0)), node_(NULL, Addr(0)) {
entry_.LazyInit(backend->File(address), address);
@@ -107,9 +312,10 @@ EntryImpl::~EntryImpl() {
bool ret = true;
for (int index = 0; index < kNumStreams; index++) {
if (user_buffers_[index].get()) {
- if (!(ret = Flush(index, entry_.Data()->data_size[index], false)))
+ if (!(ret = Flush(index)))
LOG(ERROR) << "Failed to save user data";
- } else if (unreported_size_[index]) {
+ }
+ if (unreported_size_[index]) {
backend_->ModifyStorageSize(
entry_.Data()->data_size[index] - unreported_size_[index],
entry_.Data()->data_size[index]);
@@ -302,10 +508,12 @@ int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf,
backend_->OnEvent(Stats::READ_DATA);
backend_->OnRead(buf_len);
- if (user_buffers_[index].get()) {
+ // We need the current size in disk.
+ int eof = entry_size - unreported_size_[index];
+ if (user_buffers_[index].get() &&
+ user_buffers_[index]->PreRead(eof, offset, &buf_len)) {
// Complete the operation locally.
- DCHECK(kMaxBlockSize >= offset + buf_len);
- memcpy(buf->data() , user_buffers_[index].get() + offset, buf_len);
+ buf_len = user_buffers_[index]->Read(offset, buf, buf_len);
ReportIOTime(kRead, start);
return buf_len;
}
@@ -368,28 +576,13 @@ int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf,
// Read the size at this point (it may change inside prepare).
int entry_size = entry_.Data()->data_size[index];
+ bool extending = entry_size < offset + buf_len;
+ truncate = truncate && entry_size > offset + buf_len;
if (!PrepareTarget(index, offset, buf_len, truncate))
return net::ERR_FAILED;
- if (entry_size < offset + buf_len) {
- unreported_size_[index] += offset + buf_len - entry_size;
- entry_.Data()->data_size[index] = offset + buf_len;
- entry_.set_modified();
- if (!buf_len)
- truncate = true; // Force file extension.
- } else if (truncate) {
- // If the size was modified inside PrepareTarget, we should not do
- // anything here.
- if ((entry_size > offset + buf_len) &&
- (entry_size == entry_.Data()->data_size[index])) {
- unreported_size_[index] += offset + buf_len - entry_size;
- entry_.Data()->data_size[index] = offset + buf_len;
- entry_.set_modified();
- } else {
- // Nothing to truncate.
- truncate = false;
- }
- }
+ if (extending || truncate)
+ UpdateSize(index, entry_size, offset + buf_len);
UpdateRank(true);
@@ -398,16 +591,17 @@ int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf,
if (user_buffers_[index].get()) {
// Complete the operation locally.
- if (!buf_len)
- return 0;
-
- DCHECK(kMaxBlockSize >= offset + buf_len);
- memcpy(user_buffers_[index].get() + offset, buf->data(), buf_len);
+ user_buffers_[index]->Write(offset, buf, buf_len);
ReportIOTime(kWrite, start);
return buf_len;
}
Addr address(entry_.Data()->data_addr[index]);
+ if (truncate && offset + buf_len == 0) {
+ DCHECK(!address.is_initialized());
+ return 0;
+ }
+
File* file = GetBackingFile(address, index);
if (!file)
return net::ERR_FAILED;
@@ -416,7 +610,7 @@ int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf,
if (address.is_block_file()) {
file_offset += address.start_block() * address.BlockSize() +
kBlockHeaderSize;
- } else if (truncate) {
+ } else if (truncate || (extending && !buf_len)) {
if (!file->SetLength(offset + buf_len))
return net::ERR_FAILED;
}
@@ -793,173 +987,220 @@ File* EntryImpl::GetExternalFile(Addr address, int index) {
return files_[index].get();
}
+// We keep a memory buffer for everything that ends up stored on a block file
+// (because we don't know yet the final data size), and for some of the data
+// that end up on external files. This function will initialize that memory
+// buffer and / or the files needed to store the data.
+//
+// In general, a buffer may overlap data already stored on disk, and in that
+// case, the contents of the buffer are the most accurate. It may also extend
+// the file, but we don't want to read from disk just to keep the buffer up to
+// date. This means that as soon as there is a chance to get confused about what
+// is the most recent version of some part of a file, we'll flush the buffer and
+// reuse it for the new data. Keep in mind that the normal use pattern is quite
+// simple (write sequentially from the beginning), so we optimize for handling
+// that case.
bool EntryImpl::PrepareTarget(int index, int offset, int buf_len,
bool truncate) {
- Addr address(entry_.Data()->data_addr[index]);
-
- if (address.is_initialized() || user_buffers_[index].get())
- return GrowUserBuffer(index, offset, buf_len, truncate);
+ if (truncate)
+ return HandleTruncation(index, offset, buf_len);
- if (offset + buf_len > kMaxBlockSize)
- return CreateDataBlock(index, offset + buf_len);
+ Addr address(entry_.Data()->data_addr[index]);
+ if (address.is_initialized()) {
+ if (address.is_block_file() && !MoveToLocalBuffer(index))
+ return false;
- user_buffers_[index].reset(new char[kMaxBlockSize]);
+ if (!user_buffers_[index].get() && offset < kMaxBlockSize) {
+ // We are about to create a buffer for the first 16KB, make sure that we
+ // preserve existing data.
+ if (!CopyToLocalBuffer(index))
+ return false;
+ }
+ }
- // Overwrite the parts of the buffer that are not going to be written
- // by the current operation (and yes, let's assume that nothing is going
- // to fail, and we'll actually write over the part that we are not cleaning
- // here). The point is to avoid writing random stuff to disk later on.
- ClearInvalidData(user_buffers_[index].get(), offset, buf_len);
+ if (!user_buffers_[index].get())
+ user_buffers_[index].reset(new UserBuffer(backend_));
- return true;
+ return PrepareBuffer(index, offset, buf_len);
}
// We get to this function with some data already stored. If there is a
// truncation that results on data stored internally, we'll explicitly
// handle the case here.
-bool EntryImpl::GrowUserBuffer(int index, int offset, int buf_len,
- bool truncate) {
+bool EntryImpl::HandleTruncation(int index, int offset, int buf_len) {
Addr address(entry_.Data()->data_addr[index]);
- if (offset + buf_len > kMaxBlockSize) {
- // The data has to be stored externally.
- if (address.is_initialized()) {
- if (address.is_separate_file())
- return true;
- if (!MoveToLocalBuffer(index))
- return false;
- }
- return Flush(index, offset + buf_len, true);
- }
+ int current_size = entry_.Data()->data_size[index];
+ int new_size = offset + buf_len;
+
+ if (!new_size) {
+ // This is by far the most common scenario.
+ DeleteData(address, index);
+ backend_->ModifyStorageSize(current_size - unreported_size_[index], 0);
+ entry_.Data()->data_addr[index] = 0;
+ entry_.Data()->data_size[index] = 0;
+ unreported_size_[index] = 0;
+ entry_.Store();
- if (!address.is_initialized()) {
- DCHECK(user_buffers_[index].get());
- if (truncate)
- ClearInvalidData(user_buffers_[index].get(), 0, offset + buf_len);
+ user_buffers_[index].reset();
return true;
}
- if (address.is_separate_file()) {
- if (!truncate)
- return true;
- return ImportSeparateFile(index, offset, buf_len);
- }
- // At this point we are dealing with data stored on disk, inside a block file.
- if (offset + buf_len <= address.BlockSize() * address.num_blocks())
- return true;
+ // We never postpone truncating a file, if there is one, but we may postpone
+ // telling the backend about the size reduction.
+ if (user_buffers_[index].get()) {
+ DCHECK_GE(current_size, user_buffers_[index]->Start());
+ if (!address.is_initialized()) {
+ // There is no overlap between the buffer and disk.
+ if (new_size > user_buffers_[index]->Start()) {
+ // Just truncate our buffer.
+ DCHECK_LT(new_size, user_buffers_[index]->End());
+ user_buffers_[index]->Truncate(new_size);
+ return true;
+ }
- // ... and the allocated block has to change.
- if (!MoveToLocalBuffer(index))
- return false;
+ // Just discard our buffer.
+ user_buffers_[index]->Reset();
+ return PrepareBuffer(index, offset, buf_len);
+ }
- int clear_start = entry_.Data()->data_size[index];
- if (truncate)
- clear_start = std::min(clear_start, offset + buf_len);
- else if (offset < clear_start)
- clear_start = std::max(offset + buf_len, clear_start);
+ // There is some overlap or we need to extend the file before the
+ // truncation.
+ if (offset > user_buffers_[index]->Start())
+ user_buffers_[index]->Truncate(new_size);
+ UpdateSize(index, current_size, new_size);
+ if (!Flush(index))
+ return false;
+ user_buffers_[index].reset();
+ }
- // Clear the end of the buffer.
- ClearInvalidData(user_buffers_[index].get(), 0, clear_start);
- return true;
+ // We have data somewhere, and it is not in a buffer.
+ DCHECK(!user_buffers_[index].get());
+ DCHECK(address.is_initialized());
+
+ if (new_size > kMaxBlockSize)
+ return true; // Let the operation go directly to disk.
+
+ return ImportSeparateFile(index, offset + buf_len);
}
-bool EntryImpl::MoveToLocalBuffer(int index) {
+bool EntryImpl::CopyToLocalBuffer(int index) {
Addr address(entry_.Data()->data_addr[index]);
DCHECK(!user_buffers_[index].get());
DCHECK(address.is_initialized());
- scoped_array<char> buffer(new char[kMaxBlockSize]);
+
+ int len = std::min(entry_.Data()->data_size[index], kMaxBlockSize);
+ user_buffers_[index].reset(new UserBuffer(backend_));
+ user_buffers_[index]->Write(len, NULL, 0);
File* file = GetBackingFile(address, index);
- size_t len = entry_.Data()->data_size[index];
- size_t offset = 0;
+ int offset = 0;
if (address.is_block_file())
offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
- if (!file || !file->Read(buffer.get(), len, offset, NULL, NULL))
+ if (!file ||
+ !file->Read(user_buffers_[index]->Data(), len, offset, NULL, NULL)) {
+ user_buffers_[index].reset();
+ return false;
+ }
+ return true;
+}
+
+bool EntryImpl::MoveToLocalBuffer(int index) {
+ if (!CopyToLocalBuffer(index))
return false;
+ Addr address(entry_.Data()->data_addr[index]);
DeleteData(address, index);
entry_.Data()->data_addr[index] = 0;
entry_.Store();
// If we lose this entry we'll see it as zero sized.
- backend_->ModifyStorageSize(static_cast<int>(len) - unreported_size_[index],
- 0);
- unreported_size_[index] = static_cast<int>(len);
-
- user_buffers_[index].swap(buffer);
+ int len = entry_.Data()->data_size[index];
+ backend_->ModifyStorageSize(len - unreported_size_[index], 0);
+ unreported_size_[index] = len;
return true;
}
-bool EntryImpl::ImportSeparateFile(int index, int offset, int buf_len) {
- if (entry_.Data()->data_size[index] > offset + buf_len) {
- unreported_size_[index] += offset + buf_len -
- entry_.Data()->data_size[index];
- entry_.Data()->data_size[index] = offset + buf_len;
+bool EntryImpl::ImportSeparateFile(int index, int new_size) {
+ if (entry_.Data()->data_size[index] > new_size)
+ UpdateSize(index, entry_.Data()->data_size[index], new_size);
+
+ return MoveToLocalBuffer(index);
+}
+
+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.
+ 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))
+ return false;
+ }
}
- if (!MoveToLocalBuffer(index))
- return false;
+ if (!user_buffers_[index]->PreWrite(offset, buf_len)) {
+ if (!Flush(index))
+ return false;
- // Clear the end of the buffer.
- ClearInvalidData(user_buffers_[index].get(), 0, offset + buf_len);
+ // Lets try again.
+ if (!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());
+ user_buffers_[index].reset();
+ }
+ }
return true;
}
-// The common scenario is that this is called from the destructor of the entry,
-// to write to disk what we have buffered. We don't want to hold the destructor
-// until the actual IO finishes, so we'll send an asynchronous write that will
-// free up the memory containing the data. To be consistent, this method always
-// returns with the buffer freed up (on success).
-bool EntryImpl::Flush(int index, int size, bool async) {
+bool EntryImpl::Flush(int index) {
Addr address(entry_.Data()->data_addr[index]);
DCHECK(user_buffers_[index].get());
- DCHECK(!address.is_initialized());
- if (!size)
+ if (!entry_.Data()->data_size[index]) {
+ DCHECK(!user_buffers_[index]->Size());
return true;
+ }
- if (!CreateDataBlock(index, size))
+ if (!address.is_initialized() &&
+ !CreateDataBlock(index, entry_.Data()->data_size[index]))
return false;
address.set_value(entry_.Data()->data_addr[index]);
File* file = GetBackingFile(address, index);
- size_t len = entry_.Data()->data_size[index];
- size_t offset = 0;
- if (address.is_block_file())
+ int len = user_buffers_[index]->Size();
+ int offset = user_buffers_[index]->Start();
+ if (address.is_block_file()) {
+ DCHECK_EQ(len, entry_.Data()->data_size[index]);
+ DCHECK(!offset);
offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
-
- // We just told the backend to store len bytes for real.
- DCHECK(len == static_cast<size_t>(unreported_size_[index]));
- backend_->ModifyStorageSize(0, static_cast<int>(len));
- unreported_size_[index] = 0;
+ }
if (!file)
return false;
- // TODO(rvargas): figure out if it's worth to re-enable posting operations.
- // Right now it is only used from GrowUserBuffer, not the destructor, and
- // it is not accounted for from the point of view of the total number of
- // pending operations of the cache. It is also racing with the actual write
- // on the GrowUserBuffer path because there is no code to exclude the range
- // that is going to be written.
- async = false;
- if (async) {
- if (!file->PostWrite(user_buffers_[index].get(), len, offset))
- return false;
- // The buffer is deleted from the PostWrite operation.
- ignore_result(user_buffers_[index].release());
- } else {
- if (!file->Write(user_buffers_[index].get(), len, offset, NULL, NULL))
- return false;
- user_buffers_[index].reset(NULL);
- }
+ if (!file->Write(user_buffers_[index]->Data(), len, offset, NULL, NULL))
+ return false;
+ user_buffers_[index]->Reset();
return true;
}
+void EntryImpl::UpdateSize(int index, int old_size, int new_size) {
+ if (entry_.Data()->data_size[index] == new_size)
+ return;
+
+ unreported_size_[index] += new_size - old_size;
+ entry_.Data()->data_size[index] = new_size;
+ entry_.set_modified();
+}
+
int EntryImpl::InitSparseData() {
if (sparse_.get())
return net::OK;
@@ -983,13 +1224,16 @@ uint32 EntryImpl::GetEntryFlags() {
}
void EntryImpl::GetData(int index, char** buffer, Addr* address) {
- if (user_buffers_[index].get()) {
+ if (user_buffers_[index].get() && user_buffers_[index]->Size() &&
+ !user_buffers_[index]->Start()) {
// The data is already in memory, just copy it and we're done.
int data_len = entry_.Data()->data_size[index];
- DCHECK(data_len <= kMaxBlockSize);
- *buffer = new char[data_len];
- memcpy(*buffer, user_buffers_[index].get(), data_len);
- return;
+ if (data_len <= user_buffers_[index]->Size()) {
+ DCHECK(!user_buffers_[index]->Start());
+ *buffer = new char[data_len];
+ memcpy(*buffer, user_buffers_[index]->Data(), data_len);
+ return;
+ }
}
// Bad news: we'd have to read the info from disk so instead we'll just tell
diff --git a/net/disk_cache/entry_impl.h b/net/disk_cache/entry_impl.h
index 73fb481..979e066 100644
--- a/net/disk_cache/entry_impl.h
+++ b/net/disk_cache/entry_impl.h
@@ -133,6 +133,7 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
enum {
kNumStreams = 3
};
+ class UserBuffer;
~EntryImpl();
@@ -158,17 +159,28 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
// given offset.
bool PrepareTarget(int index, int offset, int buf_len, bool truncate);
- // Grows the size of the storage used to store user data, if needed.
- bool GrowUserBuffer(int index, int offset, int buf_len, bool truncate);
+ // Adjusts the internal buffer and file handle for a write that truncates this
+ // stream.
+ bool HandleTruncation(int index, int offset, int buf_len);
+
+ // Copies data from disk to the internal buffer.
+ bool CopyToLocalBuffer(int index);
// Reads from a block data file to this object's memory buffer.
bool MoveToLocalBuffer(int index);
// Loads the external file to this object's memory buffer.
- bool ImportSeparateFile(int index, int offset, int buf_len);
+ bool ImportSeparateFile(int index, int new_size);
+
+ // Makes sure that the internal buffer can handle the a write of |buf_len|
+ // bytes to |offset|.
+ bool PrepareBuffer(int index, int offset, int buf_len);
+
+ // Flushes the in-memory data to the backing storage.
+ bool Flush(int index);
- // Flush the in-memory data to the backing storage.
- bool Flush(int index, int size, bool async);
+ // Updates the size of a given data stream.
+ void UpdateSize(int index, int old_size, int new_size);
// Initializes the sparse control object. Returns a net error code.
int InitSparseData();
@@ -195,7 +207,7 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
CacheEntryBlock entry_; // Key related information for this entry.
CacheRankingsBlock node_; // Rankings related information for this entry.
BackendImpl* backend_; // Back pointer to the cache.
- scoped_array<char> user_buffers_[kNumStreams]; // Store user data.
+ scoped_ptr<UserBuffer> user_buffers_[kNumStreams]; // Stores user data.
// Files to store external user data and key.
scoped_refptr<File> files_[kNumStreams + 1];
mutable std::string key_; // Copy of the key.
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index 859cabb..1ff033c 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -36,27 +36,31 @@ class DiskCacheEntryTest : public DiskCacheTestWithCache {
void InvalidData();
void DoomNormalEntry();
void DoomedEntry();
- void BasicSparseIO(bool async);
- void HugeSparseIO(bool async);
+ void BasicSparseIO();
+ void HugeSparseIO();
void GetAvailableRange();
void CouldBeSparse();
void DoomSparseEntry();
void PartialSparseEntry();
};
+// We need to support synchronous IO even though it is not a supported operation
+// from the point of view of the disk cache's public interface, because we use
+// it internally, not just by a few tests, but as part of the implementation
+// (see sparse_control.cc, for example).
void DiskCacheEntryTest::InternalSyncIO() {
- disk_cache::Entry *entry1 = NULL;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
- ASSERT_TRUE(NULL != entry1);
+ disk_cache::Entry* entry = NULL;
+ ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_TRUE(NULL != entry);
const int kSize1 = 10;
scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1);
CacheTestFillBuffer(buffer1->data(), kSize1, false);
- EXPECT_EQ(0, entry1->ReadData(0, 0, buffer1, kSize1, NULL));
+ EXPECT_EQ(0, entry->ReadData(0, 0, buffer1, kSize1, NULL));
base::strlcpy(buffer1->data(), "the data", kSize1);
- EXPECT_EQ(10, entry1->WriteData(0, 0, buffer1, kSize1, NULL, false));
+ EXPECT_EQ(10, entry->WriteData(0, 0, buffer1, kSize1, NULL, false));
memset(buffer1->data(), 0, kSize1);
- EXPECT_EQ(10, entry1->ReadData(0, 0, buffer1, kSize1, NULL));
+ EXPECT_EQ(10, entry->ReadData(0, 0, buffer1, kSize1, NULL));
EXPECT_STREQ("the data", buffer1->data());
const int kSize2 = 5000;
@@ -66,22 +70,26 @@ void DiskCacheEntryTest::InternalSyncIO() {
memset(buffer3->data(), 0, kSize3);
CacheTestFillBuffer(buffer2->data(), kSize2, false);
base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
- EXPECT_EQ(5000, entry1->WriteData(1, 1500, buffer2, kSize2, NULL, false));
+ EXPECT_EQ(5000, entry->WriteData(1, 1500, buffer2, kSize2, NULL, false));
memset(buffer2->data(), 0, kSize2);
- EXPECT_EQ(4989, entry1->ReadData(1, 1511, buffer2, kSize2, NULL));
+ EXPECT_EQ(4989, entry->ReadData(1, 1511, buffer2, kSize2, NULL));
EXPECT_STREQ("big data goes here", buffer2->data());
- EXPECT_EQ(5000, entry1->ReadData(1, 0, buffer2, kSize2, NULL));
+ EXPECT_EQ(5000, entry->ReadData(1, 0, buffer2, kSize2, NULL));
EXPECT_EQ(0, memcmp(buffer2->data(), buffer3->data(), 1500));
- EXPECT_EQ(1500, entry1->ReadData(1, 5000, buffer2, kSize2, NULL));
+ EXPECT_EQ(1500, entry->ReadData(1, 5000, buffer2, kSize2, NULL));
- EXPECT_EQ(0, entry1->ReadData(1, 6500, buffer2, kSize2, NULL));
- EXPECT_EQ(6500, entry1->ReadData(1, 0, buffer3, kSize3, NULL));
- EXPECT_EQ(8192, entry1->WriteData(1, 0, buffer3, 8192, NULL, false));
- EXPECT_EQ(8192, entry1->ReadData(1, 0, buffer3, kSize3, NULL));
- EXPECT_EQ(8192, entry1->GetDataSize(1));
+ EXPECT_EQ(0, entry->ReadData(1, 6500, buffer2, kSize2, NULL));
+ EXPECT_EQ(6500, entry->ReadData(1, 0, buffer3, kSize3, NULL));
+ EXPECT_EQ(8192, entry->WriteData(1, 0, buffer3, 8192, NULL, false));
+ EXPECT_EQ(8192, entry->ReadData(1, 0, buffer3, kSize3, NULL));
+ EXPECT_EQ(8192, entry->GetDataSize(1));
- entry1->Doom();
- entry1->Close();
+ // We need to delete the memory buffer on this thread.
+ EXPECT_EQ(0, entry->WriteData(0, 0, NULL, 0, NULL, true));
+ EXPECT_EQ(0, entry->WriteData(1, 0, NULL, 0, NULL, true));
+
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -99,19 +107,19 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyInternalSyncIO) {
}
void DiskCacheEntryTest::InternalAsyncIO() {
- disk_cache::Entry *entry1 = NULL;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
- ASSERT_TRUE(NULL != entry1);
+ disk_cache::Entry* entry = NULL;
+ ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_TRUE(NULL != entry);
// Avoid using internal buffers for the test. We have to write something to
// the entry and close it so that we flush the internal buffer to disk. After
// that, IO operations will be really hitting the disk. We don't care about
// the content, so just extending the entry is enough (all extensions zero-
// fill any holes).
- EXPECT_EQ(0, entry1->WriteData(0, 15 * 1024, NULL, 0, NULL, false));
- EXPECT_EQ(0, entry1->WriteData(1, 15 * 1024, NULL, 0, NULL, false));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry("the first key", &entry1));
+ EXPECT_EQ(0, WriteData(entry, 0, 15 * 1024, NULL, 0, false));
+ EXPECT_EQ(0, WriteData(entry, 1, 15 * 1024, NULL, 0, false));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry("the first key", &entry));
// Let's verify that each IO goes to the right callback object.
CallbackTest callback1(false);
@@ -143,17 +151,17 @@ void DiskCacheEntryTest::InternalAsyncIO() {
CacheTestFillBuffer(buffer2->data(), kSize2, false);
CacheTestFillBuffer(buffer3->data(), kSize3, false);
- EXPECT_EQ(0, entry1->ReadData(0, 15 * 1024, buffer1, kSize1, &callback1));
+ EXPECT_EQ(0, entry->ReadData(0, 15 * 1024, buffer1, kSize1, &callback1));
base::strlcpy(buffer1->data(), "the data", kSize1);
int expected = 0;
- int ret = entry1->WriteData(0, 0, buffer1, kSize1, &callback2, false);
+ int ret = entry->WriteData(0, 0, buffer1, kSize1, &callback2, false);
EXPECT_TRUE(10 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
memset(buffer2->data(), 0, kSize2);
- ret = entry1->ReadData(0, 0, buffer2, kSize1, &callback3);
+ ret = entry->ReadData(0, 0, buffer2, kSize1, &callback3);
EXPECT_TRUE(10 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -162,21 +170,21 @@ void DiskCacheEntryTest::InternalAsyncIO() {
EXPECT_STREQ("the data", buffer2->data());
base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
- ret = entry1->WriteData(1, 1500, buffer2, kSize2, &callback4, true);
+ ret = entry->WriteData(1, 1500, buffer2, kSize2, &callback4, true);
EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
memset(buffer3->data(), 0, kSize3);
- ret = entry1->ReadData(1, 1511, buffer3, kSize2, &callback5);
+ ret = entry->ReadData(1, 1511, buffer3, kSize2, &callback5);
EXPECT_TRUE(4989 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
EXPECT_STREQ("big data goes here", buffer3->data());
- ret = entry1->ReadData(1, 0, buffer2, kSize2, &callback6);
+ ret = entry->ReadData(1, 0, buffer2, kSize2, &callback6);
EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -185,35 +193,35 @@ void DiskCacheEntryTest::InternalAsyncIO() {
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
EXPECT_EQ(0, memcmp(buffer2->data(), buffer3->data(), 1500));
- ret = entry1->ReadData(1, 5000, buffer2, kSize2, &callback7);
+ ret = entry->ReadData(1, 5000, buffer2, kSize2, &callback7);
EXPECT_TRUE(1500 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- ret = entry1->ReadData(1, 0, buffer3, kSize3, &callback9);
+ ret = entry->ReadData(1, 0, buffer3, kSize3, &callback9);
EXPECT_TRUE(6500 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- ret = entry1->WriteData(1, 0, buffer3, 8192, &callback10, true);
+ ret = entry->WriteData(1, 0, buffer3, 8192, &callback10, true);
EXPECT_TRUE(8192 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
- ret = entry1->ReadData(1, 0, buffer3, kSize3, &callback11);
+ ret = entry->ReadData(1, 0, buffer3, kSize3, &callback11);
EXPECT_TRUE(8192 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- EXPECT_EQ(8192, entry1->GetDataSize(1));
+ EXPECT_EQ(8192, entry->GetDataSize(1));
- ret = entry1->ReadData(0, 0, buffer1, kSize1, &callback12);
+ ret = entry->ReadData(0, 0, buffer1, kSize1, &callback12);
EXPECT_TRUE(10 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- ret = entry1->ReadData(1, 0, buffer2, kSize2, &callback13);
+ ret = entry->ReadData(1, 0, buffer2, kSize2, &callback13);
EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -223,8 +231,8 @@ void DiskCacheEntryTest::InternalAsyncIO() {
EXPECT_FALSE(g_cache_tests_error);
EXPECT_EQ(expected, g_cache_tests_received);
- entry1->Doom();
- entry1->Close();
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -242,8 +250,8 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyInternalAsyncIO) {
}
void DiskCacheEntryTest::ExternalSyncIO() {
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
const int kSize1 = 17000;
const int kSize2 = 25000;
@@ -252,27 +260,31 @@ void DiskCacheEntryTest::ExternalSyncIO() {
CacheTestFillBuffer(buffer1->data(), kSize1, false);
CacheTestFillBuffer(buffer2->data(), kSize2, false);
base::strlcpy(buffer1->data(), "the data", kSize1);
- EXPECT_EQ(17000, entry1->WriteData(0, 0, buffer1, kSize1, NULL, false));
+ EXPECT_EQ(17000, entry->WriteData(0, 0, buffer1, kSize1, NULL, false));
memset(buffer1->data(), 0, kSize1);
- EXPECT_EQ(17000, entry1->ReadData(0, 0, buffer1, kSize1, NULL));
+ EXPECT_EQ(17000, entry->ReadData(0, 0, buffer1, kSize1, NULL));
EXPECT_STREQ("the data", buffer1->data());
base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
- EXPECT_EQ(25000, entry1->WriteData(1, 10000, buffer2, kSize2, NULL, false));
+ EXPECT_EQ(25000, entry->WriteData(1, 10000, buffer2, kSize2, NULL, false));
memset(buffer2->data(), 0, kSize2);
- EXPECT_EQ(24989, entry1->ReadData(1, 10011, buffer2, kSize2, NULL));
+ EXPECT_EQ(24989, entry->ReadData(1, 10011, buffer2, kSize2, NULL));
EXPECT_STREQ("big data goes here", buffer2->data());
- EXPECT_EQ(25000, entry1->ReadData(1, 0, buffer2, kSize2, NULL));
+ EXPECT_EQ(25000, entry->ReadData(1, 0, buffer2, kSize2, NULL));
EXPECT_EQ(0, memcmp(buffer2->data(), buffer2->data(), 10000));
- EXPECT_EQ(5000, entry1->ReadData(1, 30000, buffer2, kSize2, NULL));
+ EXPECT_EQ(5000, entry->ReadData(1, 30000, buffer2, kSize2, NULL));
- EXPECT_EQ(0, entry1->ReadData(1, 35000, buffer2, kSize2, NULL));
- EXPECT_EQ(17000, entry1->ReadData(1, 0, buffer1, kSize1, NULL));
- EXPECT_EQ(17000, entry1->WriteData(1, 20000, buffer1, kSize1, NULL, false));
- EXPECT_EQ(37000, entry1->GetDataSize(1));
+ EXPECT_EQ(0, entry->ReadData(1, 35000, buffer2, kSize2, NULL));
+ EXPECT_EQ(17000, entry->ReadData(1, 0, buffer1, kSize1, NULL));
+ EXPECT_EQ(17000, entry->WriteData(1, 20000, buffer1, kSize1, NULL, false));
+ EXPECT_EQ(37000, entry->GetDataSize(1));
- entry1->Doom();
- entry1->Close();
+ // We need to delete the memory buffer on this thread.
+ EXPECT_EQ(0, entry->WriteData(0, 0, NULL, 0, NULL, true));
+ EXPECT_EQ(0, entry->WriteData(1, 0, NULL, 0, NULL, true));
+
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -290,8 +302,8 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyExternalSyncIO) {
}
void DiskCacheEntryTest::ExternalAsyncIO() {
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
// Let's verify that each IO goes to the right callback object.
CallbackTest callback1(false);
@@ -320,7 +332,7 @@ void DiskCacheEntryTest::ExternalAsyncIO() {
CacheTestFillBuffer(buffer2->data(), kSize2, false);
CacheTestFillBuffer(buffer3->data(), kSize3, false);
base::strlcpy(buffer1->data(), "the data", kSize1);
- int ret = entry1->WriteData(0, 0, buffer1, kSize1, &callback1, false);
+ int ret = entry->WriteData(0, 0, buffer1, kSize1, &callback1, false);
EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -328,7 +340,7 @@ void DiskCacheEntryTest::ExternalAsyncIO() {
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
memset(buffer2->data(), 0, kSize1);
- ret = entry1->ReadData(0, 0, buffer2, kSize1, &callback2);
+ ret = entry->ReadData(0, 0, buffer2, kSize1, &callback2);
EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -337,7 +349,7 @@ void DiskCacheEntryTest::ExternalAsyncIO() {
EXPECT_STREQ("the data", buffer1->data());
base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
- ret = entry1->WriteData(1, 10000, buffer2, kSize2, &callback3, false);
+ ret = entry->WriteData(1, 10000, buffer2, kSize2, &callback3, false);
EXPECT_TRUE(25000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -345,43 +357,43 @@ void DiskCacheEntryTest::ExternalAsyncIO() {
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
memset(buffer3->data(), 0, kSize3);
- ret = entry1->ReadData(1, 10011, buffer3, kSize3, &callback4);
+ ret = entry->ReadData(1, 10011, buffer3, kSize3, &callback4);
EXPECT_TRUE(24989 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
EXPECT_STREQ("big data goes here", buffer3->data());
- ret = entry1->ReadData(1, 0, buffer2, kSize2, &callback5);
+ ret = entry->ReadData(1, 0, buffer2, kSize2, &callback5);
EXPECT_TRUE(25000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
EXPECT_EQ(0, memcmp(buffer2->data(), buffer2->data(), 10000));
- ret = entry1->ReadData(1, 30000, buffer2, kSize2, &callback6);
+ ret = entry->ReadData(1, 30000, buffer2, kSize2, &callback6);
EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- EXPECT_EQ(0, entry1->ReadData(1, 35000, buffer2, kSize2, &callback7));
- ret = entry1->ReadData(1, 0, buffer1, kSize1, &callback8);
+ EXPECT_EQ(0, entry->ReadData(1, 35000, buffer2, kSize2, &callback7));
+ ret = entry->ReadData(1, 0, buffer1, kSize1, &callback8);
EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- ret = entry1->WriteData(1, 20000, buffer1, kSize1, &callback9, false);
+ ret = entry->WriteData(1, 20000, buffer1, kSize1, &callback9, false);
EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
- EXPECT_EQ(37000, entry1->GetDataSize(1));
+ EXPECT_EQ(37000, entry->GetDataSize(1));
EXPECT_FALSE(g_cache_tests_error);
EXPECT_EQ(expected, g_cache_tests_received);
- entry1->Doom();
- entry1->Close();
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -399,7 +411,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyExternalAsyncIO) {
}
void DiskCacheEntryTest::StreamAccess() {
- disk_cache::Entry *entry = NULL;
+ disk_cache::Entry* entry = NULL;
ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
ASSERT_TRUE(NULL != entry);
@@ -410,15 +422,14 @@ void DiskCacheEntryTest::StreamAccess() {
const int kNumStreams = 3;
for (int i = 0; i < kNumStreams; i++) {
CacheTestFillBuffer(buffer1->data(), kBufferSize, false);
- EXPECT_EQ(kBufferSize, entry->WriteData(i, 0, buffer1, kBufferSize, NULL,
- false));
+ EXPECT_EQ(kBufferSize, WriteData(entry, i, 0, buffer1, kBufferSize, false));
memset(buffer2->data(), 0, kBufferSize);
- EXPECT_EQ(kBufferSize, entry->ReadData(i, 0, buffer2, kBufferSize, NULL));
+ EXPECT_EQ(kBufferSize, ReadData(entry, i, 0, buffer2, kBufferSize));
EXPECT_EQ(0, memcmp(buffer1->data(), buffer2->data(), kBufferSize));
}
EXPECT_EQ(net::ERR_INVALID_ARGUMENT,
- entry->ReadData(kNumStreams, 0, buffer1, kBufferSize, NULL));
+ ReadData(entry, kNumStreams, 0, buffer1, kBufferSize));
entry->Close();
}
@@ -434,11 +445,11 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyStreamAccess) {
}
void DiskCacheEntryTest::GetKey() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_EQ(key1, entry1->GetKey()) << "short key";
- entry1->Close();
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_EQ(key, entry->GetKey()) << "short key";
+ entry->Close();
int seed = static_cast<int>(Time::Now().ToInternalValue());
srand(seed);
@@ -447,25 +458,25 @@ void DiskCacheEntryTest::GetKey() {
CacheTestFillBuffer(key_buffer, 3000, true);
key_buffer[1000] = '\0';
- key1 = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_TRUE(key1 == entry1->GetKey()) << "1000 bytes key";
- entry1->Close();
+ key = key_buffer;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_TRUE(key == entry->GetKey()) << "1000 bytes key";
+ entry->Close();
key_buffer[1000] = 'p';
key_buffer[3000] = '\0';
- key1 = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_TRUE(key1 == entry1->GetKey()) << "medium size key";
- entry1->Close();
+ key = key_buffer;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_TRUE(key == entry->GetKey()) << "medium size key";
+ entry->Close();
CacheTestFillBuffer(key_buffer, sizeof(key_buffer), true);
key_buffer[19999] = '\0';
- key1 = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_TRUE(key1 == entry1->GetKey()) << "long key";
- entry1->Close();
+ key = key_buffer;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_TRUE(key == entry->GetKey()) << "long key";
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, GetKey) {
@@ -481,8 +492,8 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyGetKey) {
void DiskCacheEntryTest::GrowData() {
std::string key1("the first key");
- disk_cache::Entry *entry1, *entry2;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key1, &entry));
const int kSize = 20000;
scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize);
@@ -491,44 +502,58 @@ void DiskCacheEntryTest::GrowData() {
memset(buffer2->data(), 0, kSize);
base::strlcpy(buffer1->data(), "the data", kSize);
- EXPECT_EQ(10, entry1->WriteData(0, 0, buffer1, 10, NULL, false));
- EXPECT_EQ(10, entry1->ReadData(0, 0, buffer2, 10, NULL));
+ EXPECT_EQ(10, WriteData(entry, 0, 0, buffer1, 10, false));
+ EXPECT_EQ(10, ReadData(entry, 0, 0, buffer2, 10));
EXPECT_STREQ("the data", buffer2->data());
- EXPECT_EQ(10, entry1->GetDataSize(0));
+ EXPECT_EQ(10, entry->GetDataSize(0));
- EXPECT_EQ(2000, entry1->WriteData(0, 0, buffer1, 2000, NULL, false));
- EXPECT_EQ(2000, entry1->GetDataSize(0));
- EXPECT_EQ(2000, entry1->ReadData(0, 0, buffer2, 2000, NULL));
+ EXPECT_EQ(2000, WriteData(entry, 0, 0, buffer1, 2000, false));
+ EXPECT_EQ(2000, entry->GetDataSize(0));
+ EXPECT_EQ(2000, ReadData(entry, 0, 0, buffer2, 2000));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 2000));
- EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(20000, entry1->ReadData(0, 0, buffer2, kSize, NULL));
+ EXPECT_EQ(20000, WriteData(entry, 0, 0, buffer1, kSize, false));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(20000, ReadData(entry, 0, 0, buffer2, kSize));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), kSize));
- entry1->Close();
+ entry->Close();
memset(buffer2->data(), 0, kSize);
- ASSERT_EQ(net::OK, CreateEntry("Second key", &entry2));
- EXPECT_EQ(10, entry2->WriteData(0, 0, buffer1, 10, NULL, false));
- EXPECT_EQ(10, entry2->GetDataSize(0));
- entry2->Close();
+ std::string key2("Second key");
+ ASSERT_EQ(net::OK, CreateEntry(key2, &entry));
+ EXPECT_EQ(10, WriteData(entry, 0, 0, buffer1, 10, false));
+ EXPECT_EQ(10, entry->GetDataSize(0));
+ entry->Close();
// Go from an internal address to a bigger block size.
- ASSERT_EQ(net::OK, OpenEntry("Second key", &entry2));
- EXPECT_EQ(2000, entry2->WriteData(0, 0, buffer1, 2000, NULL, false));
- EXPECT_EQ(2000, entry2->GetDataSize(0));
- EXPECT_EQ(2000, entry2->ReadData(0, 0, buffer2, 2000, NULL));
+ ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ EXPECT_EQ(2000, WriteData(entry, 0, 0, buffer1, 2000, false));
+ EXPECT_EQ(2000, entry->GetDataSize(0));
+ EXPECT_EQ(2000, ReadData(entry, 0, 0, buffer2, 2000));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 2000));
- entry2->Close();
+ entry->Close();
memset(buffer2->data(), 0, kSize);
// Go from an internal address to an external one.
- ASSERT_EQ(net::OK, OpenEntry("Second key", &entry2));
- EXPECT_EQ(20000, entry2->WriteData(0, 0, buffer1, kSize, NULL, false));
- EXPECT_EQ(20000, entry2->GetDataSize(0));
- EXPECT_EQ(20000, entry2->ReadData(0, 0, buffer2, kSize, NULL));
+ ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ EXPECT_EQ(20000, WriteData(entry, 0, 0, buffer1, kSize, false));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(20000, ReadData(entry, 0, 0, buffer2, kSize));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), kSize));
- entry2->Close();
+ entry->Close();
+
+ // Double check the size from disk.
+ ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+
+ // Now extend the entry without actual data.
+ EXPECT_EQ(0, WriteData(entry, 0, 45500, buffer1, 0, false));
+ entry->Close();
+
+ // And check again from disk.
+ ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ EXPECT_EQ(45500, entry->GetDataSize(0));
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, GrowData) {
@@ -543,9 +568,9 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyGrowData) {
}
void DiskCacheEntryTest::TruncateData() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize1 = 20000;
const int kSize2 = 20000;
@@ -556,50 +581,50 @@ void DiskCacheEntryTest::TruncateData() {
memset(buffer2->data(), 0, kSize2);
// Simple truncation:
- EXPECT_EQ(200, entry1->WriteData(0, 0, buffer1, 200, NULL, false));
- EXPECT_EQ(200, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->WriteData(0, 0, buffer1, 100, NULL, false));
- EXPECT_EQ(200, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->WriteData(0, 0, buffer1, 100, NULL, true));
- EXPECT_EQ(100, entry1->GetDataSize(0));
- EXPECT_EQ(0, entry1->WriteData(0, 50, buffer1, 0, NULL, true));
- EXPECT_EQ(50, entry1->GetDataSize(0));
- EXPECT_EQ(0, entry1->WriteData(0, 0, buffer1, 0, NULL, true));
- EXPECT_EQ(0, entry1->GetDataSize(0));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry(key1, &entry1));
+ EXPECT_EQ(200, entry->WriteData(0, 0, buffer1, 200, NULL, false));
+ EXPECT_EQ(200, entry->GetDataSize(0));
+ EXPECT_EQ(100, entry->WriteData(0, 0, buffer1, 100, NULL, false));
+ EXPECT_EQ(200, entry->GetDataSize(0));
+ EXPECT_EQ(100, entry->WriteData(0, 0, buffer1, 100, NULL, true));
+ EXPECT_EQ(100, entry->GetDataSize(0));
+ EXPECT_EQ(0, entry->WriteData(0, 50, buffer1, 0, NULL, true));
+ EXPECT_EQ(50, entry->GetDataSize(0));
+ EXPECT_EQ(0, entry->WriteData(0, 0, buffer1, 0, NULL, true));
+ EXPECT_EQ(0, entry->GetDataSize(0));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// Go to an external file.
- EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer1, 20000, NULL, true));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(20000, entry1->ReadData(0, 0, buffer2, 20000, NULL));
+ EXPECT_EQ(20000, entry->WriteData(0, 0, buffer1, 20000, NULL, true));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(20000, entry->ReadData(0, 0, buffer2, 20000, NULL));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 20000));
memset(buffer2->data(), 0, kSize2);
// External file truncation
- EXPECT_EQ(18000, entry1->WriteData(0, 0, buffer1, 18000, NULL, false));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(18000, entry1->WriteData(0, 0, buffer1, 18000, NULL, true));
- EXPECT_EQ(18000, entry1->GetDataSize(0));
- EXPECT_EQ(0, entry1->WriteData(0, 17500, buffer1, 0, NULL, true));
- EXPECT_EQ(17500, entry1->GetDataSize(0));
+ EXPECT_EQ(18000, entry->WriteData(0, 0, buffer1, 18000, NULL, false));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(18000, entry->WriteData(0, 0, buffer1, 18000, NULL, true));
+ EXPECT_EQ(18000, entry->GetDataSize(0));
+ EXPECT_EQ(0, entry->WriteData(0, 17500, buffer1, 0, NULL, true));
+ EXPECT_EQ(17500, entry->GetDataSize(0));
// And back to an internal block.
- EXPECT_EQ(600, entry1->WriteData(0, 1000, buffer1, 600, NULL, true));
- EXPECT_EQ(1600, entry1->GetDataSize(0));
- EXPECT_EQ(600, entry1->ReadData(0, 1000, buffer2, 600, NULL));
+ EXPECT_EQ(600, entry->WriteData(0, 1000, buffer1, 600, NULL, true));
+ EXPECT_EQ(1600, entry->GetDataSize(0));
+ EXPECT_EQ(600, entry->ReadData(0, 1000, buffer2, 600, NULL));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 600));
- EXPECT_EQ(1000, entry1->ReadData(0, 0, buffer2, 1000, NULL));
+ EXPECT_EQ(1000, entry->ReadData(0, 0, buffer2, 1000, NULL));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 1000)) <<
"Preserves previous data";
// Go from external file to zero length.
- EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer1, 20000, NULL, true));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(0, entry1->WriteData(0, 0, buffer1, 0, NULL, true));
- EXPECT_EQ(0, entry1->GetDataSize(0));
+ EXPECT_EQ(20000, entry->WriteData(0, 0, buffer1, 20000, NULL, true));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(0, entry->WriteData(0, 0, buffer1, 0, NULL, true));
+ EXPECT_EQ(0, entry->GetDataSize(0));
- entry1->Close();
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, TruncateData) {
@@ -619,19 +644,41 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyTruncateData) {
}
void DiskCacheEntryTest::ZeroLengthIO() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
- EXPECT_EQ(0, entry1->ReadData(0, 0, NULL, 0, NULL));
- EXPECT_EQ(0, entry1->WriteData(0, 0, NULL, 0, NULL, false));
+ EXPECT_EQ(0, ReadData(entry, 0, 0, NULL, 0));
+ EXPECT_EQ(0, WriteData(entry, 0, 0, NULL, 0, false));
// This write should extend the entry.
- EXPECT_EQ(0, entry1->WriteData(0, 1000, NULL, 0, NULL, false));
- EXPECT_EQ(0, entry1->ReadData(0, 500, NULL, 0, NULL));
- EXPECT_EQ(0, entry1->ReadData(0, 2000, NULL, 0, NULL));
- EXPECT_EQ(1000, entry1->GetDataSize(0));
- entry1->Close();
+ EXPECT_EQ(0, WriteData(entry, 0, 1000, NULL, 0, false));
+ EXPECT_EQ(0, ReadData(entry, 0, 500, NULL, 0));
+ EXPECT_EQ(0, ReadData(entry, 0, 2000, NULL, 0));
+ EXPECT_EQ(1000, entry->GetDataSize(0));
+
+ EXPECT_EQ(0, WriteData(entry, 0, 100000, NULL, 0, true));
+ EXPECT_EQ(0, ReadData(entry, 0, 50000, NULL, 0));
+ EXPECT_EQ(100000, entry->GetDataSize(0));
+
+ // Lets verify the actual content.
+ const int kSize = 20;
+ const char zeros[kSize] = {};
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
+
+ CacheTestFillBuffer(buffer->data(), kSize, false);
+ EXPECT_EQ(kSize, ReadData(entry, 0, 500, buffer, kSize));
+ EXPECT_TRUE(!memcmp(buffer->data(), zeros, kSize));
+
+ CacheTestFillBuffer(buffer->data(), kSize, false);
+ EXPECT_EQ(kSize, ReadData(entry, 0, 5000, buffer, kSize));
+ EXPECT_TRUE(!memcmp(buffer->data(), zeros, kSize));
+
+ CacheTestFillBuffer(buffer->data(), kSize, false);
+ EXPECT_EQ(kSize, ReadData(entry, 0, 50000, buffer, kSize));
+ EXPECT_TRUE(!memcmp(buffer->data(), zeros, kSize));
+
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, ZeroLengthIO) {
@@ -645,11 +692,155 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyZeroLengthIO) {
ZeroLengthIO();
}
+// Tests that we handle the content correctly when buffering.
+TEST_F(DiskCacheEntryTest, Buffering) {
+ InitCache();
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ 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);
+ CacheTestFillBuffer(buffer1->data(), kSize, true);
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+
+ EXPECT_EQ(kSize, WriteData(entry, 1, 0, buffer1, kSize, false));
+ entry->Close();
+
+ // Write a little more and read what we wrote before.
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 5000, buffer1, kSize, false));
+ EXPECT_EQ(kSize, ReadData(entry, 1, 0, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+
+ // Now go to an external file.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 18000, buffer1, kSize, false));
+ entry->Close();
+
+ // Write something else and verify old data.
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 10000, buffer1, kSize, false));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 5000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 0, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 18000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+
+ // Extend the file some more.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 23000, buffer1, kSize, false));
+ entry->Close();
+
+ // And now make sure that we can deal with data in both places (ram/disk).
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 17000, buffer1, kSize, false));
+
+ // We should not overwrite the data at 18000 with this.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 19000, buffer1, kSize, false));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 18000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 17000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+
+ EXPECT_EQ(kSize, WriteData(entry, 1, 22900, buffer1, kSize, false));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(100, ReadData(entry, 1, 23000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + 100, 100));
+
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(100, ReadData(entry, 1, 23100, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + 100, 100));
+
+ entry->Close();
+}
+
+// Some extra tests to make sure that buffering works properly when changing
+// the entry size.
+TEST_F(DiskCacheEntryTest, SizeChanges) {
+ InitCache();
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+
+ 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);
+ CacheTestFillBuffer(buffer1->data(), kSize, true);
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+
+ EXPECT_EQ(kSize, WriteData(entry, 1, 0, buffer1, kSize, true));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 17000, buffer1, kSize, true));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 23000, buffer1, kSize, true));
+ entry->Close();
+
+ // Extend the file and read between the old size and the new write.
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(23000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 25000, buffer1, kSize, true));
+ EXPECT_EQ(25000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, ReadData(entry, 1, 24000, buffer2, kSize));
+ 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_TRUE(!memcmp(buffer2->data(), buffer1->data() + kSize - 35, 35));
+
+ // Read slightly before the last write.
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 24900, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), zeros, 100));
+ EXPECT_TRUE(!memcmp(buffer2->data() + 100, buffer1->data(), kSize - 100));
+
+ // Extend the entry a little more.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 26000, buffer1, kSize, true));
+ EXPECT_EQ(26000 + kSize, entry->GetDataSize(1));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 25900, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), zeros, 100));
+ EXPECT_TRUE(!memcmp(buffer2->data() + 100, buffer1->data(), kSize - 100));
+
+ // And now reduce the size.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 25000, buffer1, kSize, true));
+ EXPECT_EQ(25000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(28, ReadData(entry, 1, 25000 + kSize - 28, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + kSize - 28, 28));
+
+ // Reduce the size with a buffer that is not extending the size.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 24000, buffer1, kSize, false));
+ EXPECT_EQ(25000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 24500, buffer1, kSize, true));
+ EXPECT_EQ(24500 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, ReadData(entry, 1, 23900, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), zeros, 100));
+ EXPECT_TRUE(!memcmp(buffer2->data() + 100, buffer1->data(), kSize - 100));
+
+ // And now reduce the size below the old size.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 19000, buffer1, kSize, true));
+ EXPECT_EQ(19000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, ReadData(entry, 1, 18900, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), zeros, 100));
+ EXPECT_TRUE(!memcmp(buffer2->data() + 100, buffer1->data(), kSize - 100));
+
+ // Verify that the actual file is truncated.
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(19000 + kSize, entry->GetDataSize(1));
+
+ entry->Close();
+}
+
// Write more than the total cache capacity but to a single entry. |size| is the
// amount of bytes to write each time.
void DiskCacheEntryTest::ReuseEntry(int size) {
std::string key1("the first key");
- disk_cache::Entry *entry;
+ disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry(key1, &entry));
entry->Close();
@@ -660,8 +851,8 @@ void DiskCacheEntryTest::ReuseEntry(int size) {
CacheTestFillBuffer(buffer->data(), size, false);
for (int i = 0; i < 15; i++) {
- EXPECT_EQ(0, entry->WriteData(0, 0, buffer, 0, NULL, true));
- EXPECT_EQ(size, entry->WriteData(0, 0, buffer, size, NULL, false));
+ EXPECT_EQ(0, WriteData(entry, 0, 0, buffer, 0, true));
+ EXPECT_EQ(size, WriteData(entry, 0, 0, buffer, size, false));
entry->Close();
ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
}
@@ -703,9 +894,9 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyReuseInternalEntry) {
// Reading somewhere that was not written should return zeros.
void DiskCacheEntryTest::InvalidData() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize1 = 20000;
const int kSize2 = 20000;
@@ -718,52 +909,52 @@ void DiskCacheEntryTest::InvalidData() {
memset(buffer2->data(), 0, kSize2);
// Simple data grow:
- EXPECT_EQ(200, entry1->WriteData(0, 400, buffer1, 200, NULL, false));
- EXPECT_EQ(600, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->ReadData(0, 300, buffer3, 100, NULL));
+ EXPECT_EQ(200, WriteData(entry, 0, 400, buffer1, 200, false));
+ EXPECT_EQ(600, entry->GetDataSize(0));
+ EXPECT_EQ(100, ReadData(entry, 0, 300, buffer3, 100));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 100));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry(key1, &entry1));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// The entry is now on disk. Load it and extend it.
- EXPECT_EQ(200, entry1->WriteData(0, 800, buffer1, 200, NULL, false));
- EXPECT_EQ(1000, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->ReadData(0, 700, buffer3, 100, NULL));
+ EXPECT_EQ(200, WriteData(entry, 0, 800, buffer1, 200, false));
+ EXPECT_EQ(1000, entry->GetDataSize(0));
+ EXPECT_EQ(100, ReadData(entry, 0, 700, buffer3, 100));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 100));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry(key1, &entry1));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// This time using truncate.
- EXPECT_EQ(200, entry1->WriteData(0, 1800, buffer1, 200, NULL, true));
- EXPECT_EQ(2000, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->ReadData(0, 1500, buffer3, 100, NULL));
+ EXPECT_EQ(200, WriteData(entry, 0, 1800, buffer1, 200, true));
+ EXPECT_EQ(2000, entry->GetDataSize(0));
+ EXPECT_EQ(100, ReadData(entry, 0, 1500, buffer3, 100));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 100));
// Go to an external file.
- EXPECT_EQ(200, entry1->WriteData(0, 19800, buffer1, 200, NULL, false));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(4000, entry1->ReadData(0, 14000, buffer3, 4000, NULL));
+ EXPECT_EQ(200, WriteData(entry, 0, 19800, buffer1, 200, false));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(4000, ReadData(entry, 0, 14000, buffer3, 4000));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 4000));
// And back to an internal block.
- EXPECT_EQ(600, entry1->WriteData(0, 1000, buffer1, 600, NULL, true));
- EXPECT_EQ(1600, entry1->GetDataSize(0));
- EXPECT_EQ(600, entry1->ReadData(0, 1000, buffer3, 600, NULL));
+ EXPECT_EQ(600, WriteData(entry, 0, 1000, buffer1, 600, true));
+ EXPECT_EQ(1600, entry->GetDataSize(0));
+ EXPECT_EQ(600, ReadData(entry, 0, 1000, buffer3, 600));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer1->data(), 600));
// Extend it again.
- EXPECT_EQ(600, entry1->WriteData(0, 2000, buffer1, 600, NULL, false));
- EXPECT_EQ(2600, entry1->GetDataSize(0));
- EXPECT_EQ(200, entry1->ReadData(0, 1800, buffer3, 200, NULL));
+ EXPECT_EQ(600, WriteData(entry, 0, 2000, buffer1, 600, false));
+ EXPECT_EQ(2600, entry->GetDataSize(0));
+ EXPECT_EQ(200, ReadData(entry, 0, 1800, buffer3, 200));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 200));
// And again (with truncation flag).
- EXPECT_EQ(600, entry1->WriteData(0, 3000, buffer1, 600, NULL, true));
- EXPECT_EQ(3600, entry1->GetDataSize(0));
- EXPECT_EQ(200, entry1->ReadData(0, 2800, buffer3, 200, NULL));
+ EXPECT_EQ(600, WriteData(entry, 0, 3000, buffer1, 600, true));
+ EXPECT_EQ(3600, entry->GetDataSize(0));
+ EXPECT_EQ(200, ReadData(entry, 0, 2800, buffer3, 200));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 200));
- entry1->Close();
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, InvalidData) {
@@ -778,23 +969,23 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyInvalidData) {
}
void DiskCacheEntryTest::DoomNormalEntry() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- entry1->Doom();
- entry1->Close();
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ entry->Doom();
+ entry->Close();
const int kSize = 20000;
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
CacheTestFillBuffer(buffer->data(), kSize, true);
buffer->data()[19999] = '\0';
- key1 = buffer->data();
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer, kSize, NULL, false));
- EXPECT_EQ(20000, entry1->WriteData(1, 0, buffer, kSize, NULL, false));
- entry1->Doom();
- entry1->Close();
+ key = buffer->data();
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_EQ(20000, WriteData(entry, 0, 0, buffer, kSize, false));
+ EXPECT_EQ(20000, WriteData(entry, 1, 0, buffer, kSize, false));
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
@@ -815,7 +1006,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyDoomEntry) {
// Verify that basic operations work as expected with doomed entries.
void DiskCacheEntryTest::DoomedEntry() {
std::string key("the first key");
- disk_cache::Entry *entry;
+ disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
entry->Doom();
@@ -831,8 +1022,8 @@ void DiskCacheEntryTest::DoomedEntry() {
CacheTestFillBuffer(buffer1->data(), kSize1, false);
memset(buffer2->data(), 0, kSize2);
- EXPECT_EQ(2000, entry->WriteData(0, 0, buffer1, 2000, NULL, false));
- EXPECT_EQ(2000, entry->ReadData(0, 0, buffer2, 2000, NULL));
+ EXPECT_EQ(2000, WriteData(entry, 0, 0, buffer1, 2000, false));
+ EXPECT_EQ(2000, ReadData(entry, 0, 0, buffer2, 2000));
EXPECT_EQ(0, memcmp(buffer1->data(), buffer2->data(), kSize1));
EXPECT_EQ(key, entry->GetKey());
EXPECT_TRUE(initial < entry->GetLastModified());
@@ -892,23 +1083,18 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyEnumerationWithSparseEntries) {
// Writes |buf_1| to offset and reads it back as |buf_2|.
void VerifySparseIO(disk_cache::Entry* entry, int64 offset,
- net::IOBuffer* buf_1, int size, bool async,
- net::IOBuffer* buf_2) {
- TestCompletionCallback callback;
- TestCompletionCallback* cb = async ? &callback : NULL;
+ net::IOBuffer* buf_1, int size, net::IOBuffer* buf_2) {
+ TestCompletionCallback cb;
memset(buf_2->data(), 0, size);
- int ret = entry->ReadSparseData(offset, buf_2, size, cb);
- ret = callback.GetResult(ret);
- EXPECT_EQ(0, ret);
+ int ret = entry->ReadSparseData(offset, buf_2, size, &cb);
+ EXPECT_EQ(0, cb.GetResult(ret));
- ret = entry->WriteSparseData(offset, buf_1, size, cb);
- ret = callback.GetResult(ret);
- EXPECT_EQ(size, ret);
+ ret = entry->WriteSparseData(offset, buf_1, size, &cb);
+ EXPECT_EQ(size, cb.GetResult(ret));
- ret = entry->ReadSparseData(offset, buf_2, size, cb);
- ret = callback.GetResult(ret);
- EXPECT_EQ(size, ret);
+ ret = entry->ReadSparseData(offset, buf_2, size, &cb);
+ EXPECT_EQ(size, cb.GetResult(ret));
EXPECT_EQ(0, memcmp(buf_1->data(), buf_2->data(), size));
}
@@ -916,20 +1102,18 @@ void VerifySparseIO(disk_cache::Entry* entry, int64 offset,
// Reads |size| bytes from |entry| at |offset| and verifies that they are the
// same as the content of the provided |buffer|.
void VerifyContentSparseIO(disk_cache::Entry* entry, int64 offset, char* buffer,
- int size, bool async) {
- TestCompletionCallback callback;
- TestCompletionCallback* cb = async ? &callback : NULL;
+ int size) {
+ TestCompletionCallback cb;
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);
- ret = callback.GetResult(ret);
- EXPECT_EQ(size, ret);
+ int ret = entry->ReadSparseData(offset, buf_1, size, &cb);
+ EXPECT_EQ(size, cb.GetResult(ret));
EXPECT_EQ(0, memcmp(buf_1->data(), buffer, size));
}
-void DiskCacheEntryTest::BasicSparseIO(bool async) {
+void DiskCacheEntryTest::BasicSparseIO() {
std::string key("the first key");
disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
@@ -940,47 +1124,36 @@ void DiskCacheEntryTest::BasicSparseIO(bool async) {
CacheTestFillBuffer(buf_1->data(), kSize, false);
// Write at offset 0.
- VerifySparseIO(entry, 0, buf_1, kSize, async, buf_2);
+ VerifySparseIO(entry, 0, buf_1, kSize, buf_2);
// Write at offset 0x400000 (4 MB).
- VerifySparseIO(entry, 0x400000, buf_1, kSize, async, buf_2);
+ VerifySparseIO(entry, 0x400000, buf_1, kSize, buf_2);
// Write at offset 0x800000000 (32 GB).
- VerifySparseIO(entry, 0x800000000LL, buf_1, kSize, async, buf_2);
+ VerifySparseIO(entry, 0x800000000LL, buf_1, kSize, buf_2);
entry->Close();
// Check everything again.
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
- VerifyContentSparseIO(entry, 0, buf_1->data(), kSize, async);
- VerifyContentSparseIO(entry, 0x400000, buf_1->data(), kSize, async);
- VerifyContentSparseIO(entry, 0x800000000LL, buf_1->data(), kSize, async);
+ VerifyContentSparseIO(entry, 0, buf_1->data(), kSize);
+ VerifyContentSparseIO(entry, 0x400000, buf_1->data(), kSize);
+ VerifyContentSparseIO(entry, 0x800000000LL, buf_1->data(), kSize);
entry->Close();
}
-TEST_F(DiskCacheEntryTest, BasicSparseSyncIO) {
+TEST_F(DiskCacheEntryTest, BasicSparseIO) {
InitCache();
- BasicSparseIO(false);
+ BasicSparseIO();
}
-TEST_F(DiskCacheEntryTest, MemoryOnlyBasicSparseSyncIO) {
+TEST_F(DiskCacheEntryTest, MemoryOnlyBasicSparseIO) {
SetMemoryOnlyMode();
InitCache();
- BasicSparseIO(false);
+ BasicSparseIO();
}
-TEST_F(DiskCacheEntryTest, BasicSparseAsyncIO) {
- InitCache();
- BasicSparseIO(true);
-}
-
-TEST_F(DiskCacheEntryTest, MemoryOnlyBasicSparseAsyncIO) {
- SetMemoryOnlyMode();
- InitCache();
- BasicSparseIO(true);
-}
-
-void DiskCacheEntryTest::HugeSparseIO(bool async) {
+void DiskCacheEntryTest::HugeSparseIO() {
std::string key("the first key");
disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
@@ -992,35 +1165,24 @@ void DiskCacheEntryTest::HugeSparseIO(bool async) {
CacheTestFillBuffer(buf_1->data(), kSize, false);
// Write at offset 0x20F0000 (33 MB - 64 KB).
- VerifySparseIO(entry, 0x20F0000, buf_1, kSize, async, buf_2);
+ VerifySparseIO(entry, 0x20F0000, buf_1, kSize, buf_2);
entry->Close();
// Check it again.
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
- VerifyContentSparseIO(entry, 0x20F0000, buf_1->data(), kSize, async);
+ VerifyContentSparseIO(entry, 0x20F0000, buf_1->data(), kSize);
entry->Close();
}
-TEST_F(DiskCacheEntryTest, HugeSparseSyncIO) {
- InitCache();
- HugeSparseIO(false);
-}
-
-TEST_F(DiskCacheEntryTest, MemoryOnlyHugeSparseSyncIO) {
- SetMemoryOnlyMode();
- InitCache();
- HugeSparseIO(false);
-}
-
-TEST_F(DiskCacheEntryTest, HugeSparseAsyncIO) {
+TEST_F(DiskCacheEntryTest, HugeSparseIO) {
InitCache();
- HugeSparseIO(true);
+ HugeSparseIO();
}
-TEST_F(DiskCacheEntryTest, MemoryOnlyHugeSparseAsyncIO) {
+TEST_F(DiskCacheEntryTest, MemoryOnlyHugeSparseIO) {
SetMemoryOnlyMode();
InitCache();
- HugeSparseIO(true);
+ HugeSparseIO();
}
void DiskCacheEntryTest::GetAvailableRange() {
@@ -1033,8 +1195,8 @@ void DiskCacheEntryTest::GetAvailableRange() {
CacheTestFillBuffer(buf->data(), kSize, false);
// Write at offset 0x20F0000 (33 MB - 64 KB), and 0x20F4400 (33 MB - 47 KB).
- EXPECT_EQ(kSize, entry->WriteSparseData(0x20F0000, buf, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(0x20F4400, buf, kSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 0x20F0000, buf, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 0x20F4400, buf, kSize));
// We stop at the first empty block.
int64 start;
@@ -1095,7 +1257,7 @@ void DiskCacheEntryTest::CouldBeSparse() {
CacheTestFillBuffer(buf->data(), kSize, false);
// Write at offset 0x20F0000 (33 MB - 64 KB).
- EXPECT_EQ(kSize, entry->WriteSparseData(0x20F0000, buf, kSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 0x20F0000, buf, kSize));
EXPECT_TRUE(entry->CouldBeSparse());
entry->Close();
@@ -1109,9 +1271,9 @@ void DiskCacheEntryTest::CouldBeSparse() {
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
EXPECT_FALSE(entry->CouldBeSparse());
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buf, kSize, NULL, false));
- EXPECT_EQ(kSize, entry->WriteData(1, 0, buf, kSize, NULL, false));
- EXPECT_EQ(kSize, entry->WriteData(2, 0, buf, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buf, kSize, false));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 0, buf, kSize, false));
+ EXPECT_EQ(kSize, WriteData(entry, 2, 0, buf, kSize, false));
EXPECT_FALSE(entry->CouldBeSparse());
entry->Close();
@@ -1149,16 +1311,16 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedSparseIO) {
for (int i = 0; i < kSize; i += 1024) {
scoped_refptr<net::WrappedIOBuffer> buf_3 =
new net::WrappedIOBuffer(buf_1->data() + i);
- VerifySparseIO(entry, i, buf_3, 1024, false, buf_2);
- VerifySparseIO(entry, 9000 + i, buf_3, 1024, false, buf_2);
+ VerifySparseIO(entry, i, buf_3, 1024, buf_2);
+ VerifySparseIO(entry, 9000 + i, buf_3, 1024, buf_2);
}
// Make sure we have data written.
- VerifyContentSparseIO(entry, 0, buf_1->data(), kSize, false);
- VerifyContentSparseIO(entry, 9000, buf_1->data(), kSize, false);
+ VerifyContentSparseIO(entry, 0, buf_1->data(), kSize);
+ VerifyContentSparseIO(entry, 9000, buf_1->data(), kSize);
// This tests a large write that spans 3 entries from a misaligned offset.
- VerifySparseIO(entry, 20481, buf_1, 8192, false, buf_2);
+ VerifySparseIO(entry, 20481, buf_1, 8192, buf_2);
entry->Close();
}
@@ -1352,10 +1514,9 @@ void DiskCacheEntryTest::PartialSparseEntry() {
// The first write is just to extend the entry. The third write occupies
// a 1KB block partially, it may not be written internally depending on the
// implementation.
- EXPECT_EQ(kSize, entry->WriteSparseData(20000, buf1, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(500, buf1, kSize, NULL));
- EXPECT_EQ(kSmallSize,
- entry->WriteSparseData(1080321, buf1, kSmallSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 20000, buf1, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 500, buf1, kSize));
+ EXPECT_EQ(kSmallSize, WriteSparseData(entry, 1080321, buf1, kSmallSize));
entry->Close();
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
@@ -1363,14 +1524,14 @@ void DiskCacheEntryTest::PartialSparseEntry() {
memset(buf2->data(), 0, kSize);
EXPECT_EQ(0, entry->ReadSparseData(8000, buf2, kSize, NULL));
- EXPECT_EQ(500, entry->ReadSparseData(kSize, buf2, kSize, NULL));
+ EXPECT_EQ(500, ReadSparseData(entry, kSize, buf2, kSize));
EXPECT_EQ(0, memcmp(buf2->data(), buf1->data() + kSize - 500, 500));
- EXPECT_EQ(0, entry->ReadSparseData(0, buf2, kSize, NULL));
+ EXPECT_EQ(0, ReadSparseData(entry, 0, buf2, kSize));
// This read should not change anything.
- EXPECT_EQ(96, entry->ReadSparseData(24000, buf2, kSize, NULL));
- EXPECT_EQ(500, entry->ReadSparseData(kSize, buf2, kSize, NULL));
- EXPECT_EQ(0, entry->ReadSparseData(499, buf2, kSize, NULL));
+ EXPECT_EQ(96, ReadSparseData(entry, 24000, buf2, kSize));
+ EXPECT_EQ(500, ReadSparseData(entry, kSize, buf2, kSize));
+ EXPECT_EQ(0, ReadSparseData(entry, 99, buf2, kSize));
int rv;
int64 start;
@@ -1411,11 +1572,11 @@ void DiskCacheEntryTest::PartialSparseEntry() {
EXPECT_EQ(4600, start);
// Now make another write and verify that there is no hole in between.
- EXPECT_EQ(kSize, entry->WriteSparseData(500 + kSize, buf1, kSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 500 + kSize, buf1, kSize));
rv = entry->GetAvailableRange(1024, 10000, &start, &cb);
EXPECT_EQ(7 * 1024 + 500, cb.GetResult(rv));
EXPECT_EQ(1024, start);
- EXPECT_EQ(kSize, entry->ReadSparseData(kSize, buf2, kSize, NULL));
+ EXPECT_EQ(kSize, ReadSparseData(entry, kSize, buf2, kSize));
EXPECT_EQ(0, memcmp(buf2->data(), buf1->data() + kSize - 500, 500));
EXPECT_EQ(0, memcmp(buf2->data() + 500, buf1->data(), kSize - 500));
@@ -1445,9 +1606,9 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) {
CacheTestFillBuffer(buf1->data(), kSize, false);
const int k1Meg = 1024 * 1024;
- EXPECT_EQ(kSize, entry->WriteSparseData(8192, buf1, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(k1Meg + 8192, buf1, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(2 * k1Meg + 8192, buf1, kSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 8192, buf1, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, k1Meg + 8192, buf1, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 2 * k1Meg + 8192, buf1, kSize));
entry->Close();
EXPECT_EQ(4, cache_->GetEntryCount());
@@ -1464,7 +1625,7 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) {
for (int i = 0; i < 2; i++) {
ASSERT_EQ(net::OK, OpenEntry(child_key[i], &entry));
// Overwrite the header's magic and signature.
- EXPECT_EQ(12, entry->WriteData(2, 0, buf1, 12, NULL, false));
+ EXPECT_EQ(12, WriteData(entry, 2, 0, buf1, 12, false));
entry->Close();
}
@@ -1472,12 +1633,12 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) {
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// Two children should be gone. One while reading and one while writing.
- EXPECT_EQ(0, entry->ReadSparseData(2 * k1Meg + 8192, buf1, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(k1Meg + 16384, buf1, kSize, NULL));
- EXPECT_EQ(0, entry->ReadSparseData(k1Meg + 8192, buf1, kSize, NULL));
+ EXPECT_EQ(0, ReadSparseData(entry, 2 * k1Meg + 8192, buf1, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, k1Meg + 16384, buf1, kSize));
+ EXPECT_EQ(0, ReadSparseData(entry, k1Meg + 8192, buf1, kSize));
// We never touched this one.
- EXPECT_EQ(kSize, entry->ReadSparseData(8192, buf1, kSize, NULL));
+ EXPECT_EQ(kSize, ReadSparseData(entry, 8192, buf1, kSize));
entry->Close();
// We re-created one of the corrupt children.
diff --git a/net/disk_cache/file.h b/net/disk_cache/file.h
index 2535866..43ba5c1 100644
--- a/net/disk_cache/file.h
+++ b/net/disk_cache/file.h
@@ -59,10 +59,6 @@ class File : public base::RefCounted<File> {
bool Write(const void* buffer, size_t buffer_len, size_t offset,
FileIOCallback* callback, bool* completed);
- // Performs asynchronous writes, but doesn't notify when done. Automatically
- // deletes buffer when done.
- bool PostWrite(const void* buffer, size_t buffer_len, size_t offset);
-
// Sets the file's length. The file is truncated or extended with zeros to
// the new length.
bool SetLength(size_t length);
@@ -77,7 +73,7 @@ class File : public base::RefCounted<File> {
// Performs the actual asynchronous write. If notify is set and there is no
// callback, the call will be re-synchronized.
bool AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
- bool notify, FileIOCallback* callback, bool* completed);
+ FileIOCallback* callback, bool* completed);
private:
bool init_;
diff --git a/net/disk_cache/file_posix.cc b/net/disk_cache/file_posix.cc
index 295f744..1d842ed 100644
--- a/net/disk_cache/file_posix.cc
+++ b/net/disk_cache/file_posix.cc
@@ -37,12 +37,11 @@ class BackgroundIO : public base::RefCountedThreadSafe<BackgroundIO> {
// Read and Write are the operations that can be performed asynchronously.
// The actual parameters for the operation are setup in the constructor of
- // the object, with the exception of |delete_buffer|, that allows a write
- // without a callback. Both methods should be called from a worker thread, by
- // posting a task to the WorkerPool (they are RunnableMethods). When finished,
+ // the object. Both methods should be called from a worker thread, by posting
+ // a task to the WorkerPool (they are RunnableMethods). When finished,
// controller->OnIOComplete() is called.
void Read();
- void Write(bool delete_buffer);
+ void Write();
// This method signals the controller that this operation is finished, in the
// original thread (presumably the IO-Thread). In practice, this is a
@@ -122,8 +121,7 @@ class InFlightIO {
void PostRead(disk_cache::File* file, void* buf, size_t buf_len,
size_t offset, disk_cache::FileIOCallback* callback);
void PostWrite(disk_cache::File* file, const void* buf, size_t buf_len,
- size_t offset, disk_cache::FileIOCallback* callback,
- bool delete_buffer);
+ size_t offset, disk_cache::FileIOCallback* callback);
// Blocks the current thread until all IO operations tracked by this object
// complete.
@@ -167,12 +165,8 @@ void BackgroundIO::Cancel() {
}
// Runs on a worker thread.
-void BackgroundIO::Write(bool delete_buffer) {
+void BackgroundIO::Write() {
bool rv = file_->Write(buf_, buf_len_, offset_);
- if (delete_buffer) {
- // TODO(rvargas): remove or update this code.
- delete[] reinterpret_cast<const char*>(buf_);
- }
bytes_ = rv ? static_cast<int>(buf_len_) : -1;
controller_->OnIOComplete(this);
@@ -203,8 +197,7 @@ 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,
- bool delete_buffer) {
+ disk_cache::FileIOCallback* callback) {
scoped_refptr<BackgroundIO> operation =
new BackgroundIO(file, buf, buf_len, offset, callback, this);
io_list_.insert(operation.get());
@@ -214,8 +207,7 @@ void InFlightIO::PostWrite(disk_cache::File* file, const void* buf,
callback_thread_ = MessageLoop::current();
WorkerPool::PostTask(FROM_HERE,
- NewRunnableMethod(operation.get(), &BackgroundIO::Write,
- delete_buffer),
+ NewRunnableMethod(operation.get(), &BackgroundIO::Write),
true);
}
@@ -342,22 +334,17 @@ bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
return Write(buffer, buffer_len, offset);
}
- return AsyncWrite(buffer, buffer_len, offset, true, callback, completed);
-}
-
-bool File::PostWrite(const void* buffer, size_t buffer_len, size_t offset) {
- DCHECK(init_);
- return AsyncWrite(buffer, buffer_len, offset, false, NULL, NULL);
+ return AsyncWrite(buffer, buffer_len, offset, callback, completed);
}
bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
- bool notify, FileIOCallback* callback, bool* completed) {
+ FileIOCallback* callback, bool* completed) {
DCHECK(init_);
if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
return false;
InFlightIO* io_operations = Singleton<InFlightIO>::get();
- io_operations->PostWrite(this, buffer, buffer_len, offset, callback, !notify);
+ io_operations->PostWrite(this, buffer, buffer_len, offset, callback);
if (completed)
*completed = false;
diff --git a/net/disk_cache/file_win.cc b/net/disk_cache/file_win.cc
index 2b1f20b..1ac6c24 100644
--- a/net/disk_cache/file_win.cc
+++ b/net/disk_cache/file_win.cc
@@ -15,7 +15,7 @@ namespace {
struct MyOverlapped {
MyOverlapped(disk_cache::File* file, size_t offset,
disk_cache::FileIOCallback* callback);
- ~MyOverlapped();
+ ~MyOverlapped() {}
OVERLAPPED* overlapped() {
return &context_.overlapped;
}
@@ -23,8 +23,6 @@ struct MyOverlapped {
MessageLoopForIO::IOContext context_;
scoped_refptr<disk_cache::File> file_;
disk_cache::FileIOCallback* callback_;
- const void* buffer_;
- bool delete_buffer_; // Delete the user buffer at completion.
};
COMPILE_ASSERT(!offsetof(MyOverlapped, context_), starts_with_overlapped);
@@ -60,15 +58,6 @@ MyOverlapped::MyOverlapped(disk_cache::File* file, size_t offset,
callback_ = callback;
}
-MyOverlapped::~MyOverlapped() {
- if (delete_buffer_) {
- DCHECK(!callback_);
- // This whole thing could be updated to use IOBuffer, but PostWrite is not
- // used at the moment. TODO(rvargas): remove or update this code.
- delete[] reinterpret_cast<const char*>(buffer_);
- }
-}
-
} // namespace
namespace disk_cache {
@@ -207,29 +196,18 @@ bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
return Write(buffer, buffer_len, offset);
}
- return AsyncWrite(buffer, buffer_len, offset, true, callback, completed);
-}
-
-bool File::PostWrite(const void* buffer, size_t buffer_len, size_t offset) {
- DCHECK(init_);
- return AsyncWrite(buffer, buffer_len, offset, false, NULL, NULL);
+ return AsyncWrite(buffer, buffer_len, offset, callback, completed);
}
bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
- bool notify, FileIOCallback* callback, bool* completed) {
+ FileIOCallback* callback, bool* completed) {
DCHECK(init_);
+ DCHECK(callback);
+ DCHECK(completed);
if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
return false;
MyOverlapped* data = new MyOverlapped(this, offset, callback);
- bool dummy_completed;
- if (!callback) {
- DCHECK(!notify);
- data->delete_buffer_ = true;
- data->buffer_ = buffer;
- completed = &dummy_completed;
- }
-
DWORD size = static_cast<DWORD>(buffer_len);
DWORD actual;