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