blob: 3dcf989624207c50e54d1a3ac9330a437e1342ef [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/code_cache/simple_lru_cache.h"
#include <limits>
#include "base/feature_list.h"
#include "base/numerics/clamped_math.h"
#include "content/common/features.h"
#include "net/base/url_util.h"
namespace content {
using GetResult = SimpleLruCache::GetResult;
GetResult::GetResult(base::Time response_time, mojo_base::BigBuffer data)
: response_time(response_time), data(std::move(data)) {}
GetResult::~GetResult() = default;
GetResult::GetResult(GetResult&&) = default;
GetResult& GetResult::operator=(GetResult&&) = default;
SimpleLruCache::Value::Value(Age age, base::Time response_time, uint32_t size)
: age(age), response_time(response_time), size(size) {
DCHECK(!base::FeatureList::IsEnabled(features::kInMemoryCodeCache));
}
SimpleLruCache::Value::Value(Age age,
base::Time response_time,
uint32_t size,
base::span<const uint8_t> data)
: age(age),
response_time(response_time),
size(size),
data(data.begin(), data.end()) {
DCHECK(base::FeatureList::IsEnabled(features::kInMemoryCodeCache));
}
SimpleLruCache::Value::~Value() = default;
SimpleLruCache::Value::Value(Value&&) = default;
SimpleLruCache::Value& SimpleLruCache::Value::operator=(Value&&) = default;
SimpleLruCache::SimpleLruCache(uint64_t capacity) : capacity_(capacity) {}
SimpleLruCache::~SimpleLruCache() = default;
std::optional<GetResult> SimpleLruCache::Get(const std::string& key) {
base::Time response_time;
mojo_base::BigBuffer data;
if (!GetInternal(key, &response_time, &data)) {
return std::nullopt;
}
return std::make_optional<GetResult>(response_time, std::move(data));
}
bool SimpleLruCache::Has(const std::string& key) {
return GetInternal(key, /*response_time=*/nullptr, /*data=*/nullptr);
}
void SimpleLruCache::Put(const std::string& key,
base::Time response_time,
base::span<const uint8_t> payload) {
Delete(key);
const uint64_t size = base::ClampedNumeric<uint64_t>(key.size()) +
payload.size() + kEmptyEntrySize;
if (size > capacity_) {
// Ignore a too big entry.
return;
}
const Age age = GetNextAge();
if (base::FeatureList::IsEnabled(features::kInMemoryCodeCache)) {
entries_.emplace(key, Value(age, response_time, size, payload));
} else {
entries_.emplace(key, Value(age, response_time, size));
}
access_list_.emplace(age, std::move(key));
size_ += size;
Evict();
}
void SimpleLruCache::Delete(const std::string& key) {
const auto it = entries_.find(key);
if (it == entries_.end()) {
return;
}
DCHECK_GE(size_, it->second.size);
size_ -= it->second.size;
access_list_.erase(it->second.age);
entries_.erase(it);
}
uint64_t SimpleLruCache::GetSize() const {
return size_;
}
void SimpleLruCache::Clear() {
entries_.clear();
access_list_.clear();
size_ = 0;
}
bool SimpleLruCache::GetInternal(const std::string& key,
base::Time* response_time,
mojo_base::BigBuffer* data) {
const auto it = entries_.find(key);
if (it == entries_.end()) {
return false;
}
const Age age = GetNextAge();
access_list_.erase(it->second.age);
it->second.age = age;
access_list_.emplace(age, it->first);
if (response_time) {
*response_time = it->second.response_time;
}
if (data && base::FeatureList::IsEnabled(features::kInMemoryCodeCache)) {
*data = mojo_base::BigBuffer(it->second.data);
}
return true;
}
void SimpleLruCache::Evict() {
while (capacity_ < size_) {
auto it = access_list_.begin();
CHECK(it != access_list_.end());
DCHECK(entries_.find(it->second) != entries_.end());
Delete(it->second);
}
}
} // namespace content