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
|
// 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 NET_HTTP_NO_VARY_SEARCH_CACHE_STORAGE_H_
#define NET_HTTP_NO_VARY_SEARCH_CACHE_STORAGE_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <optional>
#include <string>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "net/base/net_export.h"
#include "net/http/no_vary_search_cache.h"
namespace net {
class NoVarySearchCache;
class NoVarySearchCacheStorageFileOperations;
// An implementation of persistence for NoVarySearchCache. Disk operations are
// performed in the background on a thread pool.
class NET_EXPORT_PRIVATE NoVarySearchCacheStorage final
: public NoVarySearchCache::Journal {
public:
enum class LoadFailed { kCannotJournal };
using LoadResult =
base::expected<std::unique_ptr<NoVarySearchCache>, LoadFailed>;
using LoadCallback = base::OnceCallback<void(LoadResult)>;
// Exposed for testing.
static constexpr std::string_view kSnapshotFilename = "snapshot.baf";
static constexpr std::string_view kJournalFilename = "journal.baj";
// Generated by the command:
// echo "snapshot.baf version 1" | md5sum | cut -b 1-8
static constexpr uint32_t kSnapshotMagicNumber = 0x4b17c1ee;
// Generated by the command:
// echo "journal.baj version 1" | md5sum | cut -b 1-8
static constexpr uint32_t kJournalMagicNumber = 0x984b3c4d;
// Max file size. We won't try to load a file larger than this. We don't
// expect the database to ever get this big.
static constexpr size_t kMaxFileSize = 100 * 1024 * 1024;
// Avoid automatically taking a new snapshot until the journal gets this big,
// even if the snapshot is smaller.
static constexpr size_t kMinimumAutoSnapshotSize = 64 * 1024;
// Create a NoVarySearchCacheStorage object to persist `cache`. Load() must be
// called in order for it to actually do anything.
NoVarySearchCacheStorage();
NoVarySearchCacheStorage(const NoVarySearchCacheStorage&) = delete;
NoVarySearchCacheStorage& operator=(const NoVarySearchCacheStorage&) = delete;
~NoVarySearchCacheStorage() override;
// Asynchronously loads a previously persisted NoVarySearchCache object using
// `file_operations`, then starts journalling to a new journal file. If an
// existing persisted cache could not be loaded, creates an empty
// NoVarySearchCache object with `max_size` configured to be
// `default_max_size`. If a new journal file could not be created, `callback`
// is called with base::unexpected(kCannotJournal). Otherwise it is called
// with a NoVarySearchCache object wrapped in a std::unique_ptr. `callback`
// should merge in any entries that were added to the temporary cache used
// during loading, and then switch to using the new cache. Any inserts or
// erasures performed on the new cache will be journalled to disk. The new
// NoVarySearchCache object should not be destroyed before this object is.
// `callback` is never called synchronously.
void Load(
std::unique_ptr<NoVarySearchCacheStorageFileOperations> file_operations,
size_t default_max_size,
LoadCallback callback);
// Serializes and persists the current state of `cache_` to disk, and starts a
// new empty journal. Does nothing if the initial load hasn't completed yet.
// This method is also called automatically any time the journal file grows
// too large.
void TakeSnapshot();
// Implementation of NoVarySearchCache::Journal.
// Serializes the arguments and posts a task to `journal_` to append the
// result to the journal.
void OnInsert(const std::string& base_url_cache_key,
const HttpNoVarySearchData& nvs_data,
const std::optional<std::string>& query,
base::Time update_time) override;
// Serializes the arguments and posts a task to `journal_` to append to the
// journal.
void OnErase(const std::string& base_url_cache_key,
const HttpNoVarySearchData& nvs_data,
const std::optional<std::string>& query) override;
bool IsJournallingForTesting() const { return static_cast<bool>(journal_); }
private:
class Journaller;
class Loader;
using JournallerPtr = std::unique_ptr<Journaller, base::OnTaskRunnerDeleter>;
// On successful creation of the Journaller on the background thread, a
// pointer to it needs to be passed back to the
// NoVarySearchCacheStorage::OnLoadComplete() method so that it can be called
// and have its lifetime managed. We also need the loaded NoVarySearchCache
// object.
struct CacheAndJournalPointers {
CacheAndJournalPointers(std::unique_ptr<NoVarySearchCache> cache,
JournallerPtr journal);
CacheAndJournalPointers(const CacheAndJournalPointers&) = delete;
// Move construction is allowed.
CacheAndJournalPointers(CacheAndJournalPointers&&);
CacheAndJournalPointers& operator=(const CacheAndJournalPointers&) = delete;
CacheAndJournalPointers& operator=(CacheAndJournalPointers&&) = delete;
~CacheAndJournalPointers();
std::unique_ptr<NoVarySearchCache> cache;
JournallerPtr journal;
};
// Called when loading the persisted NoVarySearchCache has succeeded or
// failed. Sets `cache_`, registers this object as a Journal for it, and
// assigns to `journal_` on success. Calls `callback`.
void OnLoadComplete(
LoadCallback callback,
base::expected<CacheAndJournalPointers, LoadFailed> result);
// Called when `journal_` has found that journalling failed. Clears `journal_`
// and unregisters this object as an observer.
void OnJournallingFailed();
// Appends `pickle` to the journal file.
void AppendToJournal(base::Pickle pickle);
raw_ptr<NoVarySearchCache> cache_ = nullptr;
// Task runner for file operations.
scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
// `journal_` lives on the `background_task_runner_`.
JournallerPtr journal_;
// Time when Start() was called.
base::Time start_time_;
base::WeakPtrFactory<NoVarySearchCacheStorage> weak_factory_{this};
};
} // namespace net
#endif // NET_HTTP_NO_VARY_SEARCH_CACHE_STORAGE_H_
|