File: no_vary_search_cache_storage.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (170 lines) | stat: -rw-r--r-- 6,464 bytes parent folder | download | duplicates (3)
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_