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 // The history system runs on a background thread so that potentially slow | 5 // The history system runs on a background thread so that potentially slow |
6 // database operations don't delay the browser. This backend processing is | 6 // database operations don't delay the browser. This backend processing is |
7 // represented by HistoryBackend. The HistoryService's job is to dispatch to | 7 // represented by HistoryBackend. The HistoryService's job is to dispatch to |
8 // that thread. | 8 // that thread. |
9 // | 9 // |
10 // Main thread History thread | 10 // Main thread History thread |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 DCHECK(thread_checker_.CalledOnValidThread()); | 224 DCHECK(thread_checker_.CalledOnValidThread()); |
225 // Shutdown the backend. This does nothing if Cleanup was already invoked. | 225 // Shutdown the backend. This does nothing if Cleanup was already invoked. |
226 Cleanup(); | 226 Cleanup(); |
227 } | 227 } |
228 | 228 |
229 bool HistoryService::BackendLoaded() { | 229 bool HistoryService::BackendLoaded() { |
230 DCHECK(thread_checker_.CalledOnValidThread()); | 230 DCHECK(thread_checker_.CalledOnValidThread()); |
231 return backend_loaded_; | 231 return backend_loaded_; |
232 } | 232 } |
233 | 233 |
234 void HistoryService::Cleanup() { | |
235 DCHECK(thread_checker_.CalledOnValidThread()); | |
236 if (!thread_) { | |
237 // We've already cleaned up. | |
238 return; | |
239 } | |
240 | |
241 weak_ptr_factory_.InvalidateWeakPtrs(); | |
242 | |
243 // Unload the backend. | |
244 if (history_backend_.get()) { | |
245 // Get rid of the in-memory backend. | |
246 in_memory_backend_.reset(); | |
247 | |
248 // Give the InMemoryURLIndex a chance to shutdown. | |
249 // NOTE: In tests, there may be no index. | |
250 if (in_memory_url_index_) | |
251 in_memory_url_index_->ShutDown(); | |
252 | |
253 // The backend's destructor must run on the history thread since it is not | |
254 // threadsafe. So this thread must not be the last thread holding a | |
255 // reference to the backend, or a crash could happen. | |
256 // | |
257 // We have a reference to the history backend. There is also an extra | |
258 // reference held by our delegate installed in the backend, which | |
259 // HistoryBackend::Closing will release. This means if we scheduled a call | |
260 // to HistoryBackend::Closing and *then* released our backend reference, | |
261 // there will be a race between us and the backend's Closing function to see | |
262 // who is the last holder of a reference. If the backend thread's Closing | |
263 // manages to run before we release our backend refptr, the last reference | |
264 // will be held by this thread and the destructor will be called from here. | |
265 // | |
266 // Therefore, we create a closure to run the Closing operation first. This | |
267 // holds a reference to the backend. Then we release our reference, then we | |
268 // schedule the task to run. After the task runs, it will delete its | |
269 // reference from the history thread, ensuring everything works properly. | |
270 // | |
271 // TODO(ajwong): Cleanup HistoryBackend lifetime issues. | |
272 // See http://crbug.com/99767. | |
273 history_backend_->AddRef(); | |
274 base::Closure closing_task = | |
275 base::Bind(&HistoryBackend::Closing, history_backend_.get()); | |
276 ScheduleTask(PRIORITY_NORMAL, closing_task); | |
277 closing_task.Reset(); | |
278 HistoryBackend* raw_ptr = history_backend_.get(); | |
279 history_backend_ = NULL; | |
280 thread_->message_loop()->ReleaseSoon(FROM_HERE, raw_ptr); | |
281 } | |
282 | |
283 // Delete the thread, which joins with the background thread. We defensively | |
284 // NULL the pointer before deleting it in case somebody tries to use it | |
285 // during shutdown, but this shouldn't happen. | |
286 base::Thread* thread = thread_; | |
287 thread_ = NULL; | |
288 delete thread; | |
289 } | |
290 | |
291 void HistoryService::ClearCachedDataForContextID( | 234 void HistoryService::ClearCachedDataForContextID( |
292 history::ContextID context_id) { | 235 history::ContextID context_id) { |
293 DCHECK(thread_) << "History service being called after cleanup"; | 236 DCHECK(thread_) << "History service being called after cleanup"; |
294 DCHECK(thread_checker_.CalledOnValidThread()); | 237 DCHECK(thread_checker_.CalledOnValidThread()); |
295 ScheduleAndForget(PRIORITY_NORMAL, | 238 ScheduleAndForget(PRIORITY_NORMAL, |
296 &HistoryBackend::ClearCachedDataForContextID, context_id); | 239 &HistoryBackend::ClearCachedDataForContextID, context_id); |
297 } | 240 } |
298 | 241 |
299 history::URLDatabase* HistoryService::InMemoryDatabase() { | 242 history::URLDatabase* HistoryService::InMemoryDatabase() { |
300 DCHECK(thread_checker_.CalledOnValidThread()); | 243 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
896 FROM_HERE, | 839 FROM_HERE, |
897 base::Bind(&HistoryBackend::QueryFilteredURLs, | 840 base::Bind(&HistoryBackend::QueryFilteredURLs, |
898 history_backend_.get(), | 841 history_backend_.get(), |
899 result_count, | 842 result_count, |
900 filter, | 843 filter, |
901 extended_info, | 844 extended_info, |
902 base::Unretained(result)), | 845 base::Unretained(result)), |
903 base::Bind(callback, base::Owned(result))); | 846 base::Bind(callback, base::Owned(result))); |
904 } | 847 } |
905 | 848 |
| 849 void HistoryService::Cleanup() { |
| 850 DCHECK(thread_checker_.CalledOnValidThread()); |
| 851 if (!thread_) { |
| 852 // We've already cleaned up. |
| 853 return; |
| 854 } |
| 855 |
| 856 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 857 |
| 858 // Unload the backend. |
| 859 if (history_backend_.get()) { |
| 860 // Get rid of the in-memory backend. |
| 861 in_memory_backend_.reset(); |
| 862 |
| 863 // Give the InMemoryURLIndex a chance to shutdown. |
| 864 // NOTE: In tests, there may be no index. |
| 865 if (in_memory_url_index_) |
| 866 in_memory_url_index_->ShutDown(); |
| 867 |
| 868 // The backend's destructor must run on the history thread since it is not |
| 869 // threadsafe. So this thread must not be the last thread holding a |
| 870 // reference to the backend, or a crash could happen. |
| 871 // |
| 872 // We have a reference to the history backend. There is also an extra |
| 873 // reference held by our delegate installed in the backend, which |
| 874 // HistoryBackend::Closing will release. This means if we scheduled a call |
| 875 // to HistoryBackend::Closing and *then* released our backend reference, |
| 876 // there will be a race between us and the backend's Closing function to see |
| 877 // who is the last holder of a reference. If the backend thread's Closing |
| 878 // manages to run before we release our backend refptr, the last reference |
| 879 // will be held by this thread and the destructor will be called from here. |
| 880 // |
| 881 // Therefore, we create a closure to run the Closing operation first. This |
| 882 // holds a reference to the backend. Then we release our reference, then we |
| 883 // schedule the task to run. After the task runs, it will delete its |
| 884 // reference from the history thread, ensuring everything works properly. |
| 885 // |
| 886 // TODO(ajwong): Cleanup HistoryBackend lifetime issues. |
| 887 // See http://crbug.com/99767. |
| 888 history_backend_->AddRef(); |
| 889 base::Closure closing_task = |
| 890 base::Bind(&HistoryBackend::Closing, history_backend_.get()); |
| 891 ScheduleTask(PRIORITY_NORMAL, closing_task); |
| 892 closing_task.Reset(); |
| 893 HistoryBackend* raw_ptr = history_backend_.get(); |
| 894 history_backend_ = NULL; |
| 895 thread_->message_loop()->ReleaseSoon(FROM_HERE, raw_ptr); |
| 896 } |
| 897 |
| 898 // Delete the thread, which joins with the background thread. We defensively |
| 899 // NULL the pointer before deleting it in case somebody tries to use it |
| 900 // during shutdown, but this shouldn't happen. |
| 901 base::Thread* thread = thread_; |
| 902 thread_ = NULL; |
| 903 delete thread; |
| 904 } |
| 905 |
906 void HistoryService::Observe(int type, | 906 void HistoryService::Observe(int type, |
907 const content::NotificationSource& source, | 907 const content::NotificationSource& source, |
908 const content::NotificationDetails& details) { | 908 const content::NotificationDetails& details) { |
909 DCHECK(thread_checker_.CalledOnValidThread()); | 909 DCHECK(thread_checker_.CalledOnValidThread()); |
910 if (!thread_) | 910 if (!thread_) |
911 return; | 911 return; |
912 | 912 |
913 switch (type) { | 913 switch (type) { |
914 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: { | 914 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: { |
915 // Update the visited link system for deleted URLs. We will update the | 915 // Update the visited link system for deleted URLs. We will update the |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1222 DCHECK(thread_checker_.CalledOnValidThread()); | 1222 DCHECK(thread_checker_.CalledOnValidThread()); |
1223 visit_database_observers_.RemoveObserver(observer); | 1223 visit_database_observers_.RemoveObserver(observer); |
1224 } | 1224 } |
1225 | 1225 |
1226 void HistoryService::NotifyVisitDBObserversOnAddVisit( | 1226 void HistoryService::NotifyVisitDBObserversOnAddVisit( |
1227 const history::BriefVisitInfo& info) { | 1227 const history::BriefVisitInfo& info) { |
1228 DCHECK(thread_checker_.CalledOnValidThread()); | 1228 DCHECK(thread_checker_.CalledOnValidThread()); |
1229 FOR_EACH_OBSERVER(history::VisitDatabaseObserver, visit_database_observers_, | 1229 FOR_EACH_OBSERVER(history::VisitDatabaseObserver, visit_database_observers_, |
1230 OnAddVisit(info)); | 1230 OnAddVisit(info)); |
1231 } | 1231 } |
OLD | NEW |