mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2026-06-04 21:36:29 +03:00
Import chromium-64.0.3282.119
This commit is contained in:
341
net/disk_cache/memory/mem_backend_impl.cc
Normal file
341
net/disk_cache/memory/mem_backend_impl.cc
Normal file
@@ -0,0 +1,341 @@
|
||||
// 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_backend_impl.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/sys_info.h"
|
||||
#include "base/task_scheduler/post_task.h"
|
||||
#include "base/threading/sequenced_task_runner_handle.h"
|
||||
#include "base/trace_event/memory_usage_estimator.h"
|
||||
#include "base/trace_event/process_memory_dump.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/disk_cache/cache_util.h"
|
||||
#include "net/disk_cache/memory/mem_entry_impl.h"
|
||||
|
||||
using base::Time;
|
||||
|
||||
namespace disk_cache {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kDefaultInMemoryCacheSize = 10 * 1024 * 1024;
|
||||
const int kDefaultEvictionSize = kDefaultInMemoryCacheSize / 10;
|
||||
|
||||
bool CheckLRUListOrder(const base::LinkedList<MemEntryImpl>& lru_list) {
|
||||
// TODO(gavinp): Check MemBackendImpl::current_size_ here as well.
|
||||
base::Time previous_last_use_time;
|
||||
for (base::LinkNode<MemEntryImpl>* node = lru_list.head();
|
||||
node != lru_list.end(); node = node->next()) {
|
||||
if (node->value()->GetLastUsed() < previous_last_use_time)
|
||||
return false;
|
||||
previous_last_use_time = node->value()->GetLastUsed();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MemBackendImpl::MemBackendImpl(net::NetLog* net_log)
|
||||
: max_size_(0), current_size_(0), net_log_(net_log), weak_factory_(this) {
|
||||
}
|
||||
|
||||
MemBackendImpl::~MemBackendImpl() {
|
||||
DCHECK(CheckLRUListOrder(lru_list_));
|
||||
while (!entries_.empty())
|
||||
entries_.begin()->second->Doom();
|
||||
DCHECK_EQ(0, current_size_);
|
||||
|
||||
if (!post_cleanup_callback_.is_null())
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, std::move(post_cleanup_callback_));
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<MemBackendImpl> MemBackendImpl::CreateBackend(
|
||||
int max_bytes,
|
||||
net::NetLog* net_log) {
|
||||
std::unique_ptr<MemBackendImpl> cache(
|
||||
std::make_unique<MemBackendImpl>(net_log));
|
||||
cache->SetMaxSize(max_bytes);
|
||||
if (cache->Init())
|
||||
return cache;
|
||||
|
||||
LOG(ERROR) << "Unable to create cache";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool MemBackendImpl::Init() {
|
||||
if (max_size_)
|
||||
return true;
|
||||
|
||||
int64_t total_memory = base::SysInfo::AmountOfPhysicalMemory();
|
||||
|
||||
if (total_memory <= 0) {
|
||||
max_size_ = kDefaultInMemoryCacheSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We want to use up to 2% of the computer's memory, with a limit of 50 MB,
|
||||
// reached on system with more than 2.5 GB of RAM.
|
||||
total_memory = total_memory * 2 / 100;
|
||||
if (total_memory > kDefaultInMemoryCacheSize * 5)
|
||||
max_size_ = kDefaultInMemoryCacheSize * 5;
|
||||
else
|
||||
max_size_ = static_cast<int32_t>(total_memory);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemBackendImpl::SetMaxSize(int max_bytes) {
|
||||
static_assert(sizeof(max_bytes) == sizeof(max_size_),
|
||||
"unsupported int model");
|
||||
if (max_bytes < 0)
|
||||
return false;
|
||||
|
||||
// Zero size means use the default.
|
||||
if (!max_bytes)
|
||||
return true;
|
||||
|
||||
max_size_ = max_bytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
int MemBackendImpl::MaxFileSize() const {
|
||||
return max_size_ / 8;
|
||||
}
|
||||
|
||||
void MemBackendImpl::OnEntryInserted(MemEntryImpl* entry) {
|
||||
lru_list_.Append(entry);
|
||||
}
|
||||
|
||||
void MemBackendImpl::OnEntryUpdated(MemEntryImpl* entry) {
|
||||
DCHECK(CheckLRUListOrder(lru_list_));
|
||||
// LinkedList<>::RemoveFromList() removes |entry| from |lru_list_|.
|
||||
entry->RemoveFromList();
|
||||
lru_list_.Append(entry);
|
||||
}
|
||||
|
||||
void MemBackendImpl::OnEntryDoomed(MemEntryImpl* entry) {
|
||||
DCHECK(CheckLRUListOrder(lru_list_));
|
||||
if (entry->type() == MemEntryImpl::PARENT_ENTRY)
|
||||
entries_.erase(entry->key());
|
||||
// LinkedList<>::RemoveFromList() removes |entry| from |lru_list_|.
|
||||
entry->RemoveFromList();
|
||||
}
|
||||
|
||||
void MemBackendImpl::ModifyStorageSize(int32_t delta) {
|
||||
current_size_ += delta;
|
||||
if (delta > 0)
|
||||
EvictIfNeeded();
|
||||
}
|
||||
|
||||
bool MemBackendImpl::HasExceededStorageSize() const {
|
||||
return current_size_ > max_size_;
|
||||
}
|
||||
|
||||
void MemBackendImpl::SetPostCleanupCallback(base::OnceClosure cb) {
|
||||
DCHECK(post_cleanup_callback_.is_null());
|
||||
post_cleanup_callback_ = std::move(cb);
|
||||
}
|
||||
|
||||
net::CacheType MemBackendImpl::GetCacheType() const {
|
||||
return net::MEMORY_CACHE;
|
||||
}
|
||||
|
||||
int32_t MemBackendImpl::GetEntryCount() const {
|
||||
return static_cast<int32_t>(entries_.size());
|
||||
}
|
||||
|
||||
int MemBackendImpl::OpenEntry(const std::string& key,
|
||||
Entry** entry,
|
||||
const CompletionCallback& callback) {
|
||||
EntryMap::iterator it = entries_.find(key);
|
||||
if (it == entries_.end())
|
||||
return net::ERR_FAILED;
|
||||
|
||||
it->second->Open();
|
||||
|
||||
*entry = it->second;
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
int MemBackendImpl::CreateEntry(const std::string& key,
|
||||
Entry** entry,
|
||||
const CompletionCallback& callback) {
|
||||
std::pair<EntryMap::iterator, bool> create_result =
|
||||
entries_.insert(EntryMap::value_type(key, nullptr));
|
||||
const bool did_insert = create_result.second;
|
||||
if (!did_insert)
|
||||
return net::ERR_FAILED;
|
||||
|
||||
MemEntryImpl* cache_entry = new MemEntryImpl(this, key, net_log_);
|
||||
create_result.first->second = cache_entry;
|
||||
*entry = cache_entry;
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
int MemBackendImpl::DoomEntry(const std::string& key,
|
||||
const CompletionCallback& callback) {
|
||||
EntryMap::iterator it = entries_.find(key);
|
||||
if (it == entries_.end())
|
||||
return net::ERR_FAILED;
|
||||
|
||||
it->second->Doom();
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
int MemBackendImpl::DoomAllEntries(const CompletionCallback& callback) {
|
||||
return DoomEntriesBetween(Time(), Time(), callback);
|
||||
}
|
||||
|
||||
int MemBackendImpl::DoomEntriesBetween(Time initial_time,
|
||||
Time end_time,
|
||||
const CompletionCallback& callback) {
|
||||
if (end_time.is_null())
|
||||
end_time = Time::Max();
|
||||
DCHECK_GE(end_time, initial_time);
|
||||
|
||||
base::LinkNode<MemEntryImpl>* node = lru_list_.head();
|
||||
while (node != lru_list_.end() && node->value()->GetLastUsed() < initial_time)
|
||||
node = node->next();
|
||||
while (node != lru_list_.end() && node->value()->GetLastUsed() < end_time) {
|
||||
MemEntryImpl* to_doom = node->value();
|
||||
node = node->next();
|
||||
to_doom->Doom();
|
||||
}
|
||||
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
int MemBackendImpl::DoomEntriesSince(Time initial_time,
|
||||
const CompletionCallback& callback) {
|
||||
return DoomEntriesBetween(initial_time, Time::Max(), callback);
|
||||
}
|
||||
|
||||
int MemBackendImpl::CalculateSizeOfAllEntries(
|
||||
const CompletionCallback& callback) {
|
||||
return current_size_;
|
||||
}
|
||||
|
||||
int MemBackendImpl::CalculateSizeOfEntriesBetween(
|
||||
base::Time initial_time,
|
||||
base::Time end_time,
|
||||
const CompletionCallback& callback) {
|
||||
if (end_time.is_null())
|
||||
end_time = Time::Max();
|
||||
DCHECK_GE(end_time, initial_time);
|
||||
|
||||
int size = 0;
|
||||
base::LinkNode<MemEntryImpl>* node = lru_list_.head();
|
||||
while (node != lru_list_.end() && node->value()->GetLastUsed() < initial_time)
|
||||
node = node->next();
|
||||
while (node != lru_list_.end() && node->value()->GetLastUsed() < end_time) {
|
||||
MemEntryImpl* entry = node->value();
|
||||
size += entry->GetStorageSize();
|
||||
node = node->next();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
class MemBackendImpl::MemIterator final : public Backend::Iterator {
|
||||
public:
|
||||
explicit MemIterator(base::WeakPtr<MemBackendImpl> backend)
|
||||
: backend_(backend) {}
|
||||
|
||||
int OpenNextEntry(Entry** next_entry,
|
||||
const CompletionCallback& callback) override {
|
||||
if (!backend_)
|
||||
return net::ERR_FAILED;
|
||||
|
||||
if (!backend_keys_) {
|
||||
backend_keys_ = std::make_unique<Strings>(backend_->entries_.size());
|
||||
for (const auto& iter : backend_->entries_)
|
||||
backend_keys_->push_back(iter.first);
|
||||
current_ = backend_keys_->begin();
|
||||
} else {
|
||||
current_++;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (current_ == backend_keys_->end()) {
|
||||
*next_entry = nullptr;
|
||||
backend_keys_.reset();
|
||||
return net::ERR_FAILED;
|
||||
}
|
||||
|
||||
const auto& entry_iter = backend_->entries_.find(*current_);
|
||||
if (entry_iter == backend_->entries_.end()) {
|
||||
// The key is no longer in the cache, move on to the next key.
|
||||
current_++;
|
||||
continue;
|
||||
}
|
||||
|
||||
entry_iter->second->Open();
|
||||
*next_entry = entry_iter->second;
|
||||
return net::OK;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using Strings = std::vector<std::string>;
|
||||
|
||||
base::WeakPtr<MemBackendImpl> backend_;
|
||||
std::unique_ptr<Strings> backend_keys_;
|
||||
Strings::iterator current_;
|
||||
};
|
||||
|
||||
std::unique_ptr<Backend::Iterator> MemBackendImpl::CreateIterator() {
|
||||
return std::unique_ptr<Backend::Iterator>(
|
||||
new MemIterator(weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void MemBackendImpl::OnExternalCacheHit(const std::string& key) {
|
||||
EntryMap::iterator it = entries_.find(key);
|
||||
if (it != entries_.end())
|
||||
it->second->UpdateStateOnUse(MemEntryImpl::ENTRY_WAS_NOT_MODIFIED);
|
||||
}
|
||||
|
||||
size_t MemBackendImpl::DumpMemoryStats(
|
||||
base::trace_event::ProcessMemoryDump* pmd,
|
||||
const std::string& parent_absolute_name) const {
|
||||
base::trace_event::MemoryAllocatorDump* dump =
|
||||
pmd->CreateAllocatorDump(parent_absolute_name + "/memory_backend");
|
||||
|
||||
// Entries in lru_list_ will be counted by EMU but not in entries_ since
|
||||
// they're pointers.
|
||||
size_t size = base::trace_event::EstimateMemoryUsage(lru_list_) +
|
||||
base::trace_event::EstimateMemoryUsage(entries_);
|
||||
dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes, size);
|
||||
dump->AddScalar("mem_backend_size",
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
current_size_);
|
||||
dump->AddScalar("mem_backend_max_size",
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
max_size_);
|
||||
return size;
|
||||
}
|
||||
|
||||
void MemBackendImpl::EvictIfNeeded() {
|
||||
if (current_size_ <= max_size_)
|
||||
return;
|
||||
|
||||
int target_size = std::max(0, max_size_ - kDefaultEvictionSize);
|
||||
|
||||
base::LinkNode<MemEntryImpl>* entry = lru_list_.head();
|
||||
while (current_size_ > target_size && entry != lru_list_.end()) {
|
||||
MemEntryImpl* to_doom = entry->value();
|
||||
entry = entry->next();
|
||||
if (!to_doom->InUse())
|
||||
to_doom->Doom();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace disk_cache
|
||||
142
net/disk_cache/memory/mem_backend_impl.h
Normal file
142
net/disk_cache/memory/mem_backend_impl.h
Normal file
@@ -0,0 +1,142 @@
|
||||
// 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.
|
||||
|
||||
// See net/disk_cache/disk_cache.h for the public interface of the cache.
|
||||
|
||||
#ifndef NET_DISK_CACHE_MEMORY_MEM_BACKEND_IMPL_H_
|
||||
#define NET_DISK_CACHE_MEMORY_MEM_BACKEND_IMPL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/containers/linked_list.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/time/time.h"
|
||||
#include "net/base/net_export.h"
|
||||
#include "net/disk_cache/disk_cache.h"
|
||||
#include "net/disk_cache/memory/mem_entry_impl.h"
|
||||
|
||||
namespace net {
|
||||
class NetLog;
|
||||
} // namespace net
|
||||
|
||||
namespace disk_cache {
|
||||
|
||||
// This class implements the Backend interface. An object of this class handles
|
||||
// the operations of the cache without writing to disk.
|
||||
class NET_EXPORT_PRIVATE MemBackendImpl final : public Backend {
|
||||
public:
|
||||
explicit MemBackendImpl(net::NetLog* net_log);
|
||||
~MemBackendImpl() override;
|
||||
|
||||
// Returns an instance of a Backend implemented only in memory. The returned
|
||||
// object should be deleted when not needed anymore. max_bytes is the maximum
|
||||
// size the cache can grow to. If zero is passed in as max_bytes, the cache
|
||||
// will determine the value to use based on the available memory. The returned
|
||||
// pointer can be NULL if a fatal error is found.
|
||||
static std::unique_ptr<MemBackendImpl> CreateBackend(int max_bytes,
|
||||
net::NetLog* net_log);
|
||||
|
||||
// Performs general initialization for this current instance of the cache.
|
||||
bool Init();
|
||||
|
||||
// Sets the maximum size for the total amount of data stored by this instance.
|
||||
bool SetMaxSize(int max_bytes);
|
||||
|
||||
// Returns the maximum size for a file to reside on the cache.
|
||||
int MaxFileSize() const;
|
||||
|
||||
// These next methods (before the implementation of the Backend interface) are
|
||||
// called by MemEntryImpl to update the state of the backend during the entry
|
||||
// lifecycle.
|
||||
|
||||
// Signals that new entry has been created, and should be placed in
|
||||
// |lru_list_| so that it is eligable for eviction.
|
||||
void OnEntryInserted(MemEntryImpl* entry);
|
||||
|
||||
// Signals that an entry has been updated, and thus should be moved to the end
|
||||
// of |lru_list_|.
|
||||
void OnEntryUpdated(MemEntryImpl* entry);
|
||||
|
||||
// Signals that an entry has been doomed, and so it should be removed from the
|
||||
// list of active entries as appropriate, as well as removed from the
|
||||
// |lru_list_|.
|
||||
void OnEntryDoomed(MemEntryImpl* entry);
|
||||
|
||||
// Adjust the current size of this backend by |delta|. This is used to
|
||||
// determine if eviction is neccessary and when eviction is finished.
|
||||
void ModifyStorageSize(int32_t delta);
|
||||
|
||||
// Returns true if the cache's size is greater than the maximum allowed
|
||||
// size.
|
||||
bool HasExceededStorageSize() const;
|
||||
|
||||
// Sets a callback to be posted after we are destroyed. Should be called at
|
||||
// most once.
|
||||
void SetPostCleanupCallback(base::OnceClosure cb);
|
||||
|
||||
// Backend interface.
|
||||
net::CacheType GetCacheType() const override;
|
||||
int32_t GetEntryCount() const override;
|
||||
int OpenEntry(const std::string& key,
|
||||
Entry** entry,
|
||||
const CompletionCallback& callback) override;
|
||||
int CreateEntry(const std::string& key,
|
||||
Entry** entry,
|
||||
const CompletionCallback& callback) override;
|
||||
int DoomEntry(const std::string& key,
|
||||
const CompletionCallback& callback) override;
|
||||
int DoomAllEntries(const CompletionCallback& callback) override;
|
||||
int DoomEntriesBetween(base::Time initial_time,
|
||||
base::Time end_time,
|
||||
const CompletionCallback& callback) override;
|
||||
int DoomEntriesSince(base::Time initial_time,
|
||||
const CompletionCallback& callback) override;
|
||||
int CalculateSizeOfAllEntries(const CompletionCallback& callback) override;
|
||||
int CalculateSizeOfEntriesBetween(
|
||||
base::Time initial_time,
|
||||
base::Time end_time,
|
||||
const CompletionCallback& callback) override;
|
||||
std::unique_ptr<Iterator> CreateIterator() override;
|
||||
void GetStats(base::StringPairs* stats) override {}
|
||||
void OnExternalCacheHit(const std::string& key) override;
|
||||
size_t DumpMemoryStats(
|
||||
base::trace_event::ProcessMemoryDump* pmd,
|
||||
const std::string& parent_absolute_name) const override;
|
||||
|
||||
private:
|
||||
class MemIterator;
|
||||
friend class MemIterator;
|
||||
|
||||
using EntryMap = std::unordered_map<std::string, MemEntryImpl*>;
|
||||
|
||||
// Deletes entries from the cache until the current size is below the limit.
|
||||
void EvictIfNeeded();
|
||||
|
||||
EntryMap entries_;
|
||||
|
||||
// Stored in increasing order of last use time, from least recently used to
|
||||
// most recently used.
|
||||
base::LinkedList<MemEntryImpl> lru_list_;
|
||||
|
||||
int32_t max_size_; // Maximum data size for this instance.
|
||||
int32_t current_size_;
|
||||
|
||||
net::NetLog* net_log_;
|
||||
base::OnceClosure post_cleanup_callback_;
|
||||
|
||||
base::WeakPtrFactory<MemBackendImpl> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MemBackendImpl);
|
||||
};
|
||||
|
||||
} // namespace disk_cache
|
||||
|
||||
#endif // NET_DISK_CACHE_MEMORY_MEM_BACKEND_IMPL_H_
|
||||
624
net/disk_cache/memory/mem_entry_impl.cc
Normal file
624
net/disk_cache/memory/mem_entry_impl.cc
Normal file
@@ -0,0 +1,624 @@
|
||||
// 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 <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/metrics/histogram_macros.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"
|
||||
#include "net/log/net_log_event_type.h"
|
||||
#include "net/log/net_log_source_type.h"
|
||||
|
||||
using base::Time;
|
||||
|
||||
namespace disk_cache {
|
||||
|
||||
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;
|
||||
|
||||
// This enum is used for histograms, so only append to the end.
|
||||
enum WriteResult {
|
||||
WRITE_RESULT_SUCCESS = 0,
|
||||
WRITE_RESULT_INVALID_ARGUMENT = 1,
|
||||
WRITE_RESULT_OVER_MAX_ENTRY_SIZE = 2,
|
||||
WRITE_RESULT_EXCEEDED_CACHE_STORAGE_SIZE = 3,
|
||||
WRITE_RESULT_MAX = 4,
|
||||
};
|
||||
|
||||
void RecordWriteResult(WriteResult result) {
|
||||
UMA_HISTOGRAM_ENUMERATION("MemCache.WriteResult", result, WRITE_RESULT_MAX);
|
||||
}
|
||||
|
||||
// Convert global offset to child index.
|
||||
int ToChildIndex(int64_t offset) {
|
||||
return static_cast<int>(offset >> kMaxSparseEntryBits);
|
||||
}
|
||||
|
||||
// Convert global offset to offset in child entry.
|
||||
int ToChildOffset(int64_t 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 MemEntryImpl. A separate
|
||||
// function is needed because child entries don't store their key().
|
||||
std::unique_ptr<base::Value> NetLogEntryCreationCallback(
|
||||
const MemEntryImpl* entry,
|
||||
net::NetLogCaptureMode /* capture_mode */) {
|
||||
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
|
||||
std::string key;
|
||||
switch (entry->type()) {
|
||||
case MemEntryImpl::PARENT_ENTRY:
|
||||
key = entry->key();
|
||||
break;
|
||||
case MemEntryImpl::CHILD_ENTRY:
|
||||
key = GenerateChildName(entry->parent()->key(), entry->child_id());
|
||||
break;
|
||||
}
|
||||
dict->SetString("key", key);
|
||||
dict->SetBoolean("created", true);
|
||||
return std::move(dict);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MemEntryImpl::MemEntryImpl(MemBackendImpl* backend,
|
||||
const std::string& key,
|
||||
net::NetLog* net_log)
|
||||
: MemEntryImpl(backend,
|
||||
key,
|
||||
0, // child_id
|
||||
nullptr, // parent
|
||||
net_log) {
|
||||
Open();
|
||||
// Just creating the entry (without any data) could cause the storage to
|
||||
// grow beyond capacity, but we allow such infractions.
|
||||
backend_->ModifyStorageSize(GetStorageSize());
|
||||
}
|
||||
|
||||
MemEntryImpl::MemEntryImpl(MemBackendImpl* backend,
|
||||
int child_id,
|
||||
MemEntryImpl* parent,
|
||||
net::NetLog* net_log)
|
||||
: MemEntryImpl(backend,
|
||||
std::string(), // key
|
||||
child_id,
|
||||
parent,
|
||||
net_log) {
|
||||
(*parent_->children_)[child_id] = this;
|
||||
}
|
||||
|
||||
void MemEntryImpl::Open() {
|
||||
// Only a parent entry can be opened.
|
||||
DCHECK_EQ(PARENT_ENTRY, type());
|
||||
++ref_count_;
|
||||
DCHECK_GE(ref_count_, 1);
|
||||
DCHECK(!doomed_);
|
||||
}
|
||||
|
||||
bool MemEntryImpl::InUse() const {
|
||||
if (type() == CHILD_ENTRY)
|
||||
return parent_->InUse();
|
||||
|
||||
return ref_count_ > 0;
|
||||
}
|
||||
|
||||
int MemEntryImpl::GetStorageSize() const {
|
||||
int storage_size = static_cast<int32_t>(key_.size());
|
||||
for (const auto& i : data_)
|
||||
storage_size += i.size();
|
||||
return storage_size;
|
||||
}
|
||||
|
||||
void MemEntryImpl::UpdateStateOnUse(EntryModified modified_enum) {
|
||||
if (!doomed_)
|
||||
backend_->OnEntryUpdated(this);
|
||||
|
||||
last_used_ = Time::Now();
|
||||
if (modified_enum == ENTRY_WAS_MODIFIED)
|
||||
last_modified_ = last_used_;
|
||||
}
|
||||
|
||||
void MemEntryImpl::Doom() {
|
||||
if (!doomed_) {
|
||||
doomed_ = true;
|
||||
backend_->OnEntryDoomed(this);
|
||||
net_log_.AddEvent(net::NetLogEventType::ENTRY_DOOM);
|
||||
}
|
||||
if (!ref_count_)
|
||||
delete this;
|
||||
}
|
||||
|
||||
void MemEntryImpl::Close() {
|
||||
DCHECK_EQ(PARENT_ENTRY, type());
|
||||
--ref_count_;
|
||||
DCHECK_GE(ref_count_, 0);
|
||||
if (!ref_count_ && doomed_)
|
||||
delete this;
|
||||
}
|
||||
|
||||
std::string MemEntryImpl::GetKey() const {
|
||||
// A child entry doesn't have key so this method should not be called.
|
||||
DCHECK_EQ(PARENT_ENTRY, type());
|
||||
return key_;
|
||||
}
|
||||
|
||||
Time MemEntryImpl::GetLastUsed() const {
|
||||
return last_used_;
|
||||
}
|
||||
|
||||
Time MemEntryImpl::GetLastModified() const {
|
||||
return last_modified_;
|
||||
}
|
||||
|
||||
int32_t MemEntryImpl::GetDataSize(int index) const {
|
||||
if (index < 0 || index >= kNumStreams)
|
||||
return 0;
|
||||
return data_[index].size();
|
||||
}
|
||||
|
||||
int MemEntryImpl::ReadData(int index, int offset, IOBuffer* buf, int buf_len,
|
||||
const CompletionCallback& callback) {
|
||||
if (net_log_.IsCapturing()) {
|
||||
net_log_.BeginEvent(
|
||||
net::NetLogEventType::ENTRY_READ_DATA,
|
||||
CreateNetLogReadWriteDataCallback(index, offset, buf_len, false));
|
||||
}
|
||||
|
||||
int result = InternalReadData(index, offset, buf, buf_len);
|
||||
|
||||
if (net_log_.IsCapturing()) {
|
||||
net_log_.EndEvent(net::NetLogEventType::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_.IsCapturing()) {
|
||||
net_log_.BeginEvent(
|
||||
net::NetLogEventType::ENTRY_WRITE_DATA,
|
||||
CreateNetLogReadWriteDataCallback(index, offset, buf_len, truncate));
|
||||
}
|
||||
|
||||
int result = InternalWriteData(index, offset, buf, buf_len, truncate);
|
||||
|
||||
if (net_log_.IsCapturing()) {
|
||||
net_log_.EndEvent(net::NetLogEventType::ENTRY_WRITE_DATA,
|
||||
CreateNetLogReadWriteCompleteCallback(result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int MemEntryImpl::ReadSparseData(int64_t offset,
|
||||
IOBuffer* buf,
|
||||
int buf_len,
|
||||
const CompletionCallback& callback) {
|
||||
if (net_log_.IsCapturing()) {
|
||||
net_log_.BeginEvent(net::NetLogEventType::SPARSE_READ,
|
||||
CreateNetLogSparseOperationCallback(offset, buf_len));
|
||||
}
|
||||
int result = InternalReadSparseData(offset, buf, buf_len);
|
||||
if (net_log_.IsCapturing())
|
||||
net_log_.EndEvent(net::NetLogEventType::SPARSE_READ);
|
||||
return result;
|
||||
}
|
||||
|
||||
int MemEntryImpl::WriteSparseData(int64_t offset,
|
||||
IOBuffer* buf,
|
||||
int buf_len,
|
||||
const CompletionCallback& callback) {
|
||||
if (net_log_.IsCapturing()) {
|
||||
net_log_.BeginEvent(net::NetLogEventType::SPARSE_WRITE,
|
||||
CreateNetLogSparseOperationCallback(offset, buf_len));
|
||||
}
|
||||
int result = InternalWriteSparseData(offset, buf, buf_len);
|
||||
if (net_log_.IsCapturing())
|
||||
net_log_.EndEvent(net::NetLogEventType::SPARSE_WRITE);
|
||||
return result;
|
||||
}
|
||||
|
||||
int MemEntryImpl::GetAvailableRange(int64_t offset,
|
||||
int len,
|
||||
int64_t* start,
|
||||
const CompletionCallback& callback) {
|
||||
if (net_log_.IsCapturing()) {
|
||||
net_log_.BeginEvent(net::NetLogEventType::SPARSE_GET_RANGE,
|
||||
CreateNetLogSparseOperationCallback(offset, len));
|
||||
}
|
||||
int result = InternalGetAvailableRange(offset, len, start);
|
||||
if (net_log_.IsCapturing()) {
|
||||
net_log_.EndEvent(
|
||||
net::NetLogEventType::SPARSE_GET_RANGE,
|
||||
CreateNetLogGetAvailableRangeResultCallback(*start, result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MemEntryImpl::CouldBeSparse() const {
|
||||
DCHECK_EQ(PARENT_ENTRY, type());
|
||||
return (children_.get() != nullptr);
|
||||
}
|
||||
|
||||
int MemEntryImpl::ReadyForSparseIO(const CompletionCallback& callback) {
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
size_t MemEntryImpl::EstimateMemoryUsage() const {
|
||||
// Subtlety: the entries in children_ are not double counted, as the entry
|
||||
// pointers won't be followed by EstimateMemoryUsage.
|
||||
return base::trace_event::EstimateMemoryUsage(data_) +
|
||||
base::trace_event::EstimateMemoryUsage(key_) +
|
||||
base::trace_event::EstimateMemoryUsage(children_);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
MemEntryImpl::MemEntryImpl(MemBackendImpl* backend,
|
||||
const ::std::string& key,
|
||||
int child_id,
|
||||
MemEntryImpl* parent,
|
||||
net::NetLog* net_log)
|
||||
: key_(key),
|
||||
ref_count_(0),
|
||||
child_id_(child_id),
|
||||
child_first_pos_(0),
|
||||
parent_(parent),
|
||||
last_modified_(Time::Now()),
|
||||
last_used_(last_modified_),
|
||||
backend_(backend),
|
||||
doomed_(false) {
|
||||
backend_->OnEntryInserted(this);
|
||||
net_log_ = net::NetLogWithSource::Make(
|
||||
net_log, net::NetLogSourceType::MEMORY_CACHE_ENTRY);
|
||||
net_log_.BeginEvent(net::NetLogEventType::DISK_CACHE_MEM_ENTRY_IMPL,
|
||||
base::Bind(&NetLogEntryCreationCallback, this));
|
||||
}
|
||||
|
||||
MemEntryImpl::~MemEntryImpl() {
|
||||
backend_->ModifyStorageSize(-GetStorageSize());
|
||||
|
||||
if (type() == PARENT_ENTRY) {
|
||||
if (children_) {
|
||||
EntryMap children;
|
||||
children_->swap(children);
|
||||
|
||||
for (auto& it : children) {
|
||||
// Since |this| is stored in the map, it should be guarded against
|
||||
// double dooming, which will result in double destruction.
|
||||
if (it.second != this)
|
||||
it.second->Doom();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parent_->children_->erase(child_id_);
|
||||
}
|
||||
net_log_.EndEvent(net::NetLogEventType::DISK_CACHE_MEM_ENTRY_IMPL);
|
||||
}
|
||||
|
||||
int MemEntryImpl::InternalReadData(int index, int offset, IOBuffer* buf,
|
||||
int buf_len) {
|
||||
DCHECK(type() == PARENT_ENTRY || index == kSparseData);
|
||||
|
||||
if (index < 0 || index >= kNumStreams || buf_len < 0)
|
||||
return net::ERR_INVALID_ARGUMENT;
|
||||
|
||||
int entry_size = data_[index].size();
|
||||
if (offset >= entry_size || offset < 0 || !buf_len)
|
||||
return 0;
|
||||
|
||||
if (offset + buf_len > entry_size)
|
||||
buf_len = entry_size - offset;
|
||||
|
||||
UpdateStateOnUse(ENTRY_WAS_NOT_MODIFIED);
|
||||
std::copy(data_[index].begin() + offset,
|
||||
data_[index].begin() + offset + buf_len, buf->data());
|
||||
return buf_len;
|
||||
}
|
||||
|
||||
int MemEntryImpl::InternalWriteData(int index, int offset, IOBuffer* buf,
|
||||
int buf_len, bool truncate) {
|
||||
DCHECK(type() == PARENT_ENTRY || index == kSparseData);
|
||||
|
||||
if (index < 0 || index >= kNumStreams) {
|
||||
RecordWriteResult(WRITE_RESULT_INVALID_ARGUMENT);
|
||||
return net::ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (offset < 0 || buf_len < 0) {
|
||||
RecordWriteResult(WRITE_RESULT_INVALID_ARGUMENT);
|
||||
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) {
|
||||
RecordWriteResult(WRITE_RESULT_OVER_MAX_ENTRY_SIZE);
|
||||
return net::ERR_FAILED;
|
||||
}
|
||||
|
||||
int old_data_size = data_[index].size();
|
||||
if (truncate || old_data_size < offset + buf_len) {
|
||||
int delta = offset + buf_len - old_data_size;
|
||||
backend_->ModifyStorageSize(delta);
|
||||
if (backend_->HasExceededStorageSize()) {
|
||||
backend_->ModifyStorageSize(-delta);
|
||||
RecordWriteResult(WRITE_RESULT_EXCEEDED_CACHE_STORAGE_SIZE);
|
||||
return net::ERR_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
data_[index].resize(offset + buf_len);
|
||||
|
||||
// Zero fill any hole.
|
||||
if (old_data_size < offset) {
|
||||
std::fill(data_[index].begin() + old_data_size,
|
||||
data_[index].begin() + offset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStateOnUse(ENTRY_WAS_MODIFIED);
|
||||
RecordWriteResult(WRITE_RESULT_SUCCESS);
|
||||
|
||||
if (!buf_len)
|
||||
return 0;
|
||||
|
||||
std::copy(buf->data(), buf->data() + buf_len, data_[index].begin() + offset);
|
||||
return buf_len;
|
||||
}
|
||||
|
||||
int MemEntryImpl::InternalReadSparseData(int64_t offset,
|
||||
IOBuffer* buf,
|
||||
int buf_len) {
|
||||
DCHECK_EQ(PARENT_ENTRY, type());
|
||||
|
||||
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 = GetChild(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_.IsCapturing()) {
|
||||
net_log_.BeginEvent(
|
||||
net::NetLogEventType::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_.IsCapturing()) {
|
||||
net_log_.EndEventWithNetErrorCode(
|
||||
net::NetLogEventType::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);
|
||||
}
|
||||
|
||||
UpdateStateOnUse(ENTRY_WAS_NOT_MODIFIED);
|
||||
return io_buf->BytesConsumed();
|
||||
}
|
||||
|
||||
int MemEntryImpl::InternalWriteSparseData(int64_t offset,
|
||||
IOBuffer* buf,
|
||||
int buf_len) {
|
||||
DCHECK_EQ(PARENT_ENTRY, type());
|
||||
|
||||
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 = GetChild(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_.IsCapturing()) {
|
||||
net_log_.BeginEvent(net::NetLogEventType::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_.IsCapturing()) {
|
||||
net_log_.EndEventWithNetErrorCode(
|
||||
net::NetLogEventType::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);
|
||||
}
|
||||
|
||||
UpdateStateOnUse(ENTRY_WAS_MODIFIED);
|
||||
return io_buf->BytesConsumed();
|
||||
}
|
||||
|
||||
int MemEntryImpl::InternalGetAvailableRange(int64_t offset,
|
||||
int len,
|
||||
int64_t* start) {
|
||||
DCHECK_EQ(PARENT_ENTRY, type());
|
||||
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 = nullptr;
|
||||
|
||||
// Find the first child and record the number of empty bytes.
|
||||
int empty = FindNextChild(offset, len, ¤t_child);
|
||||
if (current_child && empty < len) {
|
||||
*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;
|
||||
}
|
||||
|
||||
bool MemEntryImpl::InitSparseInfo() {
|
||||
DCHECK_EQ(PARENT_ENTRY, type());
|
||||
|
||||
if (!children_) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
MemEntryImpl* MemEntryImpl::GetChild(int64_t offset, bool create) {
|
||||
DCHECK_EQ(PARENT_ENTRY, type());
|
||||
int index = ToChildIndex(offset);
|
||||
EntryMap::iterator i = children_->find(index);
|
||||
if (i != children_->end())
|
||||
return i->second;
|
||||
if (create)
|
||||
return new MemEntryImpl(backend_, index, this, net_log_.net_log());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int MemEntryImpl::FindNextChild(int64_t offset, int len, MemEntryImpl** child) {
|
||||
DCHECK(child);
|
||||
*child = nullptr;
|
||||
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 = GetChild(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;
|
||||
}
|
||||
|
||||
} // namespace disk_cache
|
||||
196
net/disk_cache/memory/mem_entry_impl.h
Normal file
196
net/disk_cache/memory/mem_entry_impl.h
Normal file
@@ -0,0 +1,196 @@
|
||||
// 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.
|
||||
|
||||
#ifndef NET_DISK_CACHE_MEMORY_MEM_ENTRY_IMPL_H_
|
||||
#define NET_DISK_CACHE_MEMORY_MEM_ENTRY_IMPL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/linked_list.h"
|
||||
#include "base/gtest_prod_util.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/trace_event/memory_usage_estimator.h"
|
||||
#include "net/base/net_export.h"
|
||||
#include "net/disk_cache/disk_cache.h"
|
||||
#include "net/log/net_log_with_source.h"
|
||||
|
||||
namespace net {
|
||||
class NetLog;
|
||||
}
|
||||
|
||||
namespace disk_cache {
|
||||
|
||||
class MemBackendImpl;
|
||||
|
||||
// This class implements the Entry interface for the memory-only cache. An
|
||||
// object of this class represents a single entry on the cache. We use two types
|
||||
// of entries, parent and child to support sparse caching.
|
||||
//
|
||||
// A parent entry is non-sparse until a sparse method is invoked (i.e.
|
||||
// ReadSparseData, WriteSparseData, GetAvailableRange) when sparse information
|
||||
// is initialized. It then manages a list of child entries and delegates the
|
||||
// sparse API calls to the child entries. It creates and deletes child entries
|
||||
// and updates the list when needed.
|
||||
//
|
||||
// A child entry is used to carry partial cache content, non-sparse methods like
|
||||
// ReadData and WriteData cannot be applied to them. The lifetime of a child
|
||||
// entry is managed by the parent entry that created it except that the entry
|
||||
// can be evicted independently. A child entry does not have a key and it is not
|
||||
// registered in the backend's entry map.
|
||||
//
|
||||
// A sparse child entry has a fixed maximum size and can be partially
|
||||
// filled. There can only be one continous filled region in a sparse entry, as
|
||||
// illustrated by the following example:
|
||||
// | xxx ooooo |
|
||||
// x = unfilled region
|
||||
// o = filled region
|
||||
// It is guaranteed that there is at most one unfilled region and one filled
|
||||
// region, and the unfilled region (if there is one) is always before the filled
|
||||
// region. The book keeping for filled region in a sparse entry is done by using
|
||||
// the variable |child_first_pos_|.
|
||||
|
||||
class NET_EXPORT_PRIVATE MemEntryImpl final
|
||||
: public Entry,
|
||||
public base::LinkNode<MemEntryImpl> {
|
||||
public:
|
||||
enum EntryType {
|
||||
PARENT_ENTRY,
|
||||
CHILD_ENTRY,
|
||||
};
|
||||
|
||||
// Provided to better document calls to |UpdateStateOnUse()|.
|
||||
enum EntryModified {
|
||||
ENTRY_WAS_NOT_MODIFIED,
|
||||
ENTRY_WAS_MODIFIED,
|
||||
};
|
||||
|
||||
// Constructor for parent entries.
|
||||
MemEntryImpl(MemBackendImpl* backend,
|
||||
const std::string& key,
|
||||
net::NetLog* net_log);
|
||||
|
||||
// Constructor for child entries.
|
||||
MemEntryImpl(MemBackendImpl* backend,
|
||||
int child_id,
|
||||
MemEntryImpl* parent,
|
||||
net::NetLog* net_log);
|
||||
|
||||
void Open();
|
||||
bool InUse() const;
|
||||
|
||||
EntryType type() const { return parent_ ? CHILD_ENTRY : PARENT_ENTRY; }
|
||||
const std::string& key() const { return key_; }
|
||||
const MemEntryImpl* parent() const { return parent_; }
|
||||
int child_id() const { return child_id_; }
|
||||
base::Time last_used() const { return last_used_; }
|
||||
|
||||
// The in-memory size of this entry to use for the purposes of eviction.
|
||||
int GetStorageSize() const;
|
||||
|
||||
// Update an entry's position in the backend LRU list and set |last_used_|. If
|
||||
// the entry was modified, also update |last_modified_|.
|
||||
void UpdateStateOnUse(EntryModified modified_enum);
|
||||
|
||||
// From disk_cache::Entry:
|
||||
void Doom() override;
|
||||
void Close() override;
|
||||
std::string GetKey() const override;
|
||||
base::Time GetLastUsed() const override;
|
||||
base::Time GetLastModified() const override;
|
||||
int32_t GetDataSize(int index) const override;
|
||||
int ReadData(int index,
|
||||
int offset,
|
||||
IOBuffer* buf,
|
||||
int buf_len,
|
||||
const CompletionCallback& callback) override;
|
||||
int WriteData(int index,
|
||||
int offset,
|
||||
IOBuffer* buf,
|
||||
int buf_len,
|
||||
const CompletionCallback& callback,
|
||||
bool truncate) override;
|
||||
int ReadSparseData(int64_t offset,
|
||||
IOBuffer* buf,
|
||||
int buf_len,
|
||||
const CompletionCallback& callback) override;
|
||||
int WriteSparseData(int64_t offset,
|
||||
IOBuffer* buf,
|
||||
int buf_len,
|
||||
const CompletionCallback& callback) override;
|
||||
int GetAvailableRange(int64_t offset,
|
||||
int len,
|
||||
int64_t* start,
|
||||
const CompletionCallback& callback) override;
|
||||
bool CouldBeSparse() const override;
|
||||
void CancelSparseIO() override {}
|
||||
int ReadyForSparseIO(const CompletionCallback& callback) override;
|
||||
size_t EstimateMemoryUsage() const;
|
||||
|
||||
private:
|
||||
MemEntryImpl(MemBackendImpl* backend,
|
||||
const std::string& key,
|
||||
int child_id,
|
||||
MemEntryImpl* parent,
|
||||
net::NetLog* net_log);
|
||||
|
||||
using EntryMap = std::unordered_map<int, MemEntryImpl*>;
|
||||
|
||||
static const int kNumStreams = 3;
|
||||
|
||||
~MemEntryImpl() override;
|
||||
|
||||
// Do all the work for corresponding public functions. Implemented as
|
||||
// separate functions to make logging of results simpler.
|
||||
int InternalReadData(int index, int offset, IOBuffer* buf, int buf_len);
|
||||
int InternalWriteData(int index, int offset, IOBuffer* buf, int buf_len,
|
||||
bool truncate);
|
||||
int InternalReadSparseData(int64_t offset, IOBuffer* buf, int buf_len);
|
||||
int InternalWriteSparseData(int64_t offset, IOBuffer* buf, int buf_len);
|
||||
int InternalGetAvailableRange(int64_t offset, int len, int64_t* start);
|
||||
|
||||
// Initializes the children map and sparse info. This method is only called
|
||||
// on a parent entry.
|
||||
bool InitSparseInfo();
|
||||
|
||||
// Returns an entry responsible for |offset|. The returned entry can be a
|
||||
// child entry or this entry itself if |offset| points to the first range.
|
||||
// If such entry does not exist and |create| is true, a new child entry is
|
||||
// created.
|
||||
MemEntryImpl* GetChild(int64_t offset, bool create);
|
||||
|
||||
// Finds the first child located within the range [|offset|, |offset + len|).
|
||||
// Returns the number of bytes ahead of |offset| to reach the first available
|
||||
// bytes in the entry. The first child found is output to |child|.
|
||||
int FindNextChild(int64_t offset, int len, MemEntryImpl** child);
|
||||
|
||||
std::string key_;
|
||||
std::vector<char> data_[kNumStreams]; // User data.
|
||||
int ref_count_;
|
||||
|
||||
int child_id_; // The ID of a child entry.
|
||||
int child_first_pos_; // The position of the first byte in a child
|
||||
// entry.
|
||||
// Pointer to the parent entry, or nullptr if this entry is a parent entry.
|
||||
MemEntryImpl* parent_;
|
||||
std::unique_ptr<EntryMap> children_;
|
||||
|
||||
base::Time last_modified_;
|
||||
base::Time last_used_;
|
||||
MemBackendImpl* backend_; // Back pointer to the cache.
|
||||
bool doomed_; // True if this entry was removed from the cache.
|
||||
|
||||
net::NetLogWithSource net_log_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MemEntryImpl);
|
||||
};
|
||||
|
||||
} // namespace disk_cache
|
||||
|
||||
#endif // NET_DISK_CACHE_MEMORY_MEM_ENTRY_IMPL_H_
|
||||
Reference in New Issue
Block a user