Home | History | Annotate | Download | only in quota
      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 
     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 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 
     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     if ((*iter)->DoesSupport(type)) {
     82       client_tracker_map_[(*iter)->id()] =
     83           new ClientUsageTracker(this, *iter, type, special_storage_policy);
     84     }
     85   }
     86 }
     87 
     88 UsageTracker::~UsageTracker() {
     89   STLDeleteValues(&client_tracker_map_);
     90 }
     91 
     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 
     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 
    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 
    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 
    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 
    191 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 
    201 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 
    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 
    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 
    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 
    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 
    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 
    288 ClientUsageTracker::~ClientUsageTracker() {
    289   if (special_storage_policy_.get())
    290     special_storage_policy_->RemoveObserver(this);
    291 }
    292 
    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 
    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 
    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 
    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 
    374 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 
    384 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 
    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 
    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 
    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 
    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 
    492 void ClientUsageTracker::DidGetOriginsForHostUsage(
    493     const std::string& host,
    494     const std::set<GURL>& origins) {
    495   GetUsageForOrigins(host, origins);
    496 }
    497 
    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 
    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 
    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 
    570 void ClientUsageTracker::AddCachedHost(const std::string& host) {
    571   cached_hosts_.insert(host);
    572 }
    573 
    574 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 
    588 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 
    605 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 
    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 
    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 
    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 
    665 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