blob: 6bc7b6bd3d411b65d2c1204f02e9d1fe731719c6 [file] [log] [blame]
// Copyright (c) 2006-2008 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/mem_entry_impl.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/mem_backend_impl.h"
using base::Time;
namespace disk_cache {
MemEntryImpl::MemEntryImpl(MemBackendImpl* backend) {
doomed_ = false;
backend_ = backend;
ref_count_ = 0;
for (int i = 0; i < NUM_STREAMS; i++)
data_size_[i] = 0;
}
MemEntryImpl::~MemEntryImpl() {
for (int i = 0; i < NUM_STREAMS; i++)
backend_->ModifyStorageSize(data_size_[i], 0);
backend_->ModifyStorageSize(static_cast<int32>(key_.size()), 0);
}
bool MemEntryImpl::CreateEntry(const std::string& key) {
key_ = key;
last_modified_ = Time::Now();
last_used_ = Time::Now();
Open();
backend_->ModifyStorageSize(0, static_cast<int32>(key.size()));
return true;
}
void MemEntryImpl::Close() {
ref_count_--;
DCHECK(ref_count_ >= 0);
if (!ref_count_ && doomed_)
delete this;
}
void MemEntryImpl::Open() {
ref_count_++;
DCHECK(ref_count_ >= 0);
DCHECK(!doomed_);
}
bool MemEntryImpl::InUse() {
return ref_count_ > 0;
}
void MemEntryImpl::Doom() {
if (doomed_)
return;
backend_->InternalDoomEntry(this);
}
void MemEntryImpl::InternalDoom() {
doomed_ = true;
if (!ref_count_)
delete this;
}
std::string MemEntryImpl::GetKey() const {
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, char* buf, int buf_len,
net::CompletionCallback* completion_callback) {
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_[index])[offset], buf_len);
return buf_len;
}
int MemEntryImpl::WriteData(int index, int offset, const char* buf, int buf_len,
net::CompletionCallback* completion_callback,
bool truncate) {
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) {
int size = offset + buf_len;
if (size <= max_file_size)
size = kint32max;
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, buf_len);
return buf_len;
}
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);
}
} // namespace disk_cache