Index: chrome/browser/history/in_memory_url_index.cc |
=================================================================== |
--- chrome/browser/history/in_memory_url_index.cc (revision 126922) |
+++ chrome/browser/history/in_memory_url_index.cc (working copy) |
@@ -4,23 +4,52 @@ |
#include "chrome/browser/history/in_memory_url_index.h" |
+#include "base/file_util.h" |
#include "base/utf_string_conversions.h" |
#include "chrome/browser/history/history_notifications.h" |
#include "chrome/browser/history/url_database.h" |
#include "chrome/browser/history/url_index_private_data.h" |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/common/chrome_notification_types.h" |
+#include "chrome/common/url_constants.h" |
+#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/notification_details.h" |
+#include "content/public/browser/notification_service.h" |
#include "content/public/browser/notification_source.h" |
using in_memory_url_index::InMemoryURLIndexCacheItem; |
namespace history { |
+// Called by DoSaveToCacheFile to delete any old cache file at |path| when |
+// there is no private data to save. Runs on the FILE thread. |
+void DeleteCacheFile(const FilePath& path) { |
+ DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ file_util::Delete(path, false); |
+} |
+ |
+// RefCountedBool -------------------------------------------------------------- |
+ |
+RefCountedBool::~RefCountedBool() {} |
+ |
+// Restore/SaveCacheObserver --------------------------------------------------- |
+ |
+InMemoryURLIndex::RestoreCacheObserver::~RestoreCacheObserver() {} |
+ |
+InMemoryURLIndex::SaveCacheObserver::~SaveCacheObserver() {} |
+ |
+// RebuildPrivateDataFromHistoryDBTask ----------------------------------------- |
+ |
InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: |
- RebuildPrivateDataFromHistoryDBTask(InMemoryURLIndex* index) |
+ RebuildPrivateDataFromHistoryDBTask( |
+ InMemoryURLIndex* index, |
+ const std::string& languages, |
+ const std::set<std::string>& scheme_whitelist) |
: index_(index), |
- succeeded_(false) {} |
+ languages_(languages), |
+ scheme_whitelist_(scheme_whitelist), |
+ succeeded_(false) { |
+} |
InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: |
~RebuildPrivateDataFromHistoryDBTask() {} |
@@ -28,28 +57,33 @@ |
bool InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask::RunOnDBThread( |
HistoryBackend* backend, |
HistoryDatabase* db) { |
- data_.reset(URLIndexPrivateData::RebuildFromHistory(db)); |
- succeeded_ = data_.get() && !data_->history_info_map_.empty(); |
+ data_ = URLIndexPrivateData::RebuildFromHistory(db, languages_, |
+ scheme_whitelist_); |
+ succeeded_ = data_.get() && !data_->Empty(); |
if (!succeeded_) |
- data_.reset(); |
+ data_->Clear(); |
return true; |
} |
void InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask:: |
DoneRunOnMainThread() { |
- if (succeeded_) |
- index_->DoneRebuidingPrivateDataFromHistoryDB(data_.release()); |
+ index_->DoneRebuidingPrivateDataFromHistoryDB(succeeded_, data_.release()); |
} |
+// InMemoryURLIndex ------------------------------------------------------------ |
+ |
InMemoryURLIndex::InMemoryURLIndex(Profile* profile, |
const FilePath& history_dir, |
const std::string& languages) |
: profile_(profile), |
history_dir_(history_dir), |
+ languages_(languages), |
private_data_(new URLIndexPrivateData), |
+ restore_cache_observer_(NULL), |
+ save_cache_observer_(NULL), |
shutdown_(false), |
needs_to_be_cached_(false) { |
- private_data_->set_languages(languages); |
+ InMemoryURLIndex::InitializeSchemeWhitelist(&scheme_whitelist_); |
if (profile) { |
// TODO(mrossetti): Register for language change notifications. |
content::Source<Profile> source(profile); |
@@ -64,8 +98,11 @@ |
InMemoryURLIndex::InMemoryURLIndex() |
: profile_(NULL), |
private_data_(new URLIndexPrivateData), |
+ restore_cache_observer_(NULL), |
+ save_cache_observer_(NULL), |
shutdown_(false), |
needs_to_be_cached_(false) { |
+ InMemoryURLIndex::InitializeSchemeWhitelist(&scheme_whitelist_); |
} |
InMemoryURLIndex::~InMemoryURLIndex() { |
@@ -75,14 +112,14 @@ |
} |
void InMemoryURLIndex::Init() { |
- RestoreFromCacheFile(); |
+ PostRestoreFromCacheFileTask(); |
} |
void InMemoryURLIndex::ShutDown() { |
registrar_.RemoveAll(); |
cache_reader_consumer_.CancelAllRequests(); |
shutdown_ = true; |
- SaveToCacheFile(); |
+ PostSaveToCacheFileTask(); |
needs_to_be_cached_ = false; |
} |
@@ -121,12 +158,11 @@ |
OnURLsDeleted( |
content::Details<history::URLsDeletedDetails>(details).ptr()); |
break; |
- case chrome::NOTIFICATION_HISTORY_LOADED: { |
+ case chrome::NOTIFICATION_HISTORY_LOADED: |
registrar_.Remove(this, chrome::NOTIFICATION_HISTORY_LOADED, |
content::Source<Profile>(profile_)); |
ScheduleRebuildFromHistory(); |
break; |
- } |
default: |
// For simplicity, the unit tests send us all notifications, even when |
// we haven't registered for them, so don't assert here. |
@@ -135,13 +171,15 @@ |
} |
void InMemoryURLIndex::OnURLVisited(const URLVisitedDetails* details) { |
- needs_to_be_cached_ |= private_data_->UpdateURL(details->row); |
+ needs_to_be_cached_ |= |
+ private_data_->UpdateURL(details->row, languages_, scheme_whitelist_); |
} |
void InMemoryURLIndex::OnURLsModified(const URLsModifiedDetails* details) { |
for (URLRows::const_iterator row = details->changed_urls.begin(); |
row != details->changed_urls.end(); ++row) |
- needs_to_be_cached_ |= private_data_->UpdateURL(*row); |
+ needs_to_be_cached_ |= |
+ private_data_->UpdateURL(*row, languages_, scheme_whitelist_); |
} |
void InMemoryURLIndex::OnURLsDeleted(const URLsDeletedDetails* details) { |
@@ -157,24 +195,43 @@ |
// Restoring from Cache -------------------------------------------------------- |
-void InMemoryURLIndex::RestoreFromCacheFile() { |
+void InMemoryURLIndex::PostRestoreFromCacheFileTask() { |
FilePath path; |
- if (GetCacheFilePath(&path) && !shutdown_) |
- DoRestoreFromCacheFile(path); |
+ if (!GetCacheFilePath(&path) || shutdown_) |
+ return; |
+ scoped_refptr<URLIndexPrivateData> restored_private_data = |
+ new URLIndexPrivateData; |
+ content::BrowserThread::PostTaskAndReply( |
+ content::BrowserThread::FILE, FROM_HERE, |
+ base::Bind(&URLIndexPrivateData::RestoreFromFileTask, path, |
+ restored_private_data, languages_), |
+ base::Bind(&InMemoryURLIndex::OnCacheLoadDone, AsWeakPtr(), |
+ restored_private_data)); |
} |
-void InMemoryURLIndex::DoRestoreFromCacheFile(const FilePath& path) { |
- if (private_data_->RestoreFromFile(path)) |
- return; |
- |
- // When unable to restore from the cache file we must rebuild from the |
- // history database. |
- HistoryService* service = profile_->GetHistoryServiceWithoutCreating(); |
- if (service && service->backend_loaded()) |
- ScheduleRebuildFromHistory(); |
- // We must wait to rebuild until the history backend has been loaded. |
- registrar_.Add(this, chrome::NOTIFICATION_HISTORY_LOADED, |
- content::Source<Profile>(profile_)); |
+void InMemoryURLIndex::OnCacheLoadDone( |
+ scoped_refptr<URLIndexPrivateData> private_data) { |
+ if (private_data.get() && !private_data->Empty()) { |
+ private_data_ = private_data; |
+ if (restore_cache_observer_) |
+ restore_cache_observer_->OnCacheRestoreFinished(true); |
+ } else if (profile_) { |
+ // When unable to restore from the cache file delete the cache file, if |
+ // it exists, and then rebuild from the history database if it's available, |
+ // otherwise wait until the history database loaded and then rebuild. |
+ FilePath path; |
+ if (!GetCacheFilePath(&path) || shutdown_) |
+ return; |
+ content::BrowserThread::PostBlockingPoolTask( |
+ FROM_HERE, base::Bind(DeleteCacheFile, path)); |
+ HistoryService* service = profile_->GetHistoryServiceWithoutCreating(); |
+ if (service && service->backend_loaded()) { |
+ ScheduleRebuildFromHistory(); |
+ } else { |
+ registrar_.Add(this, chrome::NOTIFICATION_HISTORY_LOADED, |
+ content::Source<Profile>(profile_)); |
+ } |
+ } |
} |
// Restoring from the History DB ----------------------------------------------- |
@@ -183,34 +240,79 @@ |
HistoryService* service = |
profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); |
service->ScheduleDBTask( |
- new InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask(this), |
+ new InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask( |
+ this, languages_, scheme_whitelist_), |
&cache_reader_consumer_); |
} |
void InMemoryURLIndex::DoneRebuidingPrivateDataFromHistoryDB( |
+ bool succeeded, |
URLIndexPrivateData* data) { |
- scoped_ptr<URLIndexPrivateData> private_data(data); |
- private_data_.swap(private_data); |
- // Cache the newly rebuilt index. |
- FilePath cache_file_path; |
- if (GetCacheFilePath(&cache_file_path)) |
- private_data_->SaveToFile(cache_file_path); |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ scoped_refptr<URLIndexPrivateData> private_data(data); |
+ if (succeeded) { |
+ private_data_ = private_data; |
+ PostSaveToCacheFileTask(); // Cache the newly rebuilt index. |
+ } else { |
+ private_data_->Clear(); // Dump the old private data. |
+ // There is no need to do anything with the cache file as it was deleted |
+ // when the rebuild from the history operation was kicked off. |
+ } |
+ if (restore_cache_observer_) |
+ restore_cache_observer_->OnCacheRestoreFinished(succeeded); |
} |
void InMemoryURLIndex::RebuildFromHistory(HistoryDatabase* history_db) { |
- private_data_.reset(URLIndexPrivateData::RebuildFromHistory(history_db)); |
+ private_data_ = URLIndexPrivateData::RebuildFromHistory(history_db, |
+ languages_, |
+ scheme_whitelist_); |
} |
// Saving to Cache ------------------------------------------------------------- |
-void InMemoryURLIndex::SaveToCacheFile() { |
+void InMemoryURLIndex::PostSaveToCacheFileTask() { |
FilePath path; |
- if (GetCacheFilePath(&path)) |
- DoSaveToCacheFile(path); |
+ if (!GetCacheFilePath(&path)) |
+ return; |
+ // If there is anything in our private data then make a copy of it and tell |
+ // it to save itself to a file. |
+ URLIndexPrivateData* private_data = private_data_.get(); |
+ if (private_data && !private_data->Empty()) { |
+ // Note that ownership of the copy of our private data is passed to the |
+ // completion closure below. |
+ scoped_refptr<URLIndexPrivateData> private_data_copy = |
+ private_data->Duplicate(); |
+ scoped_refptr<RefCountedBool> succeeded(new RefCountedBool(false)); |
+ content::BrowserThread::PostTaskAndReply( |
+ content::BrowserThread::FILE, FROM_HERE, |
+ base::Bind(&URLIndexPrivateData::WritePrivateDataToCacheFileTask, |
+ private_data_copy, path, succeeded), |
+ base::Bind(&InMemoryURLIndex::OnCacheSaveDone, AsWeakPtr(), succeeded)); |
+ } else { |
+ // If there is no data in our index then delete any existing cache file. |
+ content::BrowserThread::PostBlockingPoolTask( |
+ FROM_HERE, |
+ base::Bind(DeleteCacheFile, path)); |
+ } |
} |
-void InMemoryURLIndex::DoSaveToCacheFile(const FilePath& path) { |
- private_data_->SaveToFile(path); |
+void InMemoryURLIndex::OnCacheSaveDone( |
+ scoped_refptr<RefCountedBool> succeeded) { |
+ if (save_cache_observer_) |
+ save_cache_observer_->OnCacheSaveFinished(succeeded->value()); |
} |
+// static |
+void InMemoryURLIndex::InitializeSchemeWhitelist( |
+ std::set<std::string>* whitelist) { |
+ DCHECK(whitelist); |
+ whitelist->insert(std::string(chrome::kAboutScheme)); |
+ whitelist->insert(std::string(chrome::kChromeUIScheme)); |
+ whitelist->insert(std::string(chrome::kFileScheme)); |
+ whitelist->insert(std::string(chrome::kFtpScheme)); |
+ whitelist->insert(std::string(chrome::kHttpScheme)); |
+ whitelist->insert(std::string(chrome::kHttpsScheme)); |
+ whitelist->insert(std::string(chrome::kMailToScheme)); |
+} |
+ |
} // namespace history |