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

Side by Side Diff: chrome/browser/budget_service/budget_database.cc

Issue 2620393002: Refactor budget computation to be more tuneable. (Closed)
Patch Set: Changed LayoutTest to expect integral budgets. (Also rebased) Created 3 years, 11 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 | « no previous file | chrome/browser/budget_service/budget_database_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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "chrome/browser/budget_service/budget_database.h" 5 #include "chrome/browser/budget_service/budget_database.h"
6 6
7 #include "base/memory/ptr_util.h" 7 #include "base/memory/ptr_util.h"
8 #include "base/metrics/histogram_macros.h" 8 #include "base/metrics/histogram_macros.h"
9 #include "base/time/clock.h" 9 #include "base/time/clock.h"
10 #include "base/time/default_clock.h" 10 #include "base/time/default_clock.h"
11 #include "chrome/browser/budget_service/budget.pb.h" 11 #include "chrome/browser/budget_service/budget.pb.h"
12 #include "chrome/browser/engagement/site_engagement_score.h" 12 #include "chrome/browser/engagement/site_engagement_score.h"
13 #include "chrome/browser/engagement/site_engagement_service.h" 13 #include "chrome/browser/engagement/site_engagement_service.h"
14 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
15 #include "components/leveldb_proto/proto_database_impl.h" 15 #include "components/leveldb_proto/proto_database_impl.h"
16 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/browser_thread.h"
17 #include "url/gurl.h" 17 #include "url/gurl.h"
18 #include "url/origin.h" 18 #include "url/origin.h"
19 19
20 using content::BrowserThread; 20 using content::BrowserThread;
21 21
22 namespace { 22 namespace {
23 23
24 // UMA are logged for the database with this string as part of the name. 24 // UMA are logged for the database with this string as part of the name.
25 // They will be LevelDB.*.BudgetManager. Changes here should be synchronized 25 // They will be LevelDB.*.BudgetManager. Changes here should be synchronized
26 // with histograms.xml. 26 // with histograms.xml.
27 const char kDatabaseUMAName[] = "BudgetManager"; 27 const char kDatabaseUMAName[] = "BudgetManager";
28 28
29 // The default amount of time during which a budget will be valid. 29 // The default amount of time during which a budget will be valid.
30 // This is 4 days = 96 hours. 30 constexpr int kBudgetDurationInDays = 4;
31 constexpr double kBudgetDurationInHours = 96; 31
32 // The amount of budget that a maximally engaged site should receive per hour.
33 // For context, silent push messages cost 2 each, so this allows 6 silent push
34 // messages a day for a fully engaged site. See budget_manager.cc for costs of
35 // various actions.
36 constexpr double kMaximumHourlyBudget = 12.0 / 24.0;
32 37
33 } // namespace 38 } // namespace
34 39
35 BudgetDatabase::BudgetInfo::BudgetInfo() {} 40 BudgetDatabase::BudgetInfo::BudgetInfo() {}
36 41
37 BudgetDatabase::BudgetInfo::BudgetInfo(const BudgetInfo&& other) 42 BudgetDatabase::BudgetInfo::BudgetInfo(const BudgetInfo&& other)
38 : last_engagement_award(other.last_engagement_award) { 43 : last_engagement_award(other.last_engagement_award) {
39 chunks = std::move(other.chunks); 44 chunks = std::move(other.chunks);
40 } 45 }
41 46
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 // expiration times going forward. 162 // expiration times going forward.
158 const BudgetChunks& chunks = budget_map_[origin].chunks; 163 const BudgetChunks& chunks = budget_map_[origin].chunks;
159 for (const auto& chunk : chunks) { 164 for (const auto& chunk : chunks) {
160 blink::mojom::BudgetStatePtr prediction(blink::mojom::BudgetState::New()); 165 blink::mojom::BudgetStatePtr prediction(blink::mojom::BudgetState::New());
161 total -= chunk.amount; 166 total -= chunk.amount;
162 prediction->budget_at = total; 167 prediction->budget_at = total;
163 prediction->time = chunk.expiration.ToDoubleT(); 168 prediction->time = chunk.expiration.ToDoubleT();
164 predictions.push_back(std::move(prediction)); 169 predictions.push_back(std::move(prediction));
165 } 170 }
166 171
167 DCHECK_EQ(0, total);
168
169 callback.Run(blink::mojom::BudgetServiceErrorType::NONE, 172 callback.Run(blink::mojom::BudgetServiceErrorType::NONE,
170 std::move(predictions)); 173 std::move(predictions));
171 } 174 }
172 175
173 void BudgetDatabase::SpendBudgetAfterSync(const url::Origin& origin, 176 void BudgetDatabase::SpendBudgetAfterSync(const url::Origin& origin,
174 double amount, 177 double amount,
175 const SpendBudgetCallback& callback, 178 const SpendBudgetCallback& callback,
176 bool success) { 179 bool success) {
177 if (!success) { 180 if (!success) {
178 callback.Run(blink::mojom::BudgetServiceErrorType::DATABASE_ERROR, 181 callback.Run(blink::mojom::BudgetServiceErrorType::DATABASE_ERROR,
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 // Get the SES score and add engagement budget for the site. 300 // Get the SES score and add engagement budget for the site.
298 AddEngagementBudget(origin); 301 AddEngagementBudget(origin);
299 302
300 if (needs_write) 303 if (needs_write)
301 WriteCachedValuesToDatabase(origin, callback); 304 WriteCachedValuesToDatabase(origin, callback);
302 else 305 else
303 callback.Run(success); 306 callback.Run(success);
304 } 307 }
305 308
306 void BudgetDatabase::AddEngagementBudget(const url::Origin& origin) { 309 void BudgetDatabase::AddEngagementBudget(const url::Origin& origin) {
307 // Get the current SES score, which we'll use to set a new budget. 310 // Calculate how much budget should be awarded. The award depends on the
311 // time elapsed since the last award and the SES score.
312 // By default, give the origin kBudgetDurationInDays worth of budget, but
313 // reduce that if budget has already been given during that period.
314 base::TimeDelta elapsed = base::TimeDelta::FromDays(kBudgetDurationInDays);
315 if (IsCached(origin)) {
316 elapsed = clock_->Now() - budget_map_[origin].last_engagement_award;
317 // Don't give engagement awards for periods less than an hour.
318 if (elapsed.InHours() < 1)
319 return;
320 // Cap elapsed time to the budget duration.
321 if (elapsed.InDays() > kBudgetDurationInDays)
322 elapsed = base::TimeDelta::FromDays(kBudgetDurationInDays);
323 }
324
325 // Get the current SES score, and calculate the hourly budget for that score.
308 SiteEngagementService* service = SiteEngagementService::Get(profile_); 326 SiteEngagementService* service = SiteEngagementService::Get(profile_);
309 double score = service->GetScore(origin.GetURL()); 327 double hourly_budget = kMaximumHourlyBudget *
310 328 service->GetScore(origin.GetURL()) /
311 // By default we award the "full" award. Then that ratio is decreased if 329 service->GetMaxPoints();
312 // there have been other awards recently.
313 double ratio = 1.0;
314
315 // Calculate how much budget should be awarded. If there is no entry in the
316 // cache then we award a full amount.
317 if (IsCached(origin)) {
318 base::TimeDelta elapsed =
319 clock_->Now() - budget_map_[origin].last_engagement_award;
320 int elapsed_hours = elapsed.InHours();
321 // Don't give engagement awards for periods less than an hour.
322 if (elapsed_hours < 1)
323 return;
324 if (elapsed_hours < kBudgetDurationInHours)
325 ratio = elapsed_hours / kBudgetDurationInHours;
326 }
327 330
328 // Update the last_engagement_award to the current time. If the origin wasn't 331 // Update the last_engagement_award to the current time. If the origin wasn't
329 // already in the map, this adds a new entry for it. 332 // already in the map, this adds a new entry for it.
330 budget_map_[origin].last_engagement_award = clock_->Now(); 333 budget_map_[origin].last_engagement_award = clock_->Now();
331 334
332 // Add a new chunk of budget for the origin at the default expiration time. 335 // Add a new chunk of budget for the origin at the default expiration time.
333 base::Time expiration = 336 base::Time expiration =
334 clock_->Now() + base::TimeDelta::FromHours(kBudgetDurationInHours); 337 clock_->Now() + base::TimeDelta::FromDays(kBudgetDurationInDays);
335 budget_map_[origin].chunks.emplace_back(ratio * score, expiration); 338 budget_map_[origin].chunks.emplace_back(elapsed.InHours() * hourly_budget,
339 expiration);
336 340
337 // Any time we award engagement budget, which is done at most once an hour 341 // Any time we award engagement budget, which is done at most once an hour
338 // whenever any budget action is taken, record the budget. 342 // whenever any budget action is taken, record the budget.
339 double budget = GetBudget(origin); 343 double budget = GetBudget(origin);
340 UMA_HISTOGRAM_COUNTS_100("PushMessaging.BackgroundBudget", budget); 344 UMA_HISTOGRAM_COUNTS_100("PushMessaging.BackgroundBudget", budget);
341 } 345 }
342 346
343 // Cleans up budget in the cache. Relies on the caller eventually writing the 347 // Cleans up budget in the cache. Relies on the caller eventually writing the
344 // cache back to the database. 348 // cache back to the database.
345 bool BudgetDatabase::CleanupExpiredBudget(const url::Origin& origin) { 349 bool BudgetDatabase::CleanupExpiredBudget(const url::Origin& origin) {
346 if (!IsCached(origin)) 350 if (!IsCached(origin))
347 return false; 351 return false;
348 352
349 base::Time now = clock_->Now(); 353 base::Time now = clock_->Now();
350 BudgetChunks& chunks = budget_map_[origin].chunks; 354 BudgetChunks& chunks = budget_map_[origin].chunks;
351 auto cleanup_iter = chunks.begin(); 355 auto cleanup_iter = chunks.begin();
352 356
353 // This relies on the list of chunks being in timestamp order. 357 // This relies on the list of chunks being in timestamp order.
354 while (cleanup_iter != chunks.end() && cleanup_iter->expiration <= now) 358 while (cleanup_iter != chunks.end() && cleanup_iter->expiration <= now)
355 cleanup_iter = chunks.erase(cleanup_iter); 359 cleanup_iter = chunks.erase(cleanup_iter);
356 360
357 // If the entire budget is empty now AND there have been no engagements 361 // If the entire budget is empty now AND there have been no engagements
358 // in the last kBudgetDurationInHours hours, remove this from the cache. 362 // in the last kBudgetDurationInDays days, remove this from the cache.
359 if (chunks.empty() && 363 if (chunks.empty() &&
360 budget_map_[origin].last_engagement_award < 364 budget_map_[origin].last_engagement_award <
361 clock_->Now() - base::TimeDelta::FromHours(kBudgetDurationInHours)) { 365 clock_->Now() - base::TimeDelta::FromDays(kBudgetDurationInDays)) {
362 budget_map_.erase(origin); 366 budget_map_.erase(origin);
363 return true; 367 return true;
364 } 368 }
365 369
366 // Although some things may have expired, there are some chunks still valid. 370 // Although some things may have expired, there are some chunks still valid.
367 // Don't write to the DB now, write either when all chunks expire or when the 371 // Don't write to the DB now, write either when all chunks expire or when the
368 // origin spends some budget. 372 // origin spends some budget.
369 return false; 373 return false;
370 } 374 }
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/budget_service/budget_database_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698