This source file includes following definitions.
- ToChildIndex
- ToChildOffset
- GenerateChildName
- NetLogChildEntryCreationCallback
- CreateEntry
- InternalDoom
- Open
- InUse
- Doom
- Close
- GetKey
- GetLastUsed
- GetLastModified
- GetDataSize
- ReadData
- WriteData
- ReadSparseData
- WriteSparseData
- GetAvailableRange
- CouldBeSparse
- ReadyForSparseIO
- InternalReadData
- InternalWriteData
- InternalReadSparseData
- InternalWriteSparseData
- GetAvailableRange
- PrepareTarget
- UpdateRank
- InitSparseInfo
- InitChildEntry
- OpenChild
- FindNextChild
- DetachChild
#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;
const int kMaxSparseEntryBits = 12;
const int kMaxSparseEntrySize = 1 << kMaxSparseEntryBits;
inline int ToChildIndex(int64 offset) {
return static_cast<int>(offset >> kMaxSparseEntryBits);
}
inline int ToChildOffset(int64 offset) {
return static_cast<int>(offset & (kMaxSparseEntrySize - 1));
}
std::string GenerateChildName(const std::string& base_name, int child_id) {
return base::StringPrintf("Range_%s:%i", base_name.c_str(), child_id);
}
base::Value* NetLogChildEntryCreationCallback(
const disk_cache::MemEntryImpl* parent,
int child_id,
net::NetLog::LogLevel ) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString("key", GenerateChildName(parent->GetKey(), child_id));
dict->SetBoolean("created", true);
return dict;
}
}
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);
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 (children_.get()) {
EntryMap children;
children.swap(*children_);
for (EntryMap::iterator i = children.begin();
i != children.end(); ++i) {
if (i->second != this)
i->second->Doom();
}
DCHECK(children_->empty());
}
} else {
parent_->DetachChild(child_id_);
}
delete this;
}
}
void MemEntryImpl::Open() {
DCHECK(type() == kParentEntry);
ref_count_++;
DCHECK_GE(ref_count_, 0);
DCHECK(!doomed_);
}
bool MemEntryImpl::InUse() {
if (type() == kParentEntry) {
return ref_count_ > 0;
} else {
return false;
}
}
void MemEntryImpl::Doom() {
if (doomed_)
return;
if (type() == kParentEntry) {
backend_->InternalDoomEntry(this);
} else {
backend_->RemoveFromRankingList(this);
InternalDoom();
}
}
void MemEntryImpl::Close() {
DCHECK(type() == kParentEntry);
ref_count_--;
DCHECK_GE(ref_count_, 0);
if (!ref_count_ && doomed_)
InternalDoom();
}
std::string MemEntryImpl::GetKey() const {
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();
if (offset > max_file_size || buf_len > max_file_size ||
offset + buf_len > max_file_size) {
return net::ERR_FAILED;
}
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;
scoped_refptr<net::DrainableIOBuffer> io_buf(
new net::DrainableIOBuffer(buf, buf_len));
while (io_buf->BytesRemaining()) {
MemEntryImpl* child = OpenChild(offset + io_buf->BytesConsumed(), false);
if (!child)
break;
int child_offset = ToChildOffset(offset + io_buf->BytesConsumed());
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 (ret < 0)
return ret;
else if (ret == 0)
break;
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));
while (io_buf->BytesRemaining()) {
MemEntryImpl* child = OpenChild(offset + io_buf->BytesConsumed(), true);
int child_offset = ToChildOffset(offset + io_buf->BytesConsumed());
int write_len = std::min(static_cast<int>(io_buf->BytesRemaining()),
kMaxSparseEntrySize - child_offset);
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));
}
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;
if (data_size != child_offset)
child->child_first_pos_ = child_offset;
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;
int empty = FindNextChild(offset, len, ¤t_child);
if (current_child) {
*start = offset + empty;
len -= empty;
int continuous = 0;
while (len && current_child) {
int data_size = current_child->GetDataSize(kSparseData) -
ToChildOffset(*start + continuous);
if (data_size > len)
data_size = len;
continuous += data_size;
len -= data_size;
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;
if (static_cast<int>(data_[index].size()) < offset + buf_len)
data_[index].resize(offset + buf_len);
if (offset <= entry_size)
return;
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 (GetDataSize(kSparseData))
return false;
children_.reset(new EntryMap());
(*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;
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;
while (scanned_len < len) {
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_;
int first_pos = std::max(current_child_offset, child_first_pos);
if (first_pos < current_child->GetDataSize(kSparseData)) {
*child = current_child;
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);
}
}