Index: webkit/quota/usage_tracker.cc |
=================================================================== |
--- webkit/quota/usage_tracker.cc (revision 96443) |
+++ 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)); |
+} |
+ |
+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); |
+ 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 { |