Chromium Code Reviews| Index: chrome/browser/profiles/profile_dependency_manager.cc |
| diff --git a/chrome/browser/profiles/profile_dependency_manager.cc b/chrome/browser/profiles/profile_dependency_manager.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8f1b637e092368c6d553089d274f4896af421706 |
| --- /dev/null |
| +++ b/chrome/browser/profiles/profile_dependency_manager.cc |
| @@ -0,0 +1,134 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/profiles/profile_dependency_manager.h" |
| + |
| +#include <algorithm> |
| +#include <deque> |
| + |
| +#include "chrome/browser/profiles/profile_keyed_service.h" |
| +#include "chrome/browser/profiles/profile_keyed_service_factory.h" |
| +#include "content/common/notification_service.h" |
| + |
| +class Profile; |
| + |
| +void ProfileDependencyManager::AddComponent( |
| + ProfileKeyedServiceFactory* component) { |
| + all_components_.push_back(component); |
| + destruction_order_.clear(); |
| +} |
| + |
| +void ProfileDependencyManager::RemoveComponent( |
| + ProfileKeyedServiceFactory* component) { |
| + all_components_.erase(std::remove(all_components_.begin(), |
| + all_components_.end(), |
| + component), |
| + all_components_.end()); |
| + |
| + // Remove all dependency edges that contain this component. |
| + EdgeMap::iterator it = edges_.begin(); |
| + while (it != edges_.end()) { |
| + EdgeMap::iterator temp = it; |
| + ++it; |
| + |
| + if (temp->first == component || temp->second == component) |
| + edges_.erase(temp); |
| + } |
| + |
| + destruction_order_.clear(); |
| +} |
| + |
| +void ProfileDependencyManager::AddEdge(ProfileKeyedServiceFactory* depended, |
| + ProfileKeyedServiceFactory* dependee) { |
| + edges_.insert(std::make_pair(depended, dependee)); |
| + destruction_order_.clear(); |
| +} |
| + |
| +// static |
| +ProfileDependencyManager* ProfileDependencyManager::GetInstance() { |
| + static ProfileDependencyManager* manager = |
| + Singleton<ProfileDependencyManager>::get(); |
| + return manager; |
| +} |
| + |
| +ProfileDependencyManager::ProfileDependencyManager() { |
| + // Listen for all Profile destruction messages so that we can rebroadcast |
| + // them to all Factories in a safe order. |
| + registrar_.Add(this, |
| + NotificationType::PROFILE_DESTROYED, |
| + NotificationService::AllSources()); |
| +} |
| + |
| +ProfileDependencyManager::~ProfileDependencyManager() {} |
| + |
| +void ProfileDependencyManager::BuildDestructionOrder() { |
| + // Step 1: Build a set of nodes with no incoming edges. |
| + std::deque<ProfileKeyedServiceFactory*> queue; |
| + std::copy(all_components_.begin(), |
| + all_components_.end(), |
| + std::back_inserter(queue)); |
| + |
| + std::deque<ProfileKeyedServiceFactory*>::iterator queue_end = queue.end(); |
| + for (EdgeMap::const_iterator it = edges_.begin(); |
| + it != edges_.end(); ++it) { |
| + queue_end = std::remove(queue.begin(), queue_end, it->second); |
| + } |
| + queue.erase(queue_end, queue.end()); |
| + |
| + // Step 2: Do the Kahn topological sort. |
| + std::vector<ProfileKeyedServiceFactory*> output; |
| + EdgeMap edges(edges_); |
| + while (!queue.empty()) { |
| + ProfileKeyedServiceFactory* node = queue.front(); |
| + queue.pop_front(); |
| + output.push_back(node); |
| + |
| + std::pair<EdgeMap::iterator, EdgeMap::iterator> range = |
| + edges.equal_range(node); |
| + EdgeMap::iterator it = range.first; |
| + while (it != range.second) { |
| + ProfileKeyedServiceFactory* dest = it->second; |
| + EdgeMap::iterator temp = it; |
| + it++; |
| + edges.erase(temp); |
| + |
| + bool has_incoming_edges = false; |
| + for (EdgeMap::iterator jt = edges.begin(); jt != edges.end(); ++jt) { |
| + if (jt->second == dest) { |
| + has_incoming_edges = true; |
| + break; |
| + } |
| + } |
| + |
| + if (!has_incoming_edges) |
| + queue.push_back(dest); |
| + } |
| + } |
| + |
| + if (edges.size()) { |
| + NOTREACHED() << "Dependency graph has a cycle. We are doomed."; |
| + } |
| + |
| + std::reverse(output.begin(), output.end()); |
| + destruction_order_ = output; |
| +} |
| + |
| +void ProfileDependencyManager::Observe(NotificationType type, |
| + const NotificationSource& source, |
| + const NotificationDetails& details) { |
|
Miranda Callahan
2011/03/29 19:07:04
Should probably make sure that the NotificationTyp
Elliot Glaysher
2011/03/29 22:18:29
No longer applicable.
|
| + Profile* profile = Source<Profile>(source).ptr(); |
| + |
| + if (destruction_order_.empty()) |
| + BuildDestructionOrder(); |
| + |
| + for (std::vector<ProfileKeyedServiceFactory*>::const_iterator it = |
| + destruction_order_.begin(); it != destruction_order_.end(); ++it) { |
|
Miranda Callahan
2011/03/29 19:07:04
nit: indent
Elliot Glaysher
2011/03/29 22:18:29
Indentation is correct? Breaking a statement is pr
|
| + (*it)->ProfileShutdown(profile); |
| + } |
| + |
| + for (std::vector<ProfileKeyedServiceFactory*>::const_iterator it = |
| + destruction_order_.begin(); it != destruction_order_.end(); ++it) { |
|
Miranda Callahan
2011/03/29 19:07:04
nit: indent
|
| + (*it)->ProfileDestroyed(profile); |
| + } |
| +} |