diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-08 22:34:29 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-08 22:34:29 +0000 |
commit | 0850fa6b9e60e7b925ba516d8cf563fcb18eb23a (patch) | |
tree | b269d0c9180761ab39a046ebda1e34355d78c9ab /chrome/browser/history | |
parent | 0b081d53f118869541d28139353457bd7aec32e5 (diff) | |
download | chromium_src-0850fa6b9e60e7b925ba516d8cf563fcb18eb23a.zip chromium_src-0850fa6b9e60e7b925ba516d8cf563fcb18eb23a.tar.gz chromium_src-0850fa6b9e60e7b925ba516d8cf563fcb18eb23a.tar.bz2 |
Add the ability to unload the HistoryBackend.
A small number of places used accessors like in_memory_url_database() or backend_loaded() with the expectation that if they weren't already functional, the history system was in the process of making them so. I elected to make both of these functions that triggered lazy backend initialization.
BUG=23400
TEST=none
Review URL: http://codereview.chromium.org/267019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28461 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/history')
-rw-r--r-- | chrome/browser/history/history.cc | 101 | ||||
-rw-r--r-- | chrome/browser/history/history.h | 72 |
2 files changed, 115 insertions, 58 deletions
diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc index a8ed50b..a7bf774 100644 --- a/chrome/browser/history/history.cc +++ b/chrome/browser/history/history.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -25,7 +25,6 @@ #include "chrome/browser/history/history.h" #include "app/l10n_util.h" -#include "base/file_util.h" #include "base/message_loop.h" #include "base/path_service.h" #include "base/ref_counted.h" @@ -154,29 +153,41 @@ HistoryService::~HistoryService() { bool HistoryService::Init(const FilePath& history_dir, BookmarkService* bookmark_service) { - if (!thread_->Start()) + if (!thread_->Start()) { + Cleanup(); return false; + } - // Create the history backend. - scoped_refptr<HistoryBackend> backend( - new HistoryBackend(history_dir, - new BackendDelegate(this), - bookmark_service)); - history_backend_.swap(backend); + history_dir_ = history_dir; + bookmark_service_ = bookmark_service; - ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init); + // Create the history backend. + LoadBackendIfNecessary(); return true; } -void HistoryService::Cleanup() { - if (!thread_) { - // We've already cleaned up. - return; - } +bool HistoryService::BackendLoaded() { + // NOTE: We start the backend loading even though it completes asynchronously + // and thus won't affect the return value of this function. This is because + // callers of this assume that if the backend isn't yet loaded it will be + // soon, so they will either listen for notifications or just retry this call + // later. If we've purged the backend, we haven't necessarily restarted it + // loading by now, so we need to trigger the load in order to maintain that + // expectation. + LoadBackendIfNecessary(); + return backend_loaded_; +} + +void HistoryService::UnloadBackend() { + if (!history_backend_) + return; // Already unloaded. - // Shutdown is a little subtle. The backend's destructor must run on the - // history thread since it is not threadsafe. So this thread must not be the - // last thread holding a reference to the backend, or a crash could happen. + // Get rid of the in-memory backend. + in_memory_backend_.reset(); + + // The backend's destructor must run on the history thread since it is not + // threadsafe. So this thread must not be the last thread holding a reference + // to the backend, or a crash could happen. // // We have a reference to the history backend. There is also an extra // reference held by our delegate installed in the backend, which @@ -195,6 +206,16 @@ void HistoryService::Cleanup() { NewRunnableMethod(history_backend_.get(), &HistoryBackend::Closing); history_backend_ = NULL; ScheduleTask(PRIORITY_NORMAL, closing_task); +} + +void HistoryService::Cleanup() { + if (!thread_) { + // We've already cleaned up. + return; + } + + // Unload the backend. + UnloadBackend(); // Delete the thread, which joins with the background thread. We defensively // NULL the pointer before deleting it in case somebody tries to use it @@ -209,7 +230,11 @@ void HistoryService::NotifyRenderProcessHostDestruction(const void* host) { &HistoryBackend::NotifyRenderProcessHostDestruction, host); } -history::URLDatabase* HistoryService::in_memory_database() const { +history::URLDatabase* HistoryService::InMemoryDatabase() { + // NOTE: See comments in BackendLoaded() as to why we call + // LoadBackendIfNecessary() here even though it won't affect the return value + // for this call. + LoadBackendIfNecessary(); if (in_memory_backend_.get()) return in_memory_backend_->db(); return NULL; @@ -297,7 +322,7 @@ void HistoryService::AddPage(const GURL& url, PageTransition::Type transition, const history::RedirectList& redirects, bool did_replace_entry) { - DCHECK(history_backend_) << "History service being called after cleanup"; + DCHECK(thread_) << "History service being called after cleanup"; // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a // large part of history (think iframes for ads) and we never display them in @@ -387,6 +412,7 @@ void HistoryService::SetPageContents(const GURL& url, const std::wstring& contents) { if (!CanAddURL(url)) return; + ScheduleAndForget(PRIORITY_LOW, &HistoryBackend::SetPageContents, url, contents); } @@ -411,33 +437,23 @@ HistoryService::Handle HistoryService::GetPageThumbnail( void HistoryService::GetFavicon(FaviconService::GetFaviconRequest* request, const GURL& icon_url) { - ScheduleTask(PRIORITY_NORMAL, - NewRunnableMethod(history_backend_.get(), - &HistoryBackend::GetFavIcon, - scoped_refptr<FaviconService::GetFaviconRequest>(request), - icon_url)); + Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFavIcon, NULL, request, + icon_url); } void HistoryService::UpdateFaviconMappingAndFetch( FaviconService::GetFaviconRequest* request, const GURL& page_url, const GURL& icon_url) { - ScheduleTask(PRIORITY_NORMAL, - NewRunnableMethod(history_backend_.get(), - &HistoryBackend::UpdateFavIconMappingAndFetch, - scoped_refptr<FaviconService::GetFaviconRequest>(request), - page_url, - icon_url)); + Schedule(PRIORITY_NORMAL, &HistoryBackend::UpdateFavIconMappingAndFetch, NULL, + request, page_url, icon_url); } void HistoryService::GetFaviconForURL( FaviconService::GetFaviconRequest* request, const GURL& page_url) { - ScheduleTask(PRIORITY_UI, - NewRunnableMethod(history_backend_.get(), - &HistoryBackend::GetFavIconForURL, - scoped_refptr<FaviconService::GetFaviconRequest>(request), - page_url)); + Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFavIconForURL, NULL, request, + page_url); } void HistoryService::SetFavicon(const GURL& page_url, @@ -696,6 +712,19 @@ void HistoryService::BroadcastNotifications( NotificationService::current()->Notify(type, source, det); } +void HistoryService::LoadBackendIfNecessary() { + if (!thread_ || history_backend_) + return; // Failed to init, or already started loading. + + scoped_refptr<HistoryBackend> backend( + new HistoryBackend(history_dir_, + new BackendDelegate(this), + bookmark_service_)); + history_backend_.swap(backend); + + ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init); +} + void HistoryService::OnDBLoaded() { LOG(INFO) << "History backend finished loading"; backend_loaded_ = true; diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h index cf80a57..13bbf4c 100644 --- a/chrome/browser/history/history.h +++ b/chrome/browser/history/history.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,6 +9,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/file_path.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/task.h" @@ -102,8 +103,14 @@ class HistoryService : public CancelableRequestProvider, // test if a URL is bookmarked; it may be NULL during testing. bool Init(const FilePath& history_dir, BookmarkService* bookmark_service); - // Did the backend finish loading the databases? - bool backend_loaded() const { return backend_loaded_; } + // Triggers the backend to load if it hasn't already, and then returns whether + // it's finished loading. + bool BackendLoaded(); + + // Unloads the backend without actually shutting down the history service. + // This can be used to temporarily reduce the browser process' memory + // footprint. + void UnloadBackend(); // Called on shutdown, this will tell the history backend to complete and // will release pointers to it. No other functions should be called once @@ -124,12 +131,13 @@ class HistoryService : public CancelableRequestProvider, // identification purposes, hence it is a void*. void NotifyRenderProcessHostDestruction(const void* host); - // Returns the in-memory URL database. The returned pointer MAY BE NULL if - // the in-memory database has not been loaded yet. This pointer is owned - // by the history system. Callers should not store or cache this value. + // Triggers the backend to load if it hasn't already, and then returns the + // in-memory URL database. The returned pointer MAY BE NULL if the in-memory + // database has not been loaded yet. This pointer is owned by the history + // system. Callers should not store or cache this value. // // TODO(brettw) this should return the InMemoryHistoryBackend. - history::URLDatabase* in_memory_database() const; + history::URLDatabase* InMemoryDatabase(); // Navigation ---------------------------------------------------------------- @@ -553,6 +561,9 @@ class HistoryService : public CancelableRequestProvider, void BroadcastNotifications(NotificationType type, history::HistoryDetails* details_deleted); + // Initializes the backend. + void LoadBackendIfNecessary(); + // Notification from the backend that it has finished loading. Sends // notification (NOTIFY_HISTORY_LOADED) and sets backend_loaded_ to true. void OnDBLoaded(); @@ -613,7 +624,7 @@ class HistoryService : public CancelableRequestProvider, // Schedule ------------------------------------------------------------------ // // Functions for scheduling operations on the history thread that have a - // handle and are cancelable. For fire-and-forget operations, see + // handle and may be cancelable. For fire-and-forget operations, see // ScheduleAndForget below. template<typename BackendFunc, class RequestType> @@ -621,8 +632,10 @@ class HistoryService : public CancelableRequestProvider, BackendFunc func, // Function to call on the HistoryBackend. CancelableRequestConsumerBase* consumer, RequestType* request) { - DCHECK(history_backend_) << "History service being called after cleanup"; - AddRequest(request, consumer); + DCHECK(thread_) << "History service being called after cleanup"; + LoadBackendIfNecessary(); + if (consumer) + AddRequest(request, consumer); ScheduleTask(priority, NewRunnableMethod(history_backend_.get(), func, scoped_refptr<RequestType>(request))); @@ -635,8 +648,10 @@ class HistoryService : public CancelableRequestProvider, CancelableRequestConsumerBase* consumer, RequestType* request, const ArgA& a) { - DCHECK(history_backend_) << "History service being called after cleanup"; - AddRequest(request, consumer); + DCHECK(thread_) << "History service being called after cleanup"; + LoadBackendIfNecessary(); + if (consumer) + AddRequest(request, consumer); ScheduleTask(priority, NewRunnableMethod(history_backend_.get(), func, scoped_refptr<RequestType>(request), @@ -654,8 +669,10 @@ class HistoryService : public CancelableRequestProvider, RequestType* request, const ArgA& a, const ArgB& b) { - DCHECK(history_backend_) << "History service being called after cleanup"; - AddRequest(request, consumer); + DCHECK(thread_) << "History service being called after cleanup"; + LoadBackendIfNecessary(); + if (consumer) + AddRequest(request, consumer); ScheduleTask(priority, NewRunnableMethod(history_backend_.get(), func, scoped_refptr<RequestType>(request), @@ -675,8 +692,10 @@ class HistoryService : public CancelableRequestProvider, const ArgA& a, const ArgB& b, const ArgC& c) { - DCHECK(history_backend_) << "History service being called after cleanup"; - AddRequest(request, consumer); + DCHECK(thread_) << "History service being called after cleanup"; + LoadBackendIfNecessary(); + if (consumer) + AddRequest(request, consumer); ScheduleTask(priority, NewRunnableMethod(history_backend_.get(), func, scoped_refptr<RequestType>(request), @@ -692,7 +711,8 @@ class HistoryService : public CancelableRequestProvider, template<typename BackendFunc> void ScheduleAndForget(SchedulePriority priority, BackendFunc func) { // Function to call on backend. - DCHECK(history_backend_) << "History service being called after cleanup"; + DCHECK(thread_) << "History service being called after cleanup"; + LoadBackendIfNecessary(); ScheduleTask(priority, NewRunnableMethod(history_backend_.get(), func)); } @@ -700,7 +720,8 @@ class HistoryService : public CancelableRequestProvider, void ScheduleAndForget(SchedulePriority priority, BackendFunc func, // Function to call on backend. const ArgA& a) { - DCHECK(history_backend_) << "History service being called after cleanup"; + DCHECK(thread_) << "History service being called after cleanup"; + LoadBackendIfNecessary(); ScheduleTask(priority, NewRunnableMethod(history_backend_.get(), func, a)); } @@ -709,7 +730,8 @@ class HistoryService : public CancelableRequestProvider, BackendFunc func, // Function to call on backend. const ArgA& a, const ArgB& b) { - DCHECK(history_backend_) << "History service being called after cleanup"; + DCHECK(thread_) << "History service being called after cleanup"; + LoadBackendIfNecessary(); ScheduleTask(priority, NewRunnableMethod(history_backend_.get(), func, a, b)); } @@ -720,7 +742,8 @@ class HistoryService : public CancelableRequestProvider, const ArgA& a, const ArgB& b, const ArgC& c) { - DCHECK(history_backend_) << "History service being called after cleanup"; + DCHECK(thread_) << "History service being called after cleanup"; + LoadBackendIfNecessary(); ScheduleTask(priority, NewRunnableMethod(history_backend_.get(), func, a, b, c)); } @@ -736,7 +759,8 @@ class HistoryService : public CancelableRequestProvider, const ArgB& b, const ArgC& c, const ArgD& d) { - DCHECK(history_backend_) << "History service being called after cleanup"; + DCHECK(thread_) << "History service being called after cleanup"; + LoadBackendIfNecessary(); ScheduleTask(priority, NewRunnableMethod(history_backend_.get(), func, a, b, c, d)); } @@ -770,7 +794,11 @@ class HistoryService : public CancelableRequestProvider, // completed. bool backend_loaded_; - DISALLOW_EVIL_CONSTRUCTORS(HistoryService); + // Cached values from Init(), used whenever we need to reload the backend. + FilePath history_dir_; + BookmarkService* bookmark_service_; + + DISALLOW_COPY_AND_ASSIGN(HistoryService); }; #endif // CHROME_BROWSER_HISTORY_HISTORY_H__ |