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
20namespace storage {
21
22namespace {
23
24typedef ClientUsageTracker::OriginUsageAccumulator OriginUsageAccumulator;
25typedef ClientUsageTracker::OriginSetByHost OriginSetByHost;
26
27void DidGetOriginUsage(const OriginUsageAccumulator& accumulator,
28                       const GURL& origin,
29                       int64 usage) {
30  accumulator.Run(origin, usage);
31}
32
33void 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
41bool 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
56bool 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
63void 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
73UsageTracker::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
91UsageTracker::~UsageTracker() {
92  STLDeleteValues(&client_tracker_map_);
93}
94
95ClientUsageTracker* 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
102void 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
134void 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
160void 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
187void 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
194void 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
204void 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
213void 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
222void 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
233void 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
257void 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
275ClientUsageTracker::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
293ClientUsageTracker::~ClientUsageTracker() {
294  if (special_storage_policy_.get())
295    special_storage_policy_->RemoveObserver(this);
296}
297
298void 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
327void 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
341void 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
358void 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
387void 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
397void 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
409void 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
447void 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
458void 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
487void 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
505void ClientUsageTracker::DidGetOriginsForHostUsage(
506    const std::string& host,
507    const std::set<GURL>& origins) {
508  GetUsageForOrigins(host, origins);
509}
510
511void 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
542void 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
565void 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
574void 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
592void ClientUsageTracker::AddCachedHost(const std::string& host) {
593  cached_hosts_.insert(host);
594}
595
596int64 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
610bool 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
627bool 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
636void 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
653void 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
670void 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
687bool 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