910e62b5创建于 1月15日历史提交
// 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