Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: components/doodle/doodle_service.cc

Issue 2760253003: [Doodle] Record UMA for DoodleConfig download outcome and time (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/doodle/doodle_service.h ('k') | components/doodle/doodle_service_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/doodle/doodle_service.h" 5 #include "components/doodle/doodle_service.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/metrics/histogram_macros.h"
10 #include "base/time/time.h" 11 #include "base/time/time.h"
11 #include "base/values.h" 12 #include "base/values.h"
12 #include "components/doodle/pref_names.h" 13 #include "components/doodle/pref_names.h"
13 #include "components/prefs/pref_registry.h" 14 #include "components/prefs/pref_registry.h"
14 #include "components/prefs/pref_registry_simple.h" 15 #include "components/prefs/pref_registry_simple.h"
15 #include "components/prefs/pref_service.h" 16 #include "components/prefs/pref_service.h"
16 17
17 namespace doodle { 18 namespace doodle {
18 19
20 namespace {
21
22 // Note: Keep in sync with the corresponding enum in histograms.xml. Never
23 // remove values, and only insert new values at the end.
24 enum DoodleConfigDownloadOutcome {
25 OUTCOME_NEW_DOODLE,
26 OUTCOME_REVALIDATED_DOODLE,
27 OUTCOME_CHANGED_DOODLE,
28 OUTCOME_NO_DOODLE,
29 OUTCOME_EXPIRED,
30 OUTCOME_DOWNLOAD_ERROR,
31 OUTCOME_PARSING_ERROR,
32 // Insert new values here!
33 OUTCOME_COUNT
34 };
35
36 bool DownloadOutcomeIsSuccess(DoodleConfigDownloadOutcome outcome) {
37 switch (outcome) {
38 case OUTCOME_NEW_DOODLE:
39 case OUTCOME_REVALIDATED_DOODLE:
40 case OUTCOME_CHANGED_DOODLE:
41 case OUTCOME_NO_DOODLE:
42 return true;
43 case OUTCOME_EXPIRED:
44 case OUTCOME_DOWNLOAD_ERROR:
45 case OUTCOME_PARSING_ERROR:
46 return false;
47 case OUTCOME_COUNT:
48 NOTREACHED();
49 }
50 return false;
51 }
52
53 } // namespace
54
19 // static 55 // static
20 void DoodleService::RegisterProfilePrefs(PrefRegistrySimple* pref_registry) { 56 void DoodleService::RegisterProfilePrefs(PrefRegistrySimple* pref_registry) {
21 pref_registry->RegisterDictionaryPref(prefs::kCachedConfig, 57 pref_registry->RegisterDictionaryPref(prefs::kCachedConfig,
22 new base::DictionaryValue(), 58 new base::DictionaryValue(),
23 PrefRegistry::LOSSY_PREF); 59 PrefRegistry::LOSSY_PREF);
24 pref_registry->RegisterInt64Pref(prefs::kCachedConfigExpiry, 0, 60 pref_registry->RegisterInt64Pref(prefs::kCachedConfigExpiry, 0,
25 PrefRegistry::LOSSY_PREF); 61 PrefRegistry::LOSSY_PREF);
26 } 62 }
27 63
28 DoodleService::DoodleService(PrefService* pref_service, 64 DoodleService::DoodleService(PrefService* pref_service,
29 std::unique_ptr<DoodleFetcher> fetcher, 65 std::unique_ptr<DoodleFetcher> fetcher,
30 std::unique_ptr<base::OneShotTimer> expiry_timer, 66 std::unique_ptr<base::OneShotTimer> expiry_timer,
31 std::unique_ptr<base::Clock> clock) 67 std::unique_ptr<base::Clock> clock,
68 std::unique_ptr<base::TickClock> tick_clock)
32 : pref_service_(pref_service), 69 : pref_service_(pref_service),
33 fetcher_(std::move(fetcher)), 70 fetcher_(std::move(fetcher)),
34 expiry_timer_(std::move(expiry_timer)), 71 expiry_timer_(std::move(expiry_timer)),
35 clock_(std::move(clock)) { 72 clock_(std::move(clock)),
73 tick_clock_(std::move(tick_clock)) {
36 DCHECK(pref_service_); 74 DCHECK(pref_service_);
37 DCHECK(fetcher_); 75 DCHECK(fetcher_);
38 DCHECK(expiry_timer_); 76 DCHECK(expiry_timer_);
39 DCHECK(clock_); 77 DCHECK(clock_);
78 DCHECK(tick_clock_);
40 79
41 base::Time expiry_date = base::Time::FromInternalValue( 80 base::Time expiry_date = base::Time::FromInternalValue(
42 pref_service_->GetInt64(prefs::kCachedConfigExpiry)); 81 pref_service_->GetInt64(prefs::kCachedConfigExpiry));
43 base::Optional<DoodleConfig> config = DoodleConfig::FromDictionary( 82 base::Optional<DoodleConfig> config = DoodleConfig::FromDictionary(
44 *pref_service_->GetDictionary(prefs::kCachedConfig), base::nullopt); 83 *pref_service_->GetDictionary(prefs::kCachedConfig), base::nullopt);
45 UpdateCachedConfig(expiry_date - clock_->Now(), config); 84 DoodleState state =
85 config.has_value() ? DoodleState::AVAILABLE : DoodleState::NO_DOODLE;
86 UpdateCachedConfig(/*download_time=*/base::nullopt, state,
87 expiry_date - clock_->Now(), config);
46 } 88 }
47 89
48 DoodleService::~DoodleService() = default; 90 DoodleService::~DoodleService() = default;
49 91
50 void DoodleService::Shutdown() {} 92 void DoodleService::Shutdown() {}
51 93
52 void DoodleService::AddObserver(Observer* observer) { 94 void DoodleService::AddObserver(Observer* observer) {
53 observers_.AddObserver(observer); 95 observers_.AddObserver(observer);
54 } 96 }
55 97
56 void DoodleService::RemoveObserver(Observer* observer) { 98 void DoodleService::RemoveObserver(Observer* observer) {
57 observers_.RemoveObserver(observer); 99 observers_.RemoveObserver(observer);
58 } 100 }
59 101
60 void DoodleService::Refresh() { 102 void DoodleService::Refresh() {
61 fetcher_->FetchDoodle( 103 fetcher_->FetchDoodle(base::BindOnce(&DoodleService::DoodleFetched,
62 base::BindOnce(&DoodleService::DoodleFetched, base::Unretained(this))); 104 base::Unretained(this),
105 tick_clock_->NowTicks()));
63 } 106 }
64 107
65 void DoodleService::DoodleFetched( 108 void DoodleService::DoodleFetched(
109 base::TimeTicks start_time,
66 DoodleState state, 110 DoodleState state,
67 base::TimeDelta time_to_live, 111 base::TimeDelta time_to_live,
68 const base::Optional<DoodleConfig>& doodle_config) { 112 const base::Optional<DoodleConfig>& doodle_config) {
69 UpdateCachedConfig(time_to_live, doodle_config); 113 base::TimeDelta download_time = tick_clock_->NowTicks() - start_time;
114 UpdateCachedConfig(download_time, state, time_to_live, doodle_config);
70 } 115 }
71 116
72 void DoodleService::UpdateCachedConfig( 117 void DoodleService::UpdateCachedConfig(
118 base::Optional<base::TimeDelta> download_time,
119 DoodleState state,
73 base::TimeDelta time_to_live, 120 base::TimeDelta time_to_live,
74 const base::Optional<DoodleConfig>& doodle_config) { 121 const base::Optional<DoodleConfig>& doodle_config) {
fhorschig 2017/03/21 15:26:27 80 lines and nested ifs make this really hard to r
75 // Handle the case where the new config is already expired. 122 // Handle the case where the new config is already expired.
76 bool expired = time_to_live <= base::TimeDelta(); 123 bool expired = time_to_live <= base::TimeDelta();
77 const base::Optional<DoodleConfig>& new_config = 124 const base::Optional<DoodleConfig>& new_config =
78 expired ? base::nullopt : doodle_config; 125 expired ? base::nullopt : doodle_config;
79 126
127 DoodleConfigDownloadOutcome outcome = OUTCOME_COUNT;
128
80 // If the config changed, update our cache and notify observers. 129 // If the config changed, update our cache and notify observers.
81 // Note that this checks both for existence changes as well as changes of the 130 // Note that this checks both for existence changes as well as changes of the
82 // configs themselves. 131 // configs themselves.
83 if (cached_config_ != new_config) { 132 if (cached_config_ != new_config) {
fhorschig 2017/03/21 15:26:27 Can we consider putting this branch into a new fun
Marc Treib 2017/03/21 16:10:45 Hm. Maaaybe there's a sensible way to split this u
133 bool had_config_before = cached_config_.has_value();
134
84 cached_config_ = new_config; 135 cached_config_ = new_config;
85 136
86 if (cached_config_.has_value()) { 137 if (cached_config_.has_value()) {
138 outcome = had_config_before ? OUTCOME_CHANGED_DOODLE : OUTCOME_NEW_DOODLE;
139
87 pref_service_->Set(prefs::kCachedConfig, *cached_config_->ToDictionary()); 140 pref_service_->Set(prefs::kCachedConfig, *cached_config_->ToDictionary());
88 base::Time expiry_date = clock_->Now() + time_to_live; 141 base::Time expiry_date = clock_->Now() + time_to_live;
89 pref_service_->SetInt64(prefs::kCachedConfigExpiry, 142 pref_service_->SetInt64(prefs::kCachedConfigExpiry,
90 expiry_date.ToInternalValue()); 143 expiry_date.ToInternalValue());
91 } else { 144 } else {
145 outcome = OUTCOME_NO_DOODLE;
146
92 pref_service_->ClearPref(prefs::kCachedConfig); 147 pref_service_->ClearPref(prefs::kCachedConfig);
93 pref_service_->ClearPref(prefs::kCachedConfigExpiry); 148 pref_service_->ClearPref(prefs::kCachedConfigExpiry);
94 } 149 }
95 150
96 for (auto& observer : observers_) { 151 for (auto& observer : observers_) {
97 observer.OnDoodleConfigUpdated(cached_config_); 152 observer.OnDoodleConfigUpdated(cached_config_);
98 } 153 }
154 } else {
155 outcome = cached_config_.has_value() ? OUTCOME_REVALIDATED_DOODLE
156 : OUTCOME_NO_DOODLE;
157 }
158
159 // If the update came from the network, record metrics.
160 DCHECK(outcome != OUTCOME_COUNT);
fhorschig 2017/03/21 15:26:27 Is there any chance this couldn't have happened?
Marc Treib 2017/03/21 16:10:46 Nope, hence the DCHECK.
161 if (download_time.has_value()) {
162 // Determine the final outcome. ERROR or EXPIRED override NO_DOODLE.
fhorschig 2017/03/21 15:26:27 So this complete branch is basically dead for one
Marc Treib 2017/03/21 16:10:45 Good point.
fhorschig 2017/03/21 16:41:34 Not dead but very unused for one call. that's onl
Marc Treib 2017/03/21 16:48:59 Pulled it all out into a separate DetermineDownloa
163 switch (state) {
164 case DoodleState::AVAILABLE:
165 case DoodleState::NO_DOODLE:
166 if (expired) {
167 outcome = OUTCOME_EXPIRED;
168 }
169 break;
170
171 case DoodleState::DOWNLOAD_ERROR:
172 outcome = OUTCOME_DOWNLOAD_ERROR;
173 break;
174
175 case DoodleState::PARSING_ERROR:
176 outcome = OUTCOME_PARSING_ERROR;
177 break;
178 }
179
180 UMA_HISTOGRAM_ENUMERATION("Doodle.ConfigDownloadOutcome", outcome,
181 OUTCOME_COUNT);
182
183 if (DownloadOutcomeIsSuccess(outcome)) {
184 UMA_HISTOGRAM_MEDIUM_TIMES("Doodle.ConfigDownloadTime",
185 download_time.value());
186 }
99 } 187 }
100 188
101 // Even if the configs are identical, the time-to-live might have changed. 189 // Even if the configs are identical, the time-to-live might have changed.
102 // (Re-)schedule the cache expiry. 190 // (Re-)schedule the cache expiry.
103 if (cached_config_.has_value()) { 191 if (cached_config_.has_value()) {
104 expiry_timer_->Start( 192 expiry_timer_->Start(
105 FROM_HERE, time_to_live, 193 FROM_HERE, time_to_live,
106 base::Bind(&DoodleService::DoodleExpired, base::Unretained(this))); 194 base::Bind(&DoodleService::DoodleExpired, base::Unretained(this)));
107 } else { 195 } else {
108 expiry_timer_->Stop(); 196 expiry_timer_->Stop();
109 } 197 }
110 } 198 }
111 199
112 void DoodleService::DoodleExpired() { 200 void DoodleService::DoodleExpired() {
113 DCHECK(cached_config_.has_value()); 201 DCHECK(cached_config_.has_value());
114 UpdateCachedConfig(base::TimeDelta(), base::nullopt); 202 UpdateCachedConfig(/*download_time=*/base::nullopt, DoodleState::NO_DOODLE,
203 base::TimeDelta(), base::nullopt);
115 } 204 }
116 205
117 } // namespace doodle 206 } // namespace doodle
OLDNEW
« no previous file with comments | « components/doodle/doodle_service.h ('k') | components/doodle/doodle_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698