Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(280)

Unified Diff: net/disk_cache/v3/backend_work_item.cc

Issue 17507006: Disk cache v3 ref2 Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Incl IndexTable cl Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/disk_cache/v3/backend_work_item.h ('k') | net/disk_cache/v3/backend_worker.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/disk_cache/v3/backend_work_item.cc
===================================================================
--- net/disk_cache/v3/backend_work_item.cc (revision 0)
+++ net/disk_cache/v3/backend_work_item.cc (revision 0)
@@ -0,0 +1,501 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/disk_cache/v3/backend_work_item.h"
+
+#include "base/hash.h"
+#include "base/sha1.h"
+#include "net/base/net_errors.h"
+#include "net/disk_cache/errors.h"
+#include "net/disk_cache/file.h"
+#include "net/disk_cache/storage_block-inl.h"
+#include "net/disk_cache/v3/backend_worker.h"
+#include "net/disk_cache/v3/entry_impl_v3.h"
+
+namespace {
+
+// Simple adaptor for the sha1 interface.
+void ComputeCryptoHash(const std::string& source,
+ disk_cache::ShortEntryRecord* record) {
+ DCHECK(!source.empty());
+ base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(source.data()),
+ source.size(),
+ reinterpret_cast<unsigned char*>(record->long_hash));
+}
+
+bool CryptoHashMatches(const std::string& source,
+ const disk_cache::ShortEntryRecord& record) {
+ DCHECK(!source.empty());
+ unsigned char result[20];
+ base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(source.data()),
+ source.size(), result);
+
+ return !memcmp(result, record.long_hash, sizeof(result));
+}
+
+} // namespace
+
+// ------------------------------------------------------------------------
+
+namespace disk_cache {
+
+class BackendImplV3::IOCallback : public disk_cache::FileIOCallback {
+ public:
+ explicit IOCallback(BackendImplV3::WorkItem* work_item);
+ virtual ~IOCallback() {}
+
+ // FileIOCallback implementation.
+ virtual void OnFileIOComplete(int bytes_copied) OVERRIDE;
+ void Discard();
+
+ private:
+ // Even though we need the work item alive until the operation completes, we
+ // don't grab an extra reference because the work item itself keeps an extra
+ // reference until it reaches the main thread again.
+ BackendImplV3::WorkItem* work_item_;
+
+ DISALLOW_COPY_AND_ASSIGN(IOCallback);
+};
+
+BackendImplV3::IOCallback::IOCallback(BackendImplV3::WorkItem* work_item)
+ : work_item_(work_item) {
+}
+
+void BackendImplV3::IOCallback::OnFileIOComplete(int bytes_copied) {
+ if (work_item_)
+ work_item_->DoLoop(bytes_copied);
+
+ delete this;
+}
+
+void BackendImplV3::IOCallback::Discard() {
+ work_item_ = NULL;
+ OnFileIOComplete(0);
+}
+
+// ------------------------------------------------------------------------
+
+BackendImplV3::WorkItem::WorkItem(WorkType type)
+ : type_(type),
+ result_(0),
+ flags_(0) {//init everything
+}
+
+void BackendImplV3::WorkItem::Start(BackendImplV3::Worker* worker) {
+ Trace("Work 0x%p %d", this, type());
+ worker_ = worker;
+ switch (type_) {
+ case WORK_INIT:
+ return CompleteItem(worker_->Init(flags_, &init_result_));
+ case WORK_RESTART:
+ return CompleteItem(worker_->Restart(flags_, &init_result_));
+ case WORK_GROW_INDEX:
+ return CompleteItem(worker_->GrowIndex(flags_, &init_result_));
+ case WORK_GROW_FILES:
+ return CompleteItem(worker_->GrowFiles(flags_, &init_result_));
+ case WORK_WRITE_INDEX:
+ next_state_ = STATE_WRITE_DATA;
+ break;
+ case WORK_OPEN_ENTRY:
+ next_state_ = STATE_OPEN_ENTRY;
+ break;
+ case WORK_READ_DATA:
+ next_state_ = STATE_READ_DATA;
+ break;
+ case WORK_WRITE_DATA:
+ next_state_ = STATE_WRITE_DATA;
+ break;
+ case WORK_MOVE_DATA:
+ next_state_ = STATE_MOVE_DATA;
+ break;
+ case WORK_TRUNCATE:
+ next_state_ = STATE_TRUNCATE_DATA;
+ break;
+ case WORK_DELETE:
+ return CompleteItem(worker_->Delete(address_));
+ case WORK_CLOSE:
+ return CompleteItem(worker_->Close(address_));
+ case WORK_NONE:
+ return CompleteItem(ERR_NO_ERROR);
+ default: NOTREACHED();
+ }
+ DoLoop(ERR_NO_ERROR);
+}
+
+void BackendImplV3::WorkItem::DoLoop(int result) {
+ DCHECK(next_state_ != STATE_NONE);
+ if (!worker_->IsValid())
+ return CompleteItem(result);
+
+ int rv = result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_OPEN_ENTRY:
+ DCHECK_EQ(ERR_NO_ERROR, rv);
+ rv = DoOpenEntry();
+ break;
+ case STATE_OPEN_ENTRY_COMPLETE:
+ rv = DoOpenEntryComplete(rv);
+ break;
+ case STATE_READ_KEY:
+ DCHECK_EQ(ERR_NO_ERROR, rv);
+ rv = DoReadKey();
+ break;
+ case STATE_READ_KEY_COMPLETE:
+ DCHECK_EQ(ERR_NO_ERROR, rv);
+ rv = DoReadKeyComplete();
+ break;
+ case STATE_READ_DATA:
+ DCHECK_EQ(ERR_NO_ERROR, rv);
+ rv = DoReadData();
+ break;
+ case STATE_READ_DATA_COMPLETE:
+ rv = DoReadDataComplete(rv);
+ break;
+ case STATE_WRITE_DATA:
+ DCHECK_EQ(ERR_NO_ERROR, rv);
+ rv = DoWriteData();
+ break;
+ case STATE_WRITE_DATA_COMPLETE:
+ rv = DoWriteDataComplete(rv);
+ break;
+ case STATE_MOVE_DATA:
+ DCHECK_EQ(ERR_NO_ERROR, rv);
+ rv = DoMoveData();
+ break;
+ case STATE_TRUNCATE_DATA:
+ DCHECK_EQ(ERR_NO_ERROR, rv);
+ rv = DoTruncateData();
+ break;
+ case STATE_COPY_ENTRY:
+ DCHECK_EQ(ERR_NO_ERROR, rv);
+ rv = DoCopyEntry();
+ break;
+ case STATE_COPY_ENTRY_COMPLETE:
+ rv = DoCopyEntryComplete(rv);
+ break;
+ }
+ } while (rv != ERR_PENDING && next_state_ != STATE_NONE);
+
+ if (rv != ERR_PENDING)
+ CompleteItem(rv);
+}
+
+void BackendImplV3::WorkItem::OnDone() {
+ closure_.Run(this);
+}
+
+// ------------------------------------------------------------------------
+
+BackendImplV3::WorkItem::~WorkItem() {
+}
+
+void BackendImplV3::WorkItem::CompleteItem(int result) {
+ Trace("Work done 0x%p %d %d", this, type(), result);
+ result_ = result;
+ entry_block_.reset(); // Release resources while on the worker thread.
+ worker_->DoneWithItem(this);
+}
+
+int BackendImplV3::WorkItem::DoOpenEntry() {
+ next_state_ = STATE_OPEN_ENTRY_COMPLETE;
+ for (; entries_.current < entries_.cells.size(); entries_.current++) {
+ Addr address = entries_.cells[entries_.current].GetAddress();
+ if (entries_.cells[entries_.current].GetGroup() == ENTRY_EVICTED) {
+ if (flags_ & WORK_FOR_RESURRECT)
+ return LoadShortEntryBlock(address);
+ continue;
+ }
+
+ if (flags_ & WORK_FOR_RESURRECT)
+ continue;
+ return LoadEntryBlock(address);
+ }
+ next_state_ = STATE_NONE;
+ return ERR_OPERATION_FAILED;
+}
+
+int BackendImplV3::WorkItem::DoOpenEntryComplete(int result) {
+ if (entries_.cells[entries_.current].GetGroup() == ENTRY_EVICTED) {
+ if (result != static_cast<int>(sizeof(ShortEntryRecord)))
+ return ERR_READ_FAILURE;
+
+ if (!EntryImplV3::DeletedSanityCheck(*short_entry_block_->Data()))
+ return ERR_INVALID_ENTRY;
+ } else {
+ if (result != static_cast<int>(sizeof(EntryRecord)))
+ return ERR_READ_FAILURE;
+
+ if (!EntryImplV3::BasicSanityCheck(*entry_block_->Data()))
+ return ERR_INVALID_ENTRY;
+ }
+
+ if (entries_.cells[entries_.current].GetGroup() == ENTRY_EVICTED) {
+ DCHECK(!(flags_ & WORK_FOR_EVICT));
+ if (CryptoHashMatches(key_, *short_entry_block_->Data())) {
+ // We have a match.
+ short_entry_record_.reset(short_entry_block_->ReleaseData());
+ return ERR_NO_ERROR;
+ }
+ } else {
+ next_state_ = STATE_READ_KEY;
+ return ERR_NO_ERROR;
+ }
+
+ next_state_ = STATE_OPEN_ENTRY;
+ entries_.current++;
+ return ERR_NO_ERROR;
+}
+
+int BackendImplV3::WorkItem::DoReadKey() {
+ address_.set_value(entry_block_->Data()->data_addr[0]);
+ offset_ = 0;
+ buffer_ = new net::IOBuffer(entry_block_->Data()->key_len);
+ buffer_len_ = entry_block_->Data()->key_len;
+
+ next_state_ = STATE_READ_DATA;
+ return ERR_NO_ERROR;
+}
+
+int BackendImplV3::WorkItem::DoReadKeyComplete() {
+ std::string key(buffer_->data(), buffer_len_);
+ uint32 hash = base::Hash(key);
+ Trace("DoReadKeyComplete hash 0x%x, 0x%p", hash, this);
+ DCHECK_EQ(hash, entries_.cells[entries_.current].hash());
+ if (flags() & WORK_FOR_ITERATION)
+ key_ = key;
+
+ if (flags_ & WORK_FOR_EVICT) {
+ key_ = key;
+ if (!(flags_ & WORK_NO_COPY)) {
+ next_state_ = STATE_COPY_ENTRY;
+ return ERR_NO_ERROR;
+ }
+ }
+
+ if (key == key_) {
+ // We have a match.
+ entry_record_.reset(entry_block_->ReleaseData());
+ return ERR_NO_ERROR;
+ }
+
+ next_state_ = STATE_OPEN_ENTRY;
+ entries_.current++;
+ return ERR_NO_ERROR;
+}
+
+int BackendImplV3::WorkItem::DoReadData() {
+ disk_cache::File* file = worker_->GetBackingFile(address_, false);
+ if (!file)
+ return net::ERR_FILE_NOT_FOUND;
+
+
+ size_t file_offset = offset_;
+ if (address_.is_block_file()) {
+ DCHECK_LE(offset_ + buffer_len_, kMaxBlockSize);
+ file_offset += address_.start_block() * address_.BlockSize();
+ }
+ DCHECK(buffer_len_);
+
+ bool completed;
+ IOCallback* callback = new IOCallback(this);
+
+ if (!file->Read(buffer_->data(), buffer_len_, file_offset, callback,
+ &completed)) {
+ callback->Discard();
+ return net::ERR_CACHE_READ_FAILURE;
+ }
+ next_state_ = STATE_READ_DATA_COMPLETE;
+
+ if (completed) {
+ callback->Discard();
+ return NO_ERROR;
+ }
+
+ return ERR_PENDING;
+}
+
+int BackendImplV3::WorkItem::DoReadDataComplete(int result) {
+ if (result != buffer_len_)
+ return net::ERR_CACHE_READ_FAILURE;
+
+ if (type() == WORK_OPEN_ENTRY) {
+ next_state_ = STATE_READ_KEY_COMPLETE;
+ return ERR_NO_ERROR;
+ }
+
+ return result;
+}
+
+int BackendImplV3::WorkItem::DoWriteData() {
+ disk_cache::File* file = NULL;
+ if (type_ == WORK_WRITE_INDEX)
+ file = worker_->GetBackupIndexFile();
+ else
+ file = worker_->GetBackingFile(address_, true);
+
+ if (!file)
+ return net::ERR_CACHE_WRITE_FAILURE;
+
+ DCHECK(buffer_len_);
+
+ size_t file_offset = offset_;
+ if (type_ != WORK_WRITE_INDEX && address_.is_block_file()) {
+ DCHECK_LE(offset_ + buffer_len_, kMaxBlockSize);
+ file_offset += address_.start_block() * address_.BlockSize();
+ }
+
+ bool completed;
+ IOCallback* callback = new IOCallback(this);
+
+ if (!file->Write(buffer_->data(), buffer_len_, file_offset, callback,
+ &completed)) {
+ callback->Discard();
+ return net::ERR_CACHE_WRITE_FAILURE;
+ }
+ next_state_ = STATE_WRITE_DATA_COMPLETE;
+
+ if (completed) {
+ callback->Discard();
+ return NO_ERROR;
+ }
+
+ return ERR_PENDING;
+}
+
+int BackendImplV3::WorkItem::DoWriteDataComplete(int result) {
+ if (type_ == WORK_WRITE_INDEX)
+ worker_->CloseBackupIndexFile();
+
+ if (result != buffer_len_)
+ return net::ERR_CACHE_WRITE_FAILURE;
+
+ return result;
+}
+
+int BackendImplV3::WorkItem::DoMoveData() {
+ disk_cache::File* file = worker_->GetBackingFile(address_, false);
+ if (!file)
+ return ERR_OPERATION_FAILED;
+
+ DCHECK(buffer_len_);
+
+ if (!address_.is_block_file()) {
+ NOTREACHED();
+ return ERR_OPERATION_FAILED;
+ }
+
+ offset_ = 0;
+ size_t file_offset = 0;
+ DCHECK_LE(buffer_len_, kMaxBlockSize);
+ file_offset += address_.start_block() * address_.BlockSize();
+
+ buffer_ = new net::IOBufferWithSize(buffer_len_);
+
+ // We could optimize this to be an async read, but we'd have to do that from
+ // the main thread, not from here.
+ if (!file->Read(buffer_->data(), buffer_len_, file_offset))
+ return ERR_WRITE_FAILURE;
+
+ address_ = address2_;
+ next_state_ = STATE_WRITE_DATA;
+ return NO_ERROR;
+}
+
+int BackendImplV3::WorkItem::DoTruncateData() {
+ if (address_.is_block_file())
+ return ERR_OPERATION_FAILED;
+
+ disk_cache::File* file = worker_->GetBackingFile(address_, false);
+ if (!file)
+ return ERR_OPERATION_FAILED;
+
+ if (!file->SetLength(offset_))
+ return ERR_OPERATION_FAILED;
+
+ return ERR_NO_ERROR;
+}
+
+int BackendImplV3::WorkItem::DoCopyEntry() {
+ next_state_ = STATE_COPY_ENTRY_COMPLETE;
+ Addr address = entries_.cells[1].GetAddress();
+ short_entry_block_.reset(
+ new CacheShortEntryBlock(worker_->GetMappedFile(address), address));
+
+ ShortEntryRecord* short_record = short_entry_block_->Data();
+ EntryRecord* long_record = entry_block_->Data();
+
+ short_record->hash = long_record->hash;
+ short_record->reuse_count = long_record->reuse_count;
+ short_record->refetch_count = long_record->refetch_count;
+ short_record->refetch_count = long_record->refetch_count;
+ short_record->key_len = long_record->key_len;
+ short_record->last_access_time = long_record->last_access_time;
+ ComputeCryptoHash(key_, short_record);
+
+ bool completed;
+ IOCallback* callback = new IOCallback(this);
+ if (!short_entry_block_->Store(callback, &completed)) {
+ callback->Discard();
+ next_state_ = STATE_NONE;
+ return ERR_OPERATION_FAILED;
+ }
+
+ if (completed) {
+ callback->Discard();
+ return ERR_NO_ERROR;
+ }
+
+ return ERR_PENDING;
+}
+
+int BackendImplV3::WorkItem::DoCopyEntryComplete(int result) {
+ if (result != static_cast<int>(sizeof(ShortEntryRecord)))
+ return ERR_READ_FAILURE;
+
+ entry_record_.reset(entry_block_->ReleaseData());
+ return ERR_NO_ERROR;
+}
+
+int BackendImplV3::WorkItem::LoadEntryBlock(Addr address) {
+ entry_block_.reset(new CacheEntryBlockV3(worker_->GetMappedFile(address),
+ address));
+ bool completed;
+ IOCallback* callback = new IOCallback(this);
+ if (!entry_block_->Load(callback, &completed)) {
+ callback->Discard();
+ next_state_ = STATE_NONE;
+ return ERR_OPERATION_FAILED;
+ }
+
+ if (completed) {
+ callback->Discard();
+ return ERR_NO_ERROR;
+ }
+
+ return ERR_PENDING;
+}
+
+int BackendImplV3::WorkItem::LoadShortEntryBlock(Addr address) {
+ short_entry_block_.reset(
+ new CacheShortEntryBlock(worker_->GetMappedFile(address), address));
+ bool completed;
+ IOCallback* callback = new IOCallback(this);
+ if (!short_entry_block_->Load(callback, &completed)) {
+ callback->Discard();
+ next_state_ = STATE_NONE;
+ return ERR_OPERATION_FAILED;
+ }
+
+ if (completed) {
+ callback->Discard();
+ return ERR_NO_ERROR;
+ }
+
+ return ERR_PENDING;
+}
+
+} // namespace disk_cache
Property changes on: net\disk_cache\v3\backend_work_item.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « net/disk_cache/v3/backend_work_item.h ('k') | net/disk_cache/v3/backend_worker.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698