summaryrefslogtreecommitdiffstats
path: root/net/disk_cache
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-23 22:07:36 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-23 22:07:36 +0000
commit5e892c20535dcbeae099f92148feea8473cf1445 (patch)
treee8d81957e354d53c94a5f99f5eea3ca1fdb71ea7 /net/disk_cache
parent1ca4a8b5e7fea30a0cd7437000e8381002f546af (diff)
downloadchromium_src-5e892c20535dcbeae099f92148feea8473cf1445.zip
chromium_src-5e892c20535dcbeae099f92148feea8473cf1445.tar.gz
chromium_src-5e892c20535dcbeae099f92148feea8473cf1445.tar.bz2
Disk Cache: Implement GetAvailableRange for the regular disk cache.
This is required to enable sparse caching. BUG=12258 TEST=unittest Review URL: http://codereview.chromium.org/146005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19069 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/disk_cache')
-rw-r--r--net/disk_cache/entry_unittest.cc56
-rw-r--r--net/disk_cache/sparse_control.cc90
-rw-r--r--net/disk_cache/sparse_control.h7
3 files changed, 136 insertions, 17 deletions
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index de9b153..7b7d5d3 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -37,6 +37,7 @@ class DiskCacheEntryTest : public DiskCacheTestWithCache {
void DoomedEntry();
void BasicSparseIO(bool async);
void HugeSparseIO(bool async);
+ void GetAvailableRange();
};
void DiskCacheEntryTest::InternalSyncIO() {
@@ -967,7 +968,7 @@ void DiskCacheEntryTest::HugeSparseIO(bool async) {
scoped_refptr<net::IOBuffer> buf_2 = new net::IOBuffer(kSize);
CacheTestFillBuffer(buf_1->data(), kSize, false);
- // Write at offset 0x20F0000 (20 MB - 64 KB).
+ // Write at offset 0x20F0000 (33 MB - 64 KB).
VerifySparseIO(entry, 0x20F0000, buf_1, kSize, async, buf_2);
entry->Close();
@@ -998,3 +999,56 @@ TEST_F(DiskCacheEntryTest, DISABLED_MemoryOnlyHugeSparseAsyncIO) {
InitCache();
HugeSparseIO(true);
}
+
+void DiskCacheEntryTest::GetAvailableRange() {
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_TRUE(cache_->CreateEntry(key, &entry));
+
+ const int kSize = 16 * 1024;
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize);
+ CacheTestFillBuffer(buf->data(), kSize, false);
+
+ // Write at offset 0x20F0000 (33 MB - 64 KB), and 0x20F4400 (33 MB - 47 KB).
+ EXPECT_EQ(kSize, entry->WriteSparseData(0x20F0000, buf, kSize, NULL));
+ EXPECT_EQ(kSize, entry->WriteSparseData(0x20F4400, buf, kSize, NULL));
+
+ // We stop at the first empty block.
+ int64 start;
+ EXPECT_EQ(kSize, entry->GetAvailableRange(0x20F0000, kSize * 2, &start));
+ EXPECT_EQ(0x20F0000, start);
+
+ start = 0;
+ EXPECT_EQ(0, entry->GetAvailableRange(0, kSize, &start));
+ EXPECT_EQ(0, entry->GetAvailableRange(0x20F0000 - kSize, kSize, &start));
+ EXPECT_EQ(kSize, entry->GetAvailableRange(0, 0x2100000, &start));
+ EXPECT_EQ(0x20F0000, start);
+
+ // We should be able to Read based on the results of GetAvailableRange.
+ start = -1;
+ EXPECT_EQ(0, entry->GetAvailableRange(0x2100000, kSize, &start));
+ EXPECT_EQ(0, entry->ReadSparseData(start, buf, kSize, NULL));
+
+ start = 0;
+ EXPECT_EQ(0x2000, entry->GetAvailableRange(0x20F2000, kSize, &start));
+ EXPECT_EQ(0x20F2000, start);
+ EXPECT_EQ(0x2000, entry->ReadSparseData(start, buf, kSize, NULL));
+
+ // Make sure that we respect the |len| argument.
+ start = 0;
+ EXPECT_EQ(1, entry->GetAvailableRange(0x20F0001 - kSize, kSize, &start));
+ EXPECT_EQ(0x20F0000, start);
+
+ entry->Close();
+}
+
+TEST_F(DiskCacheEntryTest, GetAvailableRange) {
+ InitCache();
+ GetAvailableRange();
+}
+
+TEST_F(DiskCacheEntryTest, DISABLED_MemoryOnlyGetAvailableRange) {
+ SetMemoryOnlyMode();
+ InitCache();
+ GetAvailableRange();
+}
diff --git a/net/disk_cache/sparse_control.cc b/net/disk_cache/sparse_control.cc
index 4550e5c..b94f0c5 100644
--- a/net/disk_cache/sparse_control.cc
+++ b/net/disk_cache/sparse_control.cc
@@ -71,16 +71,19 @@ int SparseControl::StartIO(SparseOperation op, int64 offset, net::IOBuffer* buf,
DCHECK(!user_buf_);
DCHECK(!user_callback_);
+ if (!buf && (op == kReadOperation || op == kWriteOperation))
+ return 0;
+
// Copy the operation parameters.
operation_ = op;
offset_ = offset;
- user_buf_ = new net::ReusedIOBuffer(buf, buf_len);
+ user_buf_ = buf ? new net::ReusedIOBuffer(buf, buf_len) : NULL;
buf_len_ = buf_len;
+ user_callback_ = callback;
result_ = 0;
pending_ = false;
finished_ = false;
- user_callback_ = callback;
DoChildrenIO();
@@ -97,8 +100,22 @@ int SparseControl::StartIO(SparseOperation op, int64 offset, net::IOBuffer* buf,
int SparseControl::GetAvailableRange(int64 offset, int len, int64* start) {
DCHECK(init_);
- NOTIMPLEMENTED();
- return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
+ // We don't support simultaneous IO for sparse data.
+ if (operation_ != kNoOperation)
+ return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
+
+ DCHECK(start);
+
+ range_found_ = false;
+ int result = StartIO(kGetRangeOperation, offset, NULL, len, NULL);
+ if (range_found_) {
+ *start = offset_;
+ return result;
+ }
+
+ // This is a failure. We want to return a valid start value in any case.
+ *start = offset;
+ return result < 0 ? result : 0; // Don't mask error codes to the caller.
}
// We are going to start using this entry to store sparse data, so we have to
@@ -181,8 +198,12 @@ bool SparseControl::OpenChild() {
// Se if we are tracking this child.
bool child_present = ChildPresent();
- if (kReadOperation == operation_ && !child_present)
- return false;
+ if (!child_present) {
+ if (kReadOperation == operation_)
+ return false;
+ if (kGetRangeOperation == operation_)
+ return true;
+ }
if (!child_present || !entry_->backend_->OpenEntry(key, &child_)) {
if (!entry_->backend_->CreateEntry(key, &child_)) {
@@ -273,7 +294,7 @@ bool SparseControl::VerifyRange() {
child_offset_ = static_cast<int>(offset_) & 0xfffff;
child_len_ = std::min(buf_len_, 0x100000 - child_offset_);
- // We can write to anywhere in this child.
+ // We can write to (or get info from) anywhere in this child.
if (operation_ != kReadOperation)
return true;
@@ -341,13 +362,20 @@ bool SparseControl::DoChildIO() {
net::CompletionCallback* callback = user_callback_ ? &child_callback_ : NULL;
int rv;
- if (kReadOperation == operation_) {
- rv = child_->ReadData(kSparseData, child_offset_, user_buf_, child_len_,
- callback);
- } else {
- DCHECK(kWriteOperation == operation_);
- rv = child_->WriteData(kSparseData, child_offset_, user_buf_, child_len_,
- callback, false);
+ switch (operation_) {
+ case kReadOperation:
+ rv = child_->ReadData(kSparseData, child_offset_, user_buf_, child_len_,
+ callback);
+ break;
+ case kWriteOperation:
+ rv = child_->WriteData(kSparseData, child_offset_, user_buf_, child_len_,
+ callback, false);
+ break;
+ case kGetRangeOperation:
+ rv = DoGetAvailableRange();
+ break;
+ default:
+ NOTREACHED();
}
if (rv == net::ERR_IO_PENDING) {
@@ -366,6 +394,38 @@ bool SparseControl::DoChildIO() {
return true;
}
+int SparseControl::DoGetAvailableRange() {
+ if (!child_)
+ return child_len_; // Move on to the next child.
+
+ // Check that there are no holes in this range.
+ int last_bit = (child_offset_ + child_len_ + 1023) >> 10;
+ int start = child_offset_ >> 10;
+ int bits_found = child_map_.FindBits(&start, last_bit, true);
+
+ if (!bits_found)
+ return child_len_;
+
+ // We are done. Just break the loop and reset result_ to our real result.
+ range_found_ = true;
+
+ // start now points to the first 1. Lets see if we have zeros before it.
+ int empty_start = (start << 10) - child_offset_;
+
+ // If the user is searching past the end of this child, bits_found is the
+ // right result; otherwise, we have some empty space at the start of this
+ // query that we have to substarct from the range that we searched.
+ result_ = std::min(bits_found << 10, child_len_ - empty_start);
+
+ // Only update offset_ when this query found zeros at the start.
+ if (empty_start)
+ offset_ += empty_start;
+
+ // This will actually break the loop.
+ buf_len_ = 0;
+ return 0;
+}
+
void SparseControl::DoChildIOCompleted(int result) {
if (result < 0) {
// We fail the whole operation if we encounter an error.
@@ -380,7 +440,7 @@ void SparseControl::DoChildIOCompleted(int result) {
buf_len_ -= result;
// We'll be reusing the user provided buffer for the next chunk.
- if (buf_len_)
+ if (buf_len_ && user_buf_)
user_buf_->SetOffset(result_);
}
diff --git a/net/disk_cache/sparse_control.h b/net/disk_cache/sparse_control.h
index fe65035..0c696ea 100644
--- a/net/disk_cache/sparse_control.h
+++ b/net/disk_cache/sparse_control.h
@@ -34,7 +34,8 @@ class SparseControl {
enum SparseOperation {
kNoOperation,
kReadOperation,
- kWriteOperation
+ kWriteOperation,
+ kGetRangeOperation
};
explicit SparseControl(EntryImpl* entry)
@@ -109,6 +110,9 @@ class SparseControl {
// work.
bool DoChildIO();
+ // Performs the required work for GetAvailableRange for one child.
+ int DoGetAvailableRange();
+
// Performs the required work after a single IO operations finishes.
void DoChildIOCompleted(int result);
@@ -124,6 +128,7 @@ class SparseControl {
bool pending_; // True if any child IO operation returned pending.
bool finished_;
bool init_;
+ bool range_found_; // True if GetAvailableRange found something.
SparseHeader sparse_header_; // Data about the children of entry_.
Bitmap children_map_; // The actual bitmap of children.