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