Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: chrome/browser/history/history.cc

Issue 267019: Add the ability to unload the HistoryBackend.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/history/history.h ('k') | chrome/browser/profile.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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
11 // ----------- -------------- 11 // ----------- --------------
12 // HistoryService <----------------> HistoryBackend 12 // HistoryService <----------------> HistoryBackend
13 // -> HistoryDatabase 13 // -> HistoryDatabase
14 // -> SQLite connection to History 14 // -> SQLite connection to History
15 // -> ArchivedDatabase 15 // -> ArchivedDatabase
16 // -> SQLite connection to Archived History 16 // -> SQLite connection to Archived History
17 // -> TextDatabaseManager 17 // -> TextDatabaseManager
18 // -> SQLite connection to one month's data 18 // -> SQLite connection to one month's data
19 // -> SQLite connection to one month's data 19 // -> SQLite connection to one month's data
20 // ... 20 // ...
21 // -> ThumbnailDatabase 21 // -> ThumbnailDatabase
22 // -> SQLite connection to Thumbnails 22 // -> SQLite connection to Thumbnails
23 // (and favicons) 23 // (and favicons)
24 24
25 #include "chrome/browser/history/history.h" 25 #include "chrome/browser/history/history.h"
26 26
27 #include "app/l10n_util.h" 27 #include "app/l10n_util.h"
28 #include "base/file_util.h"
29 #include "base/message_loop.h" 28 #include "base/message_loop.h"
30 #include "base/path_service.h" 29 #include "base/path_service.h"
31 #include "base/ref_counted.h" 30 #include "base/ref_counted.h"
32 #include "base/task.h" 31 #include "base/task.h"
33 #include "chrome/browser/autocomplete/history_url_provider.h" 32 #include "chrome/browser/autocomplete/history_url_provider.h"
34 #include "chrome/browser/browser_list.h" 33 #include "chrome/browser/browser_list.h"
35 #include "chrome/browser/browser_process.h" 34 #include "chrome/browser/browser_process.h"
36 #include "chrome/browser/browser_window.h" 35 #include "chrome/browser/browser_window.h"
37 #include "chrome/browser/chrome_thread.h" 36 #include "chrome/browser/chrome_thread.h"
38 #include "chrome/browser/history/download_types.h" 37 #include "chrome/browser/history/download_types.h"
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 Source<Profile>(profile_)); 146 Source<Profile>(profile_));
148 } 147 }
149 148
150 HistoryService::~HistoryService() { 149 HistoryService::~HistoryService() {
151 // Shutdown the backend. This does nothing if Cleanup was already invoked. 150 // Shutdown the backend. This does nothing if Cleanup was already invoked.
152 Cleanup(); 151 Cleanup();
153 } 152 }
154 153
155 bool HistoryService::Init(const FilePath& history_dir, 154 bool HistoryService::Init(const FilePath& history_dir,
156 BookmarkService* bookmark_service) { 155 BookmarkService* bookmark_service) {
157 if (!thread_->Start()) 156 if (!thread_->Start()) {
157 Cleanup();
158 return false; 158 return false;
159 }
160
161 history_dir_ = history_dir;
162 bookmark_service_ = bookmark_service;
159 163
160 // Create the history backend. 164 // Create the history backend.
161 scoped_refptr<HistoryBackend> backend( 165 LoadBackendIfNecessary();
162 new HistoryBackend(history_dir,
163 new BackendDelegate(this),
164 bookmark_service));
165 history_backend_.swap(backend);
166
167 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init);
168 return true; 166 return true;
169 } 167 }
170 168
171 void HistoryService::Cleanup() { 169 bool HistoryService::BackendLoaded() {
172 if (!thread_) { 170 LoadBackendIfNecessary();
173 // We've already cleaned up. 171 return backend_loaded_;
174 return; 172 }
175 }
176 173
177 // Shutdown is a little subtle. The backend's destructor must run on the 174 void HistoryService::UnloadBackend() {
178 // history thread since it is not threadsafe. So this thread must not be the 175 if (!history_backend_)
179 // last thread holding a reference to the backend, or a crash could happen. 176 return; // Already unloaded.
177
178 // Get rid of the in-memory backend.
179 in_memory_backend_.reset();
180
181 // The backend's destructor must run on the history thread since it is not
182 // threadsafe. So this thread must not be the last thread holding a reference
183 // to the backend, or a crash could happen.
180 // 184 //
181 // We have a reference to the history backend. There is also an extra 185 // We have a reference to the history backend. There is also an extra
182 // reference held by our delegate installed in the backend, which 186 // reference held by our delegate installed in the backend, which
183 // HistoryBackend::Closing will release. This means if we scheduled a call 187 // HistoryBackend::Closing will release. This means if we scheduled a call
184 // to HistoryBackend::Closing and *then* released our backend reference, there 188 // to HistoryBackend::Closing and *then* released our backend reference, there
185 // will be a race between us and the backend's Closing function to see who is 189 // will be a race between us and the backend's Closing function to see who is
186 // the last holder of a reference. If the backend thread's Closing manages to 190 // the last holder of a reference. If the backend thread's Closing manages to
187 // run before we release our backend refptr, the last reference will be held 191 // run before we release our backend refptr, the last reference will be held
188 // by this thread and the destructor will be called from here. 192 // by this thread and the destructor will be called from here.
189 // 193 //
190 // Therefore, we create a task to run the Closing operation first. This holds 194 // Therefore, we create a task to run the Closing operation first. This holds
191 // a reference to the backend. Then we release our reference, then we schedule 195 // a reference to the backend. Then we release our reference, then we schedule
192 // the task to run. After the task runs, it will delete its reference from 196 // the task to run. After the task runs, it will delete its reference from
193 // the history thread, ensuring everything works properly. 197 // the history thread, ensuring everything works properly.
194 Task* closing_task = 198 Task* closing_task =
195 NewRunnableMethod(history_backend_.get(), &HistoryBackend::Closing); 199 NewRunnableMethod(history_backend_.get(), &HistoryBackend::Closing);
196 history_backend_ = NULL; 200 history_backend_ = NULL;
197 ScheduleTask(PRIORITY_NORMAL, closing_task); 201 ScheduleTask(PRIORITY_NORMAL, closing_task);
202 }
203
204 void HistoryService::Cleanup() {
205 if (!thread_) {
206 // We've already cleaned up.
207 return;
208 }
209
210 // Unload the backend.
211 UnloadBackend();
198 212
199 // Delete the thread, which joins with the background thread. We defensively 213 // Delete the thread, which joins with the background thread. We defensively
200 // NULL the pointer before deleting it in case somebody tries to use it 214 // NULL the pointer before deleting it in case somebody tries to use it
201 // during shutdown, but this shouldn't happen. 215 // during shutdown, but this shouldn't happen.
202 base::Thread* thread = thread_; 216 base::Thread* thread = thread_;
203 thread_ = NULL; 217 thread_ = NULL;
204 delete thread; 218 delete thread;
205 } 219 }
206 220
207 void HistoryService::NotifyRenderProcessHostDestruction(const void* host) { 221 void HistoryService::NotifyRenderProcessHostDestruction(const void* host) {
208 ScheduleAndForget(PRIORITY_NORMAL, 222 ScheduleAndForget(PRIORITY_NORMAL,
209 &HistoryBackend::NotifyRenderProcessHostDestruction, host); 223 &HistoryBackend::NotifyRenderProcessHostDestruction, host);
210 } 224 }
211 225
212 history::URLDatabase* HistoryService::in_memory_database() const { 226 history::URLDatabase* HistoryService::InMemoryDatabase() {
227 LoadBackendIfNecessary();
213 if (in_memory_backend_.get()) 228 if (in_memory_backend_.get())
214 return in_memory_backend_->db(); 229 return in_memory_backend_->db();
215 return NULL; 230 return NULL;
216 } 231 }
217 232
218 void HistoryService::SetSegmentPresentationIndex(int64 segment_id, int index) { 233 void HistoryService::SetSegmentPresentationIndex(int64 segment_id, int index) {
219 ScheduleAndForget(PRIORITY_UI, 234 ScheduleAndForget(PRIORITY_UI,
220 &HistoryBackend::SetSegmentPresentationIndex, 235 &HistoryBackend::SetSegmentPresentationIndex,
221 segment_id, index); 236 segment_id, index);
222 } 237 }
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 } 305 }
291 306
292 void HistoryService::AddPage(const GURL& url, 307 void HistoryService::AddPage(const GURL& url,
293 Time time, 308 Time time,
294 const void* id_scope, 309 const void* id_scope,
295 int32 page_id, 310 int32 page_id,
296 const GURL& referrer, 311 const GURL& referrer,
297 PageTransition::Type transition, 312 PageTransition::Type transition,
298 const history::RedirectList& redirects, 313 const history::RedirectList& redirects,
299 bool did_replace_entry) { 314 bool did_replace_entry) {
300 DCHECK(history_backend_) << "History service being called after cleanup"; 315 DCHECK(thread_) << "History service being called after cleanup";
301 316
302 // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a 317 // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a
303 // large part of history (think iframes for ads) and we never display them in 318 // large part of history (think iframes for ads) and we never display them in
304 // history UI. We will still add manual subframes, which are ones the user 319 // history UI. We will still add manual subframes, which are ones the user
305 // has clicked on to get. 320 // has clicked on to get.
306 if (!CanAddURL(url)) 321 if (!CanAddURL(url))
307 return; 322 return;
308 323
309 // Add link & all redirects to visited link list. 324 // Add link & all redirects to visited link list.
310 VisitedLinkMaster* visited_links; 325 VisitedLinkMaster* visited_links;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 } 395 }
381 396
382 ScheduleAndForget(PRIORITY_NORMAL, 397 ScheduleAndForget(PRIORITY_NORMAL,
383 &HistoryBackend::AddPagesWithDetails, info); 398 &HistoryBackend::AddPagesWithDetails, info);
384 } 399 }
385 400
386 void HistoryService::SetPageContents(const GURL& url, 401 void HistoryService::SetPageContents(const GURL& url,
387 const std::wstring& contents) { 402 const std::wstring& contents) {
388 if (!CanAddURL(url)) 403 if (!CanAddURL(url))
389 return; 404 return;
405
390 ScheduleAndForget(PRIORITY_LOW, &HistoryBackend::SetPageContents, 406 ScheduleAndForget(PRIORITY_LOW, &HistoryBackend::SetPageContents,
391 url, contents); 407 url, contents);
392 } 408 }
393 409
394 void HistoryService::SetPageThumbnail(const GURL& page_url, 410 void HistoryService::SetPageThumbnail(const GURL& page_url,
395 const SkBitmap& thumbnail, 411 const SkBitmap& thumbnail,
396 const ThumbnailScore& score) { 412 const ThumbnailScore& score) {
397 if (!CanAddURL(page_url)) 413 if (!CanAddURL(page_url))
398 return; 414 return;
399 415
400 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageThumbnail, 416 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageThumbnail,
401 page_url, thumbnail, score); 417 page_url, thumbnail, score);
402 } 418 }
403 419
404 HistoryService::Handle HistoryService::GetPageThumbnail( 420 HistoryService::Handle HistoryService::GetPageThumbnail(
405 const GURL& page_url, 421 const GURL& page_url,
406 CancelableRequestConsumerBase* consumer, 422 CancelableRequestConsumerBase* consumer,
407 ThumbnailDataCallback* callback) { 423 ThumbnailDataCallback* callback) {
408 return Schedule(PRIORITY_NORMAL, &HistoryBackend::GetPageThumbnail, consumer, 424 return Schedule(PRIORITY_NORMAL, &HistoryBackend::GetPageThumbnail, consumer,
409 new history::GetPageThumbnailRequest(callback), page_url); 425 new history::GetPageThumbnailRequest(callback), page_url);
410 } 426 }
411 427
412 void HistoryService::GetFavicon(FaviconService::GetFaviconRequest* request, 428 void HistoryService::GetFavicon(FaviconService::GetFaviconRequest* request,
413 const GURL& icon_url) { 429 const GURL& icon_url) {
414 ScheduleTask(PRIORITY_NORMAL, 430 Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFavIcon, NULL, request,
415 NewRunnableMethod(history_backend_.get(), 431 icon_url);
416 &HistoryBackend::GetFavIcon,
417 scoped_refptr<FaviconService::GetFaviconRequest>(request),
418 icon_url));
419 } 432 }
420 433
421 void HistoryService::UpdateFaviconMappingAndFetch( 434 void HistoryService::UpdateFaviconMappingAndFetch(
422 FaviconService::GetFaviconRequest* request, 435 FaviconService::GetFaviconRequest* request,
423 const GURL& page_url, 436 const GURL& page_url,
424 const GURL& icon_url) { 437 const GURL& icon_url) {
425 ScheduleTask(PRIORITY_NORMAL, 438 Schedule(PRIORITY_NORMAL, &HistoryBackend::UpdateFavIconMappingAndFetch, NULL,
426 NewRunnableMethod(history_backend_.get(), 439 request, page_url, icon_url);
427 &HistoryBackend::UpdateFavIconMappingAndFetch,
428 scoped_refptr<FaviconService::GetFaviconRequest>(request),
429 page_url,
430 icon_url));
431 } 440 }
432 441
433 void HistoryService::GetFaviconForURL( 442 void HistoryService::GetFaviconForURL(
434 FaviconService::GetFaviconRequest* request, 443 FaviconService::GetFaviconRequest* request,
435 const GURL& page_url) { 444 const GURL& page_url) {
436 ScheduleTask(PRIORITY_UI, 445 Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFavIconForURL, NULL, request,
437 NewRunnableMethod(history_backend_.get(), 446 page_url);
438 &HistoryBackend::GetFavIconForURL,
439 scoped_refptr<FaviconService::GetFaviconRequest>(request),
440 page_url));
441 } 447 }
442 448
443 void HistoryService::SetFavicon(const GURL& page_url, 449 void HistoryService::SetFavicon(const GURL& page_url,
444 const GURL& icon_url, 450 const GURL& icon_url,
445 const std::vector<unsigned char>& image_data) { 451 const std::vector<unsigned char>& image_data) {
446 if (!CanAddURL(page_url)) 452 if (!CanAddURL(page_url))
447 return; 453 return;
448 454
449 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavIcon, 455 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavIcon,
450 page_url, icon_url, 456 page_url, icon_url,
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 Source<Profile> source(profile_); 695 Source<Profile> source(profile_);
690 696
691 // The details object just contains the pointer to the object that the 697 // The details object just contains the pointer to the object that the
692 // backend has allocated for us. The receiver of the notification will cast 698 // backend has allocated for us. The receiver of the notification will cast
693 // this to the proper type. 699 // this to the proper type.
694 Details<history::HistoryDetails> det(details_deleted); 700 Details<history::HistoryDetails> det(details_deleted);
695 701
696 NotificationService::current()->Notify(type, source, det); 702 NotificationService::current()->Notify(type, source, det);
697 } 703 }
698 704
705 void HistoryService::LoadBackendIfNecessary() {
706 if (!thread_ || history_backend_)
707 return; // Failed to init, or already started loading.
708
709 scoped_refptr<HistoryBackend> backend(
710 new HistoryBackend(history_dir_,
711 new BackendDelegate(this),
712 bookmark_service_));
713 history_backend_.swap(backend);
714
715 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init);
716 }
717
699 void HistoryService::OnDBLoaded() { 718 void HistoryService::OnDBLoaded() {
700 LOG(INFO) << "History backend finished loading"; 719 LOG(INFO) << "History backend finished loading";
701 backend_loaded_ = true; 720 backend_loaded_ = true;
702 NotificationService::current()->Notify(NotificationType::HISTORY_LOADED, 721 NotificationService::current()->Notify(NotificationType::HISTORY_LOADED,
703 Source<Profile>(profile_), 722 Source<Profile>(profile_),
704 Details<HistoryService>(this)); 723 Details<HistoryService>(this));
705 } 724 }
OLDNEW
« no previous file with comments | « chrome/browser/history/history.h ('k') | chrome/browser/profile.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698