OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/history/in_memory_url_index.h" | 5 #include "chrome/browser/history/in_memory_url_index.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
9 #include "chrome/browser/history/history_notifications.h" | 9 #include "chrome/browser/history/history_notifications.h" |
10 #include "chrome/browser/history/history_service_factory.h" | 10 #include "chrome/browser/history/history_service_factory.h" |
| 11 #include "chrome/browser/history/in_memory_url_cache_database.h" |
11 #include "chrome/browser/history/url_database.h" | 12 #include "chrome/browser/history/url_database.h" |
12 #include "chrome/browser/history/url_index_private_data.h" | 13 #include "chrome/browser/history/url_index_private_data.h" |
13 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
14 #include "chrome/common/chrome_notification_types.h" | 15 #include "chrome/common/chrome_notification_types.h" |
15 #include "chrome/common/url_constants.h" | |
16 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
17 #include "content/public/browser/notification_details.h" | 17 #include "content/public/browser/notification_details.h" |
18 #include "content/public/browser/notification_service.h" | 18 #include "content/public/browser/notification_service.h" |
19 #include "content/public/browser/notification_source.h" | 19 #include "content/public/browser/notification_source.h" |
20 | 20 |
21 using in_memory_url_index::InMemoryURLIndexCacheItem; | 21 using content::BrowserThread; |
22 | 22 |
23 namespace history { | 23 namespace history { |
24 | 24 |
25 // Called by DoSaveToCacheFile to delete any old cache file at |path| when | 25 // InMemoryURLIndex::Observer -------------------------------------------------- |
26 // there is no private data to save. Runs on the FILE thread. | 26 |
27 void DeleteCacheFile(const FilePath& path) { | 27 InMemoryURLIndex::Observer::Observer(InMemoryURLIndex* index) |
28 DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 28 : index_(index) { |
29 file_util::Delete(path, false); | 29 DCHECK(index); |
| 30 index_->AddObserver(this); |
30 } | 31 } |
31 | 32 |
32 // Initializes a whitelist of URL schemes. | 33 InMemoryURLIndex::Observer::~Observer() { |
33 void InitializeSchemeWhitelist(std::set<std::string>* whitelist) { | 34 index_->RemoveObserver(this); |
34 DCHECK(whitelist); | |
35 if (!whitelist->empty()) | |
36 return; // Nothing to do, already initialized. | |
37 whitelist->insert(std::string(chrome::kAboutScheme)); | |
38 whitelist->insert(std::string(chrome::kChromeUIScheme)); | |
39 whitelist->insert(std::string(chrome::kFileScheme)); | |
40 whitelist->insert(std::string(chrome::kFtpScheme)); | |
41 whitelist->insert(std::string(chrome::kHttpScheme)); | |
42 whitelist->insert(std::string(chrome::kHttpsScheme)); | |
43 whitelist->insert(std::string(chrome::kMailToScheme)); | |
44 } | 35 } |
45 | 36 |
46 // RefCountedBool -------------------------------------------------------------- | 37 void InMemoryURLIndex::Observer::Loaded() { |
47 | 38 MessageLoop::current()->QuitNow(); |
48 RefCountedBool::~RefCountedBool() {} | 39 } |
49 | |
50 // Restore/SaveCacheObserver --------------------------------------------------- | |
51 | |
52 InMemoryURLIndex::RestoreCacheObserver::~RestoreCacheObserver() {} | |
53 | |
54 InMemoryURLIndex::SaveCacheObserver::~SaveCacheObserver() {} | |
55 | 40 |
56 // RebuildPrivateDataFromHistoryDBTask ----------------------------------------- | 41 // RebuildPrivateDataFromHistoryDBTask ----------------------------------------- |
57 | 42 |
58 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: | 43 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: |
59 RebuildPrivateDataFromHistoryDBTask( | 44 RebuildPrivateDataFromHistoryDBTask(InMemoryURLIndex* index) |
60 InMemoryURLIndex* index, | |
61 const std::string& languages, | |
62 const std::set<std::string>& scheme_whitelist) | |
63 : index_(index), | 45 : index_(index), |
64 languages_(languages), | |
65 scheme_whitelist_(scheme_whitelist), | |
66 succeeded_(false) { | 46 succeeded_(false) { |
67 } | 47 } |
68 | 48 |
| 49 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: |
| 50 ~RebuildPrivateDataFromHistoryDBTask() { |
| 51 } |
| 52 |
69 bool InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask::RunOnDBThread( | 53 bool InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask::RunOnDBThread( |
70 HistoryBackend* backend, | 54 HistoryBackend* backend, |
71 HistoryDatabase* db) { | 55 HistoryDatabase* db) { |
72 data_ = URLIndexPrivateData::RebuildFromHistory(db, languages_, | 56 data_ = URLIndexPrivateData::RebuildFromHistory(db, index_->private_data()); |
73 scheme_whitelist_); | |
74 succeeded_ = data_.get() && !data_->Empty(); | 57 succeeded_ = data_.get() && !data_->Empty(); |
75 if (!succeeded_ && data_.get()) | |
76 data_->Clear(); | |
77 return true; | 58 return true; |
78 } | 59 } |
79 | 60 |
80 void InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: | 61 void InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: |
81 DoneRunOnMainThread() { | 62 DoneRunOnMainThread() { |
82 index_->DoneRebuidingPrivateDataFromHistoryDB(succeeded_, data_); | 63 index_->DoneRebuidingPrivateDataFromHistoryDB(succeeded_, data_); |
83 } | 64 } |
84 | 65 |
85 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: | 66 // IndexUpdateItem ------------------------------------------------------------- |
86 ~RebuildPrivateDataFromHistoryDBTask() { | 67 |
| 68 InMemoryURLIndex::IndexUpdateItem::IndexUpdateItem(UpdateType update_type, |
| 69 URLRow row) |
| 70 : update_type(update_type), |
| 71 row(row) { |
87 } | 72 } |
88 | 73 |
| 74 InMemoryURLIndex::IndexUpdateItem::~IndexUpdateItem() {} |
| 75 |
89 // InMemoryURLIndex ------------------------------------------------------------ | 76 // InMemoryURLIndex ------------------------------------------------------------ |
90 | 77 |
91 InMemoryURLIndex::InMemoryURLIndex(Profile* profile, | 78 InMemoryURLIndex::InMemoryURLIndex(Profile* profile, |
92 const FilePath& history_dir, | 79 const FilePath& history_dir, |
93 const std::string& languages) | 80 const std::string& languages) |
94 : profile_(profile), | 81 : profile_(profile), |
| 82 languages_(languages), |
95 history_dir_(history_dir), | 83 history_dir_(history_dir), |
96 languages_(languages), | 84 private_data_(new URLIndexPrivateData(history_dir, languages)), |
97 private_data_(new URLIndexPrivateData), | 85 sequence_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()), |
98 restore_cache_observer_(NULL), | 86 index_available_(false), |
99 save_cache_observer_(NULL), | |
100 shutdown_(false), | 87 shutdown_(false), |
101 needs_to_be_cached_(false) { | 88 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
102 InitializeSchemeWhitelist(&scheme_whitelist_); | |
103 if (profile) { | 89 if (profile) { |
104 // TODO(mrossetti): Register for language change notifications. | |
105 content::Source<Profile> source(profile); | 90 content::Source<Profile> source(profile); |
106 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source); | 91 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source); |
107 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, | 92 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, |
108 source); | 93 source); |
109 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source); | 94 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source); |
110 } | 95 } |
| 96 // Note: private_data_ will be reset after rebuilding from the history |
| 97 // database but the ownership of the database passes to the new |
| 98 // private_data_ instance so there is no need to re-register for the |
| 99 // following notification at that time. |
| 100 registrar_.Add(this, |
| 101 chrome::NOTIFICATION_IN_MEMORY_URL_CACHE_DATABASE_FAILURE, |
| 102 content::Source<InMemoryURLCacheDatabase>( |
| 103 private_data_->cache_db())); |
| 104 // TODO(mrossetti): Register for language change notifications. |
111 } | 105 } |
112 | 106 |
113 // Called only by unit tests. | 107 // Called only by unit tests. |
114 InMemoryURLIndex::InMemoryURLIndex() | 108 InMemoryURLIndex::InMemoryURLIndex(const FilePath& history_dir, |
| 109 const std::string& languages) |
115 : profile_(NULL), | 110 : profile_(NULL), |
116 private_data_(new URLIndexPrivateData), | 111 languages_(languages), |
117 restore_cache_observer_(NULL), | 112 history_dir_(history_dir), |
118 save_cache_observer_(NULL), | 113 index_available_(false), |
119 shutdown_(false), | 114 shutdown_(false), |
120 needs_to_be_cached_(false) { | 115 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
121 InitializeSchemeWhitelist(&scheme_whitelist_); | |
122 } | 116 } |
123 | 117 |
124 InMemoryURLIndex::~InMemoryURLIndex() { | 118 InMemoryURLIndex::~InMemoryURLIndex() {} |
125 // If there was a history directory (which there won't be for some unit tests) | 119 |
126 // then insure that the cache has already been saved. | 120 void InMemoryURLIndex::Init(bool disable_cache) { |
127 DCHECK(history_dir_.empty() || !needs_to_be_cached_); | 121 if (disable_cache) { |
| 122 RebuildFromHistoryIfLoaded(); |
| 123 } else { |
| 124 // It's safe to initialize the private data and the cache database without |
| 125 // using the sequenced worker pool as no other database operations will be |
| 126 // going on at the same time. |
| 127 BrowserThread::PostTaskAndReplyWithResult<bool>( |
| 128 BrowserThread::DB, FROM_HERE, |
| 129 base::Bind(&URLIndexPrivateData::Init, private_data_, sequence_token_), |
| 130 base::Bind(&InMemoryURLIndex::OnPrivateDataInitDone, |
| 131 weak_ptr_factory_.GetWeakPtr())); |
| 132 } |
128 } | 133 } |
129 | 134 |
130 void InMemoryURLIndex::Init() { | 135 void InMemoryURLIndex::OnPrivateDataInitDone(bool succeeded) { |
131 PostRestoreFromCacheFileTask(); | 136 if (shutdown_) |
| 137 return; |
| 138 if (succeeded) |
| 139 PostRestoreFromCacheTask(); |
| 140 else |
| 141 RebuildFromHistoryIfLoaded(); |
132 } | 142 } |
133 | 143 |
134 void InMemoryURLIndex::ShutDown() { | 144 void InMemoryURLIndex::Shutdown() { |
| 145 // Close down the cache database as quickly as possible. Any pending cache DB |
| 146 // transactions will detect that the database is no longer there and give up. |
135 registrar_.RemoveAll(); | 147 registrar_.RemoveAll(); |
136 cache_reader_consumer_.CancelAllRequests(); | 148 cache_reader_consumer_.CancelAllRequests(); |
137 shutdown_ = true; | 149 shutdown_ = true; |
138 FilePath path; | 150 private_data_->Shutdown(); |
139 if (!GetCacheFilePath(&path)) | |
140 return; | |
141 scoped_refptr<RefCountedBool> succeeded(new RefCountedBool(false)); | |
142 URLIndexPrivateData::WritePrivateDataToCacheFileTask( | |
143 private_data_, path, succeeded); | |
144 needs_to_be_cached_ = false; | |
145 } | 151 } |
146 | 152 |
147 void InMemoryURLIndex::ClearPrivateData() { | 153 void InMemoryURLIndex::AddObserver(InMemoryURLIndex::Observer* observer) { |
148 private_data_->Clear(); | 154 observers_.AddObserver(observer); |
149 } | 155 } |
150 | 156 |
151 bool InMemoryURLIndex::GetCacheFilePath(FilePath* file_path) { | 157 void InMemoryURLIndex::RemoveObserver(InMemoryURLIndex::Observer* observer) { |
152 if (history_dir_.empty()) | 158 observers_.RemoveObserver(observer); |
153 return false; | |
154 *file_path = history_dir_.Append(FILE_PATH_LITERAL("History Provider Cache")); | |
155 return true; | |
156 } | 159 } |
157 | 160 |
158 // Querying -------------------------------------------------------------------- | 161 // Querying -------------------------------------------------------------------- |
159 | 162 |
160 ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms( | 163 ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms( |
161 const string16& term_string) { | 164 const string16& term_string) { |
162 return private_data_->HistoryItemsForTerms(term_string); | 165 return private_data_->HistoryItemsForTerms(term_string); |
163 } | 166 } |
164 | 167 |
165 // Updating -------------------------------------------------------------------- | 168 // Updating -------------------------------------------------------------------- |
166 | 169 |
| 170 void InMemoryURLIndex::DeleteURL(const GURL& url) { |
| 171 private_data_->DeleteURL(url); |
| 172 } |
| 173 |
167 void InMemoryURLIndex::Observe(int notification_type, | 174 void InMemoryURLIndex::Observe(int notification_type, |
168 const content::NotificationSource& source, | 175 const content::NotificationSource& source, |
169 const content::NotificationDetails& details) { | 176 const content::NotificationDetails& details) { |
170 switch (notification_type) { | 177 switch (notification_type) { |
171 case chrome::NOTIFICATION_HISTORY_URL_VISITED: | 178 case chrome::NOTIFICATION_HISTORY_URL_VISITED: |
172 OnURLVisited(content::Details<URLVisitedDetails>(details).ptr()); | 179 OnURLVisited(content::Details<URLVisitedDetails>(details).ptr()); |
173 break; | 180 break; |
174 case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: | 181 case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: |
175 OnURLsModified( | 182 OnURLsModified( |
176 content::Details<history::URLsModifiedDetails>(details).ptr()); | 183 content::Details<history::URLsModifiedDetails>(details).ptr()); |
177 break; | 184 break; |
178 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: | 185 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: |
179 OnURLsDeleted( | 186 OnURLsDeleted( |
180 content::Details<history::URLsDeletedDetails>(details).ptr()); | 187 content::Details<history::URLsDeletedDetails>(details).ptr()); |
181 break; | 188 break; |
182 case chrome::NOTIFICATION_HISTORY_LOADED: | 189 case chrome::NOTIFICATION_HISTORY_LOADED: |
183 registrar_.Remove(this, chrome::NOTIFICATION_HISTORY_LOADED, | 190 registrar_.Remove(this, chrome::NOTIFICATION_HISTORY_LOADED, |
184 content::Source<Profile>(profile_)); | 191 content::Source<Profile>(profile_)); |
185 ScheduleRebuildFromHistory(); | 192 ScheduleRebuildFromHistory(); |
186 break; | 193 break; |
| 194 case chrome::NOTIFICATION_IN_MEMORY_URL_CACHE_DATABASE_FAILURE: |
| 195 RepairCacheDatabase(); |
| 196 break; |
187 default: | 197 default: |
188 // For simplicity, the unit tests send us all notifications, even when | 198 // For simplicity, the unit tests send us all notifications, even when |
189 // we haven't registered for them, so don't assert here. | 199 // we haven't registered for them, so don't assert here. |
190 break; | 200 break; |
191 } | 201 } |
192 } | 202 } |
193 | 203 |
194 void InMemoryURLIndex::OnURLVisited(const URLVisitedDetails* details) { | 204 void InMemoryURLIndex::OnURLVisited(const URLVisitedDetails* details) { |
195 needs_to_be_cached_ |= | 205 if (index_available_) |
196 private_data_->UpdateURL(details->row, languages_, scheme_whitelist_); | 206 private_data_->UpdateURL(details->row); |
| 207 else |
| 208 pending_updates_.push_back(IndexUpdateItem(UPDATE_VISIT, details->row)); |
197 } | 209 } |
198 | 210 |
199 void InMemoryURLIndex::OnURLsModified(const URLsModifiedDetails* details) { | 211 void InMemoryURLIndex::OnURLsModified(const URLsModifiedDetails* details) { |
200 for (URLRows::const_iterator row = details->changed_urls.begin(); | 212 for (URLRows::const_iterator row = details->changed_urls.begin(); |
201 row != details->changed_urls.end(); ++row) | 213 row != details->changed_urls.end(); ++row) { |
202 needs_to_be_cached_ |= | 214 if (index_available_) |
203 private_data_->UpdateURL(*row, languages_, scheme_whitelist_); | 215 private_data_->UpdateURL(*row); |
| 216 else |
| 217 pending_updates_.push_back(IndexUpdateItem(UPDATE_VISIT, *row)); |
| 218 } |
204 } | 219 } |
205 | 220 |
206 void InMemoryURLIndex::OnURLsDeleted(const URLsDeletedDetails* details) { | 221 void InMemoryURLIndex::OnURLsDeleted(const URLsDeletedDetails* details) { |
207 if (details->all_history) { | 222 if (details->all_history) { |
208 ClearPrivateData(); | 223 PostResetPrivateDataTask(); |
209 needs_to_be_cached_ = true; | |
210 } else { | 224 } else { |
211 for (URLRows::const_iterator row = details->rows.begin(); | 225 for (URLRows::const_iterator row = details->rows.begin(); |
212 row != details->rows.end(); ++row) | 226 row != details->rows.end(); ++row) { |
213 needs_to_be_cached_ |= private_data_->DeleteURL(row->url()); | 227 if (index_available_) |
| 228 DeleteURL(row->url()); |
| 229 else |
| 230 pending_updates_.push_back(IndexUpdateItem(DELETE_VISIT, *row)); |
| 231 } |
214 } | 232 } |
215 } | 233 } |
216 | 234 |
| 235 void InMemoryURLIndex::FlushPendingUpdates() { |
| 236 for (PendingUpdates::iterator i = pending_updates_.begin(); |
| 237 i != pending_updates_.end(); ++i) { |
| 238 if (i->update_type == UPDATE_VISIT) |
| 239 private_data_->UpdateURL(i->row); |
| 240 else if (i->update_type == DELETE_VISIT) |
| 241 DeleteURL(i->row.url()); |
| 242 } |
| 243 pending_updates_.clear(); |
| 244 } |
| 245 |
217 // Restoring from Cache -------------------------------------------------------- | 246 // Restoring from Cache -------------------------------------------------------- |
218 | 247 |
219 void InMemoryURLIndex::PostRestoreFromCacheFileTask() { | 248 void InMemoryURLIndex::PostRestoreFromCacheTask() { |
220 FilePath path; | 249 // It's safe to restore from the cache database without using the sequenced |
221 if (!GetCacheFilePath(&path) || shutdown_) | 250 // worker pool as no other database operations will be going on at the same |
222 return; | 251 // time. |
223 scoped_refptr<URLIndexPrivateData> restored_private_data = | 252 BrowserThread::PostTaskAndReplyWithResult<bool>( |
224 new URLIndexPrivateData; | 253 BrowserThread::DB, FROM_HERE, |
225 content::BrowserThread::PostTaskAndReply( | 254 base::Bind(&URLIndexPrivateData::RestoreFromCacheTask, private_data_), |
226 content::BrowserThread::FILE, FROM_HERE, | 255 base::Bind(&InMemoryURLIndex::OnCacheRestoreDone, |
227 base::Bind(&URLIndexPrivateData::RestoreFromFileTask, path, | 256 weak_ptr_factory_.GetWeakPtr())); |
228 restored_private_data, languages_), | |
229 base::Bind(&InMemoryURLIndex::OnCacheLoadDone, AsWeakPtr(), | |
230 restored_private_data)); | |
231 } | 257 } |
232 | 258 |
233 void InMemoryURLIndex::OnCacheLoadDone( | 259 void InMemoryURLIndex::OnCacheRestoreDone(bool succeeded) { |
234 scoped_refptr<URLIndexPrivateData> private_data) { | 260 if (shutdown_) { |
235 if (private_data.get() && !private_data->Empty()) { | 261 NotifyHasLoaded(); |
236 private_data_ = private_data; | 262 return; |
237 if (restore_cache_observer_) | 263 } |
238 restore_cache_observer_->OnCacheRestoreFinished(true); | 264 if (succeeded) { |
| 265 FlushPendingUpdates(); |
| 266 index_available_ = true; |
| 267 NotifyHasLoaded(); |
239 } else if (profile_) { | 268 } else if (profile_) { |
240 // When unable to restore from the cache file delete the cache file, if | 269 RebuildFromHistoryIfLoaded(); |
241 // it exists, and then rebuild from the history database if it's available, | |
242 // otherwise wait until the history database loaded and then rebuild. | |
243 FilePath path; | |
244 if (!GetCacheFilePath(&path) || shutdown_) | |
245 return; | |
246 content::BrowserThread::PostBlockingPoolTask( | |
247 FROM_HERE, base::Bind(DeleteCacheFile, path)); | |
248 HistoryService* service = | |
249 HistoryServiceFactory::GetForProfileWithoutCreating(profile_); | |
250 if (service && service->backend_loaded()) { | |
251 ScheduleRebuildFromHistory(); | |
252 } else { | |
253 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_LOADED, | |
254 content::Source<Profile>(profile_)); | |
255 } | |
256 } | 270 } |
257 } | 271 } |
258 | 272 |
| 273 void InMemoryURLIndex::NotifyHasLoaded() { |
| 274 FOR_EACH_OBSERVER(InMemoryURLIndex::Observer, observers_, Loaded()); |
| 275 } |
| 276 |
259 // Restoring from the History DB ----------------------------------------------- | 277 // Restoring from the History DB ----------------------------------------------- |
260 | 278 |
| 279 void InMemoryURLIndex::RebuildFromHistoryIfLoaded() { |
| 280 // When unable to restore from the cache database, rebuild from the history |
| 281 // database, if it's available, otherwise wait until the history database |
| 282 // has loaded and then rebuild the index. |
| 283 HistoryService* service = |
| 284 HistoryServiceFactory::GetForProfileIfExists(profile_, |
| 285 Profile::EXPLICIT_ACCESS); |
| 286 if (service && service->backend_loaded()) { |
| 287 ScheduleRebuildFromHistory(); |
| 288 } else { |
| 289 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_LOADED, |
| 290 content::Source<Profile>(profile_)); |
| 291 } |
| 292 } |
| 293 |
261 void InMemoryURLIndex::ScheduleRebuildFromHistory() { | 294 void InMemoryURLIndex::ScheduleRebuildFromHistory() { |
| 295 // It's possible that we were waiting on history to finish loading when |
| 296 // the profile was told to shut down. |
| 297 if (shutdown_) |
| 298 return; |
| 299 // Reset availability here as this function is called directly by unit tests. |
| 300 index_available_ = false; |
262 HistoryService* service = | 301 HistoryService* service = |
263 HistoryServiceFactory::GetForProfile(profile_, | 302 HistoryServiceFactory::GetForProfile(profile_, |
264 Profile::EXPLICIT_ACCESS); | 303 Profile::EXPLICIT_ACCESS); |
| 304 // Do not update the cache database while rebuilding. |
| 305 private_data_->set_cache_enabled(false); |
265 service->ScheduleDBTask( | 306 service->ScheduleDBTask( |
266 new InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask( | 307 new InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask(this), |
267 this, languages_, scheme_whitelist_), | |
268 &cache_reader_consumer_); | 308 &cache_reader_consumer_); |
269 } | 309 } |
270 | 310 |
271 void InMemoryURLIndex::DoneRebuidingPrivateDataFromHistoryDB( | 311 void InMemoryURLIndex::DoneRebuidingPrivateDataFromHistoryDB( |
272 bool succeeded, | 312 bool succeeded, |
273 scoped_refptr<URLIndexPrivateData> private_data) { | 313 scoped_refptr<URLIndexPrivateData> private_data) { |
274 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 314 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) || |
| 315 BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 316 if (shutdown_) |
| 317 return; |
275 if (succeeded) { | 318 if (succeeded) { |
276 private_data_ = private_data; | 319 private_data_ = private_data; |
277 PostSaveToCacheFileTask(); // Cache the newly rebuilt index. | 320 private_data_->set_cache_enabled(true); |
| 321 PostRefreshCacheTask(); // Cache the newly rebuilt index. |
278 } else { | 322 } else { |
279 private_data_->Clear(); // Dump the old private data. | 323 private_data_->set_cache_enabled(true); |
280 // There is no need to do anything with the cache file as it was deleted | 324 PostResetPrivateDataTask(); |
281 // when the rebuild from the history operation was kicked off. | |
282 } | |
283 if (restore_cache_observer_) | |
284 restore_cache_observer_->OnCacheRestoreFinished(succeeded); | |
285 } | |
286 | |
287 void InMemoryURLIndex::RebuildFromHistory(HistoryDatabase* history_db) { | |
288 private_data_ = URLIndexPrivateData::RebuildFromHistory(history_db, | |
289 languages_, | |
290 scheme_whitelist_); | |
291 } | |
292 | |
293 // Saving to Cache ------------------------------------------------------------- | |
294 | |
295 void InMemoryURLIndex::PostSaveToCacheFileTask() { | |
296 FilePath path; | |
297 if (!GetCacheFilePath(&path)) | |
298 return; | |
299 // If there is anything in our private data then make a copy of it and tell | |
300 // it to save itself to a file. | |
301 if (private_data_.get() && !private_data_->Empty()) { | |
302 // Note that ownership of the copy of our private data is passed to the | |
303 // completion closure below. | |
304 scoped_refptr<URLIndexPrivateData> private_data_copy = | |
305 private_data_->Duplicate(); | |
306 scoped_refptr<RefCountedBool> succeeded(new RefCountedBool(false)); | |
307 content::BrowserThread::PostTaskAndReply( | |
308 content::BrowserThread::FILE, FROM_HERE, | |
309 base::Bind(&URLIndexPrivateData::WritePrivateDataToCacheFileTask, | |
310 private_data_copy, path, succeeded), | |
311 base::Bind(&InMemoryURLIndex::OnCacheSaveDone, AsWeakPtr(), succeeded)); | |
312 } else { | |
313 // If there is no data in our index then delete any existing cache file. | |
314 content::BrowserThread::PostBlockingPoolTask( | |
315 FROM_HERE, | |
316 base::Bind(DeleteCacheFile, path)); | |
317 } | 325 } |
318 } | 326 } |
319 | 327 |
320 void InMemoryURLIndex::OnCacheSaveDone( | 328 // Reset Cache ----------------------------------------------------------------- |
321 scoped_refptr<RefCountedBool> succeeded) { | 329 |
322 if (save_cache_observer_) | 330 void InMemoryURLIndex::PostResetPrivateDataTask() { |
323 save_cache_observer_->OnCacheSaveFinished(succeeded->value()); | 331 index_available_ = false; |
| 332 scoped_refptr<base::SequencedTaskRunner> runner = |
| 333 BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(sequence_token_); |
| 334 DCHECK(runner.get()); |
| 335 runner->PostTaskAndReply(FROM_HERE, |
| 336 base::Bind(&URLIndexPrivateData::Reset, private_data_), |
| 337 base::Bind(&InMemoryURLIndex::OnCacheRefreshOrResetDone, |
| 338 weak_ptr_factory_.GetWeakPtr())); |
| 339 } |
| 340 |
| 341 // Refresh Cache --------------------------------------------------------------- |
| 342 |
| 343 void InMemoryURLIndex::PostRefreshCacheTask() { |
| 344 scoped_refptr<base::SequencedTaskRunner> runner = |
| 345 BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(sequence_token_); |
| 346 DCHECK(runner.get()); |
| 347 runner->PostTaskAndReply(FROM_HERE, |
| 348 base::Bind(&URLIndexPrivateData::RefreshCacheTask, private_data_), |
| 349 base::Bind(&InMemoryURLIndex::OnCacheRefreshOrResetDone, |
| 350 weak_ptr_factory_.GetWeakPtr())); |
| 351 } |
| 352 |
| 353 void InMemoryURLIndex::OnCacheRefreshOrResetDone() { |
| 354 if (shutdown_) { |
| 355 NotifyHasLoaded(); |
| 356 return; |
| 357 } |
| 358 FlushPendingUpdates(); |
| 359 index_available_ = true; |
| 360 NotifyHasLoaded(); |
| 361 } |
| 362 |
| 363 // Repair Cache ---------------------------------------------------------------- |
| 364 |
| 365 void InMemoryURLIndex::RepairCacheDatabase() { |
| 366 // The database will disable itself when it detects an error so re-enable the |
| 367 // database and try to refresh it from scratch. If that fails then the |
| 368 // database will be left in a disabled state and will be rebuilt from the |
| 369 // history database the next time the profile is opened. |
| 370 private_data_->set_cache_enabled(true); |
| 371 PostRefreshCacheTask(); // Cache the newly rebuilt index. |
324 } | 372 } |
325 | 373 |
326 } // namespace history | 374 } // namespace history |
OLD | NEW |