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