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