• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/browser/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/message_loop_proxy.h"
15 #include "base/stl_util.h"
16 #include "net/base/net_util.h"
17 #include "webkit/browser/quota/storage_monitor.h"
18 #include "webkit/browser/quota/storage_observer.h"
19 
20 namespace quota {
21 
22 namespace {
23 
24 typedef ClientUsageTracker::OriginUsageAccumulator OriginUsageAccumulator;
25 typedef ClientUsageTracker::OriginSetByHost OriginSetByHost;
26 
DidGetOriginUsage(const OriginUsageAccumulator & accumulator,const GURL & origin,int64 usage)27 void DidGetOriginUsage(const OriginUsageAccumulator& accumulator,
28                        const GURL& origin,
29                        int64 usage) {
30   accumulator.Run(origin, usage);
31 }
32 
DidGetHostUsage(const UsageCallback & callback,int64 limited_usage,int64 unlimited_usage)33 void DidGetHostUsage(const UsageCallback& callback,
34                      int64 limited_usage,
35                      int64 unlimited_usage) {
36   DCHECK_GE(limited_usage, 0);
37   DCHECK_GE(unlimited_usage, 0);
38   callback.Run(limited_usage + unlimited_usage);
39 }
40 
EraseOriginFromOriginSet(OriginSetByHost * origins_by_host,const std::string & host,const GURL & origin)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 
OriginSetContainsOrigin(const OriginSetByHost & origins,const std::string & host,const GURL & origin)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 
DidGetGlobalUsageForLimitedGlobalUsage(const UsageCallback & callback,int64 total_global_usage,int64 global_unlimited_usage)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 
UsageTracker(const QuotaClientList & clients,StorageType type,SpecialStoragePolicy * special_storage_policy,StorageMonitor * storage_monitor)73 UsageTracker::UsageTracker(const QuotaClientList& clients,
74                            StorageType type,
75                            SpecialStoragePolicy* special_storage_policy,
76                            StorageMonitor* storage_monitor)
77     : type_(type),
78       storage_monitor_(storage_monitor),
79       weak_factory_(this) {
80   for (QuotaClientList::const_iterator iter = clients.begin();
81       iter != clients.end();
82       ++iter) {
83     if ((*iter)->DoesSupport(type)) {
84       client_tracker_map_[(*iter)->id()] =
85           new ClientUsageTracker(this, *iter, type, special_storage_policy,
86                                  storage_monitor_);
87     }
88   }
89 }
90 
~UsageTracker()91 UsageTracker::~UsageTracker() {
92   STLDeleteValues(&client_tracker_map_);
93 }
94 
GetClientTracker(QuotaClient::ID client_id)95 ClientUsageTracker* UsageTracker::GetClientTracker(QuotaClient::ID client_id) {
96   ClientTrackerMap::iterator found = client_tracker_map_.find(client_id);
97   if (found != client_tracker_map_.end())
98     return found->second;
99   return NULL;
100 }
101 
GetGlobalLimitedUsage(const UsageCallback & callback)102 void UsageTracker::GetGlobalLimitedUsage(const UsageCallback& callback) {
103   if (global_usage_callbacks_.HasCallbacks()) {
104     global_usage_callbacks_.Add(base::Bind(
105         &DidGetGlobalUsageForLimitedGlobalUsage, callback));
106     return;
107   }
108 
109   if (!global_limited_usage_callbacks_.Add(callback))
110     return;
111 
112   AccumulateInfo* info = new AccumulateInfo;
113   // Calling GetGlobalLimitedUsage(accumulator) may synchronously
114   // return if the usage is cached, which may in turn dispatch
115   // the completion callback before we finish looping over
116   // all clients (because info->pending_clients may reach 0
117   // during the loop).
118   // To avoid this, we add one more pending client as a sentinel
119   // and fire the sentinel callback at the end.
120   info->pending_clients = client_tracker_map_.size() + 1;
121   UsageCallback accumulator = base::Bind(
122       &UsageTracker::AccumulateClientGlobalLimitedUsage,
123       weak_factory_.GetWeakPtr(), base::Owned(info));
124 
125   for (ClientTrackerMap::iterator iter = client_tracker_map_.begin();
126        iter != client_tracker_map_.end();
127        ++iter)
128     iter->second->GetGlobalLimitedUsage(accumulator);
129 
130   // Fire the sentinel as we've now called GetGlobalUsage for all clients.
131   accumulator.Run(0);
132 }
133 
GetGlobalUsage(const GlobalUsageCallback & callback)134 void UsageTracker::GetGlobalUsage(const GlobalUsageCallback& callback) {
135   if (!global_usage_callbacks_.Add(callback))
136     return;
137 
138   AccumulateInfo* info = new AccumulateInfo;
139   // Calling GetGlobalUsage(accumulator) may synchronously
140   // return if the usage is cached, which may in turn dispatch
141   // the completion callback before we finish looping over
142   // all clients (because info->pending_clients may reach 0
143   // during the loop).
144   // To avoid this, we add one more pending client as a sentinel
145   // and fire the sentinel callback at the end.
146   info->pending_clients = client_tracker_map_.size() + 1;
147   GlobalUsageCallback accumulator = base::Bind(
148       &UsageTracker::AccumulateClientGlobalUsage, weak_factory_.GetWeakPtr(),
149       base::Owned(info));
150 
151   for (ClientTrackerMap::iterator iter = client_tracker_map_.begin();
152        iter != client_tracker_map_.end();
153        ++iter)
154     iter->second->GetGlobalUsage(accumulator);
155 
156   // Fire the sentinel as we've now called GetGlobalUsage for all clients.
157   accumulator.Run(0, 0);
158 }
159 
GetHostUsage(const std::string & host,const UsageCallback & callback)160 void UsageTracker::GetHostUsage(const std::string& host,
161                                 const UsageCallback& callback) {
162   if (!host_usage_callbacks_.Add(host, callback))
163     return;
164 
165   AccumulateInfo* info = new AccumulateInfo;
166   // Calling GetHostUsage(accumulator) may synchronously
167   // return if the usage is cached, which may in turn dispatch
168   // the completion callback before we finish looping over
169   // all clients (because info->pending_clients may reach 0
170   // during the loop).
171   // To avoid this, we add one more pending client as a sentinel
172   // and fire the sentinel callback at the end.
173   info->pending_clients = client_tracker_map_.size() + 1;
174   UsageCallback accumulator = base::Bind(
175       &UsageTracker::AccumulateClientHostUsage, weak_factory_.GetWeakPtr(),
176       base::Owned(info), host);
177 
178   for (ClientTrackerMap::iterator iter = client_tracker_map_.begin();
179        iter != client_tracker_map_.end();
180        ++iter)
181     iter->second->GetHostUsage(host, accumulator);
182 
183   // Fire the sentinel as we've now called GetHostUsage for all clients.
184   accumulator.Run(0);
185 }
186 
UpdateUsageCache(QuotaClient::ID client_id,const GURL & origin,int64 delta)187 void UsageTracker::UpdateUsageCache(
188     QuotaClient::ID client_id, const GURL& origin, int64 delta) {
189   ClientUsageTracker* client_tracker = GetClientTracker(client_id);
190   DCHECK(client_tracker);
191   client_tracker->UpdateUsageCache(origin, delta);
192 }
193 
GetCachedHostsUsage(std::map<std::string,int64> * host_usage) const194 void UsageTracker::GetCachedHostsUsage(
195     std::map<std::string, int64>* host_usage) const {
196   DCHECK(host_usage);
197   host_usage->clear();
198   for (ClientTrackerMap::const_iterator iter = client_tracker_map_.begin();
199        iter != client_tracker_map_.end(); ++iter) {
200     iter->second->GetCachedHostsUsage(host_usage);
201   }
202 }
203 
GetCachedOrigins(std::set<GURL> * origins) const204 void UsageTracker::GetCachedOrigins(std::set<GURL>* origins) const {
205   DCHECK(origins);
206   origins->clear();
207   for (ClientTrackerMap::const_iterator iter = client_tracker_map_.begin();
208        iter != client_tracker_map_.end(); ++iter) {
209     iter->second->GetCachedOrigins(origins);
210   }
211 }
212 
SetUsageCacheEnabled(QuotaClient::ID client_id,const GURL & origin,bool enabled)213 void UsageTracker::SetUsageCacheEnabled(QuotaClient::ID client_id,
214                                         const GURL& origin,
215                                         bool enabled) {
216   ClientUsageTracker* client_tracker = GetClientTracker(client_id);
217   DCHECK(client_tracker);
218 
219   client_tracker->SetUsageCacheEnabled(origin, enabled);
220 }
221 
AccumulateClientGlobalLimitedUsage(AccumulateInfo * info,int64 limited_usage)222 void UsageTracker::AccumulateClientGlobalLimitedUsage(AccumulateInfo* info,
223                                                       int64 limited_usage) {
224   info->usage += limited_usage;
225   if (--info->pending_clients)
226     return;
227 
228   // All the clients have returned their usage data.  Dispatch the
229   // pending callbacks.
230   global_limited_usage_callbacks_.Run(MakeTuple(info->usage));
231 }
232 
AccumulateClientGlobalUsage(AccumulateInfo * info,int64 usage,int64 unlimited_usage)233 void UsageTracker::AccumulateClientGlobalUsage(AccumulateInfo* info,
234                                                int64 usage,
235                                                int64 unlimited_usage) {
236   info->usage += usage;
237   info->unlimited_usage += unlimited_usage;
238   if (--info->pending_clients)
239     return;
240 
241   // Defend against confusing inputs from clients.
242   if (info->usage < 0)
243     info->usage = 0;
244 
245   // TODO(michaeln): The unlimited number is not trustworthy, it
246   // can get out of whack when apps are installed or uninstalled.
247   if (info->unlimited_usage > info->usage)
248     info->unlimited_usage = info->usage;
249   else if (info->unlimited_usage < 0)
250     info->unlimited_usage = 0;
251 
252   // All the clients have returned their usage data.  Dispatch the
253   // pending callbacks.
254   global_usage_callbacks_.Run(MakeTuple(info->usage, info->unlimited_usage));
255 }
256 
AccumulateClientHostUsage(AccumulateInfo * info,const std::string & host,int64 usage)257 void UsageTracker::AccumulateClientHostUsage(AccumulateInfo* info,
258                                              const std::string& host,
259                                              int64 usage) {
260   info->usage += usage;
261   if (--info->pending_clients)
262     return;
263 
264   // Defend against confusing inputs from clients.
265   if (info->usage < 0)
266     info->usage = 0;
267 
268   // All the clients have returned their usage data.  Dispatch the
269   // pending callbacks.
270   host_usage_callbacks_.Run(host, MakeTuple(info->usage));
271 }
272 
273 // ClientUsageTracker ----------------------------------------------------
274 
ClientUsageTracker(UsageTracker * tracker,QuotaClient * client,StorageType type,SpecialStoragePolicy * special_storage_policy,StorageMonitor * storage_monitor)275 ClientUsageTracker::ClientUsageTracker(
276     UsageTracker* tracker, QuotaClient* client, StorageType type,
277     SpecialStoragePolicy* special_storage_policy,
278     StorageMonitor* storage_monitor)
279     : tracker_(tracker),
280       client_(client),
281       type_(type),
282       storage_monitor_(storage_monitor),
283       global_limited_usage_(0),
284       global_unlimited_usage_(0),
285       global_usage_retrieved_(false),
286       special_storage_policy_(special_storage_policy) {
287   DCHECK(tracker_);
288   DCHECK(client_);
289   if (special_storage_policy_.get())
290     special_storage_policy_->AddObserver(this);
291 }
292 
~ClientUsageTracker()293 ClientUsageTracker::~ClientUsageTracker() {
294   if (special_storage_policy_.get())
295     special_storage_policy_->RemoveObserver(this);
296 }
297 
GetGlobalLimitedUsage(const UsageCallback & callback)298 void ClientUsageTracker::GetGlobalLimitedUsage(const UsageCallback& callback) {
299   if (!global_usage_retrieved_) {
300     GetGlobalUsage(base::Bind(&DidGetGlobalUsageForLimitedGlobalUsage,
301                               callback));
302     return;
303   }
304 
305   if (non_cached_limited_origins_by_host_.empty()) {
306     callback.Run(global_limited_usage_);
307     return;
308   }
309 
310   AccumulateInfo* info = new AccumulateInfo;
311   info->pending_jobs = non_cached_limited_origins_by_host_.size() + 1;
312   UsageCallback accumulator = base::Bind(
313       &ClientUsageTracker::AccumulateLimitedOriginUsage, AsWeakPtr(),
314       base::Owned(info), callback);
315 
316   for (OriginSetByHost::iterator host_itr =
317            non_cached_limited_origins_by_host_.begin();
318        host_itr != non_cached_limited_origins_by_host_.end(); ++host_itr) {
319     for (std::set<GURL>::iterator origin_itr = host_itr->second.begin();
320          origin_itr != host_itr->second.end(); ++origin_itr)
321       client_->GetOriginUsage(*origin_itr, type_, accumulator);
322   }
323 
324   accumulator.Run(global_limited_usage_);
325 }
326 
GetGlobalUsage(const GlobalUsageCallback & callback)327 void ClientUsageTracker::GetGlobalUsage(const GlobalUsageCallback& callback) {
328   if (global_usage_retrieved_ &&
329       non_cached_limited_origins_by_host_.empty() &&
330       non_cached_unlimited_origins_by_host_.empty()) {
331     callback.Run(global_limited_usage_ + global_unlimited_usage_,
332                  global_unlimited_usage_);
333     return;
334   }
335 
336   client_->GetOriginsForType(type_, base::Bind(
337       &ClientUsageTracker::DidGetOriginsForGlobalUsage, AsWeakPtr(),
338       callback));
339 }
340 
GetHostUsage(const std::string & host,const UsageCallback & callback)341 void ClientUsageTracker::GetHostUsage(
342     const std::string& host, const UsageCallback& callback) {
343   if (ContainsKey(cached_hosts_, host) &&
344       !ContainsKey(non_cached_limited_origins_by_host_, host) &&
345       !ContainsKey(non_cached_unlimited_origins_by_host_, host)) {
346     // TODO(kinuko): Drop host_usage_map_ cache periodically.
347     callback.Run(GetCachedHostUsage(host));
348     return;
349   }
350 
351   if (!host_usage_accumulators_.Add(
352           host, base::Bind(&DidGetHostUsage, callback)))
353     return;
354   client_->GetOriginsForHost(type_, host, base::Bind(
355       &ClientUsageTracker::DidGetOriginsForHostUsage, AsWeakPtr(), host));
356 }
357 
UpdateUsageCache(const GURL & origin,int64 delta)358 void ClientUsageTracker::UpdateUsageCache(
359     const GURL& origin, int64 delta) {
360   std::string host = net::GetHostOrSpecFromURL(origin);
361   if (cached_hosts_.find(host) != cached_hosts_.end()) {
362     if (!IsUsageCacheEnabledForOrigin(origin))
363       return;
364 
365     cached_usage_by_host_[host][origin] += delta;
366     if (IsStorageUnlimited(origin))
367       global_unlimited_usage_ += delta;
368     else
369       global_limited_usage_ += delta;
370     DCHECK_GE(cached_usage_by_host_[host][origin], 0);
371     DCHECK_GE(global_limited_usage_, 0);
372 
373     // Notify the usage monitor that usage has changed. The storage monitor may
374     // be NULL during tests.
375     if (storage_monitor_) {
376       StorageObserver::Filter filter(type_, origin);
377       storage_monitor_->NotifyUsageChange(filter, delta);
378     }
379     return;
380   }
381 
382   // We don't know about this host yet, so populate our cache for it.
383   GetHostUsage(host, base::Bind(&ClientUsageTracker::DidGetHostUsageAfterUpdate,
384                                 AsWeakPtr(), origin));
385 }
386 
GetCachedHostsUsage(std::map<std::string,int64> * host_usage) const387 void ClientUsageTracker::GetCachedHostsUsage(
388     std::map<std::string, int64>* host_usage) const {
389   DCHECK(host_usage);
390   for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin();
391        host_iter != cached_usage_by_host_.end(); host_iter++) {
392     const std::string& host = host_iter->first;
393     (*host_usage)[host] += GetCachedHostUsage(host);
394   }
395 }
396 
GetCachedOrigins(std::set<GURL> * origins) const397 void ClientUsageTracker::GetCachedOrigins(std::set<GURL>* origins) const {
398   DCHECK(origins);
399   for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin();
400        host_iter != cached_usage_by_host_.end(); host_iter++) {
401     const UsageMap& origin_map = host_iter->second;
402     for (UsageMap::const_iterator origin_iter = origin_map.begin();
403          origin_iter != origin_map.end(); origin_iter++) {
404       origins->insert(origin_iter->first);
405     }
406   }
407 }
408 
SetUsageCacheEnabled(const GURL & origin,bool enabled)409 void ClientUsageTracker::SetUsageCacheEnabled(const GURL& origin,
410                                               bool enabled) {
411   std::string host = net::GetHostOrSpecFromURL(origin);
412   if (!enabled) {
413     // Erase |origin| from cache and subtract its usage.
414     HostUsageMap::iterator found_host = cached_usage_by_host_.find(host);
415     if (found_host != cached_usage_by_host_.end()) {
416       UsageMap& cached_usage_for_host = found_host->second;
417 
418       UsageMap::iterator found = cached_usage_for_host.find(origin);
419       if (found != cached_usage_for_host.end()) {
420         int64 usage = found->second;
421         UpdateUsageCache(origin, -usage);
422         cached_usage_for_host.erase(found);
423         if (cached_usage_for_host.empty()) {
424           cached_usage_by_host_.erase(found_host);
425           cached_hosts_.erase(host);
426         }
427       }
428     }
429 
430     if (IsStorageUnlimited(origin))
431       non_cached_unlimited_origins_by_host_[host].insert(origin);
432     else
433       non_cached_limited_origins_by_host_[host].insert(origin);
434   } else {
435     // Erase |origin| from |non_cached_origins_| and invalidate the usage cache
436     // for the host.
437     if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_,
438                                  host, origin) ||
439         EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_,
440                                  host, origin)) {
441       cached_hosts_.erase(host);
442       global_usage_retrieved_ = false;
443     }
444   }
445 }
446 
AccumulateLimitedOriginUsage(AccumulateInfo * info,const UsageCallback & callback,int64 usage)447 void ClientUsageTracker::AccumulateLimitedOriginUsage(
448     AccumulateInfo* info,
449     const UsageCallback& callback,
450     int64 usage) {
451   info->limited_usage += usage;
452   if (--info->pending_jobs)
453     return;
454 
455   callback.Run(info->limited_usage);
456 }
457 
DidGetOriginsForGlobalUsage(const GlobalUsageCallback & callback,const std::set<GURL> & origins)458 void ClientUsageTracker::DidGetOriginsForGlobalUsage(
459     const GlobalUsageCallback& callback,
460     const std::set<GURL>& origins) {
461   OriginSetByHost origins_by_host;
462   for (std::set<GURL>::const_iterator itr = origins.begin();
463        itr != origins.end(); ++itr)
464     origins_by_host[net::GetHostOrSpecFromURL(*itr)].insert(*itr);
465 
466   AccumulateInfo* info = new AccumulateInfo;
467   // Getting host usage may synchronously return the result if the usage is
468   // cached, which may in turn dispatch the completion callback before we finish
469   // looping over all hosts (because info->pending_jobs may reach 0 during the
470   // loop).  To avoid this, we add one more pending host as a sentinel and
471   // fire the sentinel callback at the end.
472   info->pending_jobs = origins_by_host.size() + 1;
473   HostUsageAccumulator accumulator =
474       base::Bind(&ClientUsageTracker::AccumulateHostUsage, AsWeakPtr(),
475                  base::Owned(info), callback);
476 
477   for (OriginSetByHost::iterator itr = origins_by_host.begin();
478        itr != origins_by_host.end(); ++itr) {
479     if (host_usage_accumulators_.Add(itr->first, accumulator))
480       GetUsageForOrigins(itr->first, itr->second);
481   }
482 
483   // Fire the sentinel as we've now called GetUsageForOrigins for all clients.
484   accumulator.Run(0, 0);
485 }
486 
AccumulateHostUsage(AccumulateInfo * info,const GlobalUsageCallback & callback,int64 limited_usage,int64 unlimited_usage)487 void ClientUsageTracker::AccumulateHostUsage(
488     AccumulateInfo* info,
489     const GlobalUsageCallback& callback,
490     int64 limited_usage,
491     int64 unlimited_usage) {
492   info->limited_usage += limited_usage;
493   info->unlimited_usage += unlimited_usage;
494   if (--info->pending_jobs)
495     return;
496 
497   DCHECK_GE(info->limited_usage, 0);
498   DCHECK_GE(info->unlimited_usage, 0);
499 
500   global_usage_retrieved_ = true;
501   callback.Run(info->limited_usage + info->unlimited_usage,
502                info->unlimited_usage);
503 }
504 
DidGetOriginsForHostUsage(const std::string & host,const std::set<GURL> & origins)505 void ClientUsageTracker::DidGetOriginsForHostUsage(
506     const std::string& host,
507     const std::set<GURL>& origins) {
508   GetUsageForOrigins(host, origins);
509 }
510 
GetUsageForOrigins(const std::string & host,const std::set<GURL> & origins)511 void ClientUsageTracker::GetUsageForOrigins(
512     const std::string& host,
513     const std::set<GURL>& origins) {
514   AccumulateInfo* info = new AccumulateInfo;
515   // Getting origin usage may synchronously return the result if the usage is
516   // cached, which may in turn dispatch the completion callback before we finish
517   // looping over all origins (because info->pending_jobs may reach 0 during the
518   // loop).  To avoid this, we add one more pending origin as a sentinel and
519   // fire the sentinel callback at the end.
520   info->pending_jobs = origins.size() + 1;
521   OriginUsageAccumulator accumulator =
522       base::Bind(&ClientUsageTracker::AccumulateOriginUsage, AsWeakPtr(),
523                  base::Owned(info), host);
524 
525   for (std::set<GURL>::const_iterator itr = origins.begin();
526        itr != origins.end(); ++itr) {
527     DCHECK_EQ(host, net::GetHostOrSpecFromURL(*itr));
528 
529     int64 origin_usage = 0;
530     if (GetCachedOriginUsage(*itr, &origin_usage)) {
531       accumulator.Run(*itr, origin_usage);
532     } else {
533       client_->GetOriginUsage(*itr, type_, base::Bind(
534           &DidGetOriginUsage, accumulator, *itr));
535     }
536   }
537 
538   // Fire the sentinel as we've now called GetOriginUsage for all clients.
539   accumulator.Run(GURL(), 0);
540 }
541 
AccumulateOriginUsage(AccumulateInfo * info,const std::string & host,const GURL & origin,int64 usage)542 void ClientUsageTracker::AccumulateOriginUsage(AccumulateInfo* info,
543                                                const std::string& host,
544                                                const GURL& origin,
545                                                int64 usage) {
546   if (!origin.is_empty()) {
547     if (usage < 0)
548       usage = 0;
549 
550     if (IsStorageUnlimited(origin))
551       info->unlimited_usage += usage;
552     else
553       info->limited_usage += usage;
554     if (IsUsageCacheEnabledForOrigin(origin))
555       AddCachedOrigin(origin, usage);
556   }
557   if (--info->pending_jobs)
558     return;
559 
560   AddCachedHost(host);
561   host_usage_accumulators_.Run(
562       host, MakeTuple(info->limited_usage, info->unlimited_usage));
563 }
564 
DidGetHostUsageAfterUpdate(const GURL & origin,int64 usage)565 void ClientUsageTracker::DidGetHostUsageAfterUpdate(
566     const GURL& origin, int64 usage) {
567   if (!storage_monitor_)
568     return;
569 
570   StorageObserver::Filter filter(type_, origin);
571   storage_monitor_->NotifyUsageChange(filter, 0);
572 }
573 
AddCachedOrigin(const GURL & origin,int64 new_usage)574 void ClientUsageTracker::AddCachedOrigin(
575     const GURL& origin, int64 new_usage) {
576   DCHECK(IsUsageCacheEnabledForOrigin(origin));
577 
578   std::string host = net::GetHostOrSpecFromURL(origin);
579   int64* usage = &cached_usage_by_host_[host][origin];
580   int64 delta = new_usage - *usage;
581   *usage = new_usage;
582   if (delta) {
583     if (IsStorageUnlimited(origin))
584       global_unlimited_usage_ += delta;
585     else
586       global_limited_usage_ += delta;
587   }
588   DCHECK_GE(*usage, 0);
589   DCHECK_GE(global_limited_usage_, 0);
590 }
591 
AddCachedHost(const std::string & host)592 void ClientUsageTracker::AddCachedHost(const std::string& host) {
593   cached_hosts_.insert(host);
594 }
595 
GetCachedHostUsage(const std::string & host) const596 int64 ClientUsageTracker::GetCachedHostUsage(const std::string& host) const {
597   HostUsageMap::const_iterator found = cached_usage_by_host_.find(host);
598   if (found == cached_usage_by_host_.end())
599     return 0;
600 
601   int64 usage = 0;
602   const UsageMap& map = found->second;
603   for (UsageMap::const_iterator iter = map.begin();
604        iter != map.end(); ++iter) {
605     usage += iter->second;
606   }
607   return usage;
608 }
609 
GetCachedOriginUsage(const GURL & origin,int64 * usage) const610 bool ClientUsageTracker::GetCachedOriginUsage(
611     const GURL& origin,
612     int64* usage) const {
613   std::string host = net::GetHostOrSpecFromURL(origin);
614   HostUsageMap::const_iterator found_host = cached_usage_by_host_.find(host);
615   if (found_host == cached_usage_by_host_.end())
616     return false;
617 
618   UsageMap::const_iterator found = found_host->second.find(origin);
619   if (found == found_host->second.end())
620     return false;
621 
622   DCHECK(IsUsageCacheEnabledForOrigin(origin));
623   *usage = found->second;
624   return true;
625 }
626 
IsUsageCacheEnabledForOrigin(const GURL & origin) const627 bool ClientUsageTracker::IsUsageCacheEnabledForOrigin(
628     const GURL& origin) const {
629   std::string host = net::GetHostOrSpecFromURL(origin);
630   return !OriginSetContainsOrigin(non_cached_limited_origins_by_host_,
631                                   host, origin) &&
632       !OriginSetContainsOrigin(non_cached_unlimited_origins_by_host_,
633                                host, origin);
634 }
635 
OnGranted(const GURL & origin,int change_flags)636 void ClientUsageTracker::OnGranted(const GURL& origin,
637                                    int change_flags) {
638   DCHECK(CalledOnValidThread());
639   if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) {
640     int64 usage = 0;
641     if (GetCachedOriginUsage(origin, &usage)) {
642       global_unlimited_usage_ += usage;
643       global_limited_usage_ -= usage;
644     }
645 
646     std::string host = net::GetHostOrSpecFromURL(origin);
647     if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_,
648                                  host, origin))
649       non_cached_unlimited_origins_by_host_[host].insert(origin);
650   }
651 }
652 
OnRevoked(const GURL & origin,int change_flags)653 void ClientUsageTracker::OnRevoked(const GURL& origin,
654                                    int change_flags) {
655   DCHECK(CalledOnValidThread());
656   if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) {
657     int64 usage = 0;
658     if (GetCachedOriginUsage(origin, &usage)) {
659       global_unlimited_usage_ -= usage;
660       global_limited_usage_ += usage;
661     }
662 
663     std::string host = net::GetHostOrSpecFromURL(origin);
664     if (EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_,
665                                  host, origin))
666       non_cached_limited_origins_by_host_[host].insert(origin);
667   }
668 }
669 
OnCleared()670 void ClientUsageTracker::OnCleared() {
671   DCHECK(CalledOnValidThread());
672   global_limited_usage_ += global_unlimited_usage_;
673   global_unlimited_usage_ = 0;
674 
675   for (OriginSetByHost::const_iterator host_itr =
676            non_cached_unlimited_origins_by_host_.begin();
677        host_itr != non_cached_unlimited_origins_by_host_.end();
678        ++host_itr) {
679     for (std::set<GURL>::const_iterator origin_itr = host_itr->second.begin();
680          origin_itr != host_itr->second.end();
681          ++origin_itr)
682       non_cached_limited_origins_by_host_[host_itr->first].insert(*origin_itr);
683   }
684   non_cached_unlimited_origins_by_host_.clear();
685 }
686 
IsStorageUnlimited(const GURL & origin) const687 bool ClientUsageTracker::IsStorageUnlimited(const GURL& origin) const {
688   if (type_ == kStorageTypeSyncable)
689     return false;
690   return special_storage_policy_.get() &&
691          special_storage_policy_->IsStorageUnlimited(origin);
692 }
693 
694 }  // namespace quota
695