| Index: net/disk_cache/sparse_control.cc
|
| ===================================================================
|
| --- net/disk_cache/sparse_control.cc (revision 20517)
|
| +++ net/disk_cache/sparse_control.cc (working copy)
|
| @@ -27,6 +27,12 @@
|
| // We can have up to 64k children.
|
| const int kMaxMapSize = 8 * 1024;
|
|
|
| +// The maximum number of bytes that a child can store.
|
| +const int kMaxEntrySize = 0x100000;
|
| +
|
| +// The size of each data block (tracked by the child allocation bitmap).
|
| +const int kBlockSize = 1024;
|
| +
|
| // Returns the name of of a child entry given the base_name and signature of the
|
| // parent and the child_id.
|
| // If the entry is called entry_name, child entries will be named something
|
| @@ -124,7 +130,7 @@
|
| this, &ChildrenDeleter::DeleteChildren));
|
| }
|
|
|
| -}
|
| +} // namespace.
|
|
|
| namespace disk_cache {
|
|
|
| @@ -336,44 +342,32 @@
|
|
|
| // Se if we are tracking this child.
|
| bool child_present = ChildPresent();
|
| - if (!child_present) {
|
| - if (kReadOperation == operation_)
|
| - return false;
|
| - if (kGetRangeOperation == operation_)
|
| - return true;
|
| - }
|
| + if (!child_present || !entry_->backend_->OpenEntry(key, &child_))
|
| + return ContinueWithoutChild(key);
|
|
|
| - if (!child_present || !entry_->backend_->OpenEntry(key, &child_)) {
|
| - if (!entry_->backend_->CreateEntry(key, &child_)) {
|
| - child_ = NULL;
|
| - result_ = net::ERR_CACHE_READ_FAILURE;
|
| - return false;
|
| - }
|
| - // Write signature.
|
| - InitChildData();
|
| - return true;
|
| - }
|
| -
|
| EntryImpl* child = static_cast<EntryImpl*>(child_);
|
| - if (!(CHILD_ENTRY & child->GetEntryFlags())) {
|
| - result_ = net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
|
| - return false;
|
| - }
|
| + if (!(CHILD_ENTRY & child->GetEntryFlags()) ||
|
| + child->GetDataSize(kSparseIndex) <
|
| + static_cast<int>(sizeof(child_data_)))
|
| + return KillChildAndContinue(key, false);
|
|
|
| scoped_refptr<net::WrappedIOBuffer> buf =
|
| new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_));
|
|
|
| // Read signature.
|
| int rv = child_->ReadData(kSparseIndex, 0, buf, sizeof(child_data_), NULL);
|
| - if (rv != sizeof(child_data_)) {
|
| - result_ = net::ERR_CACHE_READ_FAILURE;
|
| - return false;
|
| - }
|
| + if (rv != sizeof(child_data_))
|
| + return KillChildAndContinue(key, true); // This is a fatal failure.
|
|
|
| - // TODO(rvargas): Proper error handling and check magic etc.
|
| - if (child_data_.header.signature != sparse_header_.signature) {
|
| - result_ = net::ERR_CACHE_READ_FAILURE;
|
| - return false;
|
| + if (child_data_.header.signature != sparse_header_.signature ||
|
| + child_data_.header.magic != kIndexMagic)
|
| + return KillChildAndContinue(key, false);
|
| +
|
| + if (child_data_.header.last_block_len < 0 ||
|
| + child_data_.header.last_block_len > kBlockSize) {
|
| + // Make sure this values are always within range.
|
| + child_data_.header.last_block_len = 0;
|
| + child_data_.header.last_block = -1;
|
| }
|
|
|
| return true;
|
| @@ -397,6 +391,36 @@
|
| offset_ >> 20);
|
| }
|
|
|
| +// We are deleting the child because something went wrong.
|
| +bool SparseControl::KillChildAndContinue(const std::string& key, bool fatal) {
|
| + SetChildBit(false);
|
| + child_->Doom();
|
| + child_->Close();
|
| + child_ = NULL;
|
| + if (fatal) {
|
| + result_ = net::ERR_CACHE_READ_FAILURE;
|
| + return false;
|
| + }
|
| + return ContinueWithoutChild(key);
|
| +}
|
| +
|
| +// We were not able to open this child; see what we can do.
|
| +bool SparseControl::ContinueWithoutChild(const std::string& key) {
|
| + if (kReadOperation == operation_)
|
| + return false;
|
| + if (kGetRangeOperation == operation_)
|
| + return true;
|
| +
|
| + if (!entry_->backend_->CreateEntry(key, &child_)) {
|
| + child_ = NULL;
|
| + result_ = net::ERR_CACHE_READ_FAILURE;
|
| + return false;
|
| + }
|
| + // Write signature.
|
| + InitChildData();
|
| + return true;
|
| +}
|
| +
|
| bool SparseControl::ChildPresent() {
|
| int child_bit = static_cast<int>(offset_ >> 20);
|
| if (children_map_.Size() <= child_bit)
|
| @@ -405,14 +429,14 @@
|
| return children_map_.Get(child_bit);
|
| }
|
|
|
| -void SparseControl::SetChildBit() {
|
| +void SparseControl::SetChildBit(bool value) {
|
| int child_bit = static_cast<int>(offset_ >> 20);
|
|
|
| // We may have to increase the bitmap of child entries.
|
| if (children_map_.Size() <= child_bit)
|
| children_map_.Resize(Bitmap::RequiredArraySize(child_bit + 1) * 32, true);
|
|
|
| - children_map_.Set(child_bit, true);
|
| + children_map_.Set(child_bit, value);
|
| }
|
|
|
| void SparseControl::WriteSparseData() {
|
| @@ -430,8 +454,8 @@
|
| bool SparseControl::VerifyRange() {
|
| DCHECK_GE(result_, 0);
|
|
|
| - child_offset_ = static_cast<int>(offset_) & 0xfffff;
|
| - child_len_ = std::min(buf_len_, 0x100000 - child_offset_);
|
| + child_offset_ = static_cast<int>(offset_) & (kMaxEntrySize - 1);
|
| + child_len_ = std::min(buf_len_, kMaxEntrySize - child_offset_);
|
|
|
| // We can write to (or get info from) anywhere in this child.
|
| if (operation_ != kReadOperation)
|
| @@ -442,12 +466,23 @@
|
| int start = child_offset_ >> 10;
|
| if (child_map_.FindNextBit(&start, last_bit, false)) {
|
| // Something is not here.
|
| - if (start == child_offset_ >> 10)
|
| - return false;
|
| + DCHECK_GE(child_data_.header.last_block_len, 0);
|
| + DCHECK_LT(child_data_.header.last_block_len, kMaxEntrySize);
|
| + int partial_block_len = PartialBlockLength(start);
|
| + if (start == child_offset_ >> 10) {
|
| + // It looks like we don't have anything.
|
| + if (partial_block_len <= (child_offset_ & (kBlockSize - 1)))
|
| + return false;
|
| + }
|
|
|
| // We have the first part.
|
| - // TODO(rvargas): Avoid coming back here again after the actual read.
|
| child_len_ = (start << 10) - child_offset_;
|
| + if (partial_block_len) {
|
| + // We may have a few extra bytes.
|
| + child_len_ = std::min(child_len_ + partial_block_len, buf_len_);
|
| + }
|
| + // There is no need to read more after this one.
|
| + buf_len_ = child_len_;
|
| }
|
| return true;
|
| }
|
| @@ -456,14 +491,45 @@
|
| if (result <= 0 || operation_ != kWriteOperation)
|
| return;
|
|
|
| + DCHECK_GE(child_data_.header.last_block_len, 0);
|
| + DCHECK_LT(child_data_.header.last_block_len, kMaxEntrySize);
|
| +
|
| // Write the bitmap.
|
| - int last_bit = (child_offset_ + result + 1023) >> 10;
|
| - child_map_.SetRange(child_offset_ >> 10, last_bit, true);
|
| + int first_bit = child_offset_ >> 10;
|
| + int block_offset = child_offset_ & (kBlockSize - 1);
|
| + if (block_offset && (child_data_.header.last_block != first_bit ||
|
| + child_data_.header.last_block_len < block_offset)) {
|
| + // The first block is not completely filled; ignore it.
|
| + first_bit++;
|
| + }
|
|
|
| - // TODO(rvargas): Keep track of partial writes so that we don't consider the
|
| - // whole block to be present.
|
| + int last_bit = (child_offset_ + result) >> 10;
|
| + block_offset = (child_offset_ + result) & (kBlockSize - 1);
|
| +
|
| + if (block_offset && !child_map_.Get(last_bit)) {
|
| + // The last block is not completely filled; save it for later.
|
| + child_data_.header.last_block = last_bit;
|
| + child_data_.header.last_block_len = block_offset;
|
| + } else {
|
| + child_data_.header.last_block = -1;
|
| + }
|
| +
|
| + child_map_.SetRange(first_bit, last_bit, true);
|
| }
|
|
|
| +int SparseControl::PartialBlockLength(int block_index) const {
|
| + if (block_index == child_data_.header.last_block)
|
| + return child_data_.header.last_block_len;
|
| +
|
| + // This may be the last stored index.
|
| + int entry_len = child_->GetDataSize(kSparseData);
|
| + if (block_index == entry_len >> 10)
|
| + return entry_len & (kBlockSize - 1);
|
| +
|
| + // This is really empty.
|
| + return 0;
|
| +}
|
| +
|
| void SparseControl::InitChildData() {
|
| // We know the real type of child_.
|
| EntryImpl* child = static_cast<EntryImpl*>(child_);
|
| @@ -479,7 +545,7 @@
|
| NULL, false);
|
| if (rv != sizeof(child_data_))
|
| DLOG(ERROR) << "Failed to save child data";
|
| - SetChildBit();
|
| + SetChildBit(true);
|
| }
|
|
|
| void SparseControl::DoChildrenIO() {
|
| @@ -532,6 +598,8 @@
|
| }
|
| return false;
|
| }
|
| + if (!rv)
|
| + return false;
|
|
|
| DoChildIOCompleted(rv);
|
| return true;
|
| @@ -544,9 +612,12 @@
|
| // Check that there are no holes in this range.
|
| int last_bit = (child_offset_ + child_len_ + 1023) >> 10;
|
| int start = child_offset_ >> 10;
|
| + int partial_start_bytes = PartialBlockLength(start);
|
| int bits_found = child_map_.FindBits(&start, last_bit, true);
|
|
|
| - if (!bits_found)
|
| + // We don't care if there is a partial block in the middle of the range.
|
| + int block_offset = child_offset_ & (kBlockSize - 1);
|
| + if (!bits_found && partial_start_bytes <= block_offset)
|
| return child_len_;
|
|
|
| // We are done. Just break the loop and reset result_ to our real result.
|
| @@ -555,11 +626,19 @@
|
| // start now points to the first 1. Lets see if we have zeros before it.
|
| int empty_start = (start << 10) - child_offset_;
|
|
|
| + int bytes_found = bits_found << 10;
|
| + bytes_found += PartialBlockLength(start + bits_found);
|
| +
|
| // 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);
|
| + result_ = std::min(bytes_found, child_len_ - empty_start);
|
|
|
| + if (!bits_found) {
|
| + result_ = std::min(partial_start_bytes - block_offset, child_len_);
|
| + empty_start = 0;
|
| + }
|
| +
|
| // Only update offset_ when this query found zeros at the start.
|
| if (empty_start)
|
| offset_ += empty_start;
|
|
|