| Index: net/disk_cache/entry_impl.cc
|
| diff --git a/net/disk_cache/entry_impl.cc b/net/disk_cache/entry_impl.cc
|
| index 3cb895fd02f4456bca1e295551a18856558fd596..ff05e1158b5b786d3b9a7e74d68c185fe4c12335 100644
|
| --- a/net/disk_cache/entry_impl.cc
|
| +++ b/net/disk_cache/entry_impl.cc
|
| @@ -375,197 +375,6 @@ EntryImpl::EntryImpl(BackendImpl* backend, Addr address, bool read_only)
|
| }
|
| }
|
|
|
| -// When an entry is deleted from the cache, we clean up all the data associated
|
| -// with it for two reasons: to simplify the reuse of the block (we know that any
|
| -// unused block is filled with zeros), and to simplify the handling of write /
|
| -// read partial information from an entry (don't have to worry about returning
|
| -// data related to a previous cache entry because the range was not fully
|
| -// written before).
|
| -EntryImpl::~EntryImpl() {
|
| - Log("~EntryImpl in");
|
| -
|
| - // Save the sparse info to disk. This will generate IO for this entry and
|
| - // maybe for a child entry, so it is important to do it before deleting this
|
| - // entry.
|
| - sparse_.reset();
|
| -
|
| - // Remove this entry from the list of open entries.
|
| - backend_->OnEntryDestroyBegin(entry_.address());
|
| -
|
| - if (doomed_) {
|
| - DeleteEntryData(true);
|
| - } else {
|
| - net_log_.AddEvent(net::NetLog::TYPE_DISK_CACHE_CLOSE, NULL);
|
| - bool ret = true;
|
| - for (int index = 0; index < kNumStreams; index++) {
|
| - if (user_buffers_[index].get()) {
|
| - if (!(ret = Flush(index, 0)))
|
| - LOG(ERROR) << "Failed to save user data";
|
| - }
|
| - if (unreported_size_[index]) {
|
| - backend_->ModifyStorageSize(
|
| - entry_.Data()->data_size[index] - unreported_size_[index],
|
| - entry_.Data()->data_size[index]);
|
| - }
|
| - }
|
| -
|
| - if (!ret) {
|
| - // There was a failure writing the actual data. Mark the entry as dirty.
|
| - int current_id = backend_->GetCurrentEntryId();
|
| - node_.Data()->dirty = current_id == 1 ? -1 : current_id - 1;
|
| - node_.Store();
|
| - } else if (node_.HasData() && node_.Data()->dirty) {
|
| - node_.Data()->dirty = 0;
|
| - node_.Store();
|
| - }
|
| - }
|
| -
|
| - Trace("~EntryImpl out 0x%p", reinterpret_cast<void*>(this));
|
| - net_log_.EndEvent(net::NetLog::TYPE_DISK_CACHE_ENTRY, NULL);
|
| - backend_->OnEntryDestroyEnd();
|
| -}
|
| -
|
| -void EntryImpl::Doom() {
|
| - backend_->background_queue()->DoomEntryImpl(this);
|
| -}
|
| -
|
| -void EntryImpl::Close() {
|
| - backend_->background_queue()->CloseEntryImpl(this);
|
| -}
|
| -
|
| -std::string EntryImpl::GetKey() const {
|
| - CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_);
|
| - if (entry->Data()->key_len <= kMaxInternalKeyLength)
|
| - return std::string(entry->Data()->key);
|
| -
|
| - // We keep a copy of the key so that we can always return it, even if the
|
| - // backend is disabled.
|
| - if (!key_.empty())
|
| - return key_;
|
| -
|
| - Addr address(entry->Data()->long_key);
|
| - DCHECK(address.is_initialized());
|
| - size_t offset = 0;
|
| - if (address.is_block_file())
|
| - offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
|
| -
|
| - COMPILE_ASSERT(kNumStreams == kKeyFileIndex, invalid_key_index);
|
| - File* key_file = const_cast<EntryImpl*>(this)->GetBackingFile(address,
|
| - kKeyFileIndex);
|
| -
|
| - if (!key_file ||
|
| - !key_file->Read(WriteInto(&key_, entry->Data()->key_len + 1),
|
| - entry->Data()->key_len + 1, offset))
|
| - key_.clear();
|
| - return key_;
|
| -}
|
| -
|
| -Time EntryImpl::GetLastUsed() const {
|
| - CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_);
|
| - return Time::FromInternalValue(node->Data()->last_used);
|
| -}
|
| -
|
| -Time EntryImpl::GetLastModified() const {
|
| - CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_);
|
| - return Time::FromInternalValue(node->Data()->last_modified);
|
| -}
|
| -
|
| -int32 EntryImpl::GetDataSize(int index) const {
|
| - if (index < 0 || index >= kNumStreams)
|
| - return 0;
|
| -
|
| - CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_);
|
| - return entry->Data()->data_size[index];
|
| -}
|
| -
|
| -int EntryImpl::ReadData(int index, int offset, net::IOBuffer* buf, int buf_len,
|
| - net::CompletionCallback* callback) {
|
| - if (!callback)
|
| - return ReadDataImpl(index, offset, buf, buf_len, callback);
|
| -
|
| - DCHECK(node_.Data()->dirty || read_only_);
|
| - if (index < 0 || index >= kNumStreams)
|
| - return net::ERR_INVALID_ARGUMENT;
|
| -
|
| - int entry_size = entry_.Data()->data_size[index];
|
| - if (offset >= entry_size || offset < 0 || !buf_len)
|
| - return 0;
|
| -
|
| - if (buf_len < 0)
|
| - return net::ERR_INVALID_ARGUMENT;
|
| -
|
| - backend_->background_queue()->ReadData(this, index, offset, buf, buf_len,
|
| - callback);
|
| - return net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -int EntryImpl::WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
|
| - CompletionCallback* callback, bool truncate) {
|
| - if (!callback)
|
| - return WriteDataImpl(index, offset, buf, buf_len, callback, truncate);
|
| -
|
| - DCHECK(node_.Data()->dirty || read_only_);
|
| - if (index < 0 || index >= kNumStreams)
|
| - return net::ERR_INVALID_ARGUMENT;
|
| -
|
| - if (offset < 0 || buf_len < 0)
|
| - return net::ERR_INVALID_ARGUMENT;
|
| -
|
| - backend_->background_queue()->WriteData(this, index, offset, buf, buf_len,
|
| - truncate, callback);
|
| - return net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -int EntryImpl::ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
|
| - net::CompletionCallback* callback) {
|
| - if (!callback)
|
| - return ReadSparseDataImpl(offset, buf, buf_len, callback);
|
| -
|
| - backend_->background_queue()->ReadSparseData(this, offset, buf, buf_len,
|
| - callback);
|
| - return net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -int EntryImpl::WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
|
| - net::CompletionCallback* callback) {
|
| - if (!callback)
|
| - return WriteSparseDataImpl(offset, buf, buf_len, callback);
|
| -
|
| - backend_->background_queue()->WriteSparseData(this, offset, buf, buf_len,
|
| - callback);
|
| - return net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -int EntryImpl::GetAvailableRange(int64 offset, int len, int64* start,
|
| - CompletionCallback* callback) {
|
| - backend_->background_queue()->GetAvailableRange(this, offset, len, start,
|
| - callback);
|
| - return net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -bool EntryImpl::CouldBeSparse() const {
|
| - if (sparse_.get())
|
| - return true;
|
| -
|
| - scoped_ptr<SparseControl> sparse;
|
| - sparse.reset(new SparseControl(const_cast<EntryImpl*>(this)));
|
| - return sparse->CouldBeSparse();
|
| -}
|
| -
|
| -void EntryImpl::CancelSparseIO() {
|
| - backend_->background_queue()->CancelSparseIO(this);
|
| -}
|
| -
|
| -int EntryImpl::ReadyForSparseIO(net::CompletionCallback* callback) {
|
| - if (!sparse_.get())
|
| - return net::OK;
|
| -
|
| - backend_->background_queue()->ReadyForSparseIO(this, callback);
|
| - return net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -// ------------------------------------------------------------------------
|
| -
|
| void EntryImpl::DoomImpl() {
|
| if (doomed_)
|
| return;
|
| @@ -614,220 +423,53 @@ int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf,
|
| return result;
|
| }
|
|
|
| -int EntryImpl::InternalReadData(int index, int offset, net::IOBuffer* buf,
|
| - int buf_len, CompletionCallback* callback) {
|
| +int EntryImpl::ReadSparseDataImpl(int64 offset, net::IOBuffer* buf, int buf_len,
|
| + CompletionCallback* callback) {
|
| DCHECK(node_.Data()->dirty || read_only_);
|
| - DVLOG(2) << "Read from " << index << " at " << offset << " : " << buf_len;
|
| - if (index < 0 || index >= kNumStreams)
|
| - return net::ERR_INVALID_ARGUMENT;
|
| + int result = InitSparseData();
|
| + if (net::OK != result)
|
| + return result;
|
|
|
| - int entry_size = entry_.Data()->data_size[index];
|
| - if (offset >= entry_size || offset < 0 || !buf_len)
|
| - return 0;
|
| + TimeTicks start = TimeTicks::Now();
|
| + result = sparse_->StartIO(SparseControl::kReadOperation, offset, buf, buf_len,
|
| + callback);
|
| + ReportIOTime(kSparseRead, start);
|
| + return result;
|
| +}
|
|
|
| - if (buf_len < 0)
|
| - return net::ERR_INVALID_ARGUMENT;
|
| +int EntryImpl::WriteSparseDataImpl(int64 offset, net::IOBuffer* buf,
|
| + int buf_len, CompletionCallback* callback) {
|
| + DCHECK(node_.Data()->dirty || read_only_);
|
| + int result = InitSparseData();
|
| + if (net::OK != result)
|
| + return result;
|
|
|
| TimeTicks start = TimeTicks::Now();
|
| + result = sparse_->StartIO(SparseControl::kWriteOperation, offset, buf,
|
| + buf_len, callback);
|
| + ReportIOTime(kSparseWrite, start);
|
| + return result;
|
| +}
|
|
|
| - if (offset + buf_len > entry_size)
|
| - buf_len = entry_size - offset;
|
| +int EntryImpl::GetAvailableRangeImpl(int64 offset, int len, int64* start) {
|
| + int result = InitSparseData();
|
| + if (net::OK != result)
|
| + return result;
|
|
|
| - UpdateRank(false);
|
| + return sparse_->GetAvailableRange(offset, len, start);
|
| +}
|
|
|
| - backend_->OnEvent(Stats::READ_DATA);
|
| - backend_->OnRead(buf_len);
|
| +void EntryImpl::CancelSparseIOImpl() {
|
| + if (!sparse_.get())
|
| + return;
|
|
|
| - Addr address(entry_.Data()->data_addr[index]);
|
| - int eof = address.is_initialized() ? entry_size : 0;
|
| - if (user_buffers_[index].get() &&
|
| - user_buffers_[index]->PreRead(eof, offset, &buf_len)) {
|
| - // Complete the operation locally.
|
| - buf_len = user_buffers_[index]->Read(offset, buf, buf_len);
|
| - ReportIOTime(kRead, start);
|
| - return buf_len;
|
| - }
|
| + sparse_->CancelIO();
|
| +}
|
|
|
| - address.set_value(entry_.Data()->data_addr[index]);
|
| - DCHECK(address.is_initialized());
|
| - if (!address.is_initialized())
|
| - return net::ERR_FAILED;
|
| -
|
| - File* file = GetBackingFile(address, index);
|
| - if (!file)
|
| - return net::ERR_FAILED;
|
| -
|
| - size_t file_offset = offset;
|
| - if (address.is_block_file()) {
|
| - DCHECK_LE(offset + buf_len, kMaxBlockSize);
|
| - file_offset += address.start_block() * address.BlockSize() +
|
| - kBlockHeaderSize;
|
| - }
|
| -
|
| - SyncCallback* io_callback = NULL;
|
| - if (callback) {
|
| - io_callback = new SyncCallback(this, buf, callback,
|
| - net::NetLog::TYPE_DISK_CACHE_READ_DATA);
|
| - }
|
| -
|
| - bool completed;
|
| - if (!file->Read(buf->data(), buf_len, file_offset, io_callback, &completed)) {
|
| - if (io_callback)
|
| - io_callback->Discard();
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - if (io_callback && completed)
|
| - io_callback->Discard();
|
| -
|
| - ReportIOTime(kRead, start);
|
| - return (completed || !callback) ? buf_len : net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -int EntryImpl::InternalWriteData(int index, int offset, net::IOBuffer* buf,
|
| - int buf_len, CompletionCallback* callback,
|
| - bool truncate) {
|
| - DCHECK(node_.Data()->dirty || read_only_);
|
| - DVLOG(2) << "Write to " << index << " at " << offset << " : " << buf_len;
|
| - if (index < 0 || index >= kNumStreams)
|
| - return net::ERR_INVALID_ARGUMENT;
|
| -
|
| - if (offset < 0 || buf_len < 0)
|
| - return net::ERR_INVALID_ARGUMENT;
|
| -
|
| - int max_file_size = backend_->MaxFileSize();
|
| -
|
| - // offset or buf_len could be negative numbers.
|
| - if (offset > max_file_size || buf_len > max_file_size ||
|
| - offset + buf_len > max_file_size) {
|
| - int size = offset + buf_len;
|
| - if (size <= max_file_size)
|
| - size = kint32max;
|
| - backend_->TooMuchStorageRequested(size);
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - TimeTicks start = TimeTicks::Now();
|
| -
|
| - // Read the size at this point (it may change inside prepare).
|
| - int entry_size = entry_.Data()->data_size[index];
|
| - bool extending = entry_size < offset + buf_len;
|
| - truncate = truncate && entry_size > offset + buf_len;
|
| - Trace("To PrepareTarget 0x%x", entry_.address().value());
|
| - if (!PrepareTarget(index, offset, buf_len, truncate))
|
| - return net::ERR_FAILED;
|
| -
|
| - Trace("From PrepareTarget 0x%x", entry_.address().value());
|
| - if (extending || truncate)
|
| - UpdateSize(index, entry_size, offset + buf_len);
|
| -
|
| - UpdateRank(true);
|
| -
|
| - backend_->OnEvent(Stats::WRITE_DATA);
|
| - backend_->OnWrite(buf_len);
|
| -
|
| - if (user_buffers_[index].get()) {
|
| - // Complete the operation locally.
|
| - user_buffers_[index]->Write(offset, buf, buf_len);
|
| - ReportIOTime(kWrite, start);
|
| - return buf_len;
|
| - }
|
| -
|
| - Addr address(entry_.Data()->data_addr[index]);
|
| - if (offset + buf_len == 0) {
|
| - if (truncate) {
|
| - DCHECK(!address.is_initialized());
|
| - }
|
| - return 0;
|
| - }
|
| -
|
| - File* file = GetBackingFile(address, index);
|
| - if (!file)
|
| - return net::ERR_FAILED;
|
| -
|
| - size_t file_offset = offset;
|
| - if (address.is_block_file()) {
|
| - DCHECK_LE(offset + buf_len, kMaxBlockSize);
|
| - file_offset += address.start_block() * address.BlockSize() +
|
| - kBlockHeaderSize;
|
| - } else if (truncate || (extending && !buf_len)) {
|
| - if (!file->SetLength(offset + buf_len))
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - if (!buf_len)
|
| - return 0;
|
| -
|
| - SyncCallback* io_callback = NULL;
|
| - if (callback) {
|
| - io_callback = new SyncCallback(this, buf, callback,
|
| - net::NetLog::TYPE_DISK_CACHE_WRITE_DATA);
|
| - }
|
| -
|
| - bool completed;
|
| - if (!file->Write(buf->data(), buf_len, file_offset, io_callback,
|
| - &completed)) {
|
| - if (io_callback)
|
| - io_callback->Discard();
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - if (io_callback && completed)
|
| - io_callback->Discard();
|
| -
|
| - ReportIOTime(kWrite, start);
|
| - return (completed || !callback) ? buf_len : net::ERR_IO_PENDING;
|
| -}
|
| -
|
| -int EntryImpl::ReadSparseDataImpl(int64 offset, net::IOBuffer* buf, int buf_len,
|
| - CompletionCallback* callback) {
|
| - DCHECK(node_.Data()->dirty || read_only_);
|
| - int result = InitSparseData();
|
| - if (net::OK != result)
|
| - return result;
|
| -
|
| - TimeTicks start = TimeTicks::Now();
|
| - result = sparse_->StartIO(SparseControl::kReadOperation, offset, buf, buf_len,
|
| - callback);
|
| - ReportIOTime(kSparseRead, start);
|
| - return result;
|
| -}
|
| -
|
| -int EntryImpl::WriteSparseDataImpl(int64 offset, net::IOBuffer* buf,
|
| - int buf_len, CompletionCallback* callback) {
|
| - DCHECK(node_.Data()->dirty || read_only_);
|
| - int result = InitSparseData();
|
| - if (net::OK != result)
|
| - return result;
|
| -
|
| - TimeTicks start = TimeTicks::Now();
|
| - result = sparse_->StartIO(SparseControl::kWriteOperation, offset, buf,
|
| - buf_len, callback);
|
| - ReportIOTime(kSparseWrite, start);
|
| - return result;
|
| -}
|
| -
|
| -int EntryImpl::GetAvailableRangeImpl(int64 offset, int len, int64* start) {
|
| - int result = InitSparseData();
|
| - if (net::OK != result)
|
| - return result;
|
| -
|
| - return sparse_->GetAvailableRange(offset, len, start);
|
| -}
|
| -
|
| -void EntryImpl::CancelSparseIOImpl() {
|
| - if (!sparse_.get())
|
| - return;
|
| -
|
| - sparse_->CancelIO();
|
| -}
|
| -
|
| -int EntryImpl::ReadyForSparseIOImpl(CompletionCallback* callback) {
|
| - DCHECK(sparse_.get());
|
| - return sparse_->ReadyToUse(callback);
|
| -}
|
| -
|
| -// ------------------------------------------------------------------------
|
| +int EntryImpl::ReadyForSparseIOImpl(CompletionCallback* callback) {
|
| + DCHECK(sparse_.get());
|
| + return sparse_->ReadyToUse(callback);
|
| +}
|
|
|
| uint32 EntryImpl::GetHash() {
|
| return entry_.Data()->hash;
|
| @@ -1061,6 +703,362 @@ const net::BoundNetLog& EntryImpl::net_log() const {
|
| return net_log_;
|
| }
|
|
|
| +void EntryImpl::Doom() {
|
| + backend_->background_queue()->DoomEntryImpl(this);
|
| +}
|
| +
|
| +void EntryImpl::Close() {
|
| + backend_->background_queue()->CloseEntryImpl(this);
|
| +}
|
| +
|
| +std::string EntryImpl::GetKey() const {
|
| + CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_);
|
| + if (entry->Data()->key_len <= kMaxInternalKeyLength)
|
| + return std::string(entry->Data()->key);
|
| +
|
| + // We keep a copy of the key so that we can always return it, even if the
|
| + // backend is disabled.
|
| + if (!key_.empty())
|
| + return key_;
|
| +
|
| + Addr address(entry->Data()->long_key);
|
| + DCHECK(address.is_initialized());
|
| + size_t offset = 0;
|
| + if (address.is_block_file())
|
| + offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
|
| +
|
| + COMPILE_ASSERT(kNumStreams == kKeyFileIndex, invalid_key_index);
|
| + File* key_file = const_cast<EntryImpl*>(this)->GetBackingFile(address,
|
| + kKeyFileIndex);
|
| +
|
| + if (!key_file ||
|
| + !key_file->Read(WriteInto(&key_, entry->Data()->key_len + 1),
|
| + entry->Data()->key_len + 1, offset))
|
| + key_.clear();
|
| + return key_;
|
| +}
|
| +
|
| +Time EntryImpl::GetLastUsed() const {
|
| + CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_);
|
| + return Time::FromInternalValue(node->Data()->last_used);
|
| +}
|
| +
|
| +Time EntryImpl::GetLastModified() const {
|
| + CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_);
|
| + return Time::FromInternalValue(node->Data()->last_modified);
|
| +}
|
| +
|
| +int32 EntryImpl::GetDataSize(int index) const {
|
| + if (index < 0 || index >= kNumStreams)
|
| + return 0;
|
| +
|
| + CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_);
|
| + return entry->Data()->data_size[index];
|
| +}
|
| +
|
| +int EntryImpl::ReadData(int index, int offset, net::IOBuffer* buf, int buf_len,
|
| + net::CompletionCallback* callback) {
|
| + if (!callback)
|
| + return ReadDataImpl(index, offset, buf, buf_len, callback);
|
| +
|
| + DCHECK(node_.Data()->dirty || read_only_);
|
| + if (index < 0 || index >= kNumStreams)
|
| + return net::ERR_INVALID_ARGUMENT;
|
| +
|
| + int entry_size = entry_.Data()->data_size[index];
|
| + if (offset >= entry_size || offset < 0 || !buf_len)
|
| + return 0;
|
| +
|
| + if (buf_len < 0)
|
| + return net::ERR_INVALID_ARGUMENT;
|
| +
|
| + backend_->background_queue()->ReadData(this, index, offset, buf, buf_len,
|
| + callback);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int EntryImpl::WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
|
| + CompletionCallback* callback, bool truncate) {
|
| + if (!callback)
|
| + return WriteDataImpl(index, offset, buf, buf_len, callback, truncate);
|
| +
|
| + DCHECK(node_.Data()->dirty || read_only_);
|
| + if (index < 0 || index >= kNumStreams)
|
| + return net::ERR_INVALID_ARGUMENT;
|
| +
|
| + if (offset < 0 || buf_len < 0)
|
| + return net::ERR_INVALID_ARGUMENT;
|
| +
|
| + backend_->background_queue()->WriteData(this, index, offset, buf, buf_len,
|
| + truncate, callback);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int EntryImpl::ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
|
| + net::CompletionCallback* callback) {
|
| + if (!callback)
|
| + return ReadSparseDataImpl(offset, buf, buf_len, callback);
|
| +
|
| + backend_->background_queue()->ReadSparseData(this, offset, buf, buf_len,
|
| + callback);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int EntryImpl::WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
|
| + net::CompletionCallback* callback) {
|
| + if (!callback)
|
| + return WriteSparseDataImpl(offset, buf, buf_len, callback);
|
| +
|
| + backend_->background_queue()->WriteSparseData(this, offset, buf, buf_len,
|
| + callback);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int EntryImpl::GetAvailableRange(int64 offset, int len, int64* start,
|
| + CompletionCallback* callback) {
|
| + backend_->background_queue()->GetAvailableRange(this, offset, len, start,
|
| + callback);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +bool EntryImpl::CouldBeSparse() const {
|
| + if (sparse_.get())
|
| + return true;
|
| +
|
| + scoped_ptr<SparseControl> sparse;
|
| + sparse.reset(new SparseControl(const_cast<EntryImpl*>(this)));
|
| + return sparse->CouldBeSparse();
|
| +}
|
| +
|
| +void EntryImpl::CancelSparseIO() {
|
| + backend_->background_queue()->CancelSparseIO(this);
|
| +}
|
| +
|
| +int EntryImpl::ReadyForSparseIO(net::CompletionCallback* callback) {
|
| + if (!sparse_.get())
|
| + return net::OK;
|
| +
|
| + backend_->background_queue()->ReadyForSparseIO(this, callback);
|
| + return net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +// When an entry is deleted from the cache, we clean up all the data associated
|
| +// with it for two reasons: to simplify the reuse of the block (we know that any
|
| +// unused block is filled with zeros), and to simplify the handling of write /
|
| +// read partial information from an entry (don't have to worry about returning
|
| +// data related to a previous cache entry because the range was not fully
|
| +// written before).
|
| +EntryImpl::~EntryImpl() {
|
| + Log("~EntryImpl in");
|
| +
|
| + // Save the sparse info to disk. This will generate IO for this entry and
|
| + // maybe for a child entry, so it is important to do it before deleting this
|
| + // entry.
|
| + sparse_.reset();
|
| +
|
| + // Remove this entry from the list of open entries.
|
| + backend_->OnEntryDestroyBegin(entry_.address());
|
| +
|
| + if (doomed_) {
|
| + DeleteEntryData(true);
|
| + } else {
|
| + net_log_.AddEvent(net::NetLog::TYPE_DISK_CACHE_CLOSE, NULL);
|
| + bool ret = true;
|
| + for (int index = 0; index < kNumStreams; index++) {
|
| + if (user_buffers_[index].get()) {
|
| + if (!(ret = Flush(index, 0)))
|
| + LOG(ERROR) << "Failed to save user data";
|
| + }
|
| + if (unreported_size_[index]) {
|
| + backend_->ModifyStorageSize(
|
| + entry_.Data()->data_size[index] - unreported_size_[index],
|
| + entry_.Data()->data_size[index]);
|
| + }
|
| + }
|
| +
|
| + if (!ret) {
|
| + // There was a failure writing the actual data. Mark the entry as dirty.
|
| + int current_id = backend_->GetCurrentEntryId();
|
| + node_.Data()->dirty = current_id == 1 ? -1 : current_id - 1;
|
| + node_.Store();
|
| + } else if (node_.HasData() && node_.Data()->dirty) {
|
| + node_.Data()->dirty = 0;
|
| + node_.Store();
|
| + }
|
| + }
|
| +
|
| + Trace("~EntryImpl out 0x%p", reinterpret_cast<void*>(this));
|
| + net_log_.EndEvent(net::NetLog::TYPE_DISK_CACHE_ENTRY, NULL);
|
| + backend_->OnEntryDestroyEnd();
|
| +}
|
| +
|
| +// ------------------------------------------------------------------------
|
| +
|
| +int EntryImpl::InternalReadData(int index, int offset, net::IOBuffer* buf,
|
| + int buf_len, CompletionCallback* callback) {
|
| + DCHECK(node_.Data()->dirty || read_only_);
|
| + DVLOG(2) << "Read from " << index << " at " << offset << " : " << buf_len;
|
| + if (index < 0 || index >= kNumStreams)
|
| + return net::ERR_INVALID_ARGUMENT;
|
| +
|
| + int entry_size = entry_.Data()->data_size[index];
|
| + if (offset >= entry_size || offset < 0 || !buf_len)
|
| + return 0;
|
| +
|
| + if (buf_len < 0)
|
| + return net::ERR_INVALID_ARGUMENT;
|
| +
|
| + TimeTicks start = TimeTicks::Now();
|
| +
|
| + if (offset + buf_len > entry_size)
|
| + buf_len = entry_size - offset;
|
| +
|
| + UpdateRank(false);
|
| +
|
| + backend_->OnEvent(Stats::READ_DATA);
|
| + backend_->OnRead(buf_len);
|
| +
|
| + Addr address(entry_.Data()->data_addr[index]);
|
| + int eof = address.is_initialized() ? entry_size : 0;
|
| + if (user_buffers_[index].get() &&
|
| + user_buffers_[index]->PreRead(eof, offset, &buf_len)) {
|
| + // Complete the operation locally.
|
| + buf_len = user_buffers_[index]->Read(offset, buf, buf_len);
|
| + ReportIOTime(kRead, start);
|
| + return buf_len;
|
| + }
|
| +
|
| + address.set_value(entry_.Data()->data_addr[index]);
|
| + DCHECK(address.is_initialized());
|
| + if (!address.is_initialized())
|
| + return net::ERR_FAILED;
|
| +
|
| + File* file = GetBackingFile(address, index);
|
| + if (!file)
|
| + return net::ERR_FAILED;
|
| +
|
| + size_t file_offset = offset;
|
| + if (address.is_block_file()) {
|
| + DCHECK_LE(offset + buf_len, kMaxBlockSize);
|
| + file_offset += address.start_block() * address.BlockSize() +
|
| + kBlockHeaderSize;
|
| + }
|
| +
|
| + SyncCallback* io_callback = NULL;
|
| + if (callback) {
|
| + io_callback = new SyncCallback(this, buf, callback,
|
| + net::NetLog::TYPE_DISK_CACHE_READ_DATA);
|
| + }
|
| +
|
| + bool completed;
|
| + if (!file->Read(buf->data(), buf_len, file_offset, io_callback, &completed)) {
|
| + if (io_callback)
|
| + io_callback->Discard();
|
| + return net::ERR_FAILED;
|
| + }
|
| +
|
| + if (io_callback && completed)
|
| + io_callback->Discard();
|
| +
|
| + ReportIOTime(kRead, start);
|
| + return (completed || !callback) ? buf_len : net::ERR_IO_PENDING;
|
| +}
|
| +
|
| +int EntryImpl::InternalWriteData(int index, int offset, net::IOBuffer* buf,
|
| + int buf_len, CompletionCallback* callback,
|
| + bool truncate) {
|
| + DCHECK(node_.Data()->dirty || read_only_);
|
| + DVLOG(2) << "Write to " << index << " at " << offset << " : " << buf_len;
|
| + if (index < 0 || index >= kNumStreams)
|
| + return net::ERR_INVALID_ARGUMENT;
|
| +
|
| + if (offset < 0 || buf_len < 0)
|
| + return net::ERR_INVALID_ARGUMENT;
|
| +
|
| + int max_file_size = backend_->MaxFileSize();
|
| +
|
| + // offset or buf_len could be negative numbers.
|
| + if (offset > max_file_size || buf_len > max_file_size ||
|
| + offset + buf_len > max_file_size) {
|
| + int size = offset + buf_len;
|
| + if (size <= max_file_size)
|
| + size = kint32max;
|
| + backend_->TooMuchStorageRequested(size);
|
| + return net::ERR_FAILED;
|
| + }
|
| +
|
| + TimeTicks start = TimeTicks::Now();
|
| +
|
| + // Read the size at this point (it may change inside prepare).
|
| + int entry_size = entry_.Data()->data_size[index];
|
| + bool extending = entry_size < offset + buf_len;
|
| + truncate = truncate && entry_size > offset + buf_len;
|
| + Trace("To PrepareTarget 0x%x", entry_.address().value());
|
| + if (!PrepareTarget(index, offset, buf_len, truncate))
|
| + return net::ERR_FAILED;
|
| +
|
| + Trace("From PrepareTarget 0x%x", entry_.address().value());
|
| + if (extending || truncate)
|
| + UpdateSize(index, entry_size, offset + buf_len);
|
| +
|
| + UpdateRank(true);
|
| +
|
| + backend_->OnEvent(Stats::WRITE_DATA);
|
| + backend_->OnWrite(buf_len);
|
| +
|
| + if (user_buffers_[index].get()) {
|
| + // Complete the operation locally.
|
| + user_buffers_[index]->Write(offset, buf, buf_len);
|
| + ReportIOTime(kWrite, start);
|
| + return buf_len;
|
| + }
|
| +
|
| + Addr address(entry_.Data()->data_addr[index]);
|
| + if (offset + buf_len == 0) {
|
| + if (truncate) {
|
| + DCHECK(!address.is_initialized());
|
| + }
|
| + return 0;
|
| + }
|
| +
|
| + File* file = GetBackingFile(address, index);
|
| + if (!file)
|
| + return net::ERR_FAILED;
|
| +
|
| + size_t file_offset = offset;
|
| + if (address.is_block_file()) {
|
| + DCHECK_LE(offset + buf_len, kMaxBlockSize);
|
| + file_offset += address.start_block() * address.BlockSize() +
|
| + kBlockHeaderSize;
|
| + } else if (truncate || (extending && !buf_len)) {
|
| + if (!file->SetLength(offset + buf_len))
|
| + return net::ERR_FAILED;
|
| + }
|
| +
|
| + if (!buf_len)
|
| + return 0;
|
| +
|
| + SyncCallback* io_callback = NULL;
|
| + if (callback) {
|
| + io_callback = new SyncCallback(this, buf, callback,
|
| + net::NetLog::TYPE_DISK_CACHE_WRITE_DATA);
|
| + }
|
| +
|
| + bool completed;
|
| + if (!file->Write(buf->data(), buf_len, file_offset, io_callback,
|
| + &completed)) {
|
| + if (io_callback)
|
| + io_callback->Discard();
|
| + return net::ERR_FAILED;
|
| + }
|
| +
|
| + if (io_callback && completed)
|
| + io_callback->Discard();
|
| +
|
| + ReportIOTime(kWrite, start);
|
| + return (completed || !callback) ? buf_len : net::ERR_IO_PENDING;
|
| +}
|
| +
|
| // ------------------------------------------------------------------------
|
|
|
| bool EntryImpl::CreateDataBlock(int index, int size) {
|
|
|