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

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: gypi fix 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
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, StorageType type) {
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 StorageType type) {
420 GetUsageForOrigins(host, origins);
421 }
422
423 void ClientUsageTracker::GetUsageForOrigins(
424 const std::string& host,
425 const std::set<GURL>& origins) {
426 AccumulateInfo* info = new AccumulateInfo;
427 // Getting origin usage may synchronously return the result if the usage is
428 // cached, which may in turn dispatch the completion callback before we finish
429 // looping over all origins (because info->pending_jobs may reach 0 during the
430 // loop). To avoid this, we add one more pending origin as a sentinel and
431 // fire the sentinel callback at the end.
432 info->pending_jobs = origins.size() + 1;
433 OriginUsageAccumulator accumulator =
434 base::Bind(&ClientUsageTracker::AccumulateOriginUsage, AsWeakPtr(),
435 base::Owned(info), host);
436
437 for (std::set<GURL>::const_iterator itr = origins.begin();
438 itr != origins.end(); ++itr) {
439 DCHECK_EQ(host, net::GetHostOrSpecFromURL(*itr));
440
441 int64 origin_usage = 0;
442 if (GetCachedOriginUsage(*itr, &origin_usage)) {
443 accumulator.Run(*itr, origin_usage);
444 } else {
445 client_->GetOriginUsage(*itr, type_, base::Bind(
446 &DidGetOriginUsage, accumulator, *itr));
447 }
448 }
449
450 // Fire the sentinel as we've now called GetOriginUsage for all clients.
451 accumulator.Run(GURL(), 0);
452 }
453
454 void ClientUsageTracker::AccumulateOriginUsage(AccumulateInfo* info,
455 const std::string& host,
456 const GURL& origin,
457 int64 usage) {
458 if (!origin.is_empty()) {
459 if (usage < 0)
460 usage = 0;
461
462 if (IsUsageCacheEnabledForOrigin(origin)) {
463 info->cached_usage += usage;
464 AddCachedOrigin(origin, usage);
465 } else {
466 info->non_cached_usage += usage;
467 }
468 }
469 if (--info->pending_jobs)
470 return;
471
472 AddCachedHost(host);
473 host_usage_accumulators_.Run(
474 host, MakeTuple(info->cached_usage, info->non_cached_usage));
475 }
476
477 void ClientUsageTracker::AddCachedOrigin(
478 const GURL& origin, int64 new_usage) {
479 if (!IsUsageCacheEnabledForOrigin(origin))
480 return;
481
482 std::string host = net::GetHostOrSpecFromURL(origin);
483 int64* usage = &cached_usage_by_host_[host][origin];
484 int64 delta = new_usage - *usage;
485 *usage = new_usage;
486 if (delta) {
487 if (IsStorageUnlimited(origin))
488 global_unlimited_usage_ += delta;
489 else
490 global_limited_usage_ += delta;
491 }
492 DCHECK_GE(*usage, 0);
493 DCHECK_GE(global_limited_usage_, 0);
494 }
495
496 void ClientUsageTracker::AddCachedHost(const std::string& host) {
497 cached_hosts_.insert(host);
498 }
499
500 int64 ClientUsageTracker::GetCachedHostUsage(const std::string& host) const {
501 HostUsageMap::const_iterator found = cached_usage_by_host_.find(host);
502 if (found == cached_usage_by_host_.end())
503 return 0;
504
505 int64 usage = 0;
506 const UsageMap& map = found->second;
507 for (UsageMap::const_iterator iter = map.begin();
508 iter != map.end(); ++iter) {
509 usage += iter->second;
510 }
511 return usage;
512 }
513
514 bool ClientUsageTracker::GetCachedOriginUsage(
515 const GURL& origin,
516 int64* usage) const {
517 std::string host = net::GetHostOrSpecFromURL(origin);
518 HostUsageMap::const_iterator found_host = cached_usage_by_host_.find(host);
519 if (found_host == cached_usage_by_host_.end())
520 return false;
521
522 UsageMap::const_iterator found = found_host->second.find(origin);
523 if (found == found_host->second.end())
524 return false;
525
526 DCHECK(IsUsageCacheEnabledForOrigin(origin));
527 *usage = found->second;
528 return true;
529 }
530
531 bool ClientUsageTracker::IsUsageCacheEnabledForOrigin(
532 const GURL& origin) const {
533 std::string host = net::GetHostOrSpecFromURL(origin);
534 return !OriginSetContainsOrigin(non_cached_limited_origins_by_host_,
535 host, origin) &&
536 !OriginSetContainsOrigin(non_cached_unlimited_origins_by_host_,
537 host, origin);
538 }
539
540 void ClientUsageTracker::OnGranted(const GURL& origin,
541 int change_flags) {
542 DCHECK(CalledOnValidThread());
543 if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) {
544 int64 usage = 0;
545 if (GetCachedOriginUsage(origin, &usage)) {
546 global_unlimited_usage_ += usage;
547 global_limited_usage_ -= usage;
548 }
549
550 std::string host = net::GetHostOrSpecFromURL(origin);
551 if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_,
552 host, origin))
553 non_cached_unlimited_origins_by_host_[host].insert(origin);
554 }
555 }
556
557 void ClientUsageTracker::OnRevoked(const GURL& origin,
558 int change_flags) {
559 DCHECK(CalledOnValidThread());
560 if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) {
561 int64 usage = 0;
562 if (GetCachedOriginUsage(origin, &usage)) {
563 global_unlimited_usage_ -= usage;
564 global_limited_usage_ += usage;
565 }
566
567 std::string host = net::GetHostOrSpecFromURL(origin);
568 if (EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_,
569 host, origin))
570 non_cached_limited_origins_by_host_[host].insert(origin);
571 }
572 }
573
574 void ClientUsageTracker::OnCleared() {
575 DCHECK(CalledOnValidThread());
576 global_limited_usage_ += global_unlimited_usage_;
577 global_unlimited_usage_ = 0;
578
579 for (OriginSetByHost::const_iterator host_itr =
580 non_cached_unlimited_origins_by_host_.begin();
581 host_itr != non_cached_unlimited_origins_by_host_.end();
582 ++host_itr) {
583 for (std::set<GURL>::const_iterator origin_itr = host_itr->second.begin();
584 origin_itr != host_itr->second.end();
585 ++origin_itr)
586 non_cached_limited_origins_by_host_[host_itr->first].insert(*origin_itr);
587 }
588 non_cached_unlimited_origins_by_host_.clear();
589 }
590
591 bool ClientUsageTracker::IsStorageUnlimited(const GURL& origin) const {
592 if (type_ == kStorageTypeSyncable)
593 return false;
594 return special_storage_policy_.get() &&
595 special_storage_policy_->IsStorageUnlimited(origin);
596 }
597
598 } // namespace quota
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698