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), | 100 shutdown_(false), |
87 shutdown_(false) { | 101 needs_to_be_cached_(false) { |
| 102 InitializeSchemeWhitelist(&scheme_whitelist_); |
88 if (profile) { | 103 if (profile) { |
| 104 // TODO(mrossetti): Register for language change notifications. |
89 content::Source<Profile> source(profile); | 105 content::Source<Profile> source(profile); |
90 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source); | 106 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source); |
91 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, | 107 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, |
92 source); | 108 source); |
93 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source); | 109 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source); |
94 } | 110 } |
95 // Note: private_data_ will be reset after rebuilding from the history | |
96 // database but the ownership of the database passes to the new | |
97 // private_data_ instance so there is no need to re-register for the | |
98 // following notification at that time. | |
99 registrar_.Add(this, | |
100 chrome::NOTIFICATION_IN_MEMORY_URL_CACHE_DATABASE_FAILURE, | |
101 content::Source<InMemoryURLCacheDatabase>( | |
102 private_data_->cache_db())); | |
103 // TODO(mrossetti): Register for language change notifications. | |
104 } | 111 } |
105 | 112 |
106 // Called only by unit tests. | 113 // Called only by unit tests. |
107 InMemoryURLIndex::InMemoryURLIndex(const FilePath& history_dir, | 114 InMemoryURLIndex::InMemoryURLIndex() |
108 const std::string& languages) | |
109 : profile_(NULL), | 115 : profile_(NULL), |
110 languages_(languages), | 116 private_data_(new URLIndexPrivateData), |
111 history_dir_(history_dir), | 117 restore_cache_observer_(NULL), |
112 index_available_(false), | 118 save_cache_observer_(NULL), |
113 shutdown_(false) { | 119 shutdown_(false), |
| 120 needs_to_be_cached_(false) { |
| 121 InitializeSchemeWhitelist(&scheme_whitelist_); |
114 } | 122 } |
115 | 123 |
116 InMemoryURLIndex::~InMemoryURLIndex() {} | 124 InMemoryURLIndex::~InMemoryURLIndex() { |
117 | 125 // If there was a history directory (which there won't be for some unit tests) |
118 void InMemoryURLIndex::Init(bool disable_cache) { | 126 // then insure that the cache has already been saved. |
119 if (disable_cache) { | 127 DCHECK(history_dir_.empty() || !needs_to_be_cached_); |
120 RebuildFromHistoryIfLoaded(); | |
121 } else { | |
122 // It's safe to initialize the private data and the cache database without | |
123 // using the sequenced worker pool as no other database operations will be | |
124 // going on at the same time. | |
125 BrowserThread::PostTaskAndReplyWithResult<bool>( | |
126 BrowserThread::DB, FROM_HERE, | |
127 base::Bind(&URLIndexPrivateData::Init, private_data_, sequence_token_), | |
128 base::Bind(&InMemoryURLIndex::OnPrivateDataInitDone, AsWeakPtr())); | |
129 } | |
130 } | 128 } |
131 | 129 |
132 void InMemoryURLIndex::OnPrivateDataInitDone(bool succeeded) { | 130 void InMemoryURLIndex::Init() { |
133 if (shutdown_) | 131 PostRestoreFromCacheFileTask(); |
134 return; | |
135 if (succeeded) | |
136 PostRestoreFromCacheTask(); | |
137 else | |
138 RebuildFromHistoryIfLoaded(); | |
139 } | 132 } |
140 | 133 |
141 void InMemoryURLIndex::Shutdown() { | 134 void InMemoryURLIndex::ShutDown() { |
142 // Close down the cache database as quickly as possible. Any pending cache DB | |
143 // transactions will detect that the database is no longer there and give up. | |
144 registrar_.RemoveAll(); | 135 registrar_.RemoveAll(); |
145 cache_reader_consumer_.CancelAllRequests(); | 136 cache_reader_consumer_.CancelAllRequests(); |
146 shutdown_ = true; | 137 shutdown_ = true; |
147 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; |
148 } | 145 } |
149 | 146 |
150 void InMemoryURLIndex::AddObserver(InMemoryURLIndex::Observer* observer) { | 147 void InMemoryURLIndex::ClearPrivateData() { |
151 observers_.AddObserver(observer); | 148 private_data_->Clear(); |
152 } | 149 } |
153 | 150 |
154 void InMemoryURLIndex::RemoveObserver(InMemoryURLIndex::Observer* observer) { | 151 bool InMemoryURLIndex::GetCacheFilePath(FilePath* file_path) { |
155 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; |
156 } | 156 } |
157 | 157 |
158 // Querying -------------------------------------------------------------------- | 158 // Querying -------------------------------------------------------------------- |
159 | 159 |
160 ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms( | 160 ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms( |
161 const string16& term_string) { | 161 const string16& term_string) { |
162 return private_data_->HistoryItemsForTerms(term_string); | 162 return private_data_->HistoryItemsForTerms(term_string); |
163 } | 163 } |
164 | 164 |
165 // Updating -------------------------------------------------------------------- | 165 // Updating -------------------------------------------------------------------- |
166 | 166 |
167 void InMemoryURLIndex::DeleteURL(const GURL& url) { | |
168 private_data_->DeleteURL(url); | |
169 } | |
170 | |
171 void InMemoryURLIndex::Observe(int notification_type, | 167 void InMemoryURLIndex::Observe(int notification_type, |
172 const content::NotificationSource& source, | 168 const content::NotificationSource& source, |
173 const content::NotificationDetails& details) { | 169 const content::NotificationDetails& details) { |
174 switch (notification_type) { | 170 switch (notification_type) { |
175 case chrome::NOTIFICATION_HISTORY_URL_VISITED: | 171 case chrome::NOTIFICATION_HISTORY_URL_VISITED: |
176 OnURLVisited(content::Details<URLVisitedDetails>(details).ptr()); | 172 OnURLVisited(content::Details<URLVisitedDetails>(details).ptr()); |
177 break; | 173 break; |
178 case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: | 174 case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: |
179 OnURLsModified( | 175 OnURLsModified( |
180 content::Details<history::URLsModifiedDetails>(details).ptr()); | 176 content::Details<history::URLsModifiedDetails>(details).ptr()); |
181 break; | 177 break; |
182 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: | 178 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: |
183 OnURLsDeleted( | 179 OnURLsDeleted( |
184 content::Details<history::URLsDeletedDetails>(details).ptr()); | 180 content::Details<history::URLsDeletedDetails>(details).ptr()); |
185 break; | 181 break; |
186 case chrome::NOTIFICATION_HISTORY_LOADED: | 182 case chrome::NOTIFICATION_HISTORY_LOADED: |
187 registrar_.Remove(this, chrome::NOTIFICATION_HISTORY_LOADED, | 183 registrar_.Remove(this, chrome::NOTIFICATION_HISTORY_LOADED, |
188 content::Source<Profile>(profile_)); | 184 content::Source<Profile>(profile_)); |
189 ScheduleRebuildFromHistory(); | 185 ScheduleRebuildFromHistory(); |
190 break; | 186 break; |
191 case chrome::NOTIFICATION_IN_MEMORY_URL_CACHE_DATABASE_FAILURE: | |
192 RepairCacheDatabase(); | |
193 break; | |
194 default: | 187 default: |
195 // For simplicity, the unit tests send us all notifications, even when | 188 // For simplicity, the unit tests send us all notifications, even when |
196 // we haven't registered for them, so don't assert here. | 189 // we haven't registered for them, so don't assert here. |
197 break; | 190 break; |
198 } | 191 } |
199 } | 192 } |
200 | 193 |
201 void InMemoryURLIndex::OnURLVisited(const URLVisitedDetails* details) { | 194 void InMemoryURLIndex::OnURLVisited(const URLVisitedDetails* details) { |
202 if (index_available_) | 195 needs_to_be_cached_ |= |
203 private_data_->UpdateURL(details->row); | 196 private_data_->UpdateURL(details->row, languages_, scheme_whitelist_); |
204 else | |
205 pending_updates_.push_back(IndexUpdateItem(UPDATE_VISIT, details->row)); | |
206 } | 197 } |
207 | 198 |
208 void InMemoryURLIndex::OnURLsModified(const URLsModifiedDetails* details) { | 199 void InMemoryURLIndex::OnURLsModified(const URLsModifiedDetails* details) { |
209 for (URLRows::const_iterator row = details->changed_urls.begin(); | 200 for (URLRows::const_iterator row = details->changed_urls.begin(); |
210 row != details->changed_urls.end(); ++row) { | 201 row != details->changed_urls.end(); ++row) |
211 if (index_available_) | 202 needs_to_be_cached_ |= |
212 private_data_->UpdateURL(*row); | 203 private_data_->UpdateURL(*row, languages_, scheme_whitelist_); |
213 else | |
214 pending_updates_.push_back(IndexUpdateItem(UPDATE_VISIT, *row)); | |
215 } | |
216 } | 204 } |
217 | 205 |
218 void InMemoryURLIndex::OnURLsDeleted(const URLsDeletedDetails* details) { | 206 void InMemoryURLIndex::OnURLsDeleted(const URLsDeletedDetails* details) { |
219 if (details->all_history) { | 207 if (details->all_history) { |
220 PostResetPrivateDataTask(); | 208 ClearPrivateData(); |
| 209 needs_to_be_cached_ = true; |
221 } else { | 210 } else { |
222 for (URLRows::const_iterator row = details->rows.begin(); | 211 for (URLRows::const_iterator row = details->rows.begin(); |
223 row != details->rows.end(); ++row) { | 212 row != details->rows.end(); ++row) |
224 if (index_available_) | 213 needs_to_be_cached_ |= private_data_->DeleteURL(row->url()); |
225 DeleteURL(row->url()); | 214 } |
226 else | 215 } |
227 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_)); |
228 } | 255 } |
229 } | 256 } |
230 } | 257 } |
231 | 258 |
232 void InMemoryURLIndex::FlushPendingUpdates() { | |
233 for (PendingUpdates::iterator i = pending_updates_.begin(); | |
234 i != pending_updates_.end(); ++i) { | |
235 if (i->update_type == UPDATE_VISIT) | |
236 private_data_->UpdateURL(i->row); | |
237 else if (i->update_type == DELETE_VISIT) | |
238 DeleteURL(i->row.url()); | |
239 } | |
240 pending_updates_.clear(); | |
241 } | |
242 | |
243 // Restoring from Cache -------------------------------------------------------- | |
244 | |
245 void InMemoryURLIndex::PostRestoreFromCacheTask() { | |
246 // It's safe to restore from the cache database without using the sequenced | |
247 // worker pool as no other database operations will be going on at the same | |
248 // time. | |
249 BrowserThread::PostTaskAndReplyWithResult<bool>( | |
250 BrowserThread::DB, FROM_HERE, | |
251 base::Bind(&URLIndexPrivateData::RestoreFromCacheTask, private_data_), | |
252 base::Bind(&InMemoryURLIndex::OnCacheRestoreDone, AsWeakPtr())); | |
253 } | |
254 | |
255 void InMemoryURLIndex::OnCacheRestoreDone(bool succeeded) { | |
256 if (shutdown_) { | |
257 NotifyHasLoaded(); | |
258 return; | |
259 } | |
260 if (succeeded) { | |
261 FlushPendingUpdates(); | |
262 index_available_ = true; | |
263 NotifyHasLoaded(); | |
264 } else if (profile_) { | |
265 RebuildFromHistoryIfLoaded(); | |
266 } | |
267 } | |
268 | |
269 void InMemoryURLIndex::NotifyHasLoaded() { | |
270 FOR_EACH_OBSERVER(InMemoryURLIndex::Observer, observers_, Loaded()); | |
271 } | |
272 | |
273 // Restoring from the History DB ----------------------------------------------- | 259 // Restoring from the History DB ----------------------------------------------- |
274 | 260 |
275 void InMemoryURLIndex::RebuildFromHistoryIfLoaded() { | |
276 // When unable to restore from the cache database, rebuild from the history | |
277 // database, if it's available, otherwise wait until the history database | |
278 // has loaded and then rebuild the index. | |
279 HistoryService* service = | |
280 HistoryServiceFactory::GetForProfileIfExists(profile_, | |
281 Profile::EXPLICIT_ACCESS); | |
282 if (service && service->backend_loaded()) { | |
283 ScheduleRebuildFromHistory(); | |
284 } else { | |
285 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_LOADED, | |
286 content::Source<Profile>(profile_)); | |
287 } | |
288 } | |
289 | |
290 void InMemoryURLIndex::ScheduleRebuildFromHistory() { | 261 void InMemoryURLIndex::ScheduleRebuildFromHistory() { |
291 // It's possible that we were waiting on history to finish loading when | |
292 // the profile was told to shut down. | |
293 if (shutdown_) | |
294 return; | |
295 // Reset availability here as this function is called directly by unit tests. | |
296 index_available_ = false; | |
297 HistoryService* service = | 262 HistoryService* service = |
298 HistoryServiceFactory::GetForProfile(profile_, | 263 HistoryServiceFactory::GetForProfile(profile_, |
299 Profile::EXPLICIT_ACCESS); | 264 Profile::EXPLICIT_ACCESS); |
300 // Do not update the cache database while rebuilding. | |
301 private_data_->set_cache_enabled(false); | |
302 service->ScheduleDBTask( | 265 service->ScheduleDBTask( |
303 new InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask(this), | 266 new InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask( |
| 267 this, languages_, scheme_whitelist_), |
304 &cache_reader_consumer_); | 268 &cache_reader_consumer_); |
305 } | 269 } |
306 | 270 |
307 void InMemoryURLIndex::DoneRebuidingPrivateDataFromHistoryDB( | 271 void InMemoryURLIndex::DoneRebuidingPrivateDataFromHistoryDB( |
308 bool succeeded, | 272 bool succeeded, |
309 scoped_refptr<URLIndexPrivateData> private_data) { | 273 scoped_refptr<URLIndexPrivateData> private_data) { |
310 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) || | 274 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
311 BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
312 if (shutdown_) | |
313 return; | |
314 if (succeeded) { | 275 if (succeeded) { |
315 private_data_ = private_data; | 276 private_data_ = private_data; |
316 private_data_->set_cache_enabled(true); | 277 PostSaveToCacheFileTask(); // Cache the newly rebuilt index. |
317 PostRefreshCacheTask(); // Cache the newly rebuilt index. | |
318 } else { | 278 } else { |
319 private_data_->set_cache_enabled(true); | 279 private_data_->Clear(); // Dump the old private data. |
320 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)); |
321 } | 317 } |
322 } | 318 } |
323 | 319 |
324 // Reset Cache ----------------------------------------------------------------- | 320 void InMemoryURLIndex::OnCacheSaveDone( |
325 | 321 scoped_refptr<RefCountedBool> succeeded) { |
326 void InMemoryURLIndex::PostResetPrivateDataTask() { | 322 if (save_cache_observer_) |
327 index_available_ = false; | 323 save_cache_observer_->OnCacheSaveFinished(succeeded->value()); |
328 scoped_refptr<base::SequencedTaskRunner> runner = | |
329 BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(sequence_token_); | |
330 DCHECK(runner.get()); | |
331 runner->PostTaskAndReply(FROM_HERE, | |
332 base::Bind(&URLIndexPrivateData::Reset, private_data_), | |
333 base::Bind(&InMemoryURLIndex::OnCacheRefreshOrResetDone, AsWeakPtr())); | |
334 } | |
335 | |
336 // Refresh Cache --------------------------------------------------------------- | |
337 | |
338 void InMemoryURLIndex::PostRefreshCacheTask() { | |
339 scoped_refptr<base::SequencedTaskRunner> runner = | |
340 BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(sequence_token_); | |
341 DCHECK(runner.get()); | |
342 runner->PostTaskAndReply(FROM_HERE, | |
343 base::Bind(&URLIndexPrivateData::RefreshCacheTask, private_data_), | |
344 base::Bind(&InMemoryURLIndex::OnCacheRefreshOrResetDone, AsWeakPtr())); | |
345 } | |
346 | |
347 void InMemoryURLIndex::OnCacheRefreshOrResetDone() { | |
348 if (shutdown_) { | |
349 NotifyHasLoaded(); | |
350 return; | |
351 } | |
352 FlushPendingUpdates(); | |
353 index_available_ = true; | |
354 NotifyHasLoaded(); | |
355 } | |
356 | |
357 // Repair Cache ---------------------------------------------------------------- | |
358 | |
359 void InMemoryURLIndex::RepairCacheDatabase() { | |
360 // The database will disable itself when it detects an error so re-enable the | |
361 // database and try to refresh it from scratch. If that fails then the | |
362 // database will be left in a disabled state and will be rebuilt from the | |
363 // history database the next time the profile is opened. | |
364 private_data_->set_cache_enabled(true); | |
365 PostRefreshCacheTask(); // Cache the newly rebuilt index. | |
366 } | 324 } |
367 | 325 |
368 } // namespace history | 326 } // namespace history |
OLD | NEW |