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

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

Powered by Google App Engine
This is Rietveld 408576698