diff options
Diffstat (limited to 'net/disk_cache/sparse_control.cc')
-rw-r--r-- | net/disk_cache/sparse_control.cc | 167 |
1 files changed, 123 insertions, 44 deletions
diff --git a/net/disk_cache/sparse_control.cc b/net/disk_cache/sparse_control.cc index 4035bd3..66096a2 100644 --- a/net/disk_cache/sparse_control.cc +++ b/net/disk_cache/sparse_control.cc @@ -27,6 +27,12 @@ const int kSparseData = 1; // 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 @@ void ChildrenDeleter::DeleteChildren() { this, &ChildrenDeleter::DeleteChildren)); } -} +} // namespace. namespace disk_cache { @@ -336,44 +342,32 @@ bool SparseControl::OpenChild() { // 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_)) { - if (!entry_->backend_->CreateEntry(key, &child_)) { - child_ = NULL; - result_ = net::ERR_CACHE_READ_FAILURE; - return false; - } - // Write signature. - InitChildData(); - return true; - } + if (!child_present || !entry_->backend_->OpenEntry(key, &child_)) + return ContinueWithoutChild(key); 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 @@ std::string SparseControl::GenerateChildKey() { 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 @@ bool SparseControl::ChildPresent() { 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 @@ void SparseControl::WriteSparseData() { 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 @@ bool SparseControl::VerifyRange() { 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,12 +491,43 @@ void SparseControl::UpdateRange(int result) { 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++; + } + + int last_bit = (child_offset_ + result) >> 10; + block_offset = (child_offset_ + result) & (kBlockSize - 1); - // TODO(rvargas): Keep track of partial writes so that we don't consider the - // whole block to be present. + 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() { @@ -479,7 +545,7 @@ void SparseControl::InitChildData() { NULL, false); if (rv != sizeof(child_data_)) DLOG(ERROR) << "Failed to save child data"; - SetChildBit(); + SetChildBit(true); } void SparseControl::DoChildrenIO() { @@ -532,6 +598,8 @@ bool SparseControl::DoChildIO() { } return false; } + if (!rv) + return false; DoChildIOCompleted(rv); return true; @@ -544,9 +612,12 @@ int SparseControl::DoGetAvailableRange() { // 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,10 +626,18 @@ int SparseControl::DoGetAvailableRange() { // 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) |