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" | |
12 #include "chrome/browser/history/url_database.h" | 11 #include "chrome/browser/history/url_database.h" |
13 #include "chrome/browser/history/url_index_private_data.h" | 12 #include "chrome/browser/history/url_index_private_data.h" |
14 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
15 #include "chrome/common/chrome_notification_types.h" | 14 #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 content::BrowserThread; | 21 using in_memory_url_index::InMemoryURLIndexCacheItem; |
22 | 22 |
23 namespace history { | 23 namespace history { |
24 | 24 |
25 // InMemoryURLIndex::Observer -------------------------------------------------- | 25 // Called by DoSaveToCacheFile to delete any old cache file at |path| when |
26 | 26 // there is no private data to save. Runs on the FILE thread. |
27 InMemoryURLIndex::Observer::Observer(InMemoryURLIndex* index) | 27 void DeleteCacheFile(const FilePath& path) { |
28 : index_(index) { | 28 DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
29 DCHECK(index); | 29 file_util::Delete(path, false); |
30 index_->AddObserver(this); | |
31 } | 30 } |
32 | 31 |
33 InMemoryURLIndex::Observer::~Observer() { | 32 // Initializes a whitelist of URL schemes. |
34 index_->RemoveObserver(this); | 33 void InitializeSchemeWhitelist(std::set<std::string>* whitelist) { |
| 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)); |
35 } | 44 } |
36 | 45 |
37 void InMemoryURLIndex::Observer::Loaded() { | 46 // RefCountedBool -------------------------------------------------------------- |
38 MessageLoop::current()->QuitNow(); | 47 |
39 } | 48 RefCountedBool::~RefCountedBool() {} |
| 49 |
| 50 // Restore/SaveCacheObserver --------------------------------------------------- |
| 51 |
| 52 InMemoryURLIndex::RestoreCacheObserver::~RestoreCacheObserver() {} |
| 53 |
| 54 InMemoryURLIndex::SaveCacheObserver::~SaveCacheObserver() {} |
40 | 55 |
41 // RebuildPrivateDataFromHistoryDBTask ----------------------------------------- | 56 // RebuildPrivateDataFromHistoryDBTask ----------------------------------------- |
42 | 57 |
43 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: | 58 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: |
44 RebuildPrivateDataFromHistoryDBTask(InMemoryURLIndex* index) | 59 RebuildPrivateDataFromHistoryDBTask( |
| 60 InMemoryURLIndex* index, |
| 61 const std::string& languages, |
| 62 const std::set<std::string>& scheme_whitelist) |
45 : index_(index), | 63 : index_(index), |
| 64 languages_(languages), |
| 65 scheme_whitelist_(scheme_whitelist), |
46 succeeded_(false) { | 66 succeeded_(false) { |
47 } | 67 } |
48 | 68 |
49 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: | |
50 ~RebuildPrivateDataFromHistoryDBTask() { | |
51 } | |
52 | |
53 bool InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask::RunOnDBThread( | 69 bool InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask::RunOnDBThread( |
54 HistoryBackend* backend, | 70 HistoryBackend* backend, |
55 HistoryDatabase* db) { | 71 HistoryDatabase* db) { |
56 data_ = URLIndexPrivateData::RebuildFromHistory(db, index_->private_data()); | 72 data_ = URLIndexPrivateData::RebuildFromHistory(db, languages_, |
| 73 scheme_whitelist_); |
57 succeeded_ = data_.get() && !data_->Empty(); | 74 succeeded_ = data_.get() && !data_->Empty(); |
| 75 if (!succeeded_ && data_.get()) |
| 76 data_->Clear(); |
58 return true; | 77 return true; |
59 } | 78 } |
60 | 79 |
61 void InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: | 80 void InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: |
62 DoneRunOnMainThread() { | 81 DoneRunOnMainThread() { |
63 index_->DoneRebuidingPrivateDataFromHistoryDB(succeeded_, data_); | 82 index_->DoneRebuidingPrivateDataFromHistoryDB(succeeded_, data_); |
64 } | 83 } |
65 | 84 |
66 // IndexUpdateItem ------------------------------------------------------------- | 85 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: |
67 | 86 ~RebuildPrivateDataFromHistoryDBTask() { |
68 InMemoryURLIndex::IndexUpdateItem::IndexUpdateItem(UpdateType update_type, | |
69 URLRow row) | |
70 : update_type(update_type), | |
71 row(row) { | |
72 } | 87 } |
73 | 88 |
74 InMemoryURLIndex::IndexUpdateItem::~IndexUpdateItem() {} | |
75 | |
76 // InMemoryURLIndex ------------------------------------------------------------ | 89 // InMemoryURLIndex ------------------------------------------------------------ |
77 | 90 |
78 InMemoryURLIndex::InMemoryURLIndex(Profile* profile, | 91 InMemoryURLIndex::InMemoryURLIndex(Profile* profile, |
79 const FilePath& history_dir, | 92 const FilePath& history_dir, |
80 const std::string& languages) | 93 const std::string& languages) |
81 : profile_(profile), | 94 : profile_(profile), |
| 95 history_dir_(history_dir), |
82 languages_(languages), | 96 languages_(languages), |
83 history_dir_(history_dir), | 97 private_data_(new URLIndexPrivateData), |
84 private_data_(new URLIndexPrivateData(history_dir, languages)), | 98 restore_cache_observer_(NULL), |
85 sequence_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()), | 99 save_cache_observer_(NULL), |
86 index_available_(false), | |
87 shutdown_(false), | 100 shutdown_(false), |
88 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 101 needs_to_be_cached_(false) { |
| 102 InitializeSchemeWhitelist(&scheme_whitelist_); |
89 if (profile) { | 103 if (profile) { |
| 104 // TODO(mrossetti): Register for language change notifications. |
90 content::Source<Profile> source(profile); | 105 content::Source<Profile> source(profile); |
91 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source); | 106 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source); |
92 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, | 107 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, |
93 source); | 108 source); |
94 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source); | 109 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source); |
95 } | 110 } |
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. | |
105 } | 111 } |
106 | 112 |
107 // Called only by unit tests. | 113 // Called only by unit tests. |
108 InMemoryURLIndex::InMemoryURLIndex(const FilePath& history_dir, | 114 InMemoryURLIndex::InMemoryURLIndex() |
109 const std::string& languages) | |
110 : profile_(NULL), | 115 : profile_(NULL), |
111 languages_(languages), | 116 private_data_(new URLIndexPrivateData), |
112 history_dir_(history_dir), | 117 restore_cache_observer_(NULL), |
113 index_available_(false), | 118 save_cache_observer_(NULL), |
114 shutdown_(false), | 119 shutdown_(false), |
115 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 120 needs_to_be_cached_(false) { |
| 121 InitializeSchemeWhitelist(&scheme_whitelist_); |
116 } | 122 } |
117 | 123 |
118 InMemoryURLIndex::~InMemoryURLIndex() {} | 124 InMemoryURLIndex::~InMemoryURLIndex() { |
119 | 125 // If there was a history directory (which there won't be for some unit tests) |
120 void InMemoryURLIndex::Init(bool disable_cache) { | 126 // then insure that the cache has already been saved. |
121 if (disable_cache) { | 127 DCHECK(history_dir_.empty() || !needs_to_be_cached_); |
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 } | |
133 } | 128 } |
134 | 129 |
135 void InMemoryURLIndex::OnPrivateDataInitDone(bool succeeded) { | 130 void InMemoryURLIndex::Init() { |
136 if (shutdown_) | 131 PostRestoreFromCacheFileTask(); |
137 return; | |
138 if (succeeded) | |
139 PostRestoreFromCacheTask(); | |
140 else | |
141 RebuildFromHistoryIfLoaded(); | |
142 } | 132 } |
143 | 133 |
144 void InMemoryURLIndex::Shutdown() { | 134 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. | |
147 registrar_.RemoveAll(); | 135 registrar_.RemoveAll(); |
148 cache_reader_consumer_.CancelAllRequests(); | 136 cache_reader_consumer_.CancelAllRequests(); |
149 shutdown_ = true; | 137 shutdown_ = true; |
150 private_data_->Shutdown(); | 138 FilePath path; |
| 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; |
151 } | 145 } |
152 | 146 |
153 void InMemoryURLIndex::AddObserver(InMemoryURLIndex::Observer* observer) { | 147 void InMemoryURLIndex::ClearPrivateData() { |
154 observers_.AddObserver(observer); | 148 private_data_->Clear(); |
155 } | 149 } |
156 | 150 |
157 void InMemoryURLIndex::RemoveObserver(InMemoryURLIndex::Observer* observer) { | 151 bool InMemoryURLIndex::GetCacheFilePath(FilePath* file_path) { |
158 observers_.RemoveObserver(observer); | 152 if (history_dir_.empty()) |
| 153 return false; |
| 154 *file_path = history_dir_.Append(FILE_PATH_LITERAL("History Provider Cache")); |
| 155 return true; |
159 } | 156 } |
160 | 157 |
161 // Querying -------------------------------------------------------------------- | 158 // Querying -------------------------------------------------------------------- |
162 | 159 |
163 ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms( | 160 ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms( |
164 const string16& term_string) { | 161 const string16& term_string) { |
165 return private_data_->HistoryItemsForTerms(term_string); | 162 return private_data_->HistoryItemsForTerms(term_string); |
166 } | 163 } |
167 | 164 |
168 // Updating -------------------------------------------------------------------- | 165 // Updating -------------------------------------------------------------------- |
169 | 166 |
170 void InMemoryURLIndex::DeleteURL(const GURL& url) { | |
171 private_data_->DeleteURL(url); | |
172 } | |
173 | |
174 void InMemoryURLIndex::Observe(int notification_type, | 167 void InMemoryURLIndex::Observe(int notification_type, |
175 const content::NotificationSource& source, | 168 const content::NotificationSource& source, |
176 const content::NotificationDetails& details) { | 169 const content::NotificationDetails& details) { |
177 switch (notification_type) { | 170 switch (notification_type) { |
178 case chrome::NOTIFICATION_HISTORY_URL_VISITED: | 171 case chrome::NOTIFICATION_HISTORY_URL_VISITED: |
179 OnURLVisited(content::Details<URLVisitedDetails>(details).ptr()); | 172 OnURLVisited(content::Details<URLVisitedDetails>(details).ptr()); |
180 break; | 173 break; |
181 case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: | 174 case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: |
182 OnURLsModified( | 175 OnURLsModified( |
183 content::Details<history::URLsModifiedDetails>(details).ptr()); | 176 content::Details<history::URLsModifiedDetails>(details).ptr()); |
184 break; | 177 break; |
185 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: | 178 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: |
186 OnURLsDeleted( | 179 OnURLsDeleted( |
187 content::Details<history::URLsDeletedDetails>(details).ptr()); | 180 content::Details<history::URLsDeletedDetails>(details).ptr()); |
188 break; | 181 break; |
189 case chrome::NOTIFICATION_HISTORY_LOADED: | 182 case chrome::NOTIFICATION_HISTORY_LOADED: |
190 registrar_.Remove(this, chrome::NOTIFICATION_HISTORY_LOADED, | 183 registrar_.Remove(this, chrome::NOTIFICATION_HISTORY_LOADED, |
191 content::Source<Profile>(profile_)); | 184 content::Source<Profile>(profile_)); |
192 ScheduleRebuildFromHistory(); | 185 ScheduleRebuildFromHistory(); |
193 break; | 186 break; |
194 case chrome::NOTIFICATION_IN_MEMORY_URL_CACHE_DATABASE_FAILURE: | |
195 RepairCacheDatabase(); | |
196 break; | |
197 default: | 187 default: |
198 // For simplicity, the unit tests send us all notifications, even when | 188 // For simplicity, the unit tests send us all notifications, even when |
199 // we haven't registered for them, so don't assert here. | 189 // we haven't registered for them, so don't assert here. |
200 break; | 190 break; |
201 } | 191 } |
202 } | 192 } |
203 | 193 |
204 void InMemoryURLIndex::OnURLVisited(const URLVisitedDetails* details) { | 194 void InMemoryURLIndex::OnURLVisited(const URLVisitedDetails* details) { |
205 if (index_available_) | 195 needs_to_be_cached_ |= |
206 private_data_->UpdateURL(details->row); | 196 private_data_->UpdateURL(details->row, languages_, scheme_whitelist_); |
207 else | |
208 pending_updates_.push_back(IndexUpdateItem(UPDATE_VISIT, details->row)); | |
209 } | 197 } |
210 | 198 |
211 void InMemoryURLIndex::OnURLsModified(const URLsModifiedDetails* details) { | 199 void InMemoryURLIndex::OnURLsModified(const URLsModifiedDetails* details) { |
212 for (URLRows::const_iterator row = details->changed_urls.begin(); | 200 for (URLRows::const_iterator row = details->changed_urls.begin(); |
213 row != details->changed_urls.end(); ++row) { | 201 row != details->changed_urls.end(); ++row) |
214 if (index_available_) | 202 needs_to_be_cached_ |= |
215 private_data_->UpdateURL(*row); | 203 private_data_->UpdateURL(*row, languages_, scheme_whitelist_); |
216 else | |
217 pending_updates_.push_back(IndexUpdateItem(UPDATE_VISIT, *row)); | |
218 } | |
219 } | 204 } |
220 | 205 |
221 void InMemoryURLIndex::OnURLsDeleted(const URLsDeletedDetails* details) { | 206 void InMemoryURLIndex::OnURLsDeleted(const URLsDeletedDetails* details) { |
222 if (details->all_history) { | 207 if (details->all_history) { |
223 PostResetPrivateDataTask(); | 208 ClearPrivateData(); |
| 209 needs_to_be_cached_ = true; |
224 } else { | 210 } else { |
225 for (URLRows::const_iterator row = details->rows.begin(); | 211 for (URLRows::const_iterator row = details->rows.begin(); |
226 row != details->rows.end(); ++row) { | 212 row != details->rows.end(); ++row) |
227 if (index_available_) | 213 needs_to_be_cached_ |= private_data_->DeleteURL(row->url()); |
228 DeleteURL(row->url()); | 214 } |
229 else | 215 } |
230 pending_updates_.push_back(IndexUpdateItem(DELETE_VISIT, *row)); | 216 |
| 217 // Restoring from Cache -------------------------------------------------------- |
| 218 |
| 219 void InMemoryURLIndex::PostRestoreFromCacheFileTask() { |
| 220 FilePath path; |
| 221 if (!GetCacheFilePath(&path) || shutdown_) |
| 222 return; |
| 223 scoped_refptr<URLIndexPrivateData> restored_private_data = |
| 224 new URLIndexPrivateData; |
| 225 content::BrowserThread::PostTaskAndReply( |
| 226 content::BrowserThread::FILE, FROM_HERE, |
| 227 base::Bind(&URLIndexPrivateData::RestoreFromFileTask, path, |
| 228 restored_private_data, languages_), |
| 229 base::Bind(&InMemoryURLIndex::OnCacheLoadDone, AsWeakPtr(), |
| 230 restored_private_data)); |
| 231 } |
| 232 |
| 233 void InMemoryURLIndex::OnCacheLoadDone( |
| 234 scoped_refptr<URLIndexPrivateData> private_data) { |
| 235 if (private_data.get() && !private_data->Empty()) { |
| 236 private_data_ = private_data; |
| 237 if (restore_cache_observer_) |
| 238 restore_cache_observer_->OnCacheRestoreFinished(true); |
| 239 } else if (profile_) { |
| 240 // When unable to restore from the cache file delete the cache file, if |
| 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_)); |
231 } | 255 } |
232 } | 256 } |
233 } | 257 } |
234 | 258 |
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 | |
246 // Restoring from Cache -------------------------------------------------------- | |
247 | |
248 void InMemoryURLIndex::PostRestoreFromCacheTask() { | |
249 // It's safe to restore from the cache database without using the sequenced | |
250 // worker pool as no other database operations will be going on at the same | |
251 // time. | |
252 BrowserThread::PostTaskAndReplyWithResult<bool>( | |
253 BrowserThread::DB, FROM_HERE, | |
254 base::Bind(&URLIndexPrivateData::RestoreFromCacheTask, private_data_), | |
255 base::Bind(&InMemoryURLIndex::OnCacheRestoreDone, | |
256 weak_ptr_factory_.GetWeakPtr())); | |
257 } | |
258 | |
259 void InMemoryURLIndex::OnCacheRestoreDone(bool succeeded) { | |
260 if (shutdown_) { | |
261 NotifyHasLoaded(); | |
262 return; | |
263 } | |
264 if (succeeded) { | |
265 FlushPendingUpdates(); | |
266 index_available_ = true; | |
267 NotifyHasLoaded(); | |
268 } else if (profile_) { | |
269 RebuildFromHistoryIfLoaded(); | |
270 } | |
271 } | |
272 | |
273 void InMemoryURLIndex::NotifyHasLoaded() { | |
274 FOR_EACH_OBSERVER(InMemoryURLIndex::Observer, observers_, Loaded()); | |
275 } | |
276 | |
277 // Restoring from the History DB ----------------------------------------------- | 259 // Restoring from the History DB ----------------------------------------------- |
278 | 260 |
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 | |
294 void InMemoryURLIndex::ScheduleRebuildFromHistory() { | 261 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; | |
301 HistoryService* service = | 262 HistoryService* service = |
302 HistoryServiceFactory::GetForProfile(profile_, | 263 HistoryServiceFactory::GetForProfile(profile_, |
303 Profile::EXPLICIT_ACCESS); | 264 Profile::EXPLICIT_ACCESS); |
304 // Do not update the cache database while rebuilding. | |
305 private_data_->set_cache_enabled(false); | |
306 service->ScheduleDBTask( | 265 service->ScheduleDBTask( |
307 new InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask(this), | 266 new InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask( |
| 267 this, languages_, scheme_whitelist_), |
308 &cache_reader_consumer_); | 268 &cache_reader_consumer_); |
309 } | 269 } |
310 | 270 |
311 void InMemoryURLIndex::DoneRebuidingPrivateDataFromHistoryDB( | 271 void InMemoryURLIndex::DoneRebuidingPrivateDataFromHistoryDB( |
312 bool succeeded, | 272 bool succeeded, |
313 scoped_refptr<URLIndexPrivateData> private_data) { | 273 scoped_refptr<URLIndexPrivateData> private_data) { |
314 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) || | 274 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
315 BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
316 if (shutdown_) | |
317 return; | |
318 if (succeeded) { | 275 if (succeeded) { |
319 private_data_ = private_data; | 276 private_data_ = private_data; |
320 private_data_->set_cache_enabled(true); | 277 PostSaveToCacheFileTask(); // Cache the newly rebuilt index. |
321 PostRefreshCacheTask(); // Cache the newly rebuilt index. | |
322 } else { | 278 } else { |
323 private_data_->set_cache_enabled(true); | 279 private_data_->Clear(); // Dump the old private data. |
324 PostResetPrivateDataTask(); | 280 // There is no need to do anything with the cache file as it was deleted |
| 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)); |
325 } | 317 } |
326 } | 318 } |
327 | 319 |
328 // Reset Cache ----------------------------------------------------------------- | 320 void InMemoryURLIndex::OnCacheSaveDone( |
329 | 321 scoped_refptr<RefCountedBool> succeeded) { |
330 void InMemoryURLIndex::PostResetPrivateDataTask() { | 322 if (save_cache_observer_) |
331 index_available_ = false; | 323 save_cache_observer_->OnCacheSaveFinished(succeeded->value()); |
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. | |
372 } | 324 } |
373 | 325 |
374 } // namespace history | 326 } // namespace history |
OLD | NEW |