1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PERSISTENT_CACHE_PERSISTENT_CACHE_COLLECTION_H_
#define COMPONENTS_PERSISTENT_CACHE_PERSISTENT_CACHE_COLLECTION_H_
#include <stdint.h>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include "base/component_export.h"
#include "base/containers/lru_cache.h"
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/sequence_checker.h"
#include "base/thread_annotations.h"
#include "base/types/expected.h"
#include "components/persistent_cache/backend.h"
#include "components/persistent_cache/backend_storage.h"
#include "components/persistent_cache/buffer_provider.h"
#include "components/persistent_cache/entry_metadata.h"
namespace persistent_cache {
struct PendingBackend;
class PersistentCache;
// Use PersistentCacheCollection to seamlessly access multiple PersistentCache
// instances. For example when used instead of double-keying with backends that
// use disk storage this can result in smaller separated files. Unlike
// PersistentCache itself PersistentCacheCollection is not thread-safe in any
// way.
//
// Example:
// PersistentCacheCollection collection(temp_dir.GetPath(), 4096);
// collection.Insert("first_cache_id", "key", value_span);
// collection.Insert("second_cache_id","key", value_span);
// ASSIGN_OR_RETURN(auto entry, collection->Find("first_cache_id", "key"),
// [](persistent_cache::TransactionError error) {
// // Translate error to return type here.
// });
//
// Use PersistentCacheCollection to store and retrieve key-value pairs from
// multiple `PersistentCache`s which are created just-in-time.
//
// PersistentCaches stored in the collection can be shared through exported
// parameters but cannot keep being used after they are evicted from the
// collection. PersistentCacheCollection ensures this doesn't happen by
// automatically abandoning caches when evicted.
class COMPONENT_EXPORT(PERSISTENT_CACHE) PersistentCacheCollection {
public:
static constexpr size_t kDefaultLruCacheCapacity = 100;
// Constructs an instance that will use the default storage backend for file
// management within `top_directory`.
PersistentCacheCollection(base::FilePath top_directory,
int64_t target_footprint,
size_t lru_capacity = kDefaultLruCacheCapacity);
// Constructs an instance that will use `storage_delegate` for file management
// within `top_directory`.
PersistentCacheCollection(
base::FilePath top_directory,
int64_t target_footprint,
std::unique_ptr<BackendStorage::Delegate> storage_delegate,
size_t lru_capacity = kDefaultLruCacheCapacity);
PersistentCacheCollection(const PersistentCacheCollection&) = delete;
PersistentCacheCollection& operator=(const PersistentCacheCollection&) =
delete;
~PersistentCacheCollection();
// Pass-through to PersistentCache functions that first select the correct
// cache. `cache_id` must be a US-ASCII string consisting more-or-less of
// lower-case letters, numbers, and select punctuation; see
// `BaseNameFromCacheId()` below for gory details.
base::expected<std::optional<EntryMetadata>, TransactionError> Find(
const std::string& cache_id,
std::string_view key,
BufferProvider buffer_provider);
base::expected<void, TransactionError> Insert(
const std::string& cache_id,
std::string_view key,
base::span<const uint8_t> content,
EntryMetadata metadata = EntryMetadata{});
// Deletes all files used by the collection, including any present on-disk
// that are not actively in-use.
void DeleteAllFiles();
// Returns a pending backend for an independent read-only connection to the
// persistent cache at `cache_id`, or nothing if the cache's backend is not
// operating or the params cannot be exported.
std::optional<PendingBackend> ShareReadOnlyConnection(
const std::string& cache_id);
// Returns a pending backend for an independent read-write connection to the
// cache at `cache_id`, or nothing if the cache's backend is not operating or
// the params cannot be exported.
std::optional<PendingBackend> ShareReadWriteConnection(
const std::string& cache_id);
private:
using PersistentCacheLRUMap =
base::HashingLRUCache<std::string, std::unique_ptr<PersistentCache>>;
friend class PersistentCacheCollectionTest;
FRIEND_TEST_ALL_PREFIXES(PersistentCacheCollectionTest, BaseNameFromCacheId);
FRIEND_TEST_ALL_PREFIXES(PersistentCacheCollectionTest,
FullAllowedCharacterSetHandled);
FRIEND_TEST_ALL_PREFIXES(PersistentCacheCollectionTest, RetrievalAfterClear);
FRIEND_TEST_ALL_PREFIXES(PersistentCacheCollectionTest,
InstancesAbandonnedOnClear);
FRIEND_TEST_ALL_PREFIXES(PersistentCacheCollectionTest,
EvictWhileLockedDeletesFiles);
// Abandon `cache` associated with `cache_id` in the LRU cache.
void AbandonCache(const std::string& cache_id,
PersistentCache* persistent_cache)
VALID_CONTEXT_REQUIRED(sequence_checker_);
// To be called on receiving a transaction error from the cache at `cache_id`.
TransactionError HandleTransactionError(const std::string& cache_id,
TransactionError error);
// Deletes files in the instance's directory from oldest to newest until the
// instance is using no more than 90% of its target footprint.
void ReduceFootPrint();
// Returns the PersistentCache for `cache_id`, creating it if needed. Returns
// nullptr if creation fails.
PersistentCache* GetOrCreateCache(const std::string& cache_id);
// Clears out the LRU map for testing.
void Clear();
// Returns the basename of the file(s) used by a backend given a cache id. An
// extension MUST be added to a returned basename before use. Returns an empty
// path if `cache_id` contains any character that does not match the following
// regular expression (where '\' escapes the character it precedes):
// "[\n !\"#$&'()*+,\-./0-9:;<=>?@[\\\]_a-z|~]". In other words, `cache_id`
// must be a subset of US-ASCII consisting of newline, space, numbers,
// lower-case letters, and select punctuation.
static base::FilePath BaseNameFromCacheId(const std::string& cache_id);
// Returns a string holding all valid characters for a cache id.
static std::string GetAllAllowedCharactersInCacheIds();
// Must outlive `persistent_caches_`.
BackendStorage backend_storage_ GUARDED_BY_CONTEXT(sequence_checker_);
// Desired maximum disk footprint for the cache collection in bytes.
const int64_t target_footprint_;
const size_t lru_capacity_;
PersistentCacheLRUMap persistent_caches_
GUARDED_BY_CONTEXT(sequence_checker_);
// Running tally of how many bytes can be inserted before a footprint
// reduction is triggered.
int64_t bytes_until_footprint_reduction_
GUARDED_BY_CONTEXT(sequence_checker_);
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace persistent_cache
#endif // COMPONENTS_PERSISTENT_CACHE_PERSISTENT_CACHE_COLLECTION_H_
|