Index: net/disk_cache/memory/mem_entry_impl.cc |
diff --git a/net/disk_cache/memory/mem_entry_impl.cc b/net/disk_cache/memory/mem_entry_impl.cc |
deleted file mode 100644 |
index 7c6199b951b28febf2c2d2cb3b1c595a67ab0324..0000000000000000000000000000000000000000 |
--- a/net/disk_cache/memory/mem_entry_impl.cc |
+++ /dev/null |
@@ -1,631 +0,0 @@ |
-// 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/memory/mem_entry_impl.h" |
- |
-#include "base/bind.h" |
-#include "base/logging.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/values.h" |
-#include "net/base/io_buffer.h" |
-#include "net/base/net_errors.h" |
-#include "net/disk_cache/memory/mem_backend_impl.h" |
-#include "net/disk_cache/net_log_parameters.h" |
- |
-using base::Time; |
- |
-namespace { |
- |
-const int kSparseData = 1; |
- |
-// Maximum size of a sparse entry is 2 to the power of this number. |
-const int kMaxSparseEntryBits = 12; |
- |
-// Sparse entry has maximum size of 4KB. |
-const int kMaxSparseEntrySize = 1 << kMaxSparseEntryBits; |
- |
-// Convert global offset to child index. |
-inline int ToChildIndex(int64 offset) { |
- return static_cast<int>(offset >> kMaxSparseEntryBits); |
-} |
- |
-// Convert global offset to offset in child entry. |
-inline int ToChildOffset(int64 offset) { |
- return static_cast<int>(offset & (kMaxSparseEntrySize - 1)); |
-} |
- |
-// Returns a name for a child entry given the base_name of the parent and the |
-// child_id. This name is only used for logging purposes. |
-// If the entry is called entry_name, child entries will be named something |
-// like Range_entry_name:YYY where YYY is the number of the particular child. |
-std::string GenerateChildName(const std::string& base_name, int child_id) { |
- return base::StringPrintf("Range_%s:%i", base_name.c_str(), child_id); |
-} |
- |
-// Returns NetLog parameters for the creation of a child MemEntryImpl. Separate |
-// function needed because child entries don't suppport GetKey(). |
-base::Value* NetLogChildEntryCreationCallback( |
- const disk_cache::MemEntryImpl* parent, |
- int child_id, |
- net::NetLog::LogLevel /* log_level */) { |
- base::DictionaryValue* dict = new base::DictionaryValue(); |
- dict->SetString("key", GenerateChildName(parent->GetKey(), child_id)); |
- dict->SetBoolean("created", true); |
- return dict; |
-} |
- |
-} // namespace |
- |
-namespace disk_cache { |
- |
-MemEntryImpl::MemEntryImpl(MemBackendImpl* backend) { |
- doomed_ = false; |
- backend_ = backend; |
- ref_count_ = 0; |
- parent_ = NULL; |
- child_id_ = 0; |
- child_first_pos_ = 0; |
- next_ = NULL; |
- prev_ = NULL; |
- for (int i = 0; i < NUM_STREAMS; i++) |
- data_size_[i] = 0; |
-} |
- |
-// ------------------------------------------------------------------------ |
- |
-bool MemEntryImpl::CreateEntry(const std::string& key, net::NetLog* net_log) { |
- key_ = key; |
- Time current = Time::Now(); |
- last_modified_ = current; |
- last_used_ = current; |
- |
- net_log_ = net::BoundNetLog::Make(net_log, |
- net::NetLog::SOURCE_MEMORY_CACHE_ENTRY); |
- // Must be called after |key_| is set, so GetKey() works. |
- net_log_.BeginEvent( |
- net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL, |
- CreateNetLogEntryCreationCallback(this, true)); |
- |
- Open(); |
- backend_->ModifyStorageSize(0, static_cast<int32>(key.size())); |
- return true; |
-} |
- |
-void MemEntryImpl::InternalDoom() { |
- net_log_.AddEvent(net::NetLog::TYPE_ENTRY_DOOM); |
- doomed_ = true; |
- if (!ref_count_) { |
- if (type() == kParentEntry) { |
- // If this is a parent entry, we need to doom all the child entries. |
- if (children_.get()) { |
- EntryMap children; |
- children.swap(*children_); |
- for (EntryMap::iterator i = children.begin(); |
- i != children.end(); ++i) { |
- // Since a pointer to this object is also saved in the map, avoid |
- // dooming it. |
- if (i->second != this) |
- i->second->Doom(); |
- } |
- DCHECK(children_->empty()); |
- } |
- } else { |
- // If this is a child entry, detach it from the parent. |
- parent_->DetachChild(child_id_); |
- } |
- delete this; |
- } |
-} |
- |
-void MemEntryImpl::Open() { |
- // Only a parent entry can be opened. |
- // TODO(hclam): make sure it's correct to not apply the concept of ref |
- // counting to child entry. |
- DCHECK(type() == kParentEntry); |
- ref_count_++; |
- DCHECK_GE(ref_count_, 0); |
- DCHECK(!doomed_); |
-} |
- |
-bool MemEntryImpl::InUse() { |
- if (type() == kParentEntry) { |
- return ref_count_ > 0; |
- } else { |
- // A child entry is always not in use. The consequence is that a child entry |
- // can always be evicted while the associated parent entry is currently in |
- // used (i.e. opened). |
- return false; |
- } |
-} |
- |
-// ------------------------------------------------------------------------ |
- |
-void MemEntryImpl::Doom() { |
- if (doomed_) |
- return; |
- if (type() == kParentEntry) { |
- // Perform internal doom from the backend if this is a parent entry. |
- backend_->InternalDoomEntry(this); |
- } else { |
- // Manually detach from the backend and perform internal doom. |
- backend_->RemoveFromRankingList(this); |
- InternalDoom(); |
- } |
-} |
- |
-void MemEntryImpl::Close() { |
- // Only a parent entry can be closed. |
- DCHECK(type() == kParentEntry); |
- ref_count_--; |
- DCHECK_GE(ref_count_, 0); |
- if (!ref_count_ && doomed_) |
- InternalDoom(); |
-} |
- |
-std::string MemEntryImpl::GetKey() const { |
- // A child entry doesn't have key so this method should not be called. |
- DCHECK(type() == kParentEntry); |
- return key_; |
-} |
- |
-Time MemEntryImpl::GetLastUsed() const { |
- return last_used_; |
-} |
- |
-Time MemEntryImpl::GetLastModified() const { |
- return last_modified_; |
-} |
- |
-int32 MemEntryImpl::GetDataSize(int index) const { |
- if (index < 0 || index >= NUM_STREAMS) |
- return 0; |
- return data_size_[index]; |
-} |
- |
-int MemEntryImpl::ReadData(int index, int offset, IOBuffer* buf, int buf_len, |
- const CompletionCallback& callback) { |
- if (net_log_.IsLogging()) { |
- net_log_.BeginEvent( |
- net::NetLog::TYPE_ENTRY_READ_DATA, |
- CreateNetLogReadWriteDataCallback(index, offset, buf_len, false)); |
- } |
- |
- int result = InternalReadData(index, offset, buf, buf_len); |
- |
- if (net_log_.IsLogging()) { |
- net_log_.EndEvent( |
- net::NetLog::TYPE_ENTRY_READ_DATA, |
- CreateNetLogReadWriteCompleteCallback(result)); |
- } |
- return result; |
-} |
- |
-int MemEntryImpl::WriteData(int index, int offset, IOBuffer* buf, int buf_len, |
- const CompletionCallback& callback, bool truncate) { |
- if (net_log_.IsLogging()) { |
- net_log_.BeginEvent( |
- net::NetLog::TYPE_ENTRY_WRITE_DATA, |
- CreateNetLogReadWriteDataCallback(index, offset, buf_len, truncate)); |
- } |
- |
- int result = InternalWriteData(index, offset, buf, buf_len, truncate); |
- |
- if (net_log_.IsLogging()) { |
- net_log_.EndEvent( |
- net::NetLog::TYPE_ENTRY_WRITE_DATA, |
- CreateNetLogReadWriteCompleteCallback(result)); |
- } |
- return result; |
-} |
- |
-int MemEntryImpl::ReadSparseData(int64 offset, IOBuffer* buf, int buf_len, |
- const CompletionCallback& callback) { |
- if (net_log_.IsLogging()) { |
- net_log_.BeginEvent( |
- net::NetLog::TYPE_SPARSE_READ, |
- CreateNetLogSparseOperationCallback(offset, buf_len)); |
- } |
- int result = InternalReadSparseData(offset, buf, buf_len); |
- if (net_log_.IsLogging()) |
- net_log_.EndEvent(net::NetLog::TYPE_SPARSE_READ); |
- return result; |
-} |
- |
-int MemEntryImpl::WriteSparseData(int64 offset, IOBuffer* buf, int buf_len, |
- const CompletionCallback& callback) { |
- if (net_log_.IsLogging()) { |
- net_log_.BeginEvent( |
- net::NetLog::TYPE_SPARSE_WRITE, |
- CreateNetLogSparseOperationCallback(offset, buf_len)); |
- } |
- int result = InternalWriteSparseData(offset, buf, buf_len); |
- if (net_log_.IsLogging()) |
- net_log_.EndEvent(net::NetLog::TYPE_SPARSE_WRITE); |
- return result; |
-} |
- |
-int MemEntryImpl::GetAvailableRange(int64 offset, int len, int64* start, |
- const CompletionCallback& callback) { |
- if (net_log_.IsLogging()) { |
- net_log_.BeginEvent( |
- net::NetLog::TYPE_SPARSE_GET_RANGE, |
- CreateNetLogSparseOperationCallback(offset, len)); |
- } |
- int result = GetAvailableRange(offset, len, start); |
- if (net_log_.IsLogging()) { |
- net_log_.EndEvent( |
- net::NetLog::TYPE_SPARSE_GET_RANGE, |
- CreateNetLogGetAvailableRangeResultCallback(*start, result)); |
- } |
- return result; |
-} |
- |
-bool MemEntryImpl::CouldBeSparse() const { |
- DCHECK_EQ(kParentEntry, type()); |
- return (children_.get() != NULL); |
-} |
- |
-int MemEntryImpl::ReadyForSparseIO(const CompletionCallback& callback) { |
- return net::OK; |
-} |
- |
-// ------------------------------------------------------------------------ |
- |
-MemEntryImpl::~MemEntryImpl() { |
- for (int i = 0; i < NUM_STREAMS; i++) |
- backend_->ModifyStorageSize(data_size_[i], 0); |
- backend_->ModifyStorageSize(static_cast<int32>(key_.size()), 0); |
- net_log_.EndEvent(net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL); |
-} |
- |
-int MemEntryImpl::InternalReadData(int index, int offset, IOBuffer* buf, |
- int buf_len) { |
- DCHECK(type() == kParentEntry || index == kSparseData); |
- |
- if (index < 0 || index >= NUM_STREAMS) |
- return net::ERR_INVALID_ARGUMENT; |
- |
- int entry_size = GetDataSize(index); |
- if (offset >= entry_size || offset < 0 || !buf_len) |
- return 0; |
- |
- if (buf_len < 0) |
- return net::ERR_INVALID_ARGUMENT; |
- |
- if (offset + buf_len > entry_size) |
- buf_len = entry_size - offset; |
- |
- UpdateRank(false); |
- |
- memcpy(buf->data(), &(data_[index])[offset], buf_len); |
- return buf_len; |
-} |
- |
-int MemEntryImpl::InternalWriteData(int index, int offset, IOBuffer* buf, |
- int buf_len, bool truncate) { |
- DCHECK(type() == kParentEntry || index == kSparseData); |
- |
- if (index < 0 || index >= NUM_STREAMS) |
- return net::ERR_INVALID_ARGUMENT; |
- |
- if (offset < 0 || buf_len < 0) |
- return net::ERR_INVALID_ARGUMENT; |
- |
- int max_file_size = backend_->MaxFileSize(); |
- |
- // offset of buf_len could be negative numbers. |
- if (offset > max_file_size || buf_len > max_file_size || |
- offset + buf_len > max_file_size) { |
- return net::ERR_FAILED; |
- } |
- |
- // Read the size at this point. |
- int entry_size = GetDataSize(index); |
- |
- PrepareTarget(index, offset, buf_len); |
- |
- if (entry_size < offset + buf_len) { |
- backend_->ModifyStorageSize(entry_size, offset + buf_len); |
- data_size_[index] = offset + buf_len; |
- } else if (truncate) { |
- if (entry_size > offset + buf_len) { |
- backend_->ModifyStorageSize(entry_size, offset + buf_len); |
- data_size_[index] = offset + buf_len; |
- } |
- } |
- |
- UpdateRank(true); |
- |
- if (!buf_len) |
- return 0; |
- |
- memcpy(&(data_[index])[offset], buf->data(), buf_len); |
- return buf_len; |
-} |
- |
-int MemEntryImpl::InternalReadSparseData(int64 offset, IOBuffer* buf, |
- int buf_len) { |
- DCHECK(type() == kParentEntry); |
- |
- if (!InitSparseInfo()) |
- return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
- |
- if (offset < 0 || buf_len < 0) |
- return net::ERR_INVALID_ARGUMENT; |
- |
- // We will keep using this buffer and adjust the offset in this buffer. |
- scoped_refptr<net::DrainableIOBuffer> io_buf( |
- new net::DrainableIOBuffer(buf, buf_len)); |
- |
- // Iterate until we have read enough. |
- while (io_buf->BytesRemaining()) { |
- MemEntryImpl* child = OpenChild(offset + io_buf->BytesConsumed(), false); |
- |
- // No child present for that offset. |
- if (!child) |
- break; |
- |
- // We then need to prepare the child offset and len. |
- int child_offset = ToChildOffset(offset + io_buf->BytesConsumed()); |
- |
- // If we are trying to read from a position that the child entry has no data |
- // we should stop. |
- if (child_offset < child->child_first_pos_) |
- break; |
- if (net_log_.IsLogging()) { |
- net_log_.BeginEvent( |
- net::NetLog::TYPE_SPARSE_READ_CHILD_DATA, |
- CreateNetLogSparseReadWriteCallback(child->net_log().source(), |
- io_buf->BytesRemaining())); |
- } |
- int ret = child->ReadData(kSparseData, child_offset, io_buf.get(), |
- io_buf->BytesRemaining(), CompletionCallback()); |
- if (net_log_.IsLogging()) { |
- net_log_.EndEventWithNetErrorCode( |
- net::NetLog::TYPE_SPARSE_READ_CHILD_DATA, ret); |
- } |
- |
- // If we encounter an error in one entry, return immediately. |
- if (ret < 0) |
- return ret; |
- else if (ret == 0) |
- break; |
- |
- // Increment the counter by number of bytes read in the child entry. |
- io_buf->DidConsume(ret); |
- } |
- |
- UpdateRank(false); |
- |
- return io_buf->BytesConsumed(); |
-} |
- |
-int MemEntryImpl::InternalWriteSparseData(int64 offset, IOBuffer* buf, |
- int buf_len) { |
- DCHECK(type() == kParentEntry); |
- |
- if (!InitSparseInfo()) |
- return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
- |
- if (offset < 0 || buf_len < 0) |
- return net::ERR_INVALID_ARGUMENT; |
- |
- scoped_refptr<net::DrainableIOBuffer> io_buf( |
- new net::DrainableIOBuffer(buf, buf_len)); |
- |
- // This loop walks through child entries continuously starting from |offset| |
- // and writes blocks of data (of maximum size kMaxSparseEntrySize) into each |
- // child entry until all |buf_len| bytes are written. The write operation can |
- // start in the middle of an entry. |
- while (io_buf->BytesRemaining()) { |
- MemEntryImpl* child = OpenChild(offset + io_buf->BytesConsumed(), true); |
- int child_offset = ToChildOffset(offset + io_buf->BytesConsumed()); |
- |
- // Find the right amount to write, this evaluates the remaining bytes to |
- // write and remaining capacity of this child entry. |
- int write_len = std::min(static_cast<int>(io_buf->BytesRemaining()), |
- kMaxSparseEntrySize - child_offset); |
- |
- // Keep a record of the last byte position (exclusive) in the child. |
- int data_size = child->GetDataSize(kSparseData); |
- |
- if (net_log_.IsLogging()) { |
- net_log_.BeginEvent( |
- net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA, |
- CreateNetLogSparseReadWriteCallback(child->net_log().source(), |
- write_len)); |
- } |
- |
- // Always writes to the child entry. This operation may overwrite data |
- // previously written. |
- // TODO(hclam): if there is data in the entry and this write is not |
- // continuous we may want to discard this write. |
- int ret = child->WriteData(kSparseData, child_offset, io_buf.get(), |
- write_len, CompletionCallback(), true); |
- if (net_log_.IsLogging()) { |
- net_log_.EndEventWithNetErrorCode( |
- net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA, ret); |
- } |
- if (ret < 0) |
- return ret; |
- else if (ret == 0) |
- break; |
- |
- // Keep a record of the first byte position in the child if the write was |
- // not aligned nor continuous. This is to enable witting to the middle |
- // of an entry and still keep track of data off the aligned edge. |
- if (data_size != child_offset) |
- child->child_first_pos_ = child_offset; |
- |
- // Adjust the offset in the IO buffer. |
- io_buf->DidConsume(ret); |
- } |
- |
- UpdateRank(true); |
- |
- return io_buf->BytesConsumed(); |
-} |
- |
-int MemEntryImpl::GetAvailableRange(int64 offset, int len, int64* start) { |
- DCHECK(type() == kParentEntry); |
- DCHECK(start); |
- |
- if (!InitSparseInfo()) |
- return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
- |
- if (offset < 0 || len < 0 || !start) |
- return net::ERR_INVALID_ARGUMENT; |
- |
- MemEntryImpl* current_child = NULL; |
- |
- // Find the first child and record the number of empty bytes. |
- int empty = FindNextChild(offset, len, ¤t_child); |
- if (current_child) { |
- *start = offset + empty; |
- len -= empty; |
- |
- // Counts the number of continuous bytes. |
- int continuous = 0; |
- |
- // This loop scan for continuous bytes. |
- while (len && current_child) { |
- // Number of bytes available in this child. |
- int data_size = current_child->GetDataSize(kSparseData) - |
- ToChildOffset(*start + continuous); |
- if (data_size > len) |
- data_size = len; |
- |
- // We have found more continuous bytes so increment the count. Also |
- // decrement the length we should scan. |
- continuous += data_size; |
- len -= data_size; |
- |
- // If the next child is discontinuous, break the loop. |
- if (FindNextChild(*start + continuous, len, ¤t_child)) |
- break; |
- } |
- return continuous; |
- } |
- *start = offset; |
- return 0; |
-} |
- |
-void MemEntryImpl::PrepareTarget(int index, int offset, int buf_len) { |
- int entry_size = GetDataSize(index); |
- |
- if (entry_size >= offset + buf_len) |
- return; // Not growing the stored data. |
- |
- if (static_cast<int>(data_[index].size()) < offset + buf_len) |
- data_[index].resize(offset + buf_len); |
- |
- if (offset <= entry_size) |
- return; // There is no "hole" on the stored data. |
- |
- // Cleanup the hole not written by the user. The point is to avoid returning |
- // random stuff later on. |
- memset(&(data_[index])[entry_size], 0, offset - entry_size); |
-} |
- |
-void MemEntryImpl::UpdateRank(bool modified) { |
- Time current = Time::Now(); |
- last_used_ = current; |
- |
- if (modified) |
- last_modified_ = current; |
- |
- if (!doomed_) |
- backend_->UpdateRank(this); |
-} |
- |
-bool MemEntryImpl::InitSparseInfo() { |
- DCHECK(type() == kParentEntry); |
- |
- if (!children_.get()) { |
- // If we already have some data in sparse stream but we are being |
- // initialized as a sparse entry, we should fail. |
- if (GetDataSize(kSparseData)) |
- return false; |
- children_.reset(new EntryMap()); |
- |
- // The parent entry stores data for the first block, so save this object to |
- // index 0. |
- (*children_)[0] = this; |
- } |
- return true; |
-} |
- |
-bool MemEntryImpl::InitChildEntry(MemEntryImpl* parent, int child_id, |
- net::NetLog* net_log) { |
- DCHECK(!parent_); |
- DCHECK(!child_id_); |
- |
- net_log_ = net::BoundNetLog::Make(net_log, |
- net::NetLog::SOURCE_MEMORY_CACHE_ENTRY); |
- net_log_.BeginEvent( |
- net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL, |
- base::Bind(&NetLogChildEntryCreationCallback, parent, child_id_)); |
- |
- parent_ = parent; |
- child_id_ = child_id; |
- Time current = Time::Now(); |
- last_modified_ = current; |
- last_used_ = current; |
- // Insert this to the backend's ranking list. |
- backend_->InsertIntoRankingList(this); |
- return true; |
-} |
- |
-MemEntryImpl* MemEntryImpl::OpenChild(int64 offset, bool create) { |
- DCHECK(type() == kParentEntry); |
- int index = ToChildIndex(offset); |
- EntryMap::iterator i = children_->find(index); |
- if (i != children_->end()) { |
- return i->second; |
- } else if (create) { |
- MemEntryImpl* child = new MemEntryImpl(backend_); |
- child->InitChildEntry(this, index, net_log_.net_log()); |
- (*children_)[index] = child; |
- return child; |
- } |
- return NULL; |
-} |
- |
-int MemEntryImpl::FindNextChild(int64 offset, int len, MemEntryImpl** child) { |
- DCHECK(child); |
- *child = NULL; |
- int scanned_len = 0; |
- |
- // This loop tries to find the first existing child. |
- while (scanned_len < len) { |
- // This points to the current offset in the child. |
- int current_child_offset = ToChildOffset(offset + scanned_len); |
- MemEntryImpl* current_child = OpenChild(offset + scanned_len, false); |
- if (current_child) { |
- int child_first_pos = current_child->child_first_pos_; |
- |
- // This points to the first byte that we should be reading from, we need |
- // to take care of the filled region and the current offset in the child. |
- int first_pos = std::max(current_child_offset, child_first_pos); |
- |
- // If the first byte position we should read from doesn't exceed the |
- // filled region, we have found the first child. |
- if (first_pos < current_child->GetDataSize(kSparseData)) { |
- *child = current_child; |
- |
- // We need to advance the scanned length. |
- scanned_len += first_pos - current_child_offset; |
- break; |
- } |
- } |
- scanned_len += kMaxSparseEntrySize - current_child_offset; |
- } |
- return scanned_len; |
-} |
- |
-void MemEntryImpl::DetachChild(int child_id) { |
- children_->erase(child_id); |
-} |
- |
-} // namespace disk_cache |