OLD | NEW |
---|---|
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/metrics/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
8 #include "base/time/clock.h" | 8 #include "base/time/clock.h" |
9 #include "base/time/default_clock.h" | 9 #include "base/time/default_clock.h" |
10 #include "chrome/browser/budget_service/budget.pb.h" | 10 #include "chrome/browser/budget_service/budget.pb.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
59 const GetBudgetCallback& callback) { | 59 const GetBudgetCallback& callback) { |
60 DCHECK_EQ(origin.GetOrigin(), origin); | 60 DCHECK_EQ(origin.GetOrigin(), origin); |
61 | 61 |
62 SyncCache(origin, | 62 SyncCache(origin, |
63 base::Bind(&BudgetDatabase::GetBudgetAfterSync, | 63 base::Bind(&BudgetDatabase::GetBudgetAfterSync, |
64 weak_ptr_factory_.GetWeakPtr(), origin, callback)); | 64 weak_ptr_factory_.GetWeakPtr(), origin, callback)); |
65 } | 65 } |
66 | 66 |
67 void BudgetDatabase::SpendBudget(const GURL& origin, | 67 void BudgetDatabase::SpendBudget(const GURL& origin, |
68 double amount, | 68 double amount, |
69 const StoreBudgetCallback& callback) { | 69 const SpendBudgetCallback& callback) { |
70 SyncCache(origin, base::Bind(&BudgetDatabase::SpendBudgetAfterSync, | 70 SyncCache(origin, base::Bind(&BudgetDatabase::SpendBudgetAfterSync, |
71 weak_ptr_factory_.GetWeakPtr(), origin, amount, | 71 weak_ptr_factory_.GetWeakPtr(), origin, amount, |
72 callback)); | 72 callback)); |
73 } | 73 } |
74 | 74 |
75 void BudgetDatabase::SetClockForTesting(std::unique_ptr<base::Clock> clock) { | 75 void BudgetDatabase::SetClockForTesting(std::unique_ptr<base::Clock> clock) { |
76 clock_ = std::move(clock); | 76 clock_ = std::move(clock); |
77 } | 77 } |
78 | 78 |
79 void BudgetDatabase::OnDatabaseInit(bool success) { | 79 void BudgetDatabase::OnDatabaseInit(bool success) { |
(...skipping 11 matching lines...) Expand all Loading... | |
91 return total; | 91 return total; |
92 | 92 |
93 const BudgetInfo& info = iter->second; | 93 const BudgetInfo& info = iter->second; |
94 for (const BudgetChunk& chunk : info.chunks) | 94 for (const BudgetChunk& chunk : info.chunks) |
95 total += chunk.amount; | 95 total += chunk.amount; |
96 return total; | 96 return total; |
97 } | 97 } |
98 | 98 |
99 void BudgetDatabase::AddToCache( | 99 void BudgetDatabase::AddToCache( |
100 const GURL& origin, | 100 const GURL& origin, |
101 const AddToCacheCallback& callback, | 101 const CacheCallback& callback, |
102 bool success, | 102 bool success, |
103 std::unique_ptr<budget_service::Budget> budget_proto) { | 103 std::unique_ptr<budget_service::Budget> budget_proto) { |
104 // If the database read failed, there's nothing to add to the cache. | 104 // If the database read failed, or there's nothing to add to the cache. |
Peter Beverloo
2016/09/08 17:16:06
nit: This sentence feels incomplete now?
harkness
2016/09/13 13:41:28
Done.
| |
105 if (!success || !budget_proto) { | 105 if (!success || !budget_proto) { |
106 callback.Run(success); | 106 callback.Run(success); |
107 return; | 107 return; |
108 } | 108 } |
109 | 109 |
110 // If there were two simultaneous loads, don't overwrite the cache value, | 110 // If there were two simultaneous loads, don't overwrite the cache value, |
111 // which might have been updated after the previous load. | 111 // which might have been updated after the previous load. |
112 if (IsCached(origin)) { | 112 if (IsCached(origin)) { |
113 callback.Run(success); | 113 callback.Run(success); |
114 return; | 114 return; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
165 } | 165 } |
166 | 166 |
167 DCHECK_EQ(0, total); | 167 DCHECK_EQ(0, total); |
168 | 168 |
169 callback.Run(blink::mojom::BudgetServiceErrorType::NONE, | 169 callback.Run(blink::mojom::BudgetServiceErrorType::NONE, |
170 std::move(predictions)); | 170 std::move(predictions)); |
171 } | 171 } |
172 | 172 |
173 void BudgetDatabase::SpendBudgetAfterSync(const GURL& origin, | 173 void BudgetDatabase::SpendBudgetAfterSync(const GURL& origin, |
174 double amount, | 174 double amount, |
175 const StoreBudgetCallback& callback, | 175 const SpendBudgetCallback& callback, |
176 bool success) { | 176 bool success) { |
177 if (!success) { | 177 if (!success) { |
178 callback.Run(false /* success */); | 178 callback.Run(blink::mojom::BudgetServiceErrorType::DATABASE_ERROR, |
179 false /* success */); | |
179 return; | 180 return; |
180 } | 181 } |
181 | 182 |
182 // Get the current SES score, to generate UMA. | 183 // Get the current SES score, to generate UMA. |
183 SiteEngagementService* service = SiteEngagementService::Get(profile_); | 184 SiteEngagementService* service = SiteEngagementService::Get(profile_); |
184 double score = service->GetScore(origin); | 185 double score = service->GetScore(origin); |
185 | 186 |
186 // Walk the list of budget chunks to see if the origin has enough budget. | 187 // Walk the list of budget chunks to see if the origin has enough budget. |
187 double total = 0; | 188 double total = 0; |
188 BudgetInfo& info = budget_map_[origin.spec()]; | 189 BudgetInfo& info = budget_map_[origin.spec()]; |
189 for (const BudgetChunk& chunk : info.chunks) | 190 for (const BudgetChunk& chunk : info.chunks) |
190 total += chunk.amount; | 191 total += chunk.amount; |
191 | 192 |
192 if (total < amount) { | 193 if (total < amount) { |
193 UMA_HISTOGRAM_COUNTS_100("PushMessaging.SESForNoBudgetOrigin", score); | 194 UMA_HISTOGRAM_COUNTS_100("PushMessaging.SESForNoBudgetOrigin", score); |
194 callback.Run(false /* success */); | 195 callback.Run(blink::mojom::BudgetServiceErrorType::NONE, |
196 false /* success */); | |
195 return; | 197 return; |
196 } else if (total < amount * 2) { | 198 } else if (total < amount * 2) { |
197 UMA_HISTOGRAM_COUNTS_100("PushMessaging.SESForLowBudgetOrigin", score); | 199 UMA_HISTOGRAM_COUNTS_100("PushMessaging.SESForLowBudgetOrigin", score); |
198 } | 200 } |
199 | 201 |
200 // Walk the chunks and remove enough budget to cover the needed amount. | 202 // Walk the chunks and remove enough budget to cover the needed amount. |
201 double bill = amount; | 203 double bill = amount; |
202 for (auto iter = info.chunks.begin(); iter != info.chunks.end();) { | 204 for (auto iter = info.chunks.begin(); iter != info.chunks.end();) { |
203 if (iter->amount > bill) { | 205 if (iter->amount > bill) { |
204 iter->amount -= bill; | 206 iter->amount -= bill; |
205 bill = 0; | 207 bill = 0; |
206 break; | 208 break; |
207 } | 209 } |
208 bill -= iter->amount; | 210 bill -= iter->amount; |
209 iter = info.chunks.erase(iter); | 211 iter = info.chunks.erase(iter); |
210 } | 212 } |
211 | 213 |
212 // There should have been enough budget to cover the entire bill. | 214 // There should have been enough budget to cover the entire bill. |
213 DCHECK_EQ(0, bill); | 215 DCHECK_EQ(0, bill); |
214 | 216 |
215 // Now that the cache is updated, write the data to the database. | 217 // Now that the cache is updated, write the data to the database. |
216 // TODO(harkness): Consider adding a second parameter to the callback so the | 218 WriteCachedValuesToDatabase( |
217 // caller can distinguish between not enough budget and a failed database | 219 origin, base::Bind(&BudgetDatabase::SpendBudgetAfterWrite, |
218 // write. | 220 weak_ptr_factory_.GetWeakPtr(), callback)); |
221 } | |
222 | |
223 // This converts the bool value which is returned from the database to a Mojo | |
224 // error type. | |
225 void BudgetDatabase::SpendBudgetAfterWrite(const SpendBudgetCallback& callback, | |
226 bool write_successful) { | |
219 // TODO(harkness): If the database write fails, the cache will be out of sync | 227 // TODO(harkness): If the database write fails, the cache will be out of sync |
220 // with the database. Consider ways to mitigate this. | 228 // with the database. Consider ways to mitigate this. |
221 WriteCachedValuesToDatabase(origin, callback); | 229 if (!write_successful) { |
230 callback.Run(blink::mojom::BudgetServiceErrorType::DATABASE_ERROR, | |
231 false /* success */); | |
232 return; | |
233 } | |
234 callback.Run(blink::mojom::BudgetServiceErrorType::NONE, true /* success */); | |
222 } | 235 } |
223 | 236 |
224 void BudgetDatabase::WriteCachedValuesToDatabase( | 237 void BudgetDatabase::WriteCachedValuesToDatabase( |
225 const GURL& origin, | 238 const GURL& origin, |
226 const StoreBudgetCallback& callback) { | 239 const StoreBudgetCallback& callback) { |
227 // Create the data structures that are passed to the ProtoDatabase. | 240 // Create the data structures that are passed to the ProtoDatabase. |
228 std::unique_ptr< | 241 std::unique_ptr< |
229 leveldb_proto::ProtoDatabase<budget_service::Budget>::KeyEntryVector> | 242 leveldb_proto::ProtoDatabase<budget_service::Budget>::KeyEntryVector> |
230 entries(new leveldb_proto::ProtoDatabase< | 243 entries(new leveldb_proto::ProtoDatabase< |
231 budget_service::Budget>::KeyEntryVector()); | 244 budget_service::Budget>::KeyEntryVector()); |
(...skipping 17 matching lines...) Expand all Loading... | |
249 } else { | 262 } else { |
250 // If the origin doesn't exist in the cache, this is a remove operation. | 263 // If the origin doesn't exist in the cache, this is a remove operation. |
251 keys_to_remove->push_back(origin.spec()); | 264 keys_to_remove->push_back(origin.spec()); |
252 } | 265 } |
253 | 266 |
254 // Send the updates to the database. | 267 // Send the updates to the database. |
255 db_->UpdateEntries(std::move(entries), std::move(keys_to_remove), callback); | 268 db_->UpdateEntries(std::move(entries), std::move(keys_to_remove), callback); |
256 } | 269 } |
257 | 270 |
258 void BudgetDatabase::SyncCache(const GURL& origin, | 271 void BudgetDatabase::SyncCache(const GURL& origin, |
259 const SyncCacheCallback& callback) { | 272 const CacheCallback& callback) { |
260 DCHECK_EQ(origin, origin.GetOrigin()); | 273 DCHECK_EQ(origin, origin.GetOrigin()); |
261 | 274 |
262 // If the origin isn't already cached, add it to the cache. | 275 // If the origin isn't already cached, add it to the cache. |
263 if (!IsCached(origin)) { | 276 if (!IsCached(origin)) { |
264 AddToCacheCallback add_callback = | 277 CacheCallback add_callback = |
265 base::Bind(&BudgetDatabase::SyncLoadedCache, | 278 base::Bind(&BudgetDatabase::SyncLoadedCache, |
266 weak_ptr_factory_.GetWeakPtr(), origin, callback); | 279 weak_ptr_factory_.GetWeakPtr(), origin, callback); |
267 db_->GetEntry(origin.spec(), base::Bind(&BudgetDatabase::AddToCache, | 280 db_->GetEntry(origin.spec(), base::Bind(&BudgetDatabase::AddToCache, |
268 weak_ptr_factory_.GetWeakPtr(), | 281 weak_ptr_factory_.GetWeakPtr(), |
269 origin, add_callback)); | 282 origin, add_callback)); |
270 return; | 283 return; |
271 } | 284 } |
272 SyncLoadedCache(origin, callback, true /* success */); | 285 SyncLoadedCache(origin, callback, true /* success */); |
273 } | 286 } |
274 | 287 |
275 void BudgetDatabase::SyncLoadedCache(const GURL& origin, | 288 void BudgetDatabase::SyncLoadedCache(const GURL& origin, |
276 const SyncCacheCallback& callback, | 289 const CacheCallback& callback, |
277 bool success) { | 290 bool success) { |
278 if (!success) { | 291 if (!success) { |
279 callback.Run(false /* success */); | 292 callback.Run(false /* success */); |
280 return; | 293 return; |
281 } | 294 } |
282 | 295 |
283 // Now, cleanup any expired budget chunks for the origin. | 296 // Now, cleanup any expired budget chunks for the origin. |
284 bool needs_write = CleanupExpiredBudget(origin); | 297 bool needs_write = CleanupExpiredBudget(origin); |
285 | 298 |
286 // Get the SES score and add engagement budget for the site. | 299 // Get the SES score and add engagement budget for the site. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
350 clock_->Now() - base::TimeDelta::FromHours(kBudgetDurationInHours)) { | 363 clock_->Now() - base::TimeDelta::FromHours(kBudgetDurationInHours)) { |
351 budget_map_.erase(origin.spec()); | 364 budget_map_.erase(origin.spec()); |
352 return true; | 365 return true; |
353 } | 366 } |
354 | 367 |
355 // Although some things may have expired, there are some chunks still valid. | 368 // Although some things may have expired, there are some chunks still valid. |
356 // Don't write to the DB now, write either when all chunks expire or when the | 369 // Don't write to the DB now, write either when all chunks expire or when the |
357 // origin spends some budget. | 370 // origin spends some budget. |
358 return false; | 371 return false; |
359 } | 372 } |
OLD | NEW |