1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/optimization_guide/store_update_data.h"
6
7 #include "base/strings/string_number_conversions.h"
8 #include "components/optimization_guide/optimization_guide_features.h"
9 #include "components/optimization_guide/optimization_guide_store.h"
10 #include "components/optimization_guide/proto/hint_cache.pb.h"
11 #include "components/optimization_guide/proto/hints.pb.h"
12 #include "components/optimization_guide/proto/models.pb.h"
13
14 namespace optimization_guide {
15
16 // static
17 std::unique_ptr<StoreUpdateData>
CreateComponentStoreUpdateData(const base::Version & component_version)18 StoreUpdateData::CreateComponentStoreUpdateData(
19 const base::Version& component_version) {
20 std::unique_ptr<StoreUpdateData> update_data(new StoreUpdateData(
21 base::Optional<base::Version>(component_version),
22 base::Optional<base::Time>(), base::Optional<base::Time>()));
23 return update_data;
24 }
25
26 // static
CreateFetchedStoreUpdateData(base::Time fetch_update_time)27 std::unique_ptr<StoreUpdateData> StoreUpdateData::CreateFetchedStoreUpdateData(
28 base::Time fetch_update_time) {
29 std::unique_ptr<StoreUpdateData> update_data(
30 new StoreUpdateData(base::Optional<base::Version>(),
31 base::Optional<base::Time>(fetch_update_time),
32 base::Optional<base::Time>()));
33 return update_data;
34 }
35
36 // static
37 std::unique_ptr<StoreUpdateData>
CreatePredictionModelStoreUpdateData()38 StoreUpdateData::CreatePredictionModelStoreUpdateData() {
39 std::unique_ptr<StoreUpdateData> prediction_model_update_data(
40 new StoreUpdateData());
41 return prediction_model_update_data;
42 }
43
44 // static
45 std::unique_ptr<StoreUpdateData>
CreateHostModelFeaturesStoreUpdateData(base::Time host_model_features_update_time,base::Time expiry_time)46 StoreUpdateData::CreateHostModelFeaturesStoreUpdateData(
47 base::Time host_model_features_update_time,
48 base::Time expiry_time) {
49 std::unique_ptr<StoreUpdateData> host_model_features_update_data(
50 new StoreUpdateData(host_model_features_update_time, expiry_time));
51 return host_model_features_update_data;
52 }
53
StoreUpdateData(base::Time host_model_features_update_time,base::Time expiry_time)54 StoreUpdateData::StoreUpdateData(base::Time host_model_features_update_time,
55 base::Time expiry_time)
56 : update_time_(host_model_features_update_time),
57 expiry_time_(expiry_time),
58 entries_to_save_(std::make_unique<EntryVector>()) {
59 entry_key_prefix_ =
60 OptimizationGuideStore::GetHostModelFeaturesEntryKeyPrefix();
61 proto::StoreEntry metadata_host_model_features_entry;
62 metadata_host_model_features_entry.set_entry_type(
63 static_cast<proto::StoreEntryType>(
64 OptimizationGuideStore::StoreEntryType::kMetadata));
65 metadata_host_model_features_entry.set_update_time_secs(
66 host_model_features_update_time.ToDeltaSinceWindowsEpoch().InSeconds());
67 entries_to_save_->emplace_back(
68 OptimizationGuideStore::GetMetadataTypeEntryKey(
69 OptimizationGuideStore::MetadataType::kHostModelFeatures),
70 std::move(metadata_host_model_features_entry));
71
72 // |this| may be modified on another thread after construction but all
73 // future modifications, from that call forward, must be made on the same
74 // thread.
75 DETACH_FROM_SEQUENCE(sequence_checker_);
76 }
77
StoreUpdateData()78 StoreUpdateData::StoreUpdateData()
79 : entries_to_save_(std::make_unique<EntryVector>()) {
80 entry_key_prefix_ =
81 OptimizationGuideStore::GetPredictionModelEntryKeyPrefix();
82
83 // |this| may be modified on another thread after construction but all
84 // future modifications, from that call forward, must be made on the same
85 // thread.
86 DETACH_FROM_SEQUENCE(sequence_checker_);
87 }
88
StoreUpdateData(base::Optional<base::Version> component_version,base::Optional<base::Time> fetch_update_time,base::Optional<base::Time> expiry_time)89 StoreUpdateData::StoreUpdateData(
90 base::Optional<base::Version> component_version,
91 base::Optional<base::Time> fetch_update_time,
92 base::Optional<base::Time> expiry_time)
93 : component_version_(component_version),
94 update_time_(fetch_update_time),
95 expiry_time_(expiry_time),
96 entries_to_save_(std::make_unique<EntryVector>()) {
97 DCHECK_NE(!component_version_, !update_time_);
98
99 if (component_version_.has_value()) {
100 entry_key_prefix_ = OptimizationGuideStore::GetComponentHintEntryKeyPrefix(
101 *component_version_);
102
103 // Add a component metadata entry for the component's version.
104 proto::StoreEntry metadata_component_entry;
105
106 metadata_component_entry.set_entry_type(static_cast<proto::StoreEntryType>(
107 OptimizationGuideStore::StoreEntryType::kMetadata));
108 metadata_component_entry.set_version(component_version_->GetString());
109 entries_to_save_->emplace_back(
110 OptimizationGuideStore::GetMetadataTypeEntryKey(
111 OptimizationGuideStore::MetadataType::kComponent),
112 std::move(metadata_component_entry));
113 } else if (update_time_.has_value()) {
114 entry_key_prefix_ = OptimizationGuideStore::GetFetchedHintEntryKeyPrefix();
115 proto::StoreEntry metadata_fetched_entry;
116 metadata_fetched_entry.set_entry_type(static_cast<proto::StoreEntryType>(
117 OptimizationGuideStore::StoreEntryType::kMetadata));
118 metadata_fetched_entry.set_update_time_secs(
119 update_time_->ToDeltaSinceWindowsEpoch().InSeconds());
120 entries_to_save_->emplace_back(
121 OptimizationGuideStore::GetMetadataTypeEntryKey(
122 OptimizationGuideStore::MetadataType::kFetched),
123 std::move(metadata_fetched_entry));
124 } else {
125 NOTREACHED();
126 }
127 // |this| may be modified on another thread after construction but all
128 // future modifications, from that call forward, must be made on the same
129 // thread.
130 DETACH_FROM_SEQUENCE(sequence_checker_);
131 }
132
~StoreUpdateData()133 StoreUpdateData::~StoreUpdateData() {}
134
MoveHintIntoUpdateData(proto::Hint && hint)135 void StoreUpdateData::MoveHintIntoUpdateData(proto::Hint&& hint) {
136 // All future modifications must be made by the same thread. Note, |this| may
137 // have been constructed on another thread.
138 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
139 DCHECK(!entry_key_prefix_.empty());
140
141 // To avoid any unnecessary copying, the hint is moved into proto::StoreEntry.
142 OptimizationGuideStore::EntryKey hint_entry_key =
143 entry_key_prefix_ + hint.key();
144 proto::StoreEntry entry_proto;
145 if (component_version()) {
146 entry_proto.set_entry_type(static_cast<proto::StoreEntryType>(
147 OptimizationGuideStore::StoreEntryType::kComponentHint));
148 } else if (update_time()) {
149 base::TimeDelta expiry_duration;
150 if (hint.has_max_cache_duration()) {
151 expiry_duration =
152 base::TimeDelta().FromSeconds(hint.max_cache_duration().seconds());
153 } else {
154 expiry_duration = features::StoredFetchedHintsFreshnessDuration();
155 }
156 entry_proto.set_expiry_time_secs((base::Time::Now() + expiry_duration)
157 .ToDeltaSinceWindowsEpoch()
158 .InSeconds());
159 entry_proto.set_entry_type(static_cast<proto::StoreEntryType>(
160 OptimizationGuideStore::StoreEntryType::kFetchedHint));
161 }
162 entry_proto.set_allocated_hint(new proto::Hint(std::move(hint)));
163 entries_to_save_->emplace_back(std::move(hint_entry_key),
164 std::move(entry_proto));
165 }
166
CopyHostModelFeaturesIntoUpdateData(const proto::HostModelFeatures & host_model_features)167 void StoreUpdateData::CopyHostModelFeaturesIntoUpdateData(
168 const proto::HostModelFeatures& host_model_features) {
169 // All future modifications must be made by the same thread. Note, |this| may
170 // have been constructed on another thread.
171 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
172 DCHECK(!entry_key_prefix_.empty());
173 DCHECK(expiry_time());
174
175 // To avoid any unnecessary copying, the host model feature data is moved into
176 // proto::StoreEntry.
177 OptimizationGuideStore::EntryKey host_model_features_entry_key =
178 entry_key_prefix_ + host_model_features.host();
179 proto::StoreEntry entry_proto;
180 entry_proto.set_entry_type(static_cast<proto::StoreEntryType>(
181 OptimizationGuideStore::StoreEntryType::kHostModelFeatures));
182 entry_proto.set_expiry_time_secs(
183 expiry_time_->ToDeltaSinceWindowsEpoch().InSeconds());
184 entry_proto.mutable_host_model_features()->CopyFrom(host_model_features);
185 entries_to_save_->emplace_back(std::move(host_model_features_entry_key),
186 std::move(entry_proto));
187 }
188
CopyPredictionModelIntoUpdateData(const proto::PredictionModel & prediction_model)189 void StoreUpdateData::CopyPredictionModelIntoUpdateData(
190 const proto::PredictionModel& prediction_model) {
191 // All future modifications must be made by the same thread. Note, |this| may
192 // have been constructed on another thread.
193 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
194 DCHECK(!entry_key_prefix_.empty());
195
196 // To avoid any unnecessary copying, the prediction model is moved into
197 // proto::StoreEntry.
198 OptimizationGuideStore::EntryKey prediction_model_entry_key =
199 entry_key_prefix_ +
200 base::NumberToString(static_cast<int>(
201 prediction_model.model_info().optimization_target()));
202 proto::StoreEntry entry_proto;
203 entry_proto.set_entry_type(static_cast<proto::StoreEntryType>(
204 OptimizationGuideStore::StoreEntryType::kPredictionModel));
205 entry_proto.mutable_prediction_model()->CopyFrom(prediction_model);
206 entries_to_save_->emplace_back(std::move(prediction_model_entry_key),
207 std::move(entry_proto));
208 }
209
TakeUpdateEntries()210 std::unique_ptr<EntryVector> StoreUpdateData::TakeUpdateEntries() {
211 // TakeUpdateEntries is not be sequence checked as it only gives up ownership
212 // of the entries_to_save_ and does not modify any state.
213 DCHECK(entries_to_save_);
214
215 return std::move(entries_to_save_);
216 }
217
218 } // namespace optimization_guide
219