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