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
|
// Copyright 2024 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_H_
#define COMPONENTS_PERSISTENT_CACHE_PERSISTENT_CACHE_H_
#include <stdint.h>
#include <memory>
#include <optional>
#include <string_view>
#include <utility>
#include "base/component_export.h"
#include "base/containers/span.h"
#include "base/files/file.h"
#include "base/rand_util.h"
#include "base/synchronization/lock.h"
#include "base/timer/elapsed_timer.h"
#include "base/types/expected.h"
#include "components/persistent_cache/buffer_provider.h"
#include "components/persistent_cache/entry_metadata.h"
#include "components/persistent_cache/lock_state.h"
namespace persistent_cache {
class Backend;
struct PendingBackend;
enum class TransactionError;
// Use PersistentCache to store and retrieve key-value pairs across processes or
// threads.
//
// Example:
// // Acquire a PendingBackend.
// PendingBackend pending_backend = AcquirePendingBackend();
// auto persistent_cache = PersistentCache::Bind(std::move(pending_backend));
// if (!persistent_cache) {
// // Handle error.
// }
//
// // Add a key-value pair.
// persistent_cache->Insert("foo", base::byte_span_from_cstring("1"));
//
// // Retrieve a value.
// {
// base::HeapArray<uint8_t> content;
// ASSIGN_OR_RETURN(
// auto metadata,
// persistent_cache->Find("foo", [&content](size_t size) {
// content = base::HeapArray<uint8_t>::Uninit(size);
// return base::span(content);
// }),
// [](persistent_cache::TransactionError error) {
// // Translate and handle error here.
// });
//
// if (metadata.has_value()) {
// UseEntry(*std::move(metadata), std::move(content));
// }
// }
//
// // Inserting again overwrites anything in there if present.
// persistent_cache->Insert("foo", base::byte_span_from_cstring("2"));
//
//
// Error Handling and Recovery:
// Operations can return a `TransactionError`, which dictates the required
// recovery action.
//
// The error types are:
// - `TransactionError::kTransient`: A recoverable backend error occurred. The
// current instance is likely still usable. The caller should take the
// failure as a cache miss or retry the same operation.
// - `TransactionError::kConnectionError`: The connection to the backend was
// lost (e.g., a lock could not be acquired). The caller should destroy the
// instance and re-open with fresh parameters.
// - `TransactionError::kPermanent`: A fatal, unrecoverable error occurred,
// indicating data corruption. The caller should delete the backend storage
// then destroy the instance. No new instance should be backed by the same
// files before they are properly deleted and recreated.
//
// Resource Management:
// A PersistentCache instance holds resources like open file handles for its
// entire lifetime. It does not automatically release these on error. Destroying
// the `PersistentCache` instance is required to release those resources. This
// release then enables the caller to perform actions like deleting the cache
// files if necessary/possible.
// Use PersistentCache to store and retrieve key-value pairs across processes or
// threads.
class COMPONENT_EXPORT(PERSISTENT_CACHE) PersistentCache {
public:
// Returns a new instance on success or null on failure. Unconditionally
// consumes `pending_backend`.
static std::unique_ptr<PersistentCache> Bind(PendingBackend pending_backend);
explicit PersistentCache(std::unique_ptr<Backend> backend);
~PersistentCache();
// Not copyable or moveable.
PersistentCache(const PersistentCache&) = delete;
PersistentCache(PersistentCache&&) = delete;
PersistentCache& operator=(const PersistentCache&) = delete;
PersistentCache& operator=(PersistentCache&&) = delete;
// Returns the metadata associated with `key` in the cache, or no value if not
// found. If `key` is found, `buffer_provider` will be called exactly once
// with the size of the content. If `buffer_provider` returns a non-empty span
// (which must be sized exactly to the given content size), the content will
// be written into it. If it returns an empty span, no data is copied. Note
// that an error may be returned even if `buffer_provider` had been called.
// See class comments regarding error management.
//
// Thread-safe.
base::expected<std::optional<EntryMetadata>, TransactionError> Find(
std::string_view key,
BufferProvider buffer_provider);
// Used to add an entry containing `content` and associated with `key`.
// Metadata associated with the entry can be provided in `metadata` or the
// object can be default initialized to signify no metadata.
// Implementations are allowed to free other unused entries on demand to make
// room or fail when full. Returns a empty value on success and error value
// otherwise. See class comments regarding error management.
//
// Thread-safe.
base::expected<void, TransactionError> Insert(
std::string_view key,
base::span<const uint8_t> content,
EntryMetadata metadata = EntryMetadata{});
// Marks the instance as no longer suitable for use. Returns the state of the
// shared lock at the moment of abandonment. Once an instance is abandoned,
// all other instances that share a connection with it will report
// `TransactionError::kConnectionError` for all operations.
LockState Abandon();
Backend* GetBackendForTesting();
private:
friend class BackendStorage;
const Backend& backend() const { return *backend_; }
std::optional<base::ElapsedTimer> MaybeGetTimerForHistogram();
std::string GetFullHistogramName(std::string_view name) const;
std::unique_ptr<Backend> backend_;
static constexpr double kTimingLoggingProbability = 0.01;
base::MetricsSubSampler metrics_subsampler_
GUARDED_BY(metrics_subsampler_lock_);
base::Lock metrics_subsampler_lock_;
};
} // namespace persistent_cache
#endif // COMPONENTS_PERSISTENT_CACHE_PERSISTENT_CACHE_H_
|