| Index: net/disk_cache/sparse_control.cc
|
| ===================================================================
|
| --- net/disk_cache/sparse_control.cc (revision 20076)
|
| +++ net/disk_cache/sparse_control.cc (working copy)
|
| @@ -5,12 +5,14 @@
|
| #include "net/disk_cache/sparse_control.h"
|
|
|
| #include "base/logging.h"
|
| +#include "base/message_loop.h"
|
| #include "base/string_util.h"
|
| #include "base/time.h"
|
| #include "net/base/io_buffer.h"
|
| #include "net/base/net_errors.h"
|
| #include "net/disk_cache/backend_impl.h"
|
| #include "net/disk_cache/entry_impl.h"
|
| +#include "net/disk_cache/file.h"
|
|
|
| using base::Time;
|
|
|
| @@ -22,8 +24,108 @@
|
| // Stream of the sparse data.
|
| const int kSparseData = 1;
|
|
|
| +// We can have up to 64k children.
|
| +const int kMaxMapSize = 8 * 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
|
| +// like Range_entry_name:XXX:YYY where XXX is the entry signature and YYY is the
|
| +// number of the particular child.
|
| +std::string GenerateChildName(const std::string& base_name, int64 signature,
|
| + int64 child_id) {
|
| + return StringPrintf("Range_%s:%llx:%llx", base_name.c_str(), signature,
|
| + child_id);
|
| }
|
|
|
| +// This class deletes the children of a sparse entry.
|
| +class ChildrenDeleter
|
| + : public base::RefCounted<ChildrenDeleter>,
|
| + public disk_cache::FileIOCallback {
|
| + public:
|
| + ChildrenDeleter(disk_cache::BackendImpl* backend, const std::string& name)
|
| + : backend_(backend), name_(name) {}
|
| +
|
| + virtual void OnFileIOComplete(int bytes_copied);
|
| +
|
| + // Two ways of deleting the children: if we have the children map, use Start()
|
| + // directly, otherwise pass the data address to ReadData().
|
| + void Start(char* buffer, int len);
|
| + void ReadData(disk_cache::Addr address, int len);
|
| +
|
| + private:
|
| + void DeleteChildren();
|
| +
|
| + disk_cache::BackendImpl* backend_;
|
| + std::string name_;
|
| + disk_cache::Bitmap children_map_;
|
| + int64 signature_;
|
| + scoped_array<char> buffer_;
|
| + DISALLOW_EVIL_CONSTRUCTORS(ChildrenDeleter);
|
| +};
|
| +
|
| +// This is the callback of the file operation.
|
| +void ChildrenDeleter::OnFileIOComplete(int bytes_copied) {
|
| + char* buffer = buffer_.release();
|
| + Start(buffer, bytes_copied);
|
| +}
|
| +
|
| +void ChildrenDeleter::Start(char* buffer, int len) {
|
| + buffer_.reset(buffer);
|
| + if (len < static_cast<int>(sizeof(disk_cache::SparseData)))
|
| + return Release();
|
| +
|
| + // Just copy the information from |buffer|, delete |buffer| and start deleting
|
| + // the child entries.
|
| + disk_cache::SparseData* data =
|
| + reinterpret_cast<disk_cache::SparseData*>(buffer);
|
| + signature_ = data->header.signature;
|
| +
|
| + int num_bits = (len - sizeof(disk_cache::SparseHeader)) * 8;
|
| + children_map_.Resize(num_bits, false);
|
| + children_map_.SetMap(data->bitmap, num_bits / 32);
|
| + buffer_.reset();
|
| +
|
| + DeleteChildren();
|
| +}
|
| +
|
| +void ChildrenDeleter::ReadData(disk_cache::Addr address, int len) {
|
| + DCHECK(address.is_block_file());
|
| + disk_cache::File* file(backend_->File(address));
|
| + if (!file)
|
| + return Release();
|
| +
|
| + size_t file_offset = address.start_block() * address.BlockSize() +
|
| + disk_cache::kBlockHeaderSize;
|
| +
|
| + buffer_.reset(new char[len]);
|
| + bool completed;
|
| + if (!file->Read(buffer_.get(), len, file_offset, this, &completed))
|
| + return Release();
|
| +
|
| + if (completed)
|
| + OnFileIOComplete(len);
|
| +
|
| + // And wait until OnFileIOComplete gets called.
|
| +}
|
| +
|
| +void ChildrenDeleter::DeleteChildren() {
|
| + int child_id = 0;
|
| + if (!children_map_.FindNextSetBit(&child_id)) {
|
| + // We are done. Just delete this object.
|
| + return Release();
|
| + }
|
| + std::string child_name = GenerateChildName(name_, signature_, child_id);
|
| + backend_->DoomEntry(child_name);
|
| + children_map_.Set(child_id, false);
|
| +
|
| + // Post a task to delete the next child.
|
| + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
|
| + this, &ChildrenDeleter::DeleteChildren));
|
| +}
|
| +
|
| +}
|
| +
|
| namespace disk_cache {
|
|
|
| SparseControl::~SparseControl() {
|
| @@ -118,10 +220,43 @@
|
| return result < 0 ? result : 0; // Don't mask error codes to the caller.
|
| }
|
|
|
| +// Static
|
| +void SparseControl::DeleteChildren(EntryImpl* entry) {
|
| + DCHECK(entry->GetEntryFlags() & PARENT_ENTRY);
|
| + int data_len = entry->GetDataSize(kSparseIndex);
|
| + if (data_len < static_cast<int>(sizeof(SparseData)) ||
|
| + entry->GetDataSize(kSparseData))
|
| + return;
|
| +
|
| + int map_len = data_len - sizeof(SparseHeader);
|
| + if (map_len > kMaxMapSize || map_len % 4)
|
| + return;
|
| +
|
| + char* buffer;
|
| + Addr address;
|
| + entry->GetData(kSparseIndex, &buffer, &address);
|
| + if (!buffer && !address.is_initialized())
|
| + return;
|
| +
|
| + ChildrenDeleter* deleter = new ChildrenDeleter(entry->backend_,
|
| + entry->GetKey());
|
| + // The object will self destruct when finished.
|
| + deleter->AddRef();
|
| +
|
| + if (buffer) {
|
| + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
|
| + deleter, &ChildrenDeleter::Start, buffer, data_len));
|
| + } else {
|
| + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
|
| + deleter, &ChildrenDeleter::ReadData, address, data_len));
|
| + }
|
| +}
|
| +
|
| // We are going to start using this entry to store sparse data, so we have to
|
| // initialize our control info.
|
| int SparseControl::CreateSparseEntry() {
|
| - // TODO(rvargas): Set/check a flag in EntryStore.
|
| + if (CHILD_ENTRY & entry_->GetEntryFlags())
|
| + return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
|
|
|
| memset(&sparse_header_, 0, sizeof(sparse_header_));
|
| sparse_header_.signature = Time::Now().ToInternalValue();
|
| @@ -139,6 +274,8 @@
|
| DLOG(ERROR) << "Unable to save sparse_header_";
|
| return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
|
| }
|
| +
|
| + entry_->SetEntryFlags(PARENT_ENTRY);
|
| return net::OK;
|
| }
|
|
|
| @@ -150,11 +287,12 @@
|
| if (entry_->GetDataSize(kSparseData))
|
| return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
|
|
|
| - // TODO(rvargas): Set/check a flag in EntryStore.
|
| + if (!(PARENT_ENTRY & entry_->GetEntryFlags()))
|
| + return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
|
|
|
| // Dont't go over board with the bitmap. 8 KB gives us offsets up to 64 GB.
|
| int map_len = data_len - sizeof(sparse_header_);
|
| - if (map_len > 8 * 1024 || map_len % 4)
|
| + if (map_len > kMaxMapSize || map_len % 4)
|
| return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
|
|
|
| scoped_refptr<net::IOBuffer> buf =
|
| @@ -216,7 +354,11 @@
|
| return true;
|
| }
|
|
|
| - // TODO(rvargas): Set/check a flag in EntryStore.
|
| + EntryImpl* child = static_cast<EntryImpl*>(child_);
|
| + if (!(CHILD_ENTRY & child->GetEntryFlags())) {
|
| + result_ = net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
|
| + return false;
|
| + }
|
|
|
| scoped_refptr<net::WrappedIOBuffer> buf =
|
| new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_));
|
| @@ -250,17 +392,14 @@
|
| child_ = NULL;
|
| }
|
|
|
| -// If this entry is called entry_name, child entreies will be named something
|
| -// like Range_entry_name:XXX:YYY where XXX is the entry signature and YYY is the
|
| -// number of the particular child.
|
| std::string SparseControl::GenerateChildKey() {
|
| - return StringPrintf("Range_%s:%llx:%llx", entry_->GetKey().c_str(),
|
| - sparse_header_.signature, offset_ >> 20);
|
| + return GenerateChildName(entry_->GetKey(), sparse_header_.signature,
|
| + offset_ >> 20);
|
| }
|
|
|
| bool SparseControl::ChildPresent() {
|
| int child_bit = static_cast<int>(offset_ >> 20);
|
| - if (children_map_.Size() < child_bit)
|
| + if (children_map_.Size() <= child_bit)
|
| return false;
|
|
|
| return children_map_.Get(child_bit);
|
| @@ -326,6 +465,10 @@
|
| }
|
|
|
| void SparseControl::InitChildData() {
|
| + // We know the real type of child_.
|
| + EntryImpl* child = static_cast<EntryImpl*>(child_);
|
| + child->SetEntryFlags(CHILD_ENTRY);
|
| +
|
| memset(&child_data_, 0, sizeof(child_data_));
|
| child_data_.header = sparse_header_;
|
|
|
|
|