Index: chrome/browser/profile.cc |
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc |
index 111029baf47f2fb5a0d2bf6cad94a8c9a5f2788a..e61ae5a173506fa22a9e78f4482a30762c181f5b 100644 |
--- a/chrome/browser/profile.cc |
+++ b/chrome/browser/profile.cc |
@@ -125,6 +125,87 @@ bool HasACacheSubdir(const FilePath &dir) { |
} // namespace |
+// This helper class owns the VisitedLinkMaster and exposes a way to load it |
+// from on the file thread. |
+class VisitedLinkCreator |
+ : public base::RefCountedThreadSafe<VisitedLinkCreator> { |
+ public: |
+ enum LoadState { |
+ NOT_LOADED, |
+ FILE_LOAD_FAILED, |
+ LOAD_FINISHED |
+ }; |
+ |
+ explicit VisitedLinkCreator(Profile* profile) |
+ : listener_(new VisitedLinkEventListener()), |
+ profile_(profile), |
+ load_state_(NOT_LOADED) { |
+ visited_link_master_.reset(new VisitedLinkMaster(listener_.get(), |
+ profile_)); |
+ } |
+ |
+ // Preload the visited link master on the file thread. |
+ void Preload() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, NewRunnableMethod( |
+ this, &VisitedLinkCreator::LoadBackground)); |
+ } |
+ |
+ // This method can return NULL if for some reason we can't initialize the |
+ // visited link master. |
+ VisitedLinkMaster* GetMaster() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+ // Go ahead and try to load the VisitedLink table. If the data was |
+ // preloaded, Load() does nothing. |
+ AutoLock l(lock_); |
+ if (LOAD_FINISHED != load_state_) { |
+ bool success = false; |
+ if (FILE_LOAD_FAILED == load_state_) { |
+ success = visited_link_master_->InitFromScratch(); |
+ } else if (NOT_LOADED == load_state_) { |
+ // We haven't tried to load from file yet, so go ahead and do that. |
+ success = visited_link_master_->Init(); |
+ } |
+ |
+ if (!success) { |
+ NOTREACHED() << "Failed to init visited link master."; |
+ visited_link_master_.reset(); |
+ } |
+ load_state_ = LOAD_FINISHED; |
+ } |
+ |
+ // We don't need to lock here because after Load() has been called, we |
+ // never change vistied_link_master_. |
+ return visited_link_master_.get(); |
+ } |
+ |
+ private: |
+ // Tries to load the visited link database from the UI thread. |
+ void LoadBackground() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
+ AutoLock l(lock_); |
+ if (NOT_LOADED != load_state_) |
+ return; |
+ |
+ // We only want to try to load the data from a file (it's not thread safe |
+ // to InitFromScratch on the file thread). |
+ load_state_ = visited_link_master_->InitFromFile() ? LOAD_FINISHED |
+ : FILE_LOAD_FAILED; |
+ } |
+ |
+ scoped_ptr<VisitedLinkMaster::Listener> listener_; |
+ Profile* profile_; |
+ |
+ // This lock protects visited_link_master_ and load_state_. |
+ Lock lock_; |
+ scoped_ptr<VisitedLinkMaster> visited_link_master_; |
+ // Once created_ is true, we can stop trying to create and init the |
+ // VisitedLinkMaster. |
+ LoadState load_state_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(VisitedLinkCreator); |
+}; |
+ |
// A pointer to the request context for the default profile. See comments on |
// Profile::GetDefaultRequestContext. |
URLRequestContextGetter* Profile::default_request_context_; |
@@ -214,7 +295,9 @@ class OffTheRecordProfileImpl : public Profile, |
return reinterpret_cast<ProfileId>(this); |
} |
- virtual FilePath GetPath() { return profile_->GetPath(); } |
+ virtual FilePath GetPath() { |
+ return profile_->GetPath(); |
+ } |
virtual bool IsOffTheRecord() { |
return true; |
@@ -245,6 +328,8 @@ class OffTheRecordProfileImpl : public Profile, |
return NULL; |
} |
+ virtual void PreloadVisitedLinkMaster() {} |
+ |
virtual ExtensionsService* GetExtensionsService() { |
return NULL; |
} |
@@ -567,7 +652,6 @@ class OffTheRecordProfileImpl : public Profile, |
ProfileImpl::ProfileImpl(const FilePath& path) |
: path_(path), |
- visited_link_event_listener_(new VisitedLinkEventListener()), |
extension_devtools_manager_(NULL), |
request_context_(NULL), |
media_request_context_(NULL), |
@@ -814,15 +898,16 @@ webkit_database::DatabaseTracker* ProfileImpl::GetDatabaseTracker() { |
} |
VisitedLinkMaster* ProfileImpl::GetVisitedLinkMaster() { |
- if (!visited_link_master_.get()) { |
- scoped_ptr<VisitedLinkMaster> visited_links( |
- new VisitedLinkMaster(visited_link_event_listener_.get(), this)); |
- if (!visited_links->Init()) |
- return NULL; |
- visited_link_master_.swap(visited_links); |
- } |
+ if (!visited_link_creator_.get()) |
+ visited_link_creator_ = new VisitedLinkCreator(this); |
+ return visited_link_creator_->GetMaster(); |
+} |
- return visited_link_master_.get(); |
+void ProfileImpl::PreloadVisitedLinkMaster() { |
+ if (!visited_link_creator_.get()) { |
+ visited_link_creator_ = new VisitedLinkCreator(this); |
+ visited_link_creator_->Preload(); |
+ } |
} |
ExtensionsService* ProfileImpl::GetExtensionsService() { |