OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/suggestions/suggestions_service.h" | 5 #include "components/suggestions/suggestions_service.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
(...skipping 12 matching lines...) Expand all Loading... | |
23 #include "net/base/net_errors.h" | 23 #include "net/base/net_errors.h" |
24 #include "net/base/url_util.h" | 24 #include "net/base/url_util.h" |
25 #include "net/http/http_response_headers.h" | 25 #include "net/http/http_response_headers.h" |
26 #include "net/http/http_status_code.h" | 26 #include "net/http/http_status_code.h" |
27 #include "net/http/http_util.h" | 27 #include "net/http/http_util.h" |
28 #include "net/url_request/url_fetcher.h" | 28 #include "net/url_request/url_fetcher.h" |
29 #include "net/url_request/url_request_status.h" | 29 #include "net/url_request/url_request_status.h" |
30 #include "url/gurl.h" | 30 #include "url/gurl.h" |
31 | 31 |
32 using base::CancelableClosure; | 32 using base::CancelableClosure; |
33 using base::TimeDelta; | |
34 using base::TimeTicks; | |
33 | 35 |
34 namespace suggestions { | 36 namespace suggestions { |
35 | 37 |
36 namespace { | 38 namespace { |
37 | 39 |
38 // Used to UMA log the state of the last response from the server. | 40 // Used to UMA log the state of the last response from the server. |
39 enum SuggestionsResponseState { | 41 enum SuggestionsResponseState { |
40 RESPONSE_EMPTY, | 42 RESPONSE_EMPTY, |
41 RESPONSE_INVALID, | 43 RESPONSE_INVALID, |
42 RESPONSE_VALID, | 44 RESPONSE_VALID, |
(...skipping 24 matching lines...) Expand all Loading... | |
67 const SuggestionsProfile& suggestions, | 69 const SuggestionsProfile& suggestions, |
68 std::vector<SuggestionsService::ResponseCallback>* requestors) { | 70 std::vector<SuggestionsService::ResponseCallback>* requestors) { |
69 std::vector<SuggestionsService::ResponseCallback> temp_requestors; | 71 std::vector<SuggestionsService::ResponseCallback> temp_requestors; |
70 temp_requestors.swap(*requestors); | 72 temp_requestors.swap(*requestors); |
71 std::vector<SuggestionsService::ResponseCallback>::iterator it; | 73 std::vector<SuggestionsService::ResponseCallback>::iterator it; |
72 for (it = temp_requestors.begin(); it != temp_requestors.end(); ++it) { | 74 for (it = temp_requestors.begin(); it != temp_requestors.end(); ++it) { |
73 if (!it->is_null()) it->Run(suggestions); | 75 if (!it->is_null()) it->Run(suggestions); |
74 } | 76 } |
75 } | 77 } |
76 | 78 |
77 // Default delay used when scheduling a blacklist request. | 79 // Default delay used when scheduling a request. |
78 const int kBlacklistDefaultDelaySec = 1; | 80 const TimeDelta kDefaultSchedulingDelay = TimeDelta::FromSeconds(1); |
Mathieu
2014/12/04 18:53:32
consider having a const int and rather initialize
manzagop (departed)
2014/12/05 15:13:22
Done. Went with local variables.
| |
79 | 81 |
80 // Multiplier on the delay used when scheduling a blacklist request, in case the | 82 // Multiplier on the delay used when re-scheduling a failed request. |
81 // last observed request was unsuccessful. | 83 const int kSchedulingBackoffMultiplier = 2; |
82 const int kBlacklistBackoffMultiplier = 2; | |
83 | 84 |
84 // Maximum valid delay for scheduling a request. Candidate delays larger than | 85 // Maximum valid delay for scheduling a request. Candidate delays larger than |
85 // this are rejected. This means the maximum backoff is at least 300 / 2, i.e. | 86 // this are rejected. This means the maximum backoff is at least 5 / 2 minutes. |
86 // 2.5 minutes. | 87 const TimeDelta kSchedulingMaxDelaySec = TimeDelta::FromMinutes(5); |
87 const int kBlacklistMaxDelaySec = 300; // 5 minutes | |
88 | 88 |
89 } // namespace | 89 } // namespace |
90 | 90 |
91 const char kSuggestionsFieldTrialName[] = "ChromeSuggestions"; | 91 const char kSuggestionsFieldTrialName[] = "ChromeSuggestions"; |
92 const char kSuggestionsFieldTrialControlParam[] = "control"; | 92 const char kSuggestionsFieldTrialControlParam[] = "control"; |
93 const char kSuggestionsFieldTrialStateEnabled[] = "enabled"; | 93 const char kSuggestionsFieldTrialStateEnabled[] = "enabled"; |
94 | 94 |
95 // TODO(mathp): Put this in TemplateURL. | 95 // TODO(mathp): Put this in TemplateURL. |
96 const char kSuggestionsURL[] = "https://www.google.com/chromesuggestions?t=2"; | 96 const char kSuggestionsURL[] = "https://www.google.com/chromesuggestions?t=2"; |
97 const char kSuggestionsBlacklistURLPrefix[] = | 97 const char kSuggestionsBlacklistURLPrefix[] = |
98 "https://www.google.com/chromesuggestions/blacklist?t=2&url="; | 98 "https://www.google.com/chromesuggestions/blacklist?t=2&url="; |
99 const char kSuggestionsBlacklistURLParam[] = "url"; | 99 const char kSuggestionsBlacklistURLParam[] = "url"; |
100 | 100 |
101 // The default expiry timeout is 72 hours. | 101 // The default expiry timeout is 72 hours. |
102 const int64 kDefaultExpiryUsec = 72 * base::Time::kMicrosecondsPerHour; | 102 const int64 kDefaultExpiryUsec = 72 * base::Time::kMicrosecondsPerHour; |
103 | 103 |
104 SuggestionsService::SuggestionsService( | 104 SuggestionsService::SuggestionsService( |
105 net::URLRequestContextGetter* url_request_context, | 105 net::URLRequestContextGetter* url_request_context, |
106 scoped_ptr<SuggestionsStore> suggestions_store, | 106 scoped_ptr<SuggestionsStore> suggestions_store, |
107 scoped_ptr<ImageManager> thumbnail_manager, | 107 scoped_ptr<ImageManager> thumbnail_manager, |
108 scoped_ptr<BlacklistStore> blacklist_store) | 108 scoped_ptr<BlacklistStore> blacklist_store) |
109 : url_request_context_(url_request_context), | 109 : url_request_context_(url_request_context), |
110 suggestions_store_(suggestions_store.Pass()), | 110 suggestions_store_(suggestions_store.Pass()), |
111 thumbnail_manager_(thumbnail_manager.Pass()), | 111 thumbnail_manager_(thumbnail_manager.Pass()), |
112 blacklist_store_(blacklist_store.Pass()), | 112 blacklist_store_(blacklist_store.Pass()), |
113 blacklist_delay_sec_(kBlacklistDefaultDelaySec), | 113 scheduling_delay_(kDefaultSchedulingDelay), |
114 suggestions_url_(kSuggestionsURL), | 114 suggestions_url_(kSuggestionsURL), |
115 blacklist_url_prefix_(kSuggestionsBlacklistURLPrefix), | 115 blacklist_url_prefix_(kSuggestionsBlacklistURLPrefix), |
116 weak_ptr_factory_(this) {} | 116 weak_ptr_factory_(this) {} |
117 | 117 |
118 SuggestionsService::~SuggestionsService() {} | 118 SuggestionsService::~SuggestionsService() {} |
119 | 119 |
120 // static | 120 // static |
121 bool SuggestionsService::IsControlGroup() { | 121 bool SuggestionsService::IsControlGroup() { |
122 return GetExperimentParam(kSuggestionsFieldTrialControlParam) == | 122 return GetExperimentParam(kSuggestionsFieldTrialControlParam) == |
123 kSuggestionsFieldTrialStateEnabled; | 123 kSuggestionsFieldTrialStateEnabled; |
(...skipping 23 matching lines...) Expand all Loading... | |
147 } | 147 } |
148 | 148 |
149 void SuggestionsService::GetPageThumbnail( | 149 void SuggestionsService::GetPageThumbnail( |
150 const GURL& url, | 150 const GURL& url, |
151 base::Callback<void(const GURL&, const SkBitmap*)> callback) { | 151 base::Callback<void(const GURL&, const SkBitmap*)> callback) { |
152 thumbnail_manager_->GetImageForURL(url, callback); | 152 thumbnail_manager_->GetImageForURL(url, callback); |
153 } | 153 } |
154 | 154 |
155 void SuggestionsService::BlacklistURL( | 155 void SuggestionsService::BlacklistURL( |
156 const GURL& candidate_url, | 156 const GURL& candidate_url, |
157 const SuggestionsService::ResponseCallback& callback) { | 157 const SuggestionsService::ResponseCallback& callback, |
158 const base::Closure& fail_callback) { | |
158 DCHECK(thread_checker_.CalledOnValidThread()); | 159 DCHECK(thread_checker_.CalledOnValidThread()); |
160 | |
161 if (!blacklist_store_->BlacklistUrl(candidate_url)) { | |
162 fail_callback.Run(); | |
163 return; | |
164 } | |
165 | |
159 waiting_requestors_.push_back(callback); | 166 waiting_requestors_.push_back(callback); |
167 ServeFromCache(); | |
168 if (!pending_request_.get()) { | |
Mathieu
2014/12/04 18:53:33
put comment above here, mentioning why we only sch
manzagop (departed)
2014/12/05 15:13:22
Done.
| |
169 ScheduleBlacklistUpload(); | |
170 } | |
171 } | |
160 | 172 |
161 // Blacklist locally for immediate effect and serve the requestors. | 173 void SuggestionsService::UndoBlacklistURL( |
162 blacklist_store_->BlacklistUrl(candidate_url); | 174 const GURL& url, |
163 ServeFromCache(); | 175 const SuggestionsService::ResponseCallback& callback, |
164 | 176 const base::Closure& fail_callback) { |
165 // Send blacklisting request. Even if this request ends up not being sent | 177 DCHECK(thread_checker_.CalledOnValidThread()); |
166 // because of an ongoing request, a blacklist request is later scheduled. | 178 TimeDelta time_delta; |
167 // TODO(mathp): Currently, this will not send a request if there is already | 179 if (blacklist_store_->GetTimeUntilReadyForUpload(url, &time_delta) && |
168 // a request in flight (for suggestions or blacklist). Should we prioritize | 180 time_delta > TimeDelta::FromSeconds(0) && |
169 // blacklist requests since they actually carry a payload? | 181 blacklist_store_->RemoveUrl(url)) { |
170 IssueRequestIfNoneOngoing( | 182 // The URL was in the blacklist without being ready for upload and was |
Mathieu
2014/12/04 18:53:32
// The URL was not yet uploaded to the server and
manzagop (departed)
2014/12/05 15:13:22
Changed it, though not quite to what you propose b
| |
171 BuildBlacklistRequestURL(blacklist_url_prefix_, candidate_url)); | 183 // successfully removed. |
184 waiting_requestors_.push_back(callback); | |
185 ServeFromCache(); | |
186 return; | |
187 } | |
188 fail_callback.Run(); | |
172 } | 189 } |
173 | 190 |
174 // static | 191 // static |
175 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request, | 192 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request, |
176 GURL* url) { | 193 GURL* url) { |
177 bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(), | 194 bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(), |
178 kSuggestionsBlacklistURLPrefix, | 195 kSuggestionsBlacklistURLPrefix, |
179 true); | 196 true); |
180 if (!is_blacklist_request) return false; | 197 if (!is_blacklist_request) return false; |
181 | 198 |
(...skipping 30 matching lines...) Expand all Loading... | |
212 } | 229 } |
213 } | 230 } |
214 | 231 |
215 void SuggestionsService::IssueRequestIfNoneOngoing(const GURL& url) { | 232 void SuggestionsService::IssueRequestIfNoneOngoing(const GURL& url) { |
216 // If there is an ongoing request, let it complete. | 233 // If there is an ongoing request, let it complete. |
217 if (pending_request_.get()) { | 234 if (pending_request_.get()) { |
218 return; | 235 return; |
219 } | 236 } |
220 pending_request_.reset(CreateSuggestionsRequest(url)); | 237 pending_request_.reset(CreateSuggestionsRequest(url)); |
221 pending_request_->Start(); | 238 pending_request_->Start(); |
222 last_request_started_time_ = base::TimeTicks::Now(); | 239 last_request_started_time_ = TimeTicks::Now(); |
223 } | 240 } |
224 | 241 |
225 net::URLFetcher* SuggestionsService::CreateSuggestionsRequest(const GURL& url) { | 242 net::URLFetcher* SuggestionsService::CreateSuggestionsRequest(const GURL& url) { |
226 net::URLFetcher* request = | 243 net::URLFetcher* request = |
227 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this); | 244 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this); |
228 request->SetLoadFlags(net::LOAD_DISABLE_CACHE); | 245 request->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
229 request->SetRequestContext(url_request_context_); | 246 request->SetRequestContext(url_request_context_); |
230 // Add Chrome experiment state to the request headers. | 247 // Add Chrome experiment state to the request headers. |
231 net::HttpRequestHeaders headers; | 248 net::HttpRequestHeaders headers; |
232 variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( | 249 variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( |
(...skipping 11 matching lines...) Expand all Loading... | |
244 | 261 |
245 const net::URLRequestStatus& request_status = request->GetStatus(); | 262 const net::URLRequestStatus& request_status = request->GetStatus(); |
246 if (request_status.status() != net::URLRequestStatus::SUCCESS) { | 263 if (request_status.status() != net::URLRequestStatus::SUCCESS) { |
247 // This represents network errors (i.e. the server did not provide a | 264 // This represents network errors (i.e. the server did not provide a |
248 // response). | 265 // response). |
249 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode", | 266 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode", |
250 -request_status.error()); | 267 -request_status.error()); |
251 DVLOG(1) << "Suggestions server request failed with error: " | 268 DVLOG(1) << "Suggestions server request failed with error: " |
252 << request_status.error() << ": " | 269 << request_status.error() << ": " |
253 << net::ErrorToString(request_status.error()); | 270 << net::ErrorToString(request_status.error()); |
254 ScheduleBlacklistUpload(false); | 271 UpdateBlacklistDelay(false); |
272 ScheduleBlacklistUpload(); | |
255 return; | 273 return; |
256 } | 274 } |
257 | 275 |
258 const int response_code = request->GetResponseCode(); | 276 const int response_code = request->GetResponseCode(); |
259 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode", response_code); | 277 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode", response_code); |
260 if (response_code != net::HTTP_OK) { | 278 if (response_code != net::HTTP_OK) { |
261 // A non-200 response code means that server has no (longer) suggestions for | 279 // A non-200 response code means that server has no (longer) suggestions for |
262 // this user. Aggressively clear the cache. | 280 // this user. Aggressively clear the cache. |
263 suggestions_store_->ClearSuggestions(); | 281 suggestions_store_->ClearSuggestions(); |
264 ScheduleBlacklistUpload(false); | 282 UpdateBlacklistDelay(false); |
283 ScheduleBlacklistUpload(); | |
265 return; | 284 return; |
266 } | 285 } |
267 | 286 |
268 const base::TimeDelta latency = | 287 const TimeDelta latency = TimeTicks::Now() - last_request_started_time_; |
269 base::TimeTicks::Now() - last_request_started_time_; | |
270 UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency); | 288 UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency); |
271 | 289 |
272 // Handle a successful blacklisting. | 290 // Handle a successful blacklisting. |
273 GURL blacklisted_url; | 291 GURL blacklisted_url; |
274 if (GetBlacklistedUrl(*source, &blacklisted_url)) { | 292 if (GetBlacklistedUrl(*source, &blacklisted_url)) { |
275 blacklist_store_->RemoveUrl(blacklisted_url); | 293 blacklist_store_->RemoveUrl(blacklisted_url); |
276 } | 294 } |
277 | 295 |
278 std::string suggestions_data; | 296 std::string suggestions_data; |
279 bool success = request->GetResponseAsString(&suggestions_data); | 297 bool success = request->GetResponseAsString(&suggestions_data); |
280 DCHECK(success); | 298 DCHECK(success); |
281 | 299 |
282 // Parse the received suggestions and update the cache, or take proper action | 300 // Parse the received suggestions and update the cache, or take proper action |
283 // in the case of invalid response. | 301 // in the case of invalid response. |
284 SuggestionsProfile suggestions; | 302 SuggestionsProfile suggestions; |
285 if (suggestions_data.empty()) { | 303 if (suggestions_data.empty()) { |
286 LogResponseState(RESPONSE_EMPTY); | 304 LogResponseState(RESPONSE_EMPTY); |
287 suggestions_store_->ClearSuggestions(); | 305 suggestions_store_->ClearSuggestions(); |
288 } else if (suggestions.ParseFromString(suggestions_data)) { | 306 } else if (suggestions.ParseFromString(suggestions_data)) { |
289 LogResponseState(RESPONSE_VALID); | 307 LogResponseState(RESPONSE_VALID); |
290 int64 now_usec = (base::Time::NowFromSystemTime() - base::Time::UnixEpoch()) | 308 int64 now_usec = (base::Time::NowFromSystemTime() - base::Time::UnixEpoch()) |
291 .ToInternalValue(); | 309 .ToInternalValue(); |
292 SetDefaultExpiryTimestamp(&suggestions, now_usec + kDefaultExpiryUsec); | 310 SetDefaultExpiryTimestamp(&suggestions, now_usec + kDefaultExpiryUsec); |
293 suggestions_store_->StoreSuggestions(suggestions); | 311 suggestions_store_->StoreSuggestions(suggestions); |
294 } else { | 312 } else { |
295 LogResponseState(RESPONSE_INVALID); | 313 LogResponseState(RESPONSE_INVALID); |
296 } | 314 } |
297 | 315 |
298 ScheduleBlacklistUpload(true); | 316 UpdateBlacklistDelay(true); |
317 ScheduleBlacklistUpload(); | |
299 } | 318 } |
300 | 319 |
301 void SuggestionsService::Shutdown() { | 320 void SuggestionsService::Shutdown() { |
302 // Cancel pending request, then serve existing requestors from cache. | 321 // Cancel pending request, then serve existing requestors from cache. |
303 pending_request_.reset(NULL); | 322 pending_request_.reset(NULL); |
304 ServeFromCache(); | 323 ServeFromCache(); |
305 } | 324 } |
306 | 325 |
307 void SuggestionsService::ServeFromCache() { | 326 void SuggestionsService::ServeFromCache() { |
308 SuggestionsProfile suggestions; | 327 SuggestionsProfile suggestions; |
309 // In case of empty cache or error, |suggestions| stays empty. | 328 // In case of empty cache or error, |suggestions| stays empty. |
310 suggestions_store_->LoadSuggestions(&suggestions); | 329 suggestions_store_->LoadSuggestions(&suggestions); |
311 thumbnail_manager_->Initialize(suggestions); | 330 thumbnail_manager_->Initialize(suggestions); |
312 FilterAndServe(&suggestions); | 331 FilterAndServe(&suggestions); |
313 } | 332 } |
314 | 333 |
315 void SuggestionsService::FilterAndServe(SuggestionsProfile* suggestions) { | 334 void SuggestionsService::FilterAndServe(SuggestionsProfile* suggestions) { |
316 blacklist_store_->FilterSuggestions(suggestions); | 335 blacklist_store_->FilterSuggestions(suggestions); |
317 DispatchRequestsAndClear(*suggestions, &waiting_requestors_); | 336 DispatchRequestsAndClear(*suggestions, &waiting_requestors_); |
318 } | 337 } |
319 | 338 |
320 void SuggestionsService::ScheduleBlacklistUpload(bool last_request_successful) { | 339 void SuggestionsService::ScheduleBlacklistUpload() { |
321 DCHECK(thread_checker_.CalledOnValidThread()); | 340 DCHECK(thread_checker_.CalledOnValidThread()); |
322 | 341 TimeDelta time_delta; |
323 UpdateBlacklistDelay(last_request_successful); | 342 if (blacklist_store_->GetTimeUntilReadyForUpload(&time_delta)) { |
324 | 343 // Blacklist cache is not empty: schedule. |
325 // Schedule a blacklist upload task. | |
326 GURL blacklist_url; | |
327 if (blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) { | |
328 base::Closure blacklist_cb = | 344 base::Closure blacklist_cb = |
329 base::Bind(&SuggestionsService::UploadOneFromBlacklist, | 345 base::Bind(&SuggestionsService::UploadOneFromBlacklist, |
330 weak_ptr_factory_.GetWeakPtr()); | 346 weak_ptr_factory_.GetWeakPtr()); |
331 base::MessageLoopProxy::current()->PostDelayedTask( | 347 base::MessageLoopProxy::current()->PostDelayedTask( |
332 FROM_HERE, blacklist_cb, | 348 FROM_HERE, blacklist_cb, time_delta + scheduling_delay_); |
333 base::TimeDelta::FromSeconds(blacklist_delay_sec_)); | |
334 } | 349 } |
335 } | 350 } |
336 | 351 |
337 void SuggestionsService::UploadOneFromBlacklist() { | 352 void SuggestionsService::UploadOneFromBlacklist() { |
338 DCHECK(thread_checker_.CalledOnValidThread()); | 353 DCHECK(thread_checker_.CalledOnValidThread()); |
339 | 354 |
340 GURL blacklist_url; | 355 GURL blacklist_url; |
341 if (!blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) | 356 if (blacklist_store_->GetCandidateForUpload(&blacklist_url)) { |
342 return; // Local blacklist is empty. | 357 // Issue a blacklisting request. Even if this request ends up not being sent |
358 // because of an ongoing request, a blacklist request is later scheduled. | |
359 IssueRequestIfNoneOngoing( | |
360 BuildBlacklistRequestURL(blacklist_url_prefix_, blacklist_url)); | |
361 return; | |
362 } | |
343 | 363 |
344 // Send blacklisting request. Even if this request ends up not being sent | 364 // Even though there's no candidate for upload, the blacklist might not be |
345 // because of an ongoing request, a blacklist request is later scheduled. | 365 // empty. |
346 IssueRequestIfNoneOngoing( | 366 ScheduleBlacklistUpload(); |
347 BuildBlacklistRequestURL(blacklist_url_prefix_, blacklist_url)); | |
348 } | 367 } |
349 | 368 |
350 void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) { | 369 void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) { |
351 DCHECK(thread_checker_.CalledOnValidThread()); | 370 DCHECK(thread_checker_.CalledOnValidThread()); |
352 | 371 |
353 if (last_request_successful) { | 372 if (last_request_successful) { |
354 blacklist_delay_sec_ = kBlacklistDefaultDelaySec; | 373 scheduling_delay_ = kDefaultSchedulingDelay; |
355 } else { | 374 } else { |
356 int candidate_delay = blacklist_delay_sec_ * kBlacklistBackoffMultiplier; | 375 TimeDelta candidate_delay = |
357 if (candidate_delay < kBlacklistMaxDelaySec) | 376 scheduling_delay_ * kSchedulingBackoffMultiplier; |
358 blacklist_delay_sec_ = candidate_delay; | 377 if (candidate_delay < kSchedulingMaxDelaySec) |
378 scheduling_delay_ = candidate_delay; | |
359 } | 379 } |
360 } | 380 } |
361 | 381 |
362 } // namespace suggestions | 382 } // namespace suggestions |
OLD | NEW |