Chromium Code Reviews| Index: webkit/quota/usage_tracker.cc |
| =================================================================== |
| --- webkit/quota/usage_tracker.cc (revision 96053) |
| +++ webkit/quota/usage_tracker.cc (working copy) |
| @@ -4,6 +4,7 @@ |
| #include "webkit/quota/usage_tracker.h" |
| +#include <algorithm> |
| #include <deque> |
| #include <set> |
| #include <string> |
| @@ -15,6 +16,12 @@ |
| namespace quota { |
| +namespace { |
| +bool SortByHost(const GURL& lhs, const GURL& rhs) { |
| + return net::GetHostOrSpecFromURL(lhs) > net::GetHostOrSpecFromURL(rhs); |
| +} |
| +} |
| + |
| // A task class for getting the total amount of data used for a collection of |
| // origins. This class is self-destructed. |
| class ClientUsageTracker::GatherUsageTaskBase : public QuotaTask { |
| @@ -36,34 +43,42 @@ |
| // Get total usage for the given |origins|. |
| void GetUsageForOrigins(const std::set<GURL>& origins, StorageType type) { |
| DCHECK(original_message_loop()->BelongsToCurrentThread()); |
| - std::set<GURL> origins_to_process; |
| // We do not get usage for origins for which we have valid usage cache. |
| - client_tracker()->DetermineOriginsToGetUsage(origins, &origins_to_process); |
| - if (origins_to_process.empty()) { |
| + std::vector<GURL> origins_to_gather; |
| + std::set<GURL> cached_origins; |
| + client_tracker()->GetCachedOrigins(&cached_origins); |
| + std::set<GURL> already_added; |
| + for (std::set<GURL>::const_iterator iter = origins.begin(); |
| + iter != origins.end(); ++iter) { |
| + if (cached_origins.find(*iter) == cached_origins.end() && |
| + already_added.insert(*iter).second) { |
| + origins_to_gather.push_back(*iter); |
| + } |
| + } |
| + if (origins_to_gather.empty()) { |
| CallCompleted(); |
| DeleteSoon(); |
| return; |
| } |
| + // Sort them so we can detect when we've gathered all info for a particular |
| + // host in DidGetUsage. |
| + std::sort(origins_to_gather.begin(), origins_to_gather.end(), SortByHost); |
| + |
| // First, fully populate the pending queue because GetOriginUsage may call |
| // the completion callback immediately. |
| - for (std::set<GURL>::const_iterator iter = origins_to_process.begin(); |
| - iter != origins_to_process.end(); iter++) |
| + for (std::vector<GURL>::const_iterator iter = origins_to_gather.begin(); |
| + iter != origins_to_gather.end(); iter++) |
| pending_origins_.push_back(*iter); |
| - for (std::set<GURL>::const_iterator iter = origins_to_process.begin(); |
| - iter != origins_to_process.end(); iter++) |
| + for (std::vector<GURL>::const_iterator iter = origins_to_gather.begin(); |
| + iter != origins_to_gather.end(); iter++) |
| client_->GetOriginUsage( |
| *iter, |
| tracker_->type(), |
| callback_factory_.NewCallback(&GatherUsageTaskBase::DidGetUsage)); |
| } |
| - bool IsOriginDone(const GURL& origin) const { |
| - DCHECK(original_message_loop()->BelongsToCurrentThread()); |
| - return origin_usage_map_.find(origin) != origin_usage_map_.end(); |
| - } |
| - |
| protected: |
| virtual void Aborted() OVERRIDE { |
| DeleteSoon(); |
| @@ -71,12 +86,13 @@ |
| UsageTracker* tracker() const { return tracker_; } |
| ClientUsageTracker* client_tracker() const { return client_tracker_; } |
| - const std::map<GURL, int64>& origin_usage_map() const { |
| - return origin_usage_map_; |
| - } |
| private: |
| void DidGetUsage(int64 usage) { |
| + DCHECK(original_message_loop()->BelongsToCurrentThread()); |
| + DCHECK(!pending_origins_.empty()); |
| + DCHECK(client_tracker_); |
| + |
| // Defend against confusing inputs from QuotaClients. |
| DCHECK_GE(usage, 0); |
| if (usage < 0) |
| @@ -84,10 +100,16 @@ |
| // This code assumes DidGetUsage callbacks are called in the same |
| // order as we dispatched GetOriginUsage calls. |
| - DCHECK(original_message_loop()->BelongsToCurrentThread()); |
| - DCHECK(!pending_origins_.empty()); |
| - origin_usage_map_[pending_origins_.front()] = usage; |
| + const GURL& origin = pending_origins_.front(); |
| + std::string host = net::GetHostOrSpecFromURL(origin); |
| + client_tracker_->AddCachedOrigin(origin, usage); |
| + |
| pending_origins_.pop_front(); |
| + if (pending_origins_.empty() || |
| + host != net::GetHostOrSpecFromURL(pending_origins_.front())) { |
| + client_tracker_->AddCachedHost(host); |
| + } |
| + |
| if (pending_origins_.empty()) { |
| // We're done. |
| CallCompleted(); |
| @@ -129,7 +151,7 @@ |
| } |
| virtual void Completed() OVERRIDE { |
| - client_tracker()->DidGetGlobalUsage(origin_usage_map()); |
| + client_tracker()->GatherGlobalUsageComplete(); |
| } |
| private: |
| @@ -164,7 +186,7 @@ |
| } |
| virtual void Completed() OVERRIDE { |
| - client_tracker()->DidGetHostUsage(host_, origin_usage_map()); |
| + client_tracker()->GatherHostUsageComplete(host_); |
| } |
| private: |
| @@ -255,10 +277,8 @@ |
| DCHECK(origins); |
| origins->clear(); |
| for (ClientTrackerMap::const_iterator iter = client_tracker_map_.begin(); |
| - iter != client_tracker_map_.end(); |
| - ++iter) { |
| - const std::set<GURL>& client_origins = iter->second->cached_origins(); |
| - origins->insert(client_origins.begin(), client_origins.end()); |
| + iter != client_tracker_map_.end(); ++iter) { |
| + iter->second->GetCachedOrigins(origins); |
| } |
| } |
| @@ -350,135 +370,109 @@ |
| void ClientUsageTracker::GetHostUsage( |
| const std::string& host, HostUsageCallback* callback) { |
| - std::map<std::string, int64>::iterator found = host_usage_map_.find(host); |
| - if (found != host_usage_map_.end()) { |
| + HostSet::const_iterator found = cached_hosts_.find(host); |
| + if (found != cached_hosts_.end()) { |
| // TODO(kinuko): Drop host_usage_map_ cache periodically. |
| - callback->Run(host, type_, found->second); |
| + callback->Run(host, type_, GetCachedHostUsage(host)); |
| delete callback; |
| return; |
| } |
| - DCHECK(!host_usage_callbacks_.HasCallbacks(host)); |
| - DCHECK(host_usage_tasks_.find(host) == host_usage_tasks_.end()); |
| - host_usage_callbacks_.Add(host, callback); |
| - if (global_usage_task_) |
| + if (!host_usage_callbacks_.Add(host, callback) || global_usage_task_) |
| return; |
| GatherHostUsageTask* task = new GatherHostUsageTask(tracker_, client_, host); |
| host_usage_tasks_[host] = task; |
| task->Start(); |
| } |
| -void ClientUsageTracker::DetermineOriginsToGetUsage( |
| - const std::set<GURL>& origins, std::set<GURL>* origins_to_process) { |
| - DCHECK(origins_to_process); |
| - for (std::set<GURL>::const_iterator iter = origins.begin(); |
| - iter != origins.end(); ++iter) { |
| - if (cached_origins_.find(*iter) == cached_origins_.end()) |
| - origins_to_process->insert(*iter); |
| - } |
| -} |
| - |
| void ClientUsageTracker::UpdateUsageCache( |
| const GURL& origin, int64 delta) { |
| std::string host = net::GetHostOrSpecFromURL(origin); |
| - if (cached_origins_.find(origin) != cached_origins_.end()) { |
| - host_usage_map_[host] += delta; |
| + if (cached_hosts_.find(host) != cached_hosts_.end()) { |
| + cached_usage_[host][origin] += delta; |
| global_usage_ += delta; |
| if (IsStorageUnlimited(origin)) |
| global_unlimited_usage_ += delta; |
| - DCHECK_GE(host_usage_map_[host], 0); |
| + DCHECK_GE(cached_usage_[host][origin], 0); |
| DCHECK_GE(global_usage_, 0); |
| return; |
| } |
| - if (global_usage_retrieved_ || |
| - host_usage_map_.find(host) != host_usage_map_.end()) { |
| - // This might be for a new origin. |
| - cached_origins_.insert(origin); |
| - host_usage_map_[host] += delta; |
| - global_usage_ += delta; |
| - if (IsStorageUnlimited(origin)) |
| - global_unlimited_usage_ += delta; |
| - DCHECK_GE(host_usage_map_[host], 0); |
| - DCHECK_GE(global_usage_, 0); |
| - return; |
| + |
| + // We don't know about this host yet, so populate our cache for it. |
| + GetHostUsage(host, |
| + NewCallback(this, &ClientUsageTracker::NoopHostUsageCallback)); |
|
kinuko
2011/08/11 15:35:16
nice simplification.
|
| +} |
| + |
| +void ClientUsageTracker::GetCachedOrigins(std::set<GURL>* origins) const { |
| + DCHECK(origins); |
| + for (HostUsageMap::const_iterator host_iter = cached_usage_.begin(); |
| + host_iter != cached_usage_.end(); host_iter++) { |
| + const UsageMap& origin_map = host_iter->second; |
| + for (UsageMap::const_iterator origin_iter = origin_map.begin(); |
| + origin_iter != origin_map.end(); origin_iter++) { |
| + origins->insert(origin_iter->first); |
| + } |
| } |
| - // See if the origin has been processed in outstanding gather tasks |
| - // and add up the delta if it has. |
| - if (global_usage_task_ && global_usage_task_->IsOriginDone(origin)) { |
| - host_usage_map_[host] += delta; |
| +} |
| + |
| +void ClientUsageTracker::AddCachedOrigin( |
| + const GURL& origin, int64 usage) { |
| + std::string host = net::GetHostOrSpecFromURL(origin); |
| + UsageMap::iterator iter = cached_usage_[host]. |
| + insert(UsageMap::value_type(origin, 0)).first; |
| + int64 old_usage = iter->second; |
| + iter->second = usage; |
| + int64 delta = usage - old_usage; |
| + if (delta) { |
| global_usage_ += delta; |
| if (IsStorageUnlimited(origin)) |
| global_unlimited_usage_ += delta; |
| - DCHECK_GE(host_usage_map_[host], 0); |
| - DCHECK_GE(global_usage_, 0); |
| - return; |
| } |
| - if (host_usage_tasks_.find(host) != host_usage_tasks_.end() && |
| - host_usage_tasks_[host]->IsOriginDone(origin)) { |
| - host_usage_map_[host] += delta; |
| - DCHECK_GE(host_usage_map_[host], 0); |
| - } |
| - // Otherwise we have not cached usage info for the origin yet. |
| - // Succeeding GetUsage tasks would eventually catch the change. |
| + DCHECK_GE(iter->second, 0); |
| + DCHECK_GE(global_usage_, 0); |
| } |
| -void ClientUsageTracker::DidGetGlobalUsage( |
| - const std::map<GURL, int64>& origin_usage_map) { |
| +void ClientUsageTracker::AddCachedHost(const std::string& host) { |
| + cached_hosts_.insert(host); |
| +} |
| + |
| +void ClientUsageTracker::GatherGlobalUsageComplete() { |
| DCHECK(global_usage_task_ != NULL); |
| global_usage_task_ = NULL; |
| // TODO(kinuko): Record when it has retrieved the global usage. |
| global_usage_retrieved_ = true; |
| - for (std::map<GURL, int64>::const_iterator iter = origin_usage_map.begin(); |
| - iter != origin_usage_map.end(); |
| - ++iter) { |
| - if (cached_origins_.insert(iter->first).second) { |
| - global_usage_ += iter->second; |
| - if (IsStorageUnlimited(iter->first)) |
| - global_unlimited_usage_ += iter->second; |
| - std::string host = net::GetHostOrSpecFromURL(iter->first); |
| - host_usage_map_[host] += iter->second; |
| - DCHECK_GE(host_usage_map_[host], 0); |
| - DCHECK_GE(global_usage_, 0); |
| - } |
| - } |
| - // Dispatches the global usage callback. |
| DCHECK(global_usage_callback_.HasCallbacks()); |
| global_usage_callback_.Run(type_, global_usage_, global_unlimited_usage_); |
| - // Dispatches host usage callbacks. |
| for (HostUsageCallbackMap::iterator iter = host_usage_callbacks_.Begin(); |
| - iter != host_usage_callbacks_.End(); |
| - ++iter) { |
| - std::map<std::string, int64>::iterator found = |
| - host_usage_map_.find(iter->first); |
| - if (found == host_usage_map_.end()) |
| - iter->second.Run(iter->first, type_, 0); |
| - else |
| - iter->second.Run(iter->first, type_, found->second); |
| + iter != host_usage_callbacks_.End(); ++iter) { |
| + iter->second.Run(iter->first, type_, GetCachedHostUsage(iter->first)); |
| } |
| host_usage_callbacks_.Clear(); |
| } |
| -void ClientUsageTracker::DidGetHostUsage( |
| - const std::string& host, |
| - const std::map<GURL, int64>& origin_usage_map) { |
| +void ClientUsageTracker::GatherHostUsageComplete(const std::string& host) { |
| DCHECK(host_usage_tasks_.find(host) != host_usage_tasks_.end()); |
| host_usage_tasks_.erase(host); |
| - for (std::map<GURL, int64>::const_iterator iter = origin_usage_map.begin(); |
| - iter != origin_usage_map.end(); |
| - ++iter) { |
| - if (cached_origins_.insert(iter->first).second) { |
| - global_usage_ += iter->second; |
| - if (IsStorageUnlimited(iter->first)) |
| - global_unlimited_usage_ += iter->second; |
| - host_usage_map_[host] += iter->second; |
| - DCHECK_GE(host_usage_map_[host], 0); |
| - DCHECK_GE(global_usage_, 0); |
| - } |
| + host_usage_callbacks_.Run(host, host, type_, GetCachedHostUsage(host)); |
| +} |
| + |
| +int64 ClientUsageTracker::GetCachedHostUsage(const std::string& host) { |
| + HostUsageMap::const_iterator found = cached_usage_.find(host); |
|
kinuko
2011/08/11 15:35:16
nit: extra space between found and =
|
| + if (found == cached_usage_.end()) |
| + return 0; |
| + |
| + int64 usage = 0; |
| + const UsageMap& map = found->second; |
| + for (UsageMap::const_iterator iter = map.begin(); |
| + iter != map.end(); ++iter) { |
| + usage += iter->second; |
| } |
| + return usage; |
| +} |
| - // Dispatches the host usage callback. |
| - host_usage_callbacks_.Run(host, host, type_, host_usage_map_[host]); |
| +void ClientUsageTracker::NoopHostUsageCallback( |
| + const std::string& host, StorageType type, int64 usage) { |
| } |
| bool ClientUsageTracker::IsStorageUnlimited(const GURL& origin) const { |