Index: net/disk_cache/v3/sparse_control_v3.cc |
=================================================================== |
--- net/disk_cache/v3/sparse_control_v3.cc (revision 232523) |
+++ net/disk_cache/v3/sparse_control_v3.cc (working copy) |
@@ -2,23 +2,22 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "net/disk_cache/sparse_control.h" |
+#include "net/disk_cache/v3/sparse_control_v3.h" |
#include "base/bind.h" |
#include "base/format_macros.h" |
#include "base/logging.h" |
#include "base/message_loop/message_loop.h" |
-#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
#include "base/time/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" |
#include "net/disk_cache/net_log_parameters.h" |
+#include "net/disk_cache/v3/backend_impl_v3.h" |
+#include "net/disk_cache/v3/entry_impl_v3.h" |
using base::Time; |
+using base::Bind; |
namespace { |
@@ -49,57 +48,49 @@ |
} |
// This class deletes the children of a sparse entry. |
-class ChildrenDeleter |
- : public base::RefCounted<ChildrenDeleter>, |
- public disk_cache::FileIOCallback { |
+class ChildrenDeleter : public base::RefCountedThreadSafe<ChildrenDeleter> { |
public: |
- ChildrenDeleter(disk_cache::BackendImpl* backend, const std::string& name) |
+ ChildrenDeleter(disk_cache::BackendImplV3* backend, const std::string& name) |
: backend_(backend->GetWeakPtr()), name_(name), signature_(0) {} |
- virtual void OnFileIOComplete(int bytes_copied) OVERRIDE; |
- |
// 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 Start(net::IOBuffer* buffer, int len); |
void ReadData(disk_cache::Addr address, int len); |
private: |
- friend class base::RefCounted<ChildrenDeleter>; |
+ friend class base::RefCountedThreadSafe<ChildrenDeleter>; |
virtual ~ChildrenDeleter() {} |
void DeleteChildren(); |
+ void OnReadComplete(int result); |
+ void OnDoomComplete(int result); |
- base::WeakPtr<disk_cache::BackendImpl> backend_; |
+ base::WeakPtr<disk_cache::BackendImplV3> backend_; |
std::string name_; |
disk_cache::Bitmap children_map_; |
int64 signature_; |
- scoped_ptr<char[]> buffer_; |
+ scoped_refptr<net::IOBuffer> buffer_; |
DISALLOW_COPY_AND_ASSIGN(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); |
+void ChildrenDeleter::Start(net::IOBuffer* buffer, int len) { |
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); |
+ reinterpret_cast<disk_cache::SparseData*>(buffer->data()); |
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(); |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ Bind(&ChildrenDeleter::DeleteChildren, |
+ this)); |
} |
void ChildrenDeleter::ReadData(disk_cache::Addr address, int len) { |
@@ -107,50 +98,44 @@ |
if (!backend_) |
return Release(); |
- 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. |
+ buffer_ = new net::IOBuffer(len); |
+ backend_->ReadData(NULL, address, 0, buffer_, len, |
+ Bind(&ChildrenDeleter::OnReadComplete, this)); |
} |
void ChildrenDeleter::DeleteChildren() { |
int child_id = 0; |
- if (!children_map_.FindNextSetBit(&child_id) || !backend_) { |
- // We are done. Just delete this object. |
- return Release(); |
+ for (int rv = net::OK; rv != net::ERR_IO_PENDING;) { |
+ if (!children_map_.FindNextSetBit(&child_id) || !backend_) { |
+ // We are done. Just delete this object. |
+ return Release(); |
+ } |
+ std::string child_name = GenerateChildName(name_, signature_, child_id); |
+ rv = backend_->DoomEntry(child_name, |
+ Bind(&ChildrenDeleter::OnDoomComplete, this)); |
+ children_map_.Set(child_id, false); |
} |
- std::string child_name = GenerateChildName(name_, signature_, child_id); |
- backend_->SyncDoomEntry(child_name); |
- children_map_.Set(child_id, false); |
+} |
- // Post a task to delete the next child. |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&ChildrenDeleter::DeleteChildren, this)); |
+void ChildrenDeleter::OnReadComplete(int result) { |
+ Start(buffer_, result); |
} |
+void ChildrenDeleter::OnDoomComplete(int result) { |
+ DeleteChildren(); |
+} |
+ |
// ----------------------------------------------------------------------- |
// Returns the NetLog event type corresponding to a SparseOperation. |
net::NetLog::EventType GetSparseEventType( |
- disk_cache::SparseControl::SparseOperation operation) { |
+ disk_cache::SparseControlV3::SparseOperation operation) { |
switch (operation) { |
- case disk_cache::SparseControl::kReadOperation: |
+ case disk_cache::SparseControlV3::kReadOperation: |
return net::NetLog::TYPE_SPARSE_READ; |
- case disk_cache::SparseControl::kWriteOperation: |
+ case disk_cache::SparseControlV3::kWriteOperation: |
return net::NetLog::TYPE_SPARSE_WRITE; |
- case disk_cache::SparseControl::kGetRangeOperation: |
+ case disk_cache::SparseControlV3::kGetRangeOperation: |
return net::NetLog::TYPE_SPARSE_GET_RANGE; |
default: |
NOTREACHED(); |
@@ -158,63 +143,57 @@ |
} |
} |
-// Logs the end event for |operation| on a child entry. Range operations log |
-// no events for each child they search through. |
-void LogChildOperationEnd(const net::BoundNetLog& net_log, |
- disk_cache::SparseControl::SparseOperation operation, |
- int result) { |
- if (net_log.IsLoggingAllEvents()) { |
- net::NetLog::EventType event_type; |
- switch (operation) { |
- case disk_cache::SparseControl::kReadOperation: |
- event_type = net::NetLog::TYPE_SPARSE_READ_CHILD_DATA; |
- break; |
- case disk_cache::SparseControl::kWriteOperation: |
- event_type = net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA; |
- break; |
- case disk_cache::SparseControl::kGetRangeOperation: |
- return; |
- default: |
- NOTREACHED(); |
- return; |
- } |
- net_log.EndEventWithNetErrorCode(event_type, result); |
- } |
-} |
- |
} // namespace. |
namespace disk_cache { |
-SparseControl::SparseControl(EntryImpl* entry) |
+SparseControlV3::SparseControlV3(EntryImplV3* entry) |
: entry_(entry), |
child_(NULL), |
operation_(kNoOperation), |
- pending_(false), |
- finished_(false), |
+ next_state_(STATE_NONE), |
init_(false), |
range_found_(false), |
abort_(false), |
+ valid_(false), |
+ closing_(false), |
child_map_(child_data_.bitmap, kNumSparseBits, kNumSparseBits / 32), |
+ callback_(base::Bind(&SparseControlV3::OnIOComplete, |
+ base::Unretained(this))), |
offset_(0), |
buf_len_(0), |
child_offset_(0), |
child_len_(0), |
- result_(0) { |
+ result_(0), |
+ range_start_(NULL) { |
memset(&sparse_header_, 0, sizeof(sparse_header_)); |
memset(&child_data_, 0, sizeof(child_data_)); |
} |
-SparseControl::~SparseControl() { |
- if (child_) |
- CloseChild(); |
- if (init_) |
- WriteSparseData(); |
+SparseControlV3::~SparseControlV3() { |
} |
-bool SparseControl::CouldBeSparse() const { |
- DCHECK(!init_); |
+void SparseControlV3::Close() { |
+ if (closing_) |
+ return; |
+ if (operation_ != kNoOperation || valid_) { |
+ closing_ = true; |
+ entry_->AddRef(); |
+ if (operation_ != kNoOperation) |
+ return; |
+ DCHECK_EQ(next_state_, STATE_NONE); |
+ DCHECK(user_callback_.is_null()); |
+ next_state_ = STATE_CLOSE; |
+ int rv = DoLoop(net::OK); |
+ return; |
+ } |
+} |
+ |
+bool SparseControlV3::CouldBeSparse() const { |
+ if (init_) |
+ return valid_; |
+ |
if (entry_->GetDataSize(kSparseData)) |
return false; |
@@ -222,9 +201,9 @@ |
return (entry_->GetDataSize(kSparseIndex) != 0); |
} |
-int SparseControl::StartIO(SparseOperation op, int64 offset, net::IOBuffer* buf, |
- int buf_len, const CompletionCallback& callback) { |
- DCHECK(init_); |
+int SparseControlV3::StartIO(SparseOperation op, int64 offset, |
+ net::IOBuffer* buf, int buf_len, |
+ const CompletionCallback& callback) { |
// We don't support simultaneous IO for sparse data. |
if (operation_ != kNoOperation) |
return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
@@ -239,6 +218,9 @@ |
DCHECK(!user_buf_); |
DCHECK(user_callback_.is_null()); |
+ if (init_ && !valid_) |
+ return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
+ |
if (!buf && (op == kReadOperation || op == kWriteOperation)) |
return 0; |
@@ -247,11 +229,8 @@ |
offset_ = offset; |
user_buf_ = buf ? new net::DrainableIOBuffer(buf, buf_len) : NULL; |
buf_len_ = buf_len; |
- user_callback_ = callback; |
result_ = 0; |
- pending_ = false; |
- finished_ = false; |
abort_ = false; |
if (entry_->net_log().IsLoggingAllEvents()) { |
@@ -259,60 +238,63 @@ |
GetSparseEventType(operation_), |
CreateNetLogSparseOperationCallback(offset_, buf_len_)); |
} |
- DoChildrenIO(); |
- if (!pending_) { |
- // Everything was done synchronously. |
+ DCHECK_EQ(next_state_, STATE_NONE); |
+ next_state_ = init_ ? STATE_GET_CHILD_KEY : STATE_INIT; |
+ |
+ int rv = DoLoop(net::OK); |
+ if (rv == net::ERR_IO_PENDING) { |
+ user_callback_ = callback; |
+ entry_->AddRef(); // Self preservation while we're working. |
+ } else { |
operation_ = kNoOperation; |
user_buf_ = NULL; |
- user_callback_.Reset(); |
- return result_; |
} |
- return net::ERR_IO_PENDING; |
+ return rv; |
} |
-int SparseControl::GetAvailableRange(int64 offset, int len, int64* start) { |
- DCHECK(init_); |
+int SparseControlV3::GetAvailableRange(int64 offset, int len, int64* start, |
+ const CompletionCallback& callback) { |
// We don't support simultaneous IO for sparse data. |
if (operation_ != kNoOperation) |
return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
DCHECK(start); |
+ // If there is a failure, we want to return a valid start. |
+ *start = offset; |
range_found_ = false; |
- int result = StartIO( |
- kGetRangeOperation, offset, NULL, len, CompletionCallback()); |
+ range_start_ = start; |
+ int result = StartIO(kGetRangeOperation, offset, NULL, len, callback); |
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. |
+ return result; |
} |
-void SparseControl::CancelIO() { |
+void SparseControlV3::CancelIO() { |
if (operation_ == kNoOperation) |
return; |
abort_ = true; |
} |
-int SparseControl::ReadyToUse(const CompletionCallback& callback) { |
+int SparseControlV3::ReadyToUse(const CompletionCallback& callback) { |
if (!abort_) |
return net::OK; |
// We'll grab another reference to keep this object alive because we just have |
// one extra reference due to the pending IO operation itself, but we'll |
// release that one before invoking user_callback_. |
- entry_->AddRef(); // Balanced in DoAbortCallbacks. |
+ entry_->AddRef(); // Balanced in HanldeAbortCallbacks. |
abort_callbacks_.push_back(callback); |
return net::ERR_IO_PENDING; |
} |
// Static |
-void SparseControl::DeleteChildren(EntryImpl* entry) { |
+void SparseControlV3::DeleteChildren(EntryImplV3* entry) { |
DCHECK(entry->GetEntryFlags() & PARENT_ENTRY); |
int data_len = entry->GetDataSize(kSparseIndex); |
if (data_len < static_cast<int>(sizeof(SparseData)) || |
@@ -323,7 +305,7 @@ |
if (map_len > kMaxMapSize || map_len % 4) |
return; |
- char* buffer; |
+ scoped_refptr<net::IOBuffer> buffer; |
Addr address; |
entry->GetData(kSparseIndex, &buffer, &address); |
if (!buffer && !address.is_initialized()) |
@@ -337,20 +319,100 @@ |
// The object will self destruct when finished. |
deleter->AddRef(); |
- if (buffer) { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&ChildrenDeleter::Start, deleter, buffer, data_len)); |
- } else { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&ChildrenDeleter::ReadData, deleter, address, data_len)); |
- } |
+ if (buffer) |
+ deleter->Start(buffer, data_len); |
+ else |
+ deleter->ReadData(address, data_len); |
} |
// ----------------------------------------------------------------------- |
-int SparseControl::Init() { |
+int SparseControlV3::DoLoop(int result) { |
+ DCHECK(next_state_ != STATE_NONE); |
+ |
+ int rv = result; |
+ do { |
+ State state = next_state_; |
+ next_state_ = STATE_NONE; |
+ switch (state) { |
+ case STATE_INIT: |
+ DCHECK_EQ(net::OK, rv); |
+ rv = DoInit(); |
+ break; |
+ case STATE_CREATE_SPARSE_ENTRY: |
+ DCHECK_EQ(net::OK, rv); |
+ rv = DoCreateSparseEntry(); |
+ break; |
+ case STATE_CREATE_SPARSE_ENTRY_COMPLETE: |
+ rv = DoCreateSparseEntryComplete(rv); |
+ break; |
+ case STATE_OPEN_SPARSE_ENTRY: |
+ rv = DoOpenSparseEntry(rv); |
+ break; |
+ case STATE_OPEN_SPARSE_ENTRY_COMPLETE: |
+ rv = DoOpenSparseEntryComplete(rv); |
+ break; |
+ case STATE_READ_BITMAP_COMPLETE: |
+ rv = DoReadBitmapComplete(rv); |
+ break; |
+ case STATE_GET_CHILD_KEY: |
+ DCHECK_EQ(net::OK, rv); |
+ rv = DoGetChildKey(); |
+ break; |
+ case STATE_OPEN_CHILD: |
+ DCHECK_EQ(net::OK, rv); |
+ rv = DoOpenChild(); |
+ break; |
+ case STATE_OPEN_CHILD_COMPLETE: |
+ rv = DoOpenChildComplete(rv); |
+ break; |
+ case STATE_CREATE_CHILD: |
+ DCHECK_EQ(net::OK, rv); |
+ rv = DoCreateChild(); |
+ break; |
+ case STATE_CREATE_CHILD_COMPLETE: |
+ rv = DoCreateChildComplete(rv); |
+ break; |
+ case STATE_READ_SIGNATURE_COMPLETE: |
+ rv = DoReadSignatureComplete(rv); |
+ break; |
+ case STATE_CLOSE_CHILD: |
+ DCHECK_EQ(net::OK, rv); |
+ rv = DoCloseChild(); |
+ break; |
+ case STATE_CLOSE_CHILD_COMPLETE: |
+ rv = DoCloseChildComplete(rv); |
+ break; |
+ case STATE_DO_CHILD_IO: |
+ DCHECK_EQ(net::OK, rv); |
+ rv = DoChildIO(); |
+ break; |
+ case STATE_DO_CHILD_IO_COMPLETE: |
+ rv = DoChildIOComplete(rv); |
+ break; |
+ case STATE_CLOSE: |
+ DCHECK_EQ(net::OK, rv); |
+ rv = DoClose(); |
+ break; |
+ case STATE_WRITE_BITMAP: |
+ DCHECK_EQ(net::OK, rv); |
+ rv = DoWriteBitmap(); |
+ break; |
+ case STATE_WRITE_BITMAP_COMPLETE: |
+ rv = DoWriteBitmapComplete(rv); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ } while (rv != net::ERR_IO_PENDING && next_state_ != STATE_NONE); |
+ |
+ if (rv != net::ERR_IO_PENDING) |
+ HandleResult(rv); |
+ |
+ return rv; |
+} |
+ |
+int SparseControlV3::DoInit() { |
DCHECK(!init_); |
// We should not have sparse data for the exposed entry. |
@@ -360,26 +422,23 @@ |
// Now see if there is something where we store our data. |
int rv = net::OK; |
int data_len = entry_->GetDataSize(kSparseIndex); |
- if (!data_len) { |
- rv = CreateSparseEntry(); |
- } else { |
- rv = OpenSparseEntry(data_len); |
+ if (data_len) { |
+ next_state_ = STATE_OPEN_SPARSE_ENTRY; |
+ return data_len; |
} |
- |
- if (rv == net::OK) |
- init_ = true; |
- return rv; |
+ next_state_ = STATE_CREATE_SPARSE_ENTRY; |
+ return net::OK; |
} |
// We are going to start using this entry to store sparse data, so we have to |
// initialize our control info. |
-int SparseControl::CreateSparseEntry() { |
+int SparseControlV3::DoCreateSparseEntry() { |
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(); |
- sparse_header_.magic = kIndexMagic; |
+ sparse_header_.magic = kIndexMagicV3; |
sparse_header_.parent_key_len = entry_->GetKey().size(); |
children_map_.Resize(kNumSparseBits, true); |
@@ -387,19 +446,26 @@ |
scoped_refptr<net::IOBuffer> buf( |
new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_))); |
- int rv = entry_->WriteData(kSparseIndex, 0, buf.get(), sizeof(sparse_header_), |
- CompletionCallback(), false); |
- if (rv != sizeof(sparse_header_)) { |
+ next_state_ = STATE_CREATE_SPARSE_ENTRY_COMPLETE; |
+ return entry_->WriteData(kSparseIndex, 0, buf, sizeof(sparse_header_), |
+ callback_, false); |
+} |
+ |
+int SparseControlV3::DoCreateSparseEntryComplete(int result) { |
+ if (result != sizeof(sparse_header_)) { |
DLOG(ERROR) << "Unable to save sparse_header_"; |
return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
} |
entry_->SetEntryFlags(PARENT_ENTRY); |
+ init_ = true; |
+ valid_ = true; |
+ next_state_ = STATE_GET_CHILD_KEY; |
return net::OK; |
} |
// We are opening an entry from disk. Make sure that our control data is there. |
-int SparseControl::OpenSparseEntry(int data_len) { |
+int SparseControlV3::DoOpenSparseEntry(int data_len) { |
if (data_len < static_cast<int>(sizeof(SparseData))) |
return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
@@ -418,71 +484,102 @@ |
new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_))); |
// Read header. |
- int rv = entry_->ReadData(kSparseIndex, 0, buf.get(), sizeof(sparse_header_), |
- CompletionCallback()); |
- if (rv != static_cast<int>(sizeof(sparse_header_))) |
+ next_state_ = STATE_OPEN_SPARSE_ENTRY_COMPLETE; |
+ return entry_->ReadData(kSparseIndex, 0, buf, sizeof(sparse_header_), |
+ callback_); |
+} |
+ |
+int SparseControlV3::DoOpenSparseEntryComplete(int result) { |
+ if (result != static_cast<int>(sizeof(sparse_header_))) |
return net::ERR_CACHE_READ_FAILURE; |
// The real validation should be performed by the caller. This is just to |
// double check. |
- if (sparse_header_.magic != kIndexMagic || |
+ if (sparse_header_.magic != kIndexMagicV3 || |
sparse_header_.parent_key_len != |
static_cast<int>(entry_->GetKey().size())) |
return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
// Read the actual bitmap. |
- buf = new net::IOBuffer(map_len); |
- rv = entry_->ReadData(kSparseIndex, sizeof(sparse_header_), buf.get(), |
- map_len, CompletionCallback()); |
- if (rv != map_len) |
+ int map_len = entry_->GetDataSize(kSparseIndex) - sizeof(sparse_header_); |
+ buf_ = new net::IOBuffer(map_len); |
+ next_state_ = STATE_READ_BITMAP_COMPLETE; |
+ return entry_->ReadData(kSparseIndex, sizeof(sparse_header_), buf_, map_len, |
+ callback_); |
+} |
+ |
+int SparseControlV3::DoReadBitmapComplete(int result) { |
+ int map_len = entry_->GetDataSize(kSparseIndex) - sizeof(sparse_header_); |
+ if (result != map_len) |
return net::ERR_CACHE_READ_FAILURE; |
// Grow the bitmap to the current size and copy the bits. |
children_map_.Resize(map_len * 8, false); |
- children_map_.SetMap(reinterpret_cast<uint32*>(buf->data()), map_len); |
+ children_map_.SetMap(reinterpret_cast<uint32*>(buf_->data()), map_len); |
+ init_ = true; |
+ valid_ = true; |
+ next_state_ = STATE_GET_CHILD_KEY; |
return net::OK; |
} |
-bool SparseControl::OpenChild() { |
- DCHECK_GE(result_, 0); |
- |
- std::string key = GenerateChildKey(); |
+int SparseControlV3::DoGetChildKey() { |
+ key_ = GenerateChildKey(); |
if (child_) { |
// Keep using the same child or open another one?. |
- if (key == child_->GetKey()) |
- return true; |
- CloseChild(); |
+ if (key_ == child_->GetKey()) { |
+ next_state_ = STATE_DO_CHILD_IO; |
+ return net::OK; |
+ } |
+ next_state_ = STATE_CLOSE_CHILD; |
+ return net::OK; |
} |
+ next_state_ = STATE_OPEN_CHILD; |
+ return net::OK; |
+} |
+int SparseControlV3::DoOpenChild() { |
// See if we are tracking this child. |
- if (!ChildPresent()) |
- return ContinueWithoutChild(key); |
+ if (!ChildPresent()) { |
+ next_state_ = STATE_CREATE_CHILD; |
+ return net::OK; |
+ } |
if (!entry_->backend_) |
- return false; |
+ return net::ERR_FAILED; |
- child_ = entry_->backend_->OpenEntryImpl(key); |
- if (!child_) |
- return ContinueWithoutChild(key); |
+ next_state_ = STATE_OPEN_CHILD_COMPLETE; |
+ return entry_->backend_->OpenEntry(key_, &child_, callback_); |
+} |
- EntryImpl* child = static_cast<EntryImpl*>(child_); |
+int SparseControlV3::DoOpenChildComplete(int result) { |
+ if (!child_) { |
+ next_state_ = STATE_CREATE_CHILD; |
+ return net::OK; |
+ } |
+ |
+ EntryImplV3* child = static_cast<EntryImplV3*>(child_); |
if (!(CHILD_ENTRY & child->GetEntryFlags()) || |
child->GetDataSize(kSparseIndex) < |
- static_cast<int>(sizeof(child_data_))) |
- return KillChildAndContinue(key, false); |
+ static_cast<int>(sizeof(child_data_))) { |
+ return KillChildAndContinue(); |
+ } |
scoped_refptr<net::WrappedIOBuffer> buf( |
new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_))); |
// Read signature. |
- int rv = child_->ReadData(kSparseIndex, 0, buf.get(), sizeof(child_data_), |
- CompletionCallback()); |
- if (rv != sizeof(child_data_)) |
- return KillChildAndContinue(key, true); // This is a fatal failure. |
+ next_state_ = STATE_READ_SIGNATURE_COMPLETE; |
+ return child_->ReadData(kSparseIndex, 0, buf, sizeof(child_data_), |
+ callback_); |
+} |
+int SparseControlV3::DoReadSignatureComplete(int result) { |
+ if (result != sizeof(child_data_)) |
+ return KillChildAndContinue(); |
+ |
if (child_data_.header.signature != sparse_header_.signature || |
- child_data_.header.magic != kIndexMagic) |
- return KillChildAndContinue(key, false); |
+ child_data_.header.magic != kIndexMagicV3) |
+ return KillChildAndContinue(); |
if (child_data_.header.last_block_len < 0 || |
child_data_.header.last_block_len > kBlockSize) { |
@@ -491,160 +588,156 @@ |
child_data_.header.last_block = -1; |
} |
- return true; |
+ next_state_ = STATE_DO_CHILD_IO; |
+ return net::OK; |
} |
-void SparseControl::CloseChild() { |
+int SparseControlV3::DoCloseChild() { |
+ next_state_ = STATE_CLOSE_CHILD_COMPLETE; |
scoped_refptr<net::WrappedIOBuffer> buf( |
new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_))); |
// Save the allocation bitmap before closing the child entry. |
- int rv = child_->WriteData(kSparseIndex, 0, buf.get(), sizeof(child_data_), |
- CompletionCallback(), |
- false); |
- if (rv != sizeof(child_data_)) |
+ return child_->WriteData(kSparseIndex, 0, buf, sizeof(child_data_), |
+ callback_, false); |
+} |
+ |
+int SparseControlV3::DoCloseChildComplete(int result) { |
+ if (result != sizeof(child_data_)) |
DLOG(ERROR) << "Failed to save child data"; |
- child_->Release(); |
+ child_->Close(); |
child_ = NULL; |
+ |
+ DCHECK(valid_); |
+ if (closing_ && user_callback_.is_null()) |
+ next_state_= STATE_WRITE_BITMAP; |
+ else |
+ next_state_ = STATE_OPEN_CHILD; |
+ |
+ return net::OK; |
} |
// We were not able to open this child; see what we can do. |
-bool SparseControl::ContinueWithoutChild(const std::string& key) { |
+int SparseControlV3::DoCreateChild() { |
if (kReadOperation == operation_) |
- return false; |
- if (kGetRangeOperation == operation_) |
- return true; |
+ return 0; |
+ if (kGetRangeOperation == operation_) { |
+ next_state_ = STATE_DO_CHILD_IO; |
+ return net::OK; |
+ } |
if (!entry_->backend_) |
- return false; |
+ return net::ERR_FAILED; |
- child_ = entry_->backend_->CreateEntryImpl(key); |
- if (!child_) { |
- child_ = NULL; |
- result_ = net::ERR_CACHE_READ_FAILURE; |
- return false; |
- } |
+ next_state_ = STATE_CREATE_CHILD_COMPLETE; |
+ return entry_->backend_->CreateEntry(key_, &child_, callback_); |
+} |
+ |
+int SparseControlV3::DoCreateChildComplete(int result) { |
+ if (result != net::OK) |
+ return net::ERR_CACHE_READ_FAILURE; |
+ |
// Write signature. |
InitChildData(); |
- return true; |
+ next_state_ = STATE_DO_CHILD_IO; |
+ return net::OK; |
} |
-void SparseControl::WriteSparseData() { |
+int SparseControlV3::DoWriteBitmap() { |
+ next_state_ = STATE_WRITE_BITMAP_COMPLETE; |
scoped_refptr<net::IOBuffer> buf(new net::WrappedIOBuffer( |
reinterpret_cast<const char*>(children_map_.GetMap()))); |
int len = children_map_.ArraySize() * 4; |
- int rv = entry_->WriteData(kSparseIndex, sizeof(sparse_header_), buf.get(), |
- len, CompletionCallback(), false); |
- if (rv != len) { |
+ return entry_->WriteData(kSparseIndex, sizeof(sparse_header_), buf, len, |
+ callback_, false); |
+} |
+ |
+int SparseControlV3::DoWriteBitmapComplete(int result) { |
+ if (result != children_map_.ArraySize() * 4) { |
DLOG(ERROR) << "Unable to save sparse map"; |
} |
+ return net::OK; |
} |
-bool SparseControl::DoChildIO() { |
- finished_ = true; |
- if (!buf_len_ || result_ < 0) |
- return false; |
- |
- if (!OpenChild()) |
- return false; |
- |
+int SparseControlV3::DoChildIO() { |
if (!VerifyRange()) |
- return false; |
+ return 0; |
- // We have more work to do. Let's not trigger a callback to the caller. |
- finished_ = false; |
- CompletionCallback callback; |
- if (!user_callback_.is_null()) { |
- callback = |
- base::Bind(&SparseControl::OnChildIOCompleted, base::Unretained(this)); |
- } |
- |
int rv = 0; |
switch (operation_) { |
case kReadOperation: |
- if (entry_->net_log().IsLoggingAllEvents()) { |
- entry_->net_log().BeginEvent( |
- net::NetLog::TYPE_SPARSE_READ_CHILD_DATA, |
- CreateNetLogSparseReadWriteCallback(child_->net_log().source(), |
- child_len_)); |
- } |
- rv = child_->ReadDataImpl(kSparseData, child_offset_, user_buf_.get(), |
- child_len_, callback); |
+ LogChildOperationStart(); |
+ rv = child_->ReadData(kSparseData, child_offset_, user_buf_, |
+ child_len_, callback_); |
break; |
case kWriteOperation: |
- if (entry_->net_log().IsLoggingAllEvents()) { |
- entry_->net_log().BeginEvent( |
- net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA, |
- CreateNetLogSparseReadWriteCallback(child_->net_log().source(), |
- child_len_)); |
- } |
- rv = child_->WriteDataImpl(kSparseData, child_offset_, user_buf_.get(), |
- child_len_, callback, false); |
+ LogChildOperationStart(); |
+ rv = child_->WriteData(kSparseData, child_offset_, user_buf_, |
+ child_len_, callback_, false); |
break; |
case kGetRangeOperation: |
- rv = DoGetAvailableRange(); |
+ rv = GetAvailableRangeImpl(); |
break; |
default: |
NOTREACHED(); |
} |
- if (rv == net::ERR_IO_PENDING) { |
- if (!pending_) { |
- pending_ = true; |
- // The child will protect himself against closing the entry while IO is in |
- // progress. However, this entry can still be closed, and that would not |
- // be a good thing for us, so we increase the refcount until we're |
- // finished doing sparse stuff. |
- entry_->AddRef(); // Balanced in DoUserCallback. |
- } |
- return false; |
- } |
- if (!rv) |
- return false; |
- |
- DoChildIOCompleted(rv); |
- return true; |
+ next_state_ = STATE_DO_CHILD_IO_COMPLETE; |
+ return rv; |
} |
-void SparseControl::DoChildIOCompleted(int result) { |
- LogChildOperationEnd(entry_->net_log(), operation_, result); |
- if (result < 0) { |
- // We fail the whole operation if we encounter an error. |
- result_ = result; |
- return; |
- } |
+int SparseControlV3::DoChildIOComplete(int result) { |
+ LogChildOperationEnd(result); |
+ if (result < 0) |
+ return LogCompletion(result); |
+ |
UpdateRange(result); |
- result_ += result; |
+ if (operation_ != kGetRangeOperation) |
+ result_ += result; |
offset_ += result; |
buf_len_ -= result; |
+ if (!buf_len_) |
+ return LogCompletion(result_); |
+ |
// We'll be reusing the user provided buffer for the next chunk. |
if (buf_len_ && user_buf_) |
user_buf_->DidConsume(result); |
+ |
+ next_state_ = STATE_GET_CHILD_KEY; |
+ return net::OK; |
} |
-std::string SparseControl::GenerateChildKey() { |
+int SparseControlV3::DoClose() { |
+ DCHECK(valid_); |
+ DCHECK(user_callback_.is_null()); |
+ if (child_) |
+ next_state_= STATE_CLOSE_CHILD; |
+ else if (valid_) |
+ next_state_= STATE_WRITE_BITMAP; |
+ |
+ return net::OK; |
+} |
+ |
+std::string SparseControlV3::GenerateChildKey() { |
return GenerateChildName(entry_->GetKey(), sparse_header_.signature, |
offset_ >> 20); |
} |
// We are deleting the child because something went wrong. |
-bool SparseControl::KillChildAndContinue(const std::string& key, bool fatal) { |
+int SparseControlV3::KillChildAndContinue() { |
SetChildBit(false); |
- child_->DoomImpl(); |
- child_->Release(); |
+ child_->Doom(); |
+ child_->Close(); |
child_ = NULL; |
- if (fatal) { |
- result_ = net::ERR_CACHE_READ_FAILURE; |
- return false; |
- } |
- return ContinueWithoutChild(key); |
+ next_state_ = STATE_CREATE_CHILD; |
+ return net::OK; |
} |
-bool SparseControl::ChildPresent() { |
+bool SparseControlV3::ChildPresent() { |
int child_bit = static_cast<int>(offset_ >> 20); |
if (children_map_.Size() <= child_bit) |
return false; |
@@ -652,7 +745,7 @@ |
return children_map_.Get(child_bit); |
} |
-void SparseControl::SetChildBit(bool value) { |
+void SparseControlV3::SetChildBit(bool value) { |
int child_bit = static_cast<int>(offset_ >> 20); |
// We may have to increase the bitmap of child entries. |
@@ -662,9 +755,7 @@ |
children_map_.Set(child_bit, value); |
} |
-bool SparseControl::VerifyRange() { |
- DCHECK_GE(result_, 0); |
- |
+bool SparseControlV3::VerifyRange() { |
child_offset_ = static_cast<int>(offset_) & (kMaxEntrySize - 1); |
child_len_ = std::min(buf_len_, kMaxEntrySize - child_offset_); |
@@ -698,7 +789,7 @@ |
return true; |
} |
-void SparseControl::UpdateRange(int result) { |
+void SparseControlV3::UpdateRange(int result) { |
if (result <= 0 || operation_ != kWriteOperation) |
return; |
@@ -735,7 +826,7 @@ |
child_map_.SetRange(first_bit, last_bit, true); |
} |
-int SparseControl::PartialBlockLength(int block_index) const { |
+int SparseControlV3::PartialBlockLength(int block_index) const { |
if (block_index == child_data_.header.last_block) |
return child_data_.header.last_block_len; |
@@ -748,9 +839,9 @@ |
return 0; |
} |
-void SparseControl::InitChildData() { |
+void SparseControlV3::InitChildData() { |
// We know the real type of child_. |
- EntryImpl* child = static_cast<EntryImpl*>(child_); |
+ EntryImplV3* child = static_cast<EntryImplV3*>(child_); |
child->SetEntryFlags(CHILD_ENTRY); |
memset(&child_data_, 0, sizeof(child_data_)); |
@@ -759,14 +850,14 @@ |
scoped_refptr<net::WrappedIOBuffer> buf( |
new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_))); |
- int rv = child_->WriteData(kSparseIndex, 0, buf.get(), sizeof(child_data_), |
+ int rv = child_->WriteData(kSparseIndex, 0, buf, sizeof(child_data_), |
CompletionCallback(), false); |
if (rv != sizeof(child_data_)) |
DLOG(ERROR) << "Failed to save child data"; |
SetChildBit(true); |
} |
-int SparseControl::DoGetAvailableRange() { |
+int SparseControlV3::GetAvailableRangeImpl() { |
if (!child_) |
return child_len_; // Move on to the next child. |
@@ -813,19 +904,91 @@ |
return 0; |
} |
-void SparseControl::DoUserCallback() { |
- DCHECK(!user_callback_.is_null()); |
+void SparseControlV3::LogChildOperationStart() { |
+ net::NetLog::EventType type = (operation_ == kReadOperation) ? |
+ net::NetLog::TYPE_SPARSE_READ_CHILD_DATA : |
+ net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA; |
+ |
+ if (entry_->net_log().IsLoggingAllEvents()) { |
+ disk_cache::EntryImplV3* entry = |
+ reinterpret_cast<disk_cache::EntryImplV3*>(child_); |
+ entry_->net_log().BeginEvent( |
+ type, |
+ CreateNetLogSparseReadWriteCallback(entry->net_log().source(), |
+ child_len_)); |
+ } |
+} |
+ |
+void SparseControlV3::LogChildOperationEnd(int result) { |
+ if (entry_->net_log().IsLoggingAllEvents()) { |
+ net::NetLog::EventType event_type; |
+ switch (operation_) { |
+ case disk_cache::SparseControlV3::kReadOperation: |
+ event_type = net::NetLog::TYPE_SPARSE_READ_CHILD_DATA; |
+ break; |
+ case disk_cache::SparseControlV3::kWriteOperation: |
+ event_type = net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA; |
+ break; |
+ case disk_cache::SparseControlV3::kGetRangeOperation: |
+ return; |
+ default: |
+ NOTREACHED(); |
+ return; |
+ } |
+ entry_->net_log().EndEventWithNetErrorCode(event_type, result); |
+ } |
+} |
+ |
+int SparseControlV3::LogCompletion(int result) { |
+ if (!entry_->net_log().IsLoggingAllEvents()) |
+ return result; |
+ |
+ if (kGetRangeOperation == operation_) { |
+ entry_->net_log().EndEvent( |
+ net::NetLog::TYPE_SPARSE_GET_RANGE, |
+ CreateNetLogGetAvailableRangeResultCallback(offset_, result)); |
+ } else { |
+ entry_->net_log().EndEvent(GetSparseEventType(operation_)); |
+ } |
+ return result; |
+} |
+ |
+void SparseControlV3::HandleResult(int result) { |
+ if (!result && result_) |
+ result = result_; |
+ |
+ if (result > 0 && operation_ == kGetRangeOperation) |
+ *range_start_ = offset_; |
+ |
+ user_buf_ = NULL; |
+ operation_ = kNoOperation; |
+ next_state_ = STATE_NONE; |
+ |
+ if (user_callback_.is_null()) { |
+ if (closing_) { |
+ closing_ = false; |
+ entry_->Release(); // Don't touch object after this line. |
+ } |
+ return; |
+ } |
+ |
CompletionCallback cb = user_callback_; |
user_callback_.Reset(); |
- user_buf_ = NULL; |
- pending_ = false; |
- operation_ = kNoOperation; |
- int rv = result_; |
+ bool closing = closing_; |
+ DCHECK(!closing_ || !entry_->HasOneRef()); |
+ |
entry_->Release(); // Don't touch object after this line. |
- cb.Run(rv); |
+ cb.Run(result); |
+ |
+ if (closing) { |
+ // This object is not gone yet, but there's more work to do before the |
+ // destructor runs. |
+ next_state_ = STATE_CLOSE; |
+ int rv = DoLoop(net::OK); |
+ } |
} |
-void SparseControl::DoAbortCallbacks() { |
+void SparseControlV3::HanldeAbortCallbacks() { |
for (size_t i = 0; i < abort_callbacks_.size(); i++) { |
// Releasing all references to entry_ may result in the destruction of this |
// object so we should not be touching it after the last Release(). |
@@ -838,9 +1001,8 @@ |
} |
} |
-void SparseControl::OnChildIOCompleted(int result) { |
+void SparseControlV3::OnIOComplete(int result) { |
DCHECK_NE(net::ERR_IO_PENDING, result); |
- DoChildIOCompleted(result); |
if (abort_) { |
// We'll return the current result of the operation, which may be less than |
@@ -852,17 +1014,15 @@ |
} |
// We have an indirect reference to this object for every callback so if |
// there is only one callback, we may delete this object before reaching |
- // DoAbortCallbacks. |
+ // HanldeAbortCallbacks. |
bool has_abort_callbacks = !abort_callbacks_.empty(); |
- DoUserCallback(); |
+ HandleResult(result); |
if (has_abort_callbacks) |
- DoAbortCallbacks(); |
+ HanldeAbortCallbacks(); |
return; |
} |
- // We are running a callback from the message loop. It's time to restart what |
- // we were doing before. |
- DoChildrenIO(); |
+ DoLoop(result); |
} |
} // namespace disk_cache |