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

Side by Side Diff: webkit/quota/usage_tracker.cc

Issue 16010007: Move webkit/quota files to webkit/browser/quota or webkit/common/quota (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « webkit/quota/usage_tracker.h ('k') | webkit/quota/usage_tracker_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
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "webkit/quota/usage_tracker.h"
6
7 #include <algorithm>
8 #include <deque>
9 #include <set>
10 #include <string>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/message_loop_proxy.h"
15 #include "base/stl_util.h"
16 #include "net/base/net_util.h"
17
18 namespace quota {
19
20 namespace {
21
22 typedef ClientUsageTracker::OriginUsageAccumulator OriginUsageAccumulator;
23 typedef ClientUsageTracker::OriginSetByHost OriginSetByHost;
24
25 void DidGetOriginUsage(const OriginUsageAccumulator& accumulator,
26 const GURL& origin,
27 int64 usage) {
28 accumulator.Run(origin, usage);
29 }
30
31 void DidGetHostUsage(const UsageCallback& callback,
32 int64 cached_usage,
33 int64 non_cached_usage) {
34 DCHECK_GE(cached_usage, 0);
35 DCHECK_GE(non_cached_usage, 0);
36 callback.Run(cached_usage + non_cached_usage);
37 }
38
39 void NoopHostUsageCallback(int64 usage) {}
40
41 bool EraseOriginFromOriginSet(OriginSetByHost* origins_by_host,
42 const std::string& host,
43 const GURL& origin) {
44 OriginSetByHost::iterator found = origins_by_host->find(host);
45 if (found == origins_by_host->end())
46 return false;
47
48 if (!found->second.erase(origin))
49 return false;
50
51 if (found->second.empty())
52 origins_by_host->erase(host);
53 return true;
54 }
55
56 bool OriginSetContainsOrigin(const OriginSetByHost& origins,
57 const std::string& host,
58 const GURL& origin) {
59 OriginSetByHost::const_iterator itr = origins.find(host);
60 return itr != origins.end() && ContainsKey(itr->second, origin);
61 }
62
63 void DidGetGlobalUsageForLimitedGlobalUsage(const UsageCallback& callback,
64 int64 total_global_usage,
65 int64 global_unlimited_usage) {
66 callback.Run(total_global_usage - global_unlimited_usage);
67 }
68
69 } // namespace
70
71 // UsageTracker ----------------------------------------------------------
72
73 UsageTracker::UsageTracker(const QuotaClientList& clients,
74 StorageType type,
75 SpecialStoragePolicy* special_storage_policy)
76 : type_(type),
77 weak_factory_(this) {
78 for (QuotaClientList::const_iterator iter = clients.begin();
79 iter != clients.end();
80 ++iter) {
81 client_tracker_map_[(*iter)->id()] =
82 new ClientUsageTracker(this, *iter, type, special_storage_policy);
83 }
84 }
85
86 UsageTracker::~UsageTracker() {
87 STLDeleteValues(&client_tracker_map_);
88 }
89
90 ClientUsageTracker* UsageTracker::GetClientTracker(QuotaClient::ID client_id) {
91 ClientTrackerMap::iterator found = client_tracker_map_.find(client_id);
92 if (found != client_tracker_map_.end())
93 return found->second;
94 return NULL;
95 }
96
97 void UsageTracker::GetGlobalLimitedUsage(const UsageCallback& callback) {
98 GetGlobalUsage(base::Bind(&DidGetGlobalUsageForLimitedGlobalUsage, callback));
99 }
100
101 void UsageTracker::GetGlobalUsage(const GlobalUsageCallback& callback) {
102 if (!global_usage_callbacks_.Add(callback))
103 return;
104
105 AccumulateInfo* info = new AccumulateInfo;
106 // Calling GetGlobalUsage(accumulator) may synchronously
107 // return if the usage is cached, which may in turn dispatch
108 // the completion callback before we finish looping over
109 // all clients (because info->pending_clients may reach 0
110 // during the loop).
111 // To avoid this, we add one more pending client as a sentinel
112 // and fire the sentinel callback at the end.
113 info->pending_clients = client_tracker_map_.size() + 1;
114 GlobalUsageCallback accumulator = base::Bind(
115 &UsageTracker::AccumulateClientGlobalUsage, weak_factory_.GetWeakPtr(),
116 base::Owned(info));
117
118 for (ClientTrackerMap::iterator iter = client_tracker_map_.begin();
119 iter != client_tracker_map_.end();
120 ++iter)
121 iter->second->GetGlobalUsage(accumulator);
122
123 // Fire the sentinel as we've now called GetGlobalUsage for all clients.
124 accumulator.Run(0, 0);
125 }
126
127 void UsageTracker::GetHostUsage(const std::string& host,
128 const UsageCallback& callback) {
129 if (!host_usage_callbacks_.Add(host, callback))
130 return;
131
132 AccumulateInfo* info = new AccumulateInfo;
133 // Calling GetHostUsage(accumulator) may synchronously
134 // return if the usage is cached, which may in turn dispatch
135 // the completion callback before we finish looping over
136 // all clients (because info->pending_clients may reach 0
137 // during the loop).
138 // To avoid this, we add one more pending client as a sentinel
139 // and fire the sentinel callback at the end.
140 info->pending_clients = client_tracker_map_.size() + 1;
141 UsageCallback accumulator = base::Bind(
142 &UsageTracker::AccumulateClientHostUsage, weak_factory_.GetWeakPtr(),
143 base::Owned(info), host);
144
145 for (ClientTrackerMap::iterator iter = client_tracker_map_.begin();
146 iter != client_tracker_map_.end();
147 ++iter)
148 iter->second->GetHostUsage(host, accumulator);
149
150 // Fire the sentinel as we've now called GetHostUsage for all clients.
151 accumulator.Run(0);
152 }
153
154 void UsageTracker::UpdateUsageCache(
155 QuotaClient::ID client_id, const GURL& origin, int64 delta) {
156 ClientUsageTracker* client_tracker = GetClientTracker(client_id);
157 DCHECK(client_tracker);
158 client_tracker->UpdateUsageCache(origin, delta);
159 }
160
161 void UsageTracker::GetCachedHostsUsage(
162 std::map<std::string, int64>* host_usage) const {
163 DCHECK(host_usage);
164 host_usage->clear();
165 for (ClientTrackerMap::const_iterator iter = client_tracker_map_.begin();
166 iter != client_tracker_map_.end(); ++iter) {
167 iter->second->GetCachedHostsUsage(host_usage);
168 }
169 }
170
171 void UsageTracker::GetCachedOrigins(std::set<GURL>* origins) const {
172 DCHECK(origins);
173 origins->clear();
174 for (ClientTrackerMap::const_iterator iter = client_tracker_map_.begin();
175 iter != client_tracker_map_.end(); ++iter) {
176 iter->second->GetCachedOrigins(origins);
177 }
178 }
179
180 void UsageTracker::SetUsageCacheEnabled(QuotaClient::ID client_id,
181 const GURL& origin,
182 bool enabled) {
183 ClientUsageTracker* client_tracker = GetClientTracker(client_id);
184 DCHECK(client_tracker);
185
186 client_tracker->SetUsageCacheEnabled(origin, enabled);
187 }
188
189 void UsageTracker::AccumulateClientGlobalUsage(AccumulateInfo* info,
190 int64 usage,
191 int64 unlimited_usage) {
192 info->usage += usage;
193 info->unlimited_usage += unlimited_usage;
194
195 if (--info->pending_clients)
196 return;
197
198 // Defend against confusing inputs from clients.
199 if (info->usage < 0)
200 info->usage = 0;
201
202 // TODO(michaeln): The unlimited number is not trustworthy, it
203 // can get out of whack when apps are installed or uninstalled.
204 if (info->unlimited_usage > info->usage)
205 info->unlimited_usage = info->usage;
206 else if (info->unlimited_usage < 0)
207 info->unlimited_usage = 0;
208
209 // All the clients have returned their usage data. Dispatch the
210 // pending callbacks.
211 global_usage_callbacks_.Run(MakeTuple(info->usage, info->unlimited_usage));
212 }
213
214 void UsageTracker::AccumulateClientHostUsage(AccumulateInfo* info,
215 const std::string& host,
216 int64 usage) {
217 info->usage += usage;
218 if (--info->pending_clients)
219 return;
220
221 // Defend against confusing inputs from clients.
222 if (info->usage < 0)
223 info->usage = 0;
224
225 // All the clients have returned their usage data. Dispatch the
226 // pending callbacks.
227 host_usage_callbacks_.Run(host, MakeTuple(info->usage));
228 }
229
230 // ClientUsageTracker ----------------------------------------------------
231
232 ClientUsageTracker::ClientUsageTracker(
233 UsageTracker* tracker, QuotaClient* client, StorageType type,
234 SpecialStoragePolicy* special_storage_policy)
235 : tracker_(tracker),
236 client_(client),
237 type_(type),
238 global_limited_usage_(0),
239 global_unlimited_usage_(0),
240 global_usage_retrieved_(false),
241 special_storage_policy_(special_storage_policy) {
242 DCHECK(tracker_);
243 DCHECK(client_);
244 if (special_storage_policy_)
245 special_storage_policy_->AddObserver(this);
246 }
247
248 ClientUsageTracker::~ClientUsageTracker() {
249 if (special_storage_policy_)
250 special_storage_policy_->RemoveObserver(this);
251 }
252
253 void ClientUsageTracker::GetGlobalUsage(const GlobalUsageCallback& callback) {
254 if (global_usage_retrieved_ &&
255 non_cached_limited_origins_by_host_.empty() &&
256 non_cached_unlimited_origins_by_host_.empty()) {
257 callback.Run(global_limited_usage_ + global_unlimited_usage_,
258 global_unlimited_usage_);
259 return;
260 }
261
262 client_->GetOriginsForType(type_, base::Bind(
263 &ClientUsageTracker::DidGetOriginsForGlobalUsage, AsWeakPtr(),
264 callback));
265 }
266
267 void ClientUsageTracker::GetHostUsage(
268 const std::string& host, const UsageCallback& callback) {
269 if (ContainsKey(cached_hosts_, host) &&
270 !ContainsKey(non_cached_limited_origins_by_host_, host) &&
271 !ContainsKey(non_cached_unlimited_origins_by_host_, host)) {
272 // TODO(kinuko): Drop host_usage_map_ cache periodically.
273 callback.Run(GetCachedHostUsage(host));
274 return;
275 }
276
277 if (!host_usage_accumulators_.Add(host, base::Bind(
278 &DidGetHostUsage, callback)))
279 return;
280 client_->GetOriginsForHost(type_, host, base::Bind(
281 &ClientUsageTracker::DidGetOriginsForHostUsage, AsWeakPtr(), host));
282 }
283
284 void ClientUsageTracker::UpdateUsageCache(
285 const GURL& origin, int64 delta) {
286 std::string host = net::GetHostOrSpecFromURL(origin);
287 if (cached_hosts_.find(host) != cached_hosts_.end()) {
288 if (!IsUsageCacheEnabledForOrigin(origin))
289 return;
290
291 cached_usage_by_host_[host][origin] += delta;
292 if (IsStorageUnlimited(origin))
293 global_unlimited_usage_ += delta;
294 else
295 global_limited_usage_ += delta;
296 DCHECK_GE(cached_usage_by_host_[host][origin], 0);
297 DCHECK_GE(global_limited_usage_, 0);
298 return;
299 }
300
301 // We don't know about this host yet, so populate our cache for it.
302 GetHostUsage(host, base::Bind(&NoopHostUsageCallback));
303 }
304
305 void ClientUsageTracker::GetCachedHostsUsage(
306 std::map<std::string, int64>* host_usage) const {
307 DCHECK(host_usage);
308 for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin();
309 host_iter != cached_usage_by_host_.end(); host_iter++) {
310 const std::string& host = host_iter->first;
311 (*host_usage)[host] += GetCachedHostUsage(host);
312 }
313 }
314
315 void ClientUsageTracker::GetCachedOrigins(std::set<GURL>* origins) const {
316 DCHECK(origins);
317 for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin();
318 host_iter != cached_usage_by_host_.end(); host_iter++) {
319 const UsageMap& origin_map = host_iter->second;
320 for (UsageMap::const_iterator origin_iter = origin_map.begin();
321 origin_iter != origin_map.end(); origin_iter++) {
322 origins->insert(origin_iter->first);
323 }
324 }
325 }
326
327 void ClientUsageTracker::SetUsageCacheEnabled(const GURL& origin,
328 bool enabled) {
329 std::string host = net::GetHostOrSpecFromURL(origin);
330 if (!enabled) {
331 // Erase |origin| from cache and subtract its usage.
332 HostUsageMap::iterator found_host = cached_usage_by_host_.find(host);
333 if (found_host != cached_usage_by_host_.end()) {
334 UsageMap& cached_usage_for_host = found_host->second;
335
336 UsageMap::iterator found = cached_usage_for_host.find(origin);
337 if (found != cached_usage_for_host.end()) {
338 int64 usage = found->second;
339 UpdateUsageCache(origin, -usage);
340 cached_usage_for_host.erase(found);
341 if (cached_usage_for_host.empty()) {
342 cached_usage_by_host_.erase(found_host);
343 cached_hosts_.erase(host);
344 }
345 }
346 }
347
348 if (IsStorageUnlimited(origin))
349 non_cached_unlimited_origins_by_host_[host].insert(origin);
350 else
351 non_cached_limited_origins_by_host_[host].insert(origin);
352 } else {
353 // Erase |origin| from |non_cached_origins_| and invalidate the usage cache
354 // for the host.
355 if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_,
356 host, origin) ||
357 EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_,
358 host, origin)) {
359 cached_hosts_.erase(host);
360 global_usage_retrieved_ = false;
361 }
362 }
363 }
364
365 void ClientUsageTracker::DidGetOriginsForGlobalUsage(
366 const GlobalUsageCallback& callback,
367 const std::set<GURL>& origins) {
368 OriginSetByHost origins_by_host;
369 for (std::set<GURL>::const_iterator itr = origins.begin();
370 itr != origins.end(); ++itr)
371 origins_by_host[net::GetHostOrSpecFromURL(*itr)].insert(*itr);
372
373 AccumulateInfo* info = new AccumulateInfo;
374 // Getting host usage may synchronously return the result if the usage is
375 // cached, which may in turn dispatch the completion callback before we finish
376 // looping over all hosts (because info->pending_jobs may reach 0 during the
377 // loop). To avoid this, we add one more pending host as a sentinel and
378 // fire the sentinel callback at the end.
379 info->pending_jobs = origins_by_host.size() + 1;
380 HostUsageAccumulator accumulator =
381 base::Bind(&ClientUsageTracker::AccumulateHostUsage, AsWeakPtr(),
382 base::Owned(info), callback);
383
384 for (OriginSetByHost::iterator itr = origins_by_host.begin();
385 itr != origins_by_host.end(); ++itr) {
386 if (host_usage_accumulators_.Add(itr->first, accumulator))
387 GetUsageForOrigins(itr->first, itr->second);
388 }
389
390 // Fire the sentinel as we've now called GetUsageForOrigins for all clients.
391 accumulator.Run(0, 0);
392 }
393
394 void ClientUsageTracker::AccumulateHostUsage(
395 AccumulateInfo* info,
396 const GlobalUsageCallback& callback,
397 int64 cached_usage,
398 int64 non_cached_usage) {
399 info->cached_usage += cached_usage;
400 info->non_cached_usage += non_cached_usage;
401 if (--info->pending_jobs)
402 return;
403
404 int64 total_usage = info->cached_usage + info->non_cached_usage;
405 int64 unlimited_usage = global_unlimited_usage_ + info->non_cached_usage;
406
407 DCHECK_GE(total_usage, 0);
408 DCHECK_GE(unlimited_usage, 0);
409 if (unlimited_usage > total_usage)
410 unlimited_usage = total_usage;
411
412 global_usage_retrieved_ = true;
413 callback.Run(total_usage, unlimited_usage);
414 }
415
416 void ClientUsageTracker::DidGetOriginsForHostUsage(
417 const std::string& host,
418 const std::set<GURL>& origins) {
419 GetUsageForOrigins(host, origins);
420 }
421
422 void ClientUsageTracker::GetUsageForOrigins(
423 const std::string& host,
424 const std::set<GURL>& origins) {
425 AccumulateInfo* info = new AccumulateInfo;
426 // Getting origin usage may synchronously return the result if the usage is
427 // cached, which may in turn dispatch the completion callback before we finish
428 // looping over all origins (because info->pending_jobs may reach 0 during the
429 // loop). To avoid this, we add one more pending origin as a sentinel and
430 // fire the sentinel callback at the end.
431 info->pending_jobs = origins.size() + 1;
432 OriginUsageAccumulator accumulator =
433 base::Bind(&ClientUsageTracker::AccumulateOriginUsage, AsWeakPtr(),
434 base::Owned(info), host);
435
436 for (std::set<GURL>::const_iterator itr = origins.begin();
437 itr != origins.end(); ++itr) {
438 DCHECK_EQ(host, net::GetHostOrSpecFromURL(*itr));
439
440 int64 origin_usage = 0;
441 if (GetCachedOriginUsage(*itr, &origin_usage)) {
442 accumulator.Run(*itr, origin_usage);
443 } else {
444 client_->GetOriginUsage(*itr, type_, base::Bind(
445 &DidGetOriginUsage, accumulator, *itr));
446 }
447 }
448
449 // Fire the sentinel as we've now called GetOriginUsage for all clients.
450 accumulator.Run(GURL(), 0);
451 }
452
453 void ClientUsageTracker::AccumulateOriginUsage(AccumulateInfo* info,
454 const std::string& host,
455 const GURL& origin,
456 int64 usage) {
457 if (!origin.is_empty()) {
458 if (usage < 0)
459 usage = 0;
460
461 if (IsUsageCacheEnabledForOrigin(origin)) {
462 info->cached_usage += usage;
463 AddCachedOrigin(origin, usage);
464 } else {
465 info->non_cached_usage += usage;
466 }
467 }
468 if (--info->pending_jobs)
469 return;
470
471 AddCachedHost(host);
472 host_usage_accumulators_.Run(
473 host, MakeTuple(info->cached_usage, info->non_cached_usage));
474 }
475
476 void ClientUsageTracker::AddCachedOrigin(
477 const GURL& origin, int64 new_usage) {
478 if (!IsUsageCacheEnabledForOrigin(origin))
479 return;
480
481 std::string host = net::GetHostOrSpecFromURL(origin);
482 int64* usage = &cached_usage_by_host_[host][origin];
483 int64 delta = new_usage - *usage;
484 *usage = new_usage;
485 if (delta) {
486 if (IsStorageUnlimited(origin))
487 global_unlimited_usage_ += delta;
488 else
489 global_limited_usage_ += delta;
490 }
491 DCHECK_GE(*usage, 0);
492 DCHECK_GE(global_limited_usage_, 0);
493 }
494
495 void ClientUsageTracker::AddCachedHost(const std::string& host) {
496 cached_hosts_.insert(host);
497 }
498
499 int64 ClientUsageTracker::GetCachedHostUsage(const std::string& host) const {
500 HostUsageMap::const_iterator found = cached_usage_by_host_.find(host);
501 if (found == cached_usage_by_host_.end())
502 return 0;
503
504 int64 usage = 0;
505 const UsageMap& map = found->second;
506 for (UsageMap::const_iterator iter = map.begin();
507 iter != map.end(); ++iter) {
508 usage += iter->second;
509 }
510 return usage;
511 }
512
513 bool ClientUsageTracker::GetCachedOriginUsage(
514 const GURL& origin,
515 int64* usage) const {
516 std::string host = net::GetHostOrSpecFromURL(origin);
517 HostUsageMap::const_iterator found_host = cached_usage_by_host_.find(host);
518 if (found_host == cached_usage_by_host_.end())
519 return false;
520
521 UsageMap::const_iterator found = found_host->second.find(origin);
522 if (found == found_host->second.end())
523 return false;
524
525 DCHECK(IsUsageCacheEnabledForOrigin(origin));
526 *usage = found->second;
527 return true;
528 }
529
530 bool ClientUsageTracker::IsUsageCacheEnabledForOrigin(
531 const GURL& origin) const {
532 std::string host = net::GetHostOrSpecFromURL(origin);
533 return !OriginSetContainsOrigin(non_cached_limited_origins_by_host_,
534 host, origin) &&
535 !OriginSetContainsOrigin(non_cached_unlimited_origins_by_host_,
536 host, origin);
537 }
538
539 void ClientUsageTracker::OnGranted(const GURL& origin,
540 int change_flags) {
541 DCHECK(CalledOnValidThread());
542 if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) {
543 int64 usage = 0;
544 if (GetCachedOriginUsage(origin, &usage)) {
545 global_unlimited_usage_ += usage;
546 global_limited_usage_ -= usage;
547 }
548
549 std::string host = net::GetHostOrSpecFromURL(origin);
550 if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_,
551 host, origin))
552 non_cached_unlimited_origins_by_host_[host].insert(origin);
553 }
554 }
555
556 void ClientUsageTracker::OnRevoked(const GURL& origin,
557 int change_flags) {
558 DCHECK(CalledOnValidThread());
559 if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) {
560 int64 usage = 0;
561 if (GetCachedOriginUsage(origin, &usage)) {
562 global_unlimited_usage_ -= usage;
563 global_limited_usage_ += usage;
564 }
565
566 std::string host = net::GetHostOrSpecFromURL(origin);
567 if (EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_,
568 host, origin))
569 non_cached_limited_origins_by_host_[host].insert(origin);
570 }
571 }
572
573 void ClientUsageTracker::OnCleared() {
574 DCHECK(CalledOnValidThread());
575 global_limited_usage_ += global_unlimited_usage_;
576 global_unlimited_usage_ = 0;
577
578 for (OriginSetByHost::const_iterator host_itr =
579 non_cached_unlimited_origins_by_host_.begin();
580 host_itr != non_cached_unlimited_origins_by_host_.end();
581 ++host_itr) {
582 for (std::set<GURL>::const_iterator origin_itr = host_itr->second.begin();
583 origin_itr != host_itr->second.end();
584 ++origin_itr)
585 non_cached_limited_origins_by_host_[host_itr->first].insert(*origin_itr);
586 }
587 non_cached_unlimited_origins_by_host_.clear();
588 }
589
590 bool ClientUsageTracker::IsStorageUnlimited(const GURL& origin) const {
591 if (type_ == kStorageTypeSyncable)
592 return false;
593 return special_storage_policy_.get() &&
594 special_storage_policy_->IsStorageUnlimited(origin);
595 }
596
597 } // namespace quota
OLDNEW
« no previous file with comments | « webkit/quota/usage_tracker.h ('k') | webkit/quota/usage_tracker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698