summaryrefslogtreecommitdiff
path: root/chromium/components/optimization_guide/hint_cache.h
blob: 64076571f0ddb9e5341b1f63f6643150a2d8cf92 (plain)
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_OPTIMIZATION_GUIDE_HINT_CACHE_H_
#define COMPONENTS_OPTIMIZATION_GUIDE_HINT_CACHE_H_

#include <string>

#include "base/callback.h"
#include "base/containers/mru_cache.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/time/clock.h"
#include "components/optimization_guide/memory_hint.h"
#include "components/optimization_guide/optimization_guide_store.h"
#include "components/optimization_guide/proto/hints.pb.h"

class GURL;

namespace optimization_guide {
class StoreUpdateData;

using HintLoadedCallback = base::OnceCallback<void(const proto::Hint*)>;

// Contains a set of optimization hints received from the Cacao service. This
// may include hints received from the ComponentUpdater and hints fetched from a
// Cacao Optimization Guide Service API. The availability of hints is queryable
// via host name and full URL. The cache itself consists of a backing store,
// which allows for asynchronous loading of any available host-keyed hint, and
// an MRU host-keyed cache and a url-keyed cache, which can be used to
// synchronously retrieve recently loaded hints keyed by URL or host.
class HintCache {
 public:
  // Construct the HintCache with a backing store and an optional max host-keyed
  // cache size. While |optimization_guide_store| is required,
  // |max_memory_cache_hints| is optional and the default max size will be used
  // if it is not provided.
  explicit HintCache(
      std::unique_ptr<OptimizationGuideStore> optimization_guide_store,
      base::Optional<int> max_memory_cache_hints = base::Optional<int>());
  ~HintCache();

  // Initializes the backing store contained within the hint cache and
  // asynchronously runs the callback after initialization is complete.
  // If |purge_existing_data| is set to true, then the cache will purge any
  // pre-existing data and begin in a clean state.
  void Initialize(bool purge_existing_data, base::OnceClosure callback);

  // Returns a StoreUpdateData. During component processing, hints from the
  // component are moved into the StoreUpdateData. After component
  // processing completes, the component update data is provided to the backing
  // store in UpdateComponentHints() and used to update its component hints. In
  // the case the provided component version is not newer than the store's
  // version, nullptr will be returned by the call.
  std::unique_ptr<StoreUpdateData> MaybeCreateUpdateDataForComponentHints(
      const base::Version& version) const;

  // Returns an UpdateData created by the store to hold updates for fetched
  // hints. No version is needed nor applicable for fetched hints. During
  // processing of the GetHintsResponse, hints are moved into the update data.
  // After processing is complete, the update data is provided to the backing
  // store to update hints. |update_time| specifies when the hints within the
  // created update data will be scheduled to be updated.
  std::unique_ptr<StoreUpdateData> CreateUpdateDataForFetchedHints(
      base::Time update_time) const;

  // Updates the store's component data using the provided StoreUpdateData
  // and asynchronously runs the provided callback after the update finishes.
  void UpdateComponentHints(std::unique_ptr<StoreUpdateData> component_data,
                            base::OnceClosure callback);

  // Process |get_hints_response| to be stored in the hint cache store.
  // |callback| is asynchronously run when the hints are successfully stored or
  // if the store is not available. |update_time| specifies when the hints
  // within |get_hints_response| will need to be updated next. |urls_fetched|
  // specifies the URLs for which specific hints were requested to be fetched.
  // It is expected for |this| to keep track of the result, even if a hint was
  // not returned for the URL.
  void UpdateFetchedHints(
      std::unique_ptr<proto::GetHintsResponse> get_hints_response,
      base::Time update_time,
      const base::flat_set<GURL>& urls_fetched,
      base::OnceClosure callback);

  // Purges fetched hints from the owned |optimization_guide_store| that have
  // expired.
  void PurgeExpiredFetchedHints();

  // Purges fetched hints from the owned |optimization_guide_store_| and resets
  // both in-memory hint caches.
  void ClearFetchedHints();

  // Purges fetched hints from the owned |optimization_guide_store_| and resets
  // the host-keyed cache.
  void ClearHostKeyedHints();

  // Returns whether the cache has a hint data for |host| locally (whether
  // in the host-keyed cache or persisted on disk).
  bool HasHint(const std::string& host) const;

  // Requests that hint data for |host| be loaded asynchronously and passed to
  // |callback| if/when loaded.
  void LoadHint(const std::string& host, HintLoadedCallback callback);

  // Returns the update time provided by |hint_store_|, which specifies when the
  // fetched hints within the store are ready to be updated. If |hint_store_| is
  // not initialized, base::Time() is returned.
  base::Time GetFetchedHintsUpdateTime() const;

  // Returns the hint data for |host| if found in the host-keyed cache,
  // otherwise nullptr.
  const proto::Hint* GetHostKeyedHintIfLoaded(const std::string& host);

  // Returns an unepxired hint data for |url| if found in the url-keyed cache,
  // otherwise nullptr. If the hint is expired, it is removed from the URL-keyed
  // cache. Only HTTP/HTTPS URLs without username and password are supported by
  // the URL-keyed cache, if |url| does not meet this criteria, nullptr is
  // returned. The returned hint is not guaranteed to remain valid and will
  // become invalid if any additional URL-keyed hints are added to the cache
  // that evicts the returned hint.
  proto::Hint* GetURLKeyedHint(const GURL& url);

  // Returns true if the url-keyed cache contains an entry for |url|, even if
  // the entry is empty. If a hint exists but is expired, it returns false.
  bool HasURLKeyedEntryForURL(const GURL& url);

  // Verifies and processes |hints| and moves the ones it supports into
  // |update_data| and caches any valid URL keyed hints.
  //
  // Returns true if there was at least one hint is moved into |update_data|.
  bool ProcessAndCacheHints(
      google::protobuf::RepeatedPtrField<proto::Hint>* hints,
      StoreUpdateData* update_data);

  // Returns whether the persistent hint store owned by this is available.
  bool IsHintStoreAvailable() const;

  // Override |clock_| for testing.
  void SetClockForTesting(const base::Clock* clock);

  // Add hint to the URL-keyed cache. For testing only.
  void AddHintForTesting(const GURL& gurl, std::unique_ptr<proto::Hint> hint);

 private:
  using HostKeyedHintCache =
      base::HashingMRUCache<OptimizationGuideStore::EntryKey,
                            std::unique_ptr<MemoryHint>>;

  using URLKeyedHintCache =
      base::HashingMRUCache<std::string, std::unique_ptr<MemoryHint>>;

  // The callback run after the store finishes initialization. This then runs
  // the callback initially provided by the Initialize() call.
  void OnStoreInitialized(base::OnceClosure callback);

  // The callback run after the store finishes loading a hint. This adds the
  // loaded hint to |host_keyed_cache_|, potentially purging the least recently
  // used element, and then runs the callback initially provided by the
  // LoadHint() call.
  void OnLoadStoreHint(
      HintLoadedCallback callback,
      const OptimizationGuideStore::EntryKey& store_hint_entry_key,
      std::unique_ptr<MemoryHint> hint);

  // The backing store used with this hint cache. Set during construction.
  const std::unique_ptr<OptimizationGuideStore> optimization_guide_store_;

  // The cache of host-keyed hints loaded from the store. Maps store
  // EntryKey to Hint proto. This serves two purposes:
  //  1. Allows hints to be requested on navigation and retained in memory until
  //     commit, when they can be synchronously retrieved from the cache.
  //  2. Reduces churn of needing to reload hints from frequently visited sites
  //     multiple times during a session.
  HostKeyedHintCache host_keyed_cache_;

  // The in-memory cache of URL-keyed hints fetched from the remote optimization
  // guide. Maps a full URL to Hint proto. All available URL-keyed hints are
  // maintained within the cache and are not persisted to disk.
  URLKeyedHintCache url_keyed_hint_cache_;

  // The clock used to determine if hints have expired.
  const base::Clock* clock_;

  SEQUENCE_CHECKER(sequence_checker_);

  DISALLOW_COPY_AND_ASSIGN(HintCache);
};

}  // namespace optimization_guide

#endif  // COMPONENTS_OPTIMIZATION_GUIDE_HINT_CACHE_H_