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/containers/adapters.h" | 7 #include "base/containers/adapters.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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 | 75 |
76 base::Time expiration = | 76 base::Time expiration = |
77 clock_->Now() + base::TimeDelta::FromHours(kBudgetDurationInHours); | 77 clock_->Now() + base::TimeDelta::FromHours(kBudgetDurationInHours); |
78 budget_map_[origin.spec()].second.push_back( | 78 budget_map_[origin.spec()].second.push_back( |
79 std::make_pair(amount, expiration.ToInternalValue())); | 79 std::make_pair(amount, expiration.ToInternalValue())); |
80 | 80 |
81 // Now that the cache is updated, write the data to the database. | 81 // Now that the cache is updated, write the data to the database. |
82 WriteCachedValuesToDatabase(origin, callback); | 82 WriteCachedValuesToDatabase(origin, callback); |
83 } | 83 } |
84 | 84 |
85 void BudgetDatabase::WriteCachedValuesToDatabase( | |
86 const GURL& origin, | |
87 const StoreBudgetCallback& callback) { | |
88 // Create the data structures that are passed to the ProtoDatabase. | |
89 std::unique_ptr< | |
90 leveldb_proto::ProtoDatabase<budget_service::Budget>::KeyEntryVector> | |
91 entries(new leveldb_proto::ProtoDatabase< | |
92 budget_service::Budget>::KeyEntryVector()); | |
93 std::unique_ptr<std::vector<std::string>> keys_to_remove( | |
94 new std::vector<std::string>()); | |
95 | |
96 // Each operation can either update the existing budget or remove the origin's | |
97 // budget information. | |
98 if (budget_map_.find(origin.spec()) == budget_map_.end()) { | |
99 // If the origin doesn't exist in the cache, this is a remove operation. | |
100 keys_to_remove->push_back(origin.spec()); | |
101 } else { | |
102 // Build the Budget proto object. | |
103 budget_service::Budget budget; | |
104 const BudgetInfo& info = budget_map_[origin.spec()]; | |
105 budget.set_debt(info.first); | |
106 for (const auto& chunk : info.second) { | |
107 budget_service::BudgetChunk* budget_chunk = budget.add_budget(); | |
108 budget_chunk->set_amount(chunk.first); | |
109 budget_chunk->set_expiration(chunk.second); | |
110 } | |
111 entries->push_back(std::make_pair(origin.spec(), budget)); | |
112 } | |
113 | |
114 // Send the updates to the database. | |
115 db_->UpdateEntries(std::move(entries), std::move(keys_to_remove), callback); | |
116 } | |
117 | |
118 void BudgetDatabase::OnDatabaseInit(bool success) { | 85 void BudgetDatabase::OnDatabaseInit(bool success) { |
119 // TODO(harkness): Consider caching the budget database now? | 86 // TODO(harkness): Consider caching the budget database now? |
120 } | 87 } |
121 | 88 |
122 void BudgetDatabase::AddToCache( | 89 void BudgetDatabase::AddToCache( |
123 const GURL& origin, | 90 const GURL& origin, |
124 const AddToCacheCallback& callback, | 91 const AddToCacheCallback& callback, |
125 bool success, | 92 bool success, |
126 std::unique_ptr<budget_service::Budget> budget_proto) { | 93 std::unique_ptr<budget_service::Budget> budget_proto) { |
127 // If the database read failed, there's nothing to add to the cache. | 94 // If the database read failed, there's nothing to add to the cache. |
(...skipping 17 matching lines...) Expand all Loading... | |
145 void BudgetDatabase::DidGetBudget(const GURL& origin, | 112 void BudgetDatabase::DidGetBudget(const GURL& origin, |
146 const GetBudgetDetailsCallback& callback, | 113 const GetBudgetDetailsCallback& callback, |
147 bool success) { | 114 bool success) { |
148 // If the database wasn't able to read the information, return the | 115 // If the database wasn't able to read the information, return the |
149 // failure and an empty BudgetExpectation. | 116 // failure and an empty BudgetExpectation. |
150 if (!success) { | 117 if (!success) { |
151 callback.Run(success, 0, BudgetExpectation()); | 118 callback.Run(success, 0, BudgetExpectation()); |
152 return; | 119 return; |
153 } | 120 } |
154 | 121 |
155 // Otherwise, build up the BudgetExpection. This is different from the format | 122 // First, cleanup any expired budget chunks for the origin. |
123 CleanupExpiredBudget(origin); | |
124 | |
125 // Now, build up the BudgetExpection. This is different from the format | |
156 // in which the cache stores the data. The cache stores chunks of budget and | 126 // in which the cache stores the data. The cache stores chunks of budget and |
157 // when that budget expires. The BudgetExpectation describes a set of times | 127 // when that budget expires. The BudgetExpectation describes a set of times |
158 // and the budget at those times. | 128 // and the budget at those times. |
159 const BudgetInfo& info = budget_map_[origin.spec()]; | 129 const BudgetInfo& info = budget_map_[origin.spec()]; |
160 BudgetExpectation expectation; | 130 BudgetExpectation expectation; |
161 double total = 0; | 131 double total = 0; |
162 | 132 |
163 // Starting with the chunks that expire the farthest in the future, build up | 133 // Starting with the chunks that expire the farthest in the future, build up |
164 // the budget expectations for those future times. | 134 // the budget expectations for those future times. |
165 for (const auto& chunk : base::Reversed(info.second)) { | 135 for (const auto& chunk : base::Reversed(info.second)) { |
166 expectation.push_front(std::make_pair(total, chunk.second)); | 136 expectation.push_front( |
137 std::make_pair(total, base::Time::FromInternalValue(chunk.second))); | |
167 total += chunk.first; | 138 total += chunk.first; |
168 } | 139 } |
169 | 140 |
170 // Always add one entry at the front of the list for the total budget right | 141 // Always add one entry at the front of the list for the total budget now. |
171 // now. | 142 expectation.push_front(std::make_pair(total, clock_->Now())); |
172 expectation.push_front(std::make_pair(total, 0)); | |
173 | 143 |
174 callback.Run(true /* success */, info.first, expectation); | 144 callback.Run(true /* success */, info.first, expectation); |
175 } | 145 } |
176 | 146 |
177 // Override the default clock with the specified clock. Only used for testing. | 147 // Override the default clock with the specified clock. Only used for testing. |
178 void BudgetDatabase::SetClockForTesting(std::unique_ptr<base::Clock> clock) { | 148 void BudgetDatabase::SetClockForTesting(std::unique_ptr<base::Clock> clock) { |
179 clock_ = std::move(clock); | 149 clock_ = std::move(clock); |
180 } | 150 } |
151 | |
152 void BudgetDatabase::WriteCachedValuesToDatabase( | |
153 const GURL& origin, | |
154 const StoreBudgetCallback& callback) { | |
155 // First, cleanup any expired budget chunks for the origin. | |
156 CleanupExpiredBudget(origin); | |
157 | |
158 // Create the data structures that are passed to the ProtoDatabase. | |
159 std::unique_ptr< | |
160 leveldb_proto::ProtoDatabase<budget_service::Budget>::KeyEntryVector> | |
161 entries(new leveldb_proto::ProtoDatabase< | |
162 budget_service::Budget>::KeyEntryVector()); | |
163 std::unique_ptr<std::vector<std::string>> keys_to_remove( | |
164 new std::vector<std::string>()); | |
165 | |
166 // Each operation can either update the existing budget or remove the origin's | |
167 // budget information. | |
168 if (budget_map_.find(origin.spec()) == budget_map_.end()) { | |
169 // If the origin doesn't exist in the cache, this is a remove operation. | |
170 keys_to_remove->push_back(origin.spec()); | |
171 } else { | |
172 // Build the Budget proto object. | |
173 budget_service::Budget budget; | |
174 const BudgetInfo& info = budget_map_[origin.spec()]; | |
175 budget.set_debt(info.first); | |
176 for (const auto& chunk : info.second) { | |
177 budget_service::BudgetChunk* budget_chunk = budget.add_budget(); | |
178 budget_chunk->set_amount(chunk.first); | |
179 budget_chunk->set_expiration(chunk.second); | |
180 } | |
181 entries->push_back(std::make_pair(origin.spec(), budget)); | |
182 } | |
183 | |
184 // Send the updates to the database. | |
185 db_->UpdateEntries(std::move(entries), std::move(keys_to_remove), callback); | |
186 } | |
187 | |
188 void BudgetDatabase::CleanupExpiredBudget(const GURL& origin) { | |
189 if (budget_map_.find(origin.spec()) == budget_map_.end()) | |
190 return; | |
191 | |
192 double now = clock_->Now().ToInternalValue(); | |
Peter Beverloo
2016/08/08 15:02:55
Supposedly we'd like to change the second double i
harkness
2016/08/09 12:57:40
I was thinking we would have the cache be a true m
| |
193 | |
194 BudgetChunks& chunks = budget_map_[origin.spec()].second; | |
195 auto cleanup_iter = chunks.begin(); | |
196 | |
197 // This relies on the list of chunks being in timestamp order. | |
198 while (cleanup_iter != chunks.end() && cleanup_iter->second <= now) { | |
Peter Beverloo
2016/08/08 15:02:55
nit: remove {} for one-line statements
Peter Beverloo
2016/08/08 15:02:55
Not for this CL, but I'd hope you agree that all t
harkness
2016/08/09 12:57:40
Done.
harkness
2016/08/09 12:57:40
As we discussed in person yesterday, I'm planning
| |
199 cleanup_iter = chunks.erase(cleanup_iter); | |
200 } | |
201 | |
202 // If the entire budget is empty now, cleanup the map. | |
203 if (chunks.empty()) | |
204 budget_map_.erase(origin.spec()); | |
Peter Beverloo
2016/08/08 15:02:55
Maybe add a test to verify that we actually remove
harkness
2016/08/09 12:57:40
Added a test and found a bug/incomplete implementa
Peter Beverloo
2016/08/09 13:12:42
As the British would say: "woop!"
| |
205 } | |
OLD | NEW |