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 "storage/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 "storage/browser/quota/storage_monitor.h"
     18 #include "storage/browser/quota/storage_observer.h"
     19 
     20 namespace storage {
     21 
     22 namespace {
     23 
     24 typedef ClientUsageTracker::OriginUsageAccumulator OriginUsageAccumulator;
     25 typedef ClientUsageTracker::OriginSetByHost OriginSetByHost;
     26 
     27 void DidGetOriginUsage(const OriginUsageAccumulator& accumulator,
     28                        const GURL& origin,
     29                        int64 usage) {
     30   accumulator.Run(origin, usage);
     31 }
     32 
     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 
     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                            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 
     91 UsageTracker::~UsageTracker() {
     92   STLDeleteValues(&client_tracker_map_);
     93 }
     94 
     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 
    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 
    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 
    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 
    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 
    194 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 
    204 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 
    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 
    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 
    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 
    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 
    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 
    293 ClientUsageTracker::~ClientUsageTracker() {
    294   if (special_storage_policy_.get())
    295     special_storage_policy_->RemoveObserver(this);
    296 }
    297 
    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 
    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 
    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 
    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 
    387 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 
    397 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 
    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 
    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 
    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 
    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 
    505 void ClientUsageTracker::DidGetOriginsForHostUsage(
    506     const std::string& host,
    507     const std::set<GURL>& origins) {
    508   GetUsageForOrigins(host, origins);
    509 }
    510 
    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 
    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 
    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 
    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 
    592 void ClientUsageTracker::AddCachedHost(const std::string& host) {
    593   cached_hosts_.insert(host);
    594 }
    595 
    596 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 
    610 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 
    627 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 
    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 
    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 
    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 
    687 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 storage
    695