Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: chrome/browser/profiles/profile_dependency_manager.cc

Issue 13454032: Extract DependencyGraph from ProfileDependencyManager. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: no void* Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/profiles/profile_dependency_manager.h" 5 #include "chrome/browser/profiles/profile_dependency_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <deque> 8 #include <deque>
9 #include <iterator> 9 #include <iterator>
10 10
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 #ifndef NDEBUG 124 #ifndef NDEBUG
125 #include "base/command_line.h" 125 #include "base/command_line.h"
126 #include "base/file_util.h" 126 #include "base/file_util.h"
127 #include "chrome/common/chrome_switches.h" 127 #include "chrome/common/chrome_switches.h"
128 #endif 128 #endif
129 129
130 class Profile; 130 class Profile;
131 131
132 void ProfileDependencyManager::AddComponent( 132 void ProfileDependencyManager::AddComponent(
133 ProfileKeyedBaseFactory* component) { 133 ProfileKeyedBaseFactory* component) {
134 all_components_.push_back(component); 134 dependency_graph_.AddNode(component);
135 destruction_order_.clear();
136 } 135 }
137 136
138 void ProfileDependencyManager::RemoveComponent( 137 void ProfileDependencyManager::RemoveComponent(
139 ProfileKeyedBaseFactory* component) { 138 ProfileKeyedBaseFactory* component) {
140 all_components_.erase(std::remove(all_components_.begin(), 139 dependency_graph_.RemoveNode(component);
141 all_components_.end(),
142 component),
143 all_components_.end());
144
145 // Remove all dependency edges that contain this component.
146 EdgeMap::iterator it = edges_.begin();
147 while (it != edges_.end()) {
148 EdgeMap::iterator temp = it;
149 ++it;
150
151 if (temp->first == component || temp->second == component)
152 edges_.erase(temp);
153 }
154
155 destruction_order_.clear();
156 } 140 }
157 141
158 void ProfileDependencyManager::AddEdge(ProfileKeyedBaseFactory* depended, 142 void ProfileDependencyManager::AddEdge(ProfileKeyedBaseFactory* depended,
159 ProfileKeyedBaseFactory* dependee) { 143 ProfileKeyedBaseFactory* dependee) {
160 edges_.insert(std::make_pair(depended, dependee)); 144 dependency_graph_.AddEdge(depended, dependee);
161 destruction_order_.clear();
162 } 145 }
163 146
164 void ProfileDependencyManager::CreateProfileServices(Profile* profile, 147 void ProfileDependencyManager::CreateProfileServices(Profile* profile,
165 bool is_testing_profile) { 148 bool is_testing_profile) {
166 #ifndef NDEBUG 149 #ifndef NDEBUG
167 // Unmark |profile| as dead. This exists because of unit tests, which will 150 // Unmark |profile| as dead. This exists because of unit tests, which will
168 // often have similar stack structures. 0xWhatever might be created, go out 151 // often have similar stack structures. 0xWhatever might be created, go out
169 // of scope, and then a new Profile object might be created at 0xWhatever. 152 // of scope, and then a new Profile object might be created at 0xWhatever.
170 dead_profile_pointers_.erase(profile); 153 dead_profile_pointers_.erase(profile);
171 #endif 154 #endif
172 155
173 AssertFactoriesBuilt(); 156 AssertFactoriesBuilt();
174 157
175 if (destruction_order_.empty()) 158 std::vector<DependencyNode*> construction_order;
176 BuildDestructionOrder(profile); 159 if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
160 NOTREACHED();
161 }
177 162
178 // Iterate in reverse destruction order for creation. 163 #ifndef NDEBUG
179 for (std::vector<ProfileKeyedBaseFactory*>::reverse_iterator rit = 164 DumpProfileDependencies(profile);
180 destruction_order_.rbegin(); rit != destruction_order_.rend(); 165 #endif
181 ++rit) { 166
167 for (size_t i = 0; i < construction_order.size(); i++) {
168 ProfileKeyedBaseFactory* factory =
169 static_cast<ProfileKeyedBaseFactory*>(construction_order[i]);
170
182 if (!profile->IsOffTheRecord()) { 171 if (!profile->IsOffTheRecord()) {
183 // We only register preferences on normal profiles because the incognito 172 // We only register preferences on normal profiles because the incognito
184 // profile shares the pref service with the normal one. 173 // profile shares the pref service with the normal one.
185 (*rit)->RegisterUserPrefsOnProfile(profile); 174 factory->RegisterUserPrefsOnProfile(profile);
186 } 175 }
187 176
188 if (is_testing_profile && (*rit)->ServiceIsNULLWhileTesting()) { 177 if (is_testing_profile && factory->ServiceIsNULLWhileTesting()) {
189 (*rit)->SetEmptyTestingFactory(profile); 178 factory->SetEmptyTestingFactory(profile);
190 } else if ((*rit)->ServiceIsCreatedWithProfile()) { 179 } else if (factory->ServiceIsCreatedWithProfile()) {
191 // Create the service. 180 // Create the service.
192 (*rit)->CreateServiceNow(profile); 181 factory->CreateServiceNow(profile);
193 } 182 }
194 } 183 }
195 } 184 }
196 185
197 void ProfileDependencyManager::DestroyProfileServices(Profile* profile) { 186 void ProfileDependencyManager::DestroyProfileServices(Profile* profile) {
198 if (destruction_order_.empty()) 187 std::vector<DependencyNode*> destruction_order;
199 BuildDestructionOrder(profile); 188 if (!dependency_graph_.GetDestructionOrder(&destruction_order)) {
200 189 NOTREACHED();
201 for (std::vector<ProfileKeyedBaseFactory*>::const_iterator it =
202 destruction_order_.begin(); it != destruction_order_.end(); ++it) {
203 (*it)->ProfileShutdown(profile);
204 } 190 }
205 191
206 #ifndef NDEBUG 192 #ifndef NDEBUG
193 DumpProfileDependencies(profile);
194 #endif
195
196 for (size_t i = 0; i < destruction_order.size(); i++) {
197 ProfileKeyedBaseFactory* factory =
198 static_cast<ProfileKeyedBaseFactory*>(destruction_order[i]);
199 factory->ProfileShutdown(profile);
200 }
201
202 #ifndef NDEBUG
207 // The profile is now dead to the rest of the program. 203 // The profile is now dead to the rest of the program.
208 dead_profile_pointers_.insert(profile); 204 dead_profile_pointers_.insert(profile);
209 #endif 205 #endif
210 206
211 for (std::vector<ProfileKeyedBaseFactory*>::const_iterator it = 207 for (size_t i = 0; i < destruction_order.size(); i++) {
212 destruction_order_.begin(); it != destruction_order_.end(); ++it) { 208 ProfileKeyedBaseFactory* factory =
213 (*it)->ProfileDestroyed(profile); 209 static_cast<ProfileKeyedBaseFactory*>(destruction_order[i]);
210 factory->ProfileDestroyed(profile);
214 } 211 }
215 } 212 }
216 213
217 #ifndef NDEBUG 214 #ifndef NDEBUG
218 void ProfileDependencyManager::AssertProfileWasntDestroyed(Profile* profile) { 215 void ProfileDependencyManager::AssertProfileWasntDestroyed(Profile* profile) {
219 if (dead_profile_pointers_.find(profile) != dead_profile_pointers_.end()) { 216 if (dead_profile_pointers_.find(profile) != dead_profile_pointers_.end()) {
220 NOTREACHED() << "Attempted to access a Profile that was ShutDown(). This " 217 NOTREACHED() << "Attempted to access a Profile that was ShutDown(). This "
221 << "is most likely a heap smasher in progress. After " 218 << "is most likely a heap smasher in progress. After "
222 << "ProfileKeyedService::Shutdown() completes, your service " 219 << "ProfileKeyedService::Shutdown() completes, your service "
223 << "MUST NOT refer to depended Profile services again."; 220 << "MUST NOT refer to depended Profile services again.";
224 } 221 }
225 } 222 }
226 #endif 223 #endif
227 224
228 // static 225 // static
229 ProfileDependencyManager* ProfileDependencyManager::GetInstance() { 226 ProfileDependencyManager* ProfileDependencyManager::GetInstance() {
230 return Singleton<ProfileDependencyManager>::get(); 227 return Singleton<ProfileDependencyManager>::get();
231 } 228 }
232 229
230 namespace {
231
232 std::string ProfileKeyedBaseFactoryGetNodeName(DependencyNode* node) {
233 return static_cast<ProfileKeyedBaseFactory*>(node)->name();
234 }
235
236 } // namespace
237
233 ProfileDependencyManager::ProfileDependencyManager() 238 ProfileDependencyManager::ProfileDependencyManager()
234 : built_factories_(false) { 239 : built_factories_(false),
240 dependency_graph_(base::Bind(&ProfileKeyedBaseFactoryGetNodeName)) {
235 } 241 }
236 242
237 ProfileDependencyManager::~ProfileDependencyManager() {} 243 ProfileDependencyManager::~ProfileDependencyManager() {}
238 244
239 // This method gets the instance of each ServiceFactory. We do this so that 245 // This method gets the instance of each ServiceFactory. We do this so that
240 // each ServiceFactory initializes itself and registers its dependencies with 246 // each ServiceFactory initializes itself and registers its dependencies with
241 // the global PreferenceDependencyManager. We need to have a complete 247 // the global PreferenceDependencyManager. We need to have a complete
242 // dependency graph when we create a profile so we can dispatch the profile 248 // dependency graph when we create a profile so we can dispatch the profile
243 // creation message to the services that want to create their services at 249 // creation message to the services that want to create their services at
244 // profile creation time. 250 // profile creation time.
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 ThemeServiceFactory::GetInstance(); 385 ThemeServiceFactory::GetInstance();
380 #endif 386 #endif
381 TokenCacheServiceFactory::GetInstance(); 387 TokenCacheServiceFactory::GetInstance();
382 TokenServiceFactory::GetInstance(); 388 TokenServiceFactory::GetInstance();
383 UserStyleSheetWatcherFactory::GetInstance(); 389 UserStyleSheetWatcherFactory::GetInstance();
384 WebDataServiceFactory::GetInstance(); 390 WebDataServiceFactory::GetInstance();
385 391
386 built_factories_ = true; 392 built_factories_ = true;
387 } 393 }
388 394
389 void ProfileDependencyManager::BuildDestructionOrder(Profile* profile) { 395 #ifndef NDEBUG
390 #if !defined(NDEBUG) 396 void ProfileDependencyManager::DumpProfileDependencies(Profile* profile) {
391 // Whenever we try to build a destruction ordering, we should also dump a 397 // Whenever we try to build a destruction ordering, we should also dump a
392 // dependency graph to "/path/to/profile/profile-dependencies.dot". 398 // dependency graph to "/path/to/profile/profile-dependencies.dot".
393 if (CommandLine::ForCurrentProcess()->HasSwitch( 399 if (CommandLine::ForCurrentProcess()->HasSwitch(
394 switches::kDumpProfileDependencyGraph)) { 400 switches::kDumpProfileDependencyGraph)) {
395 base::FilePath dot_file = 401 base::FilePath dot_file =
396 profile->GetPath().AppendASCII("profile-dependencies.dot"); 402 profile->GetPath().AppendASCII("profile-dependencies.dot");
397 std::string contents = DumpGraphvizDependency(); 403 std::string contents = dependency_graph_.DumpAsGraphviz("Profile");
398 file_util::WriteFile(dot_file, contents.c_str(), contents.size()); 404 file_util::WriteFile(dot_file, contents.c_str(), contents.size());
399 } 405 }
406 }
400 #endif 407 #endif
401
402 // Step 1: Build a set of nodes with no incoming edges.
403 std::deque<ProfileKeyedBaseFactory*> queue;
404 std::copy(all_components_.begin(),
405 all_components_.end(),
406 std::back_inserter(queue));
407
408 std::deque<ProfileKeyedBaseFactory*>::iterator queue_end = queue.end();
409 for (EdgeMap::const_iterator it = edges_.begin();
410 it != edges_.end(); ++it) {
411 queue_end = std::remove(queue.begin(), queue_end, it->second);
412 }
413 queue.erase(queue_end, queue.end());
414
415 // Step 2: Do the Kahn topological sort.
416 std::vector<ProfileKeyedBaseFactory*> output;
417 EdgeMap edges(edges_);
418 while (!queue.empty()) {
419 ProfileKeyedBaseFactory* node = queue.front();
420 queue.pop_front();
421 output.push_back(node);
422
423 std::pair<EdgeMap::iterator, EdgeMap::iterator> range =
424 edges.equal_range(node);
425 EdgeMap::iterator it = range.first;
426 while (it != range.second) {
427 ProfileKeyedBaseFactory* dest = it->second;
428 EdgeMap::iterator temp = it;
429 it++;
430 edges.erase(temp);
431
432 bool has_incoming_edges = false;
433 for (EdgeMap::iterator jt = edges.begin(); jt != edges.end(); ++jt) {
434 if (jt->second == dest) {
435 has_incoming_edges = true;
436 break;
437 }
438 }
439
440 if (!has_incoming_edges)
441 queue.push_back(dest);
442 }
443 }
444
445 if (edges.size()) {
446 NOTREACHED() << "Dependency graph has a cycle. We are doomed.";
447 }
448
449 std::reverse(output.begin(), output.end());
450 destruction_order_ = output;
451 }
452
453 #if !defined(NDEBUG)
454
455 std::string ProfileDependencyManager::DumpGraphvizDependency() {
456 std::string result("digraph {\n");
457
458 // Make a copy of all components.
459 std::deque<ProfileKeyedBaseFactory*> components;
460 std::copy(all_components_.begin(),
461 all_components_.end(),
462 std::back_inserter(components));
463
464 // State all dependencies and remove |second| so we don't generate an
465 // implicit dependency on the Profile hard coded node.
466 std::deque<ProfileKeyedBaseFactory*>::iterator components_end =
467 components.end();
468 result.append(" /* Dependencies */\n");
469 for (EdgeMap::const_iterator it = edges_.begin(); it != edges_.end(); ++it) {
470 result.append(" ");
471 result.append(it->second->name());
472 result.append(" -> ");
473 result.append(it->first->name());
474 result.append(";\n");
475
476 components_end = std::remove(components.begin(), components_end,
477 it->second);
478 }
479 components.erase(components_end, components.end());
480
481 // Every node that doesn't depend on anything else will implicitly depend on
482 // the Profile.
483 result.append("\n /* Toplevel attachments */\n");
484 for (std::deque<ProfileKeyedBaseFactory*>::const_iterator it =
485 components.begin(); it != components.end(); ++it) {
486 result.append(" ");
487 result.append((*it)->name());
488 result.append(" -> Profile;\n");
489 }
490
491 result.append("\n /* Toplevel profile */\n");
492 result.append(" Profile [shape=box];\n");
493
494 result.append("}\n");
495 return result;
496 }
497
498 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698