diff options
author | georgey@chromium.org <georgey@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-17 00:44:51 +0000 |
---|---|---|
committer | georgey@chromium.org <georgey@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-17 00:44:51 +0000 |
commit | 9c8242a77c7788a30112f6d840c12e481f312362 (patch) | |
tree | 0b1c4f96986206d413296113d632045d707c2d93 | |
parent | 67c4e954ea58ea701c7500d622901ff3f7a03f60 (diff) | |
download | chromium_src-9c8242a77c7788a30112f6d840c12e481f312362.zip chromium_src-9c8242a77c7788a30112f6d840c12e481f312362.tar.gz chromium_src-9c8242a77c7788a30112f6d840c12e481f312362.tar.bz2 |
Fixes and simplification to ShortcutsBackend including addition of "DeleteAll"
TEST=unit-tests
BUG=none
Review URL: http://codereview.chromium.org/7821011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@101611 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/autocomplete/shortcuts_provider.cc | 67 | ||||
-rw-r--r-- | chrome/browser/autocomplete/shortcuts_provider.h | 23 | ||||
-rw-r--r-- | chrome/browser/autocomplete/shortcuts_provider_unittest.cc | 115 | ||||
-rw-r--r-- | chrome/browser/history/shortcuts_backend.cc | 205 | ||||
-rw-r--r-- | chrome/browser/history/shortcuts_backend.h | 75 | ||||
-rw-r--r-- | chrome/browser/history/shortcuts_backend_unittest.cc | 58 | ||||
-rw-r--r-- | chrome/browser/history/shortcuts_database.cc | 75 | ||||
-rw-r--r-- | chrome/browser/history/shortcuts_database.h | 13 | ||||
-rw-r--r-- | chrome/browser/history/shortcuts_database_unittest.cc | 16 |
9 files changed, 326 insertions, 321 deletions
diff --git a/chrome/browser/autocomplete/shortcuts_provider.cc b/chrome/browser/autocomplete/shortcuts_provider.cc index 1b29dac..4ef6ae9 100644 --- a/chrome/browser/autocomplete/shortcuts_provider.cc +++ b/chrome/browser/autocomplete/shortcuts_provider.cc @@ -61,11 +61,12 @@ ShortcutsProvider::ShortcutsProvider(ACProviderListener* listener, Profile* profile) : AutocompleteProvider(listener, profile, "ShortcutsProvider"), languages_(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)), + initialized_(false), shortcuts_backend_(profile->GetShortcutsBackend()) { if (shortcuts_backend_.get()) { shortcuts_backend_->AddObserver(this); if (shortcuts_backend_->initialized()) - LoadShortcuts(); + initialized_ = true; } } @@ -81,6 +82,9 @@ void ShortcutsProvider::Start(const AutocompleteInput& input, if (input.type() == AutocompleteInput::INVALID) return; + if (!initialized_) + return; + base::TimeTicks start_time = base::TimeTicks::Now(); GetMatches(input); if (input.text().length() < 6) { @@ -114,29 +118,7 @@ void ShortcutsProvider::DeleteMatch(const AutocompleteMatch& match) { } void ShortcutsProvider::OnShortcutsLoaded() { - LoadShortcuts(); -} - -void ShortcutsProvider::OnShortcutAddedOrUpdated(const Shortcut& shortcut) { - shortcuts_provider::GuidToShortcutsIteratorMap::iterator it = - guid_map_.find(shortcut.id); - if (it != guid_map_.end()) { - shortcuts_map_.erase(it->second); - } - guid_map_[shortcut.id] = shortcuts_map_.insert( - std::make_pair(base::i18n::ToLower(shortcut.text), shortcut)); -} - -void ShortcutsProvider::OnShortcutsRemoved( - const std::vector<std::string>& shortcuts_ids) { - for (size_t i = 0; i < shortcuts_ids.size(); ++i) { - shortcuts_provider::GuidToShortcutsIteratorMap::iterator it = - guid_map_.find(shortcuts_ids[i]); - if (it != guid_map_.end()) { - shortcuts_map_.erase(it->second); - guid_map_.erase(it); - } - } + initialized_ = true; } void ShortcutsProvider::DeleteMatchesWithURLs(const std::set<GURL>& urls) { @@ -145,13 +127,6 @@ void ShortcutsProvider::DeleteMatchesWithURLs(const std::set<GURL>& urls) { } void ShortcutsProvider::DeleteShortcutsWithURLs(const std::set<GURL>& urls) { - for (ShortcutMap::iterator it = shortcuts_map_.begin(); - it != shortcuts_map_.end();) { - if (urls.find(it->second.url) != urls.end()) - shortcuts_map_.erase(it++); - else - ++it; - } if (!shortcuts_backend_.get()) return; // We are off the record. for (std::set<GURL>::const_iterator url = urls.begin(); url != urls.end(); @@ -165,8 +140,8 @@ void ShortcutsProvider::GetMatches(const AutocompleteInput& input) { string16 term_string(base::i18n::ToLower(input.text())); DCHECK(!term_string.empty()); - for (ShortcutMap::iterator it = FindFirstMatch(term_string); - it != shortcuts_map_.end() && + for (ShortcutMap::const_iterator it = FindFirstMatch(term_string); + it != shortcuts_backend_->shortcuts_map().end() && StartsWith(it->first, term_string, true); ++it) matches_.push_back(ShortcutToACMatch(input, term_string, it)); std::partial_sort(matches_.begin(), @@ -182,7 +157,7 @@ void ShortcutsProvider::GetMatches(const AutocompleteInput& input) { AutocompleteMatch ShortcutsProvider::ShortcutToACMatch( const AutocompleteInput& input, const string16& term_string, - ShortcutMap::iterator it) { + ShortcutMap::const_iterator it) { AutocompleteMatch match(this, CalculateScore(term_string, it->second), true, AutocompleteMatch::HISTORY_TITLE); match.destination_url = it->second.url; @@ -280,13 +255,15 @@ ACMatchClassifications ShortcutsProvider::ClassifyAllMatchesInString( return output; } -ShortcutMap::iterator ShortcutsProvider::FindFirstMatch( +ShortcutMap::const_iterator ShortcutsProvider::FindFirstMatch( const string16& keyword) { - ShortcutMap::iterator it = shortcuts_map_.lower_bound(keyword); + ShortcutMap::const_iterator it = + shortcuts_backend_->shortcuts_map().lower_bound(keyword); // Lower bound not necessarily matches the keyword, check for item pointed by // the lower bound iterator to at least start with keyword. - return ((it == shortcuts_map_.end()) || - StartsWith(it->first, keyword, true)) ? it : shortcuts_map_.end(); + return ((it == shortcuts_backend_->shortcuts_map().end()) || + StartsWith(it->first, keyword, true)) ? it : + shortcuts_backend_->shortcuts_map().end(); } // static @@ -320,11 +297,11 @@ int ShortcutsProvider::CalculateScore(const string16& terms, 0.5); } -void ShortcutsProvider::LoadShortcuts() { - DCHECK(shortcuts_backend_.get()); - guid_map_.clear(); - CHECK(shortcuts_backend_->GetShortcuts(&shortcuts_map_)); - for (shortcuts_provider::ShortcutMap::iterator it = shortcuts_map_.begin(); - it != shortcuts_map_.end(); ++it) - guid_map_[it->second.id] = it; +void ShortcutsProvider::set_shortcuts_backend( + history::ShortcutsBackend* shortcuts_backend) { + DCHECK(shortcuts_backend); + shortcuts_backend_ = shortcuts_backend; + shortcuts_backend_->AddObserver(this); + if (shortcuts_backend_->initialized()) + initialized_ = true; } diff --git a/chrome/browser/autocomplete/shortcuts_provider.h b/chrome/browser/autocomplete/shortcuts_provider.h index 38161d4..d41a70b 100644 --- a/chrome/browser/autocomplete/shortcuts_provider.h +++ b/chrome/browser/autocomplete/shortcuts_provider.h @@ -51,10 +51,6 @@ class ShortcutsProvider // ShortcutsBackendObserver: virtual void OnShortcutsLoaded() OVERRIDE; - virtual void OnShortcutAddedOrUpdated( - const shortcuts_provider::Shortcut& shortcut) OVERRIDE; - virtual void OnShortcutsRemoved( - const std::vector<std::string>& shortcut_ids) OVERRIDE; void DeleteMatchesWithURLs(const std::set<GURL>& urls); void DeleteShortcutsWithURLs(const std::set<GURL>& urls); @@ -65,7 +61,7 @@ class ShortcutsProvider AutocompleteMatch ShortcutToACMatch( const AutocompleteInput& input, const string16& terms, - shortcuts_provider::ShortcutMap::iterator it); + shortcuts_provider::ShortcutMap::const_iterator it); // Given |text| and a corresponding base set of classifications // |original_class|, adds ACMatchClassification::MATCH markers for all @@ -85,25 +81,16 @@ class ShortcutsProvider // Returns iterator to first item in |shortcuts_map_| matching |keyword|. // Returns shortcuts_map_.end() if there are no matches. - shortcuts_provider::ShortcutMap::iterator FindFirstMatch( + shortcuts_provider::ShortcutMap::const_iterator FindFirstMatch( const string16& keyword); static int CalculateScore(const string16& terms, const shortcuts_provider::Shortcut& shortcut); - - // Loads shortcuts from the backend. - void LoadShortcuts(); + // For unit-test only. + void set_shortcuts_backend(history::ShortcutsBackend* shortcuts_backend); std::string languages_; - - // The following two maps are duplicated from the ShortcutsBackend. If any - // of the copies of ShortcutProvider makes a change and calls ShortcutBackend - // the change will be committed to storage and to the back-end's copy on the - // DB thread and propagated back to all copies of provider, so eventually they - // all are going to be in sync. - shortcuts_provider::ShortcutMap shortcuts_map_; - // This is a helper map for quick access to a shortcut by guid. - shortcuts_provider::GuidToShortcutsIteratorMap guid_map_; + bool initialized_; scoped_refptr<history::ShortcutsBackend> shortcuts_backend_; }; diff --git a/chrome/browser/autocomplete/shortcuts_provider_unittest.cc b/chrome/browser/autocomplete/shortcuts_provider_unittest.cc index 534c53d..7b98206 100644 --- a/chrome/browser/autocomplete/shortcuts_provider_unittest.cc +++ b/chrome/browser/autocomplete/shortcuts_provider_unittest.cc @@ -18,6 +18,7 @@ #include "chrome/browser/autocomplete/autocomplete_match.h" #include "chrome/browser/history/history.h" #include "chrome/browser/history/in_memory_url_index.h" +#include "chrome/browser/history/shortcuts_backend.h" #include "chrome/browser/history/url_database.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/common/pref_names.h" @@ -31,6 +32,7 @@ using base::TimeDelta; namespace { struct TestShortcutInfo { + std::string guid; std::string url; std::string title; // The text that orginally was searched for. std::string contents; @@ -40,62 +42,79 @@ struct TestShortcutInfo { int typed_count; int days_from_now; } shortcut_test_db[] = { - { "http://www.google.com/", "goog", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E0", + "http://www.google.com/", "goog", "Google", "0,1,4,0", "Google", "0,3,4,1", 100, 1 }, - { "http://slashdot.org/", "slash", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E1", + "http://slashdot.org/", "slash", "slashdot.org", "0,3,5,1", "Slashdot - News for nerds, stuff that matters", "0,2,5,0", 100, 0}, - { "http://slashdot.org/", "news", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E2", + "http://slashdot.org/", "news", "slashdot.org", "0,1", "Slashdot - News for nerds, stuff that matters", "0,0,11,2,15,0", 5, 0}, - { "http://sports.yahoo.com/", "news", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E3", + "http://sports.yahoo.com/", "news", "sports.yahoo.com", "0,1", "Yahoo! Sports - Sports News, Scores, Rumors, Fantasy Games, and more", "0,0,23,2,27,0", 5, 2}, - { "http://www.cnn.com/index.html", "news weather", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E4", + "http://www.cnn.com/index.html", "news weather", "www.cnn.com/index.html", "0,1", "CNN.com - Breaking News, U.S., World, Weather, Entertainment & Video", "0,0,19,2,23,0,38,2,45,0", 10, 1}, - { "http://sports.yahoo.com/", "nhl scores", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E5", + "http://sports.yahoo.com/", "nhl scores", "sports.yahoo.com", "0,1", "Yahoo! Sports - Sports News, Scores, Rumors, Fantasy Games, and more", "0,0,29,2,35,0", 10, 1}, - { "http://www.nhl.com/scores/index.html", "nhl scores", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E6", + "http://www.nhl.com/scores/index.html", "nhl scores", "www.nhl.com/scores/index.html", "0,1,4,3,7,1", "January 13, 2010 - NHL.com - Scores", "0,0,19,2,22,0,29,2,35,0", 1, 5}, - { "http://www.testsite.com/a.html", "just", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E7", + "http://www.testsite.com/a.html", "just", "www.testsite.com/a.html", "0,1", "Test - site - just a test", "0,0,14,2,18,0", 1, 5}, - { "http://www.testsite.com/b.html", "just", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E8", + "http://www.testsite.com/b.html", "just", "www.testsite.com/b.html", "0,1", "Test - site - just a test", "0,0,14,2,18,0", 2, 5}, - { "http://www.testsite.com/c.html", "just", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880E9", + "http://www.testsite.com/c.html", "just", "www.testsite.com/c.html", "0,1", "Test - site - just a test", "0,0,14,2,18,0", 1, 8}, - { "http://www.testsite.com/d.html", "just a", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880EA", + "http://www.testsite.com/d.html", "just a", "www.testsite.com/d.html", "0,1", "Test - site - just a test", "0,0,14,2,18,0", 1, 12}, - { "http://www.testsite.com/e.html", "just a t", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880EB", + "http://www.testsite.com/e.html", "just a t", "www.testsite.com/e.html", "0,1", "Test - site - just a test", "0,0,14,2,18,0", 1, 12}, - { "http://www.testsite.com/f.html", "just a te", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880EC", + "http://www.testsite.com/f.html", "just a te", "www.testsite.com/f.html", "0,1", "Test - site - just a test", "0,0,14,2,18,0", 1, 12}, - { "http://www.daysagotest.com/a.html", "ago", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880ED", + "http://www.daysagotest.com/a.html", "ago", "www.daysagotest.com/a.html", "0,1,8,3,11,1", "Test - site", "0,0", 1, 1}, - { "http://www.daysagotest.com/b.html", "ago", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880EE", + "http://www.daysagotest.com/b.html", "ago", "www.daysagotest.com/b.html", "0,1,8,3,11,1", "Test - site", "0,0", 1, 2}, - { "http://www.daysagotest.com/c.html", "ago", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880EF", + "http://www.daysagotest.com/c.html", "ago", "www.daysagotest.com/c.html", "0,1,8,3,11,1", "Test - site", "0,0", 1, 3}, - { "http://www.daysagotest.com/d.html", "ago", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880F0", + "http://www.daysagotest.com/d.html", "ago", "www.daysagotest.com/d.html", "0,1,8,3,11,1", "Test - site", "0,0", 1, 4}, }; -} // end namespace +} // namespace class ShortcutsProviderTest : public testing::Test, public ACProviderListener { @@ -139,6 +158,7 @@ class ShortcutsProviderTest : public testing::Test, ACMatches ac_matches_; // The resulting matches after running RunTest. + scoped_refptr<history::ShortcutsBackend> mock_backend_; scoped_refptr<ShortcutsProvider> provider_; }; @@ -154,6 +174,9 @@ void ShortcutsProviderTest::SetUp() { profile_.reset(new TestingProfile()); profile_->CreateHistoryService(true, false); provider_ = new ShortcutsProvider(this, profile_.get()); + mock_backend_ = new history::ShortcutsBackend(FilePath(), profile_.get()); + mock_backend_->Init(); + provider_->set_shortcuts_backend(mock_backend_.get()); FillData(); } @@ -163,7 +186,7 @@ void ShortcutsProviderTest::TearDown() { void ShortcutsProviderTest::FillData() { DCHECK(provider_.get()); - provider_->shortcuts_map_.clear(); + mock_backend_->DeleteAllShortcuts(); for (size_t i = 0; i < arraysize(shortcut_test_db); ++i) { const TestShortcutInfo& cur = shortcut_test_db[i]; const GURL current_url(cur.url); @@ -177,8 +200,8 @@ void ShortcutsProviderTest::FillData() { shortcuts_provider::SpansFromString( ASCIIToUTF16(cur.description_class))); shortcut.last_access_time = visit_time; - provider_->shortcuts_map_.insert(std::make_pair(ASCIIToUTF16(cur.title), - shortcut)); + shortcut.id = cur.guid; + mock_backend_->AddShortcut(shortcut); } } @@ -536,18 +559,22 @@ TEST_F(ShortcutsProviderTest, CalculateScore) { TEST_F(ShortcutsProviderTest, DeleteMatch) { TestShortcutInfo shortcuts_to_test_delete[3] = { - { "http://www.deletetest.com/1.html", "delete", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880F1", + "http://www.deletetest.com/1.html", "delete", "http://www.deletetest.com/1.html", "0,2", "Erase this shortcut!", "0,0", 1, 1}, - { "http://www.deletetest.com/1.html", "erase", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880F2", + "http://www.deletetest.com/1.html", "erase", "http://www.deletetest.com/1.html", "0,2", "Erase this shortcut!", "0,0", 1, 1}, - { "http://www.deletetest.com/2.html", "delete", + { "BD85DBA2-8C29-49F9-84AE-48E1E90880F3", + "http://www.deletetest.com/2.html", "delete", "http://www.deletetest.com/2.html", "0,2", "Erase this shortcut!", "0,0", 1, 1}, }; - size_t original_shortcuts_count = provider_->shortcuts_map_.size(); + size_t original_shortcuts_count = + provider_->shortcuts_backend_->shortcuts_map().size(); for (size_t i = 0; i < arraysize(shortcuts_to_test_delete); ++i) { const TestShortcutInfo& cur = shortcuts_to_test_delete[i]; @@ -562,15 +589,18 @@ TEST_F(ShortcutsProviderTest, DeleteMatch) { shortcuts_provider::SpansFromString( ASCIIToUTF16(cur.description_class))); shortcut.last_access_time = visit_time; - provider_->shortcuts_map_.insert(std::make_pair(ASCIIToUTF16(cur.title), - shortcut)); + shortcut.id = cur.guid; + mock_backend_->AddShortcut(shortcut); } - EXPECT_EQ(original_shortcuts_count + 3, provider_->shortcuts_map_.size()); - EXPECT_FALSE(provider_->shortcuts_map_.end() == - provider_->shortcuts_map_.find(ASCIIToUTF16("delete"))); - EXPECT_FALSE(provider_->shortcuts_map_.end() == - provider_->shortcuts_map_.find(ASCIIToUTF16("erase"))); + EXPECT_EQ(original_shortcuts_count + 3, + provider_->shortcuts_backend_->shortcuts_map().size()); + EXPECT_FALSE(provider_->shortcuts_backend_->shortcuts_map().end() == + provider_->shortcuts_backend_->shortcuts_map().find( + ASCIIToUTF16("delete"))); + EXPECT_FALSE(provider_->shortcuts_backend_->shortcuts_map().end() == + provider_->shortcuts_backend_->shortcuts_map().find( + ASCIIToUTF16("erase"))); AutocompleteMatch match(provider_, 1200, true, AutocompleteMatch::HISTORY_TITLE); @@ -583,18 +613,23 @@ TEST_F(ShortcutsProviderTest, DeleteMatch) { // |shortcuts_to_test_delete[0]| and |shortcuts_to_test_delete[1]| should be // deleted, but not |shortcuts_to_test_delete[2]| as it has different url. - EXPECT_EQ(original_shortcuts_count + 1, provider_->shortcuts_map_.size()); - EXPECT_FALSE(provider_->shortcuts_map_.end() == - provider_->shortcuts_map_.find(ASCIIToUTF16("delete"))); - EXPECT_TRUE(provider_->shortcuts_map_.end() == - provider_->shortcuts_map_.find(ASCIIToUTF16("erase"))); + EXPECT_EQ(original_shortcuts_count + 1, + provider_->shortcuts_backend_->shortcuts_map().size()); + EXPECT_FALSE(provider_->shortcuts_backend_->shortcuts_map().end() == + provider_->shortcuts_backend_->shortcuts_map().find( + ASCIIToUTF16("delete"))); + EXPECT_TRUE(provider_->shortcuts_backend_->shortcuts_map().end() == + provider_->shortcuts_backend_->shortcuts_map().find( + ASCIIToUTF16("erase"))); match.destination_url = GURL(shortcuts_to_test_delete[2].url); match.contents = ASCIIToUTF16(shortcuts_to_test_delete[2].contents); match.description = ASCIIToUTF16(shortcuts_to_test_delete[2].description); provider_->DeleteMatch(match); - EXPECT_EQ(original_shortcuts_count, provider_->shortcuts_map_.size()); - EXPECT_TRUE(provider_->shortcuts_map_.end() == - provider_->shortcuts_map_.find(ASCIIToUTF16("delete"))); + EXPECT_EQ(original_shortcuts_count, + provider_->shortcuts_backend_->shortcuts_map().size()); + EXPECT_TRUE(provider_->shortcuts_backend_->shortcuts_map().end() == + provider_->shortcuts_backend_->shortcuts_map().find( + ASCIIToUTF16("delete"))); } diff --git a/chrome/browser/history/shortcuts_backend.cc b/chrome/browser/history/shortcuts_backend.cc index 9c8d2ca..6505027 100644 --- a/chrome/browser/history/shortcuts_backend.cc +++ b/chrome/browser/history/shortcuts_backend.cc @@ -28,8 +28,8 @@ namespace history { ShortcutsBackend::ShortcutsBackend(const FilePath& db_folder_path, Profile *profile) : current_state_(NOT_INITIALIZED), - observer_list_(new ObserverListThreadSafe<ShortcutsBackendObserver>()), - db_(db_folder_path) { + db_(new ShortcutsDatabase(db_folder_path)), + no_db_access_(db_folder_path.empty()) { // |profile| can be NULL in tests. if (profile) { notification_registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, @@ -42,146 +42,151 @@ ShortcutsBackend::ShortcutsBackend(const FilePath& db_folder_path, ShortcutsBackend::~ShortcutsBackend() {} bool ShortcutsBackend::Init() { - if (base::subtle::NoBarrier_CompareAndSwap(¤t_state_, - NOT_INITIALIZED, - INITIALIZING) == NOT_INITIALIZED) { - return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, - NewRunnableMethod(this, &ShortcutsBackend::InitInternal)); + if (current_state_ == NOT_INITIALIZED) { + current_state_ = INITIALIZING; + if (no_db_access_) { + current_state_ = INITIALIZED; + return true; + } else { + return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, + NewRunnableMethod(this, &ShortcutsBackend::InitInternal)); + } } else { return false; } } -bool ShortcutsBackend::AddShortcut(shortcuts_provider::Shortcut shortcut) { - // It is safe to add a shortcut while the backend is being initialized since - // the addition will occur on the same thread as the initialization. - DCHECK(current_state_ != NOT_INITIALIZED); +bool ShortcutsBackend::AddShortcut( + const shortcuts_provider::Shortcut& shortcut) { + if (!initialized()) + return false; + DCHECK(guid_map_.find(shortcut.id) == guid_map_.end()); + guid_map_[shortcut.id] = shortcuts_map_.insert( + std::make_pair(base::i18n::ToLower(shortcut.text), shortcut)); + FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_, + OnShortcutsChanged()); + if (no_db_access_) + return true; return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, - NewRunnableMethod(this, &ShortcutsBackend::AddOrUpdateShortcutInternal, - shortcut, true)); + NewRunnableMethod(db_.get(), &ShortcutsDatabase::AddShortcut, shortcut)); } -bool ShortcutsBackend::UpdateShortcut(shortcuts_provider::Shortcut shortcut) { - DCHECK(initialized()); +bool ShortcutsBackend::UpdateShortcut( + const shortcuts_provider::Shortcut& shortcut) { + if (!initialized()) + return false; + shortcuts_provider::GuidToShortcutsIteratorMap::iterator it = + guid_map_.find(shortcut.id); + if (it != guid_map_.end()) + shortcuts_map_.erase(it->second); + guid_map_[shortcut.id] = shortcuts_map_.insert( + std::make_pair(base::i18n::ToLower(shortcut.text), shortcut)); + FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_, + OnShortcutsChanged()); + if (no_db_access_) + return true; return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, - NewRunnableMethod(this, &ShortcutsBackend::AddOrUpdateShortcutInternal, - shortcut, false)); + NewRunnableMethod(db_.get(), &ShortcutsDatabase::UpdateShortcut, + shortcut)); } bool ShortcutsBackend::DeleteShortcutsWithIds( const std::vector<std::string>& shortcut_ids) { - DCHECK(initialized()); + if (!initialized()) + return false; + for (size_t i = 0; i < shortcut_ids.size(); ++i) { + shortcuts_provider::GuidToShortcutsIteratorMap::iterator it = + guid_map_.find(shortcut_ids[i]); + if (it != guid_map_.end()) { + shortcuts_map_.erase(it->second); + guid_map_.erase(it); + } + } + FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_, + OnShortcutsChanged()); + if (no_db_access_) + return true; return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, - NewRunnableMethod(this, &ShortcutsBackend::DeleteShortcutsWithIdsInternal, + NewRunnableMethod(db_.get(), &ShortcutsDatabase::DeleteShortcutsWithIds, shortcut_ids)); } bool ShortcutsBackend::DeleteShortcutsWithUrl(const GURL& shortcut_url) { - DCHECK(initialized()); + if (!initialized()) + return false; + std::vector<std::string> shortcut_ids; + for (shortcuts_provider::GuidToShortcutsIteratorMap::iterator + it = guid_map_.begin(); + it != guid_map_.end();) { + if (it->second->second.url == shortcut_url) { + shortcut_ids.push_back(it->first); + shortcuts_map_.erase(it->second); + guid_map_.erase(it++); + } else { + ++it; + } + } + FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_, + OnShortcutsChanged()); + if (no_db_access_) + return true; return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, - NewRunnableMethod(this, &ShortcutsBackend::DeleteShortcutsWithUrlInternal, + NewRunnableMethod(db_.get(), &ShortcutsDatabase::DeleteShortcutsWithUrl, shortcut_url.spec())); } -bool ShortcutsBackend::GetShortcuts( - shortcuts_provider::ShortcutMap* shortcuts) { - DCHECK(initialized()); - DCHECK(shortcuts); - +bool ShortcutsBackend::DeleteAllShortcuts() { if (!initialized()) return false; - shortcuts->clear(); - base::AutoLock lock(data_access_lock_); - shortcuts->insert(shortcuts_map_.begin(), shortcuts_map_.end()); - return true; + shortcuts_map_.clear(); + guid_map_.clear(); + FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_, + OnShortcutsChanged()); + if (no_db_access_) + return true; + return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, + NewRunnableMethod(db_.get(), &ShortcutsDatabase::DeleteAllShortcuts)); } void ShortcutsBackend::InitInternal() { - db_.Init(); + DCHECK(current_state_ == INITIALIZING); + db_->Init(); shortcuts_provider::GuidToShortcutMap shortcuts; - db_.LoadShortcuts(&shortcuts); + db_->LoadShortcuts(&shortcuts); + temp_shortcuts_map_.reset(new shortcuts_provider::ShortcutMap); + temp_guid_map_.reset(new shortcuts_provider::GuidToShortcutsIteratorMap); for (shortcuts_provider::GuidToShortcutMap::iterator it = shortcuts.begin(); it != shortcuts.end(); ++it) { - guid_map_[it->first] = shortcuts_map_.insert( + (*temp_guid_map_)[it->first] = temp_shortcuts_map_->insert( std::make_pair(base::i18n::ToLower(it->second.text), it->second)); } - base::subtle::NoBarrier_CompareAndSwap(¤t_state_, INITIALIZING, - INITIALIZED); - observer_list_->Notify(&ShortcutsBackendObserver::OnShortcutsLoaded); -} - -void ShortcutsBackend::AddOrUpdateShortcutInternal( - shortcuts_provider::Shortcut shortcut, bool add) { - { - // Update local copy. - base::AutoLock lock(data_access_lock_); - shortcuts_provider::GuidToShortcutsIteratorMap::iterator it = - guid_map_.find(shortcut.id); - if (it != guid_map_.end()) - shortcuts_map_.erase(it->second); - guid_map_[shortcut.id] = shortcuts_map_.insert( - std::make_pair(base::i18n::ToLower(shortcut.text), shortcut)); - } - if (add) - db_.AddShortcut(shortcut); - else - db_.UpdateShortcut(shortcut); - observer_list_->Notify(&ShortcutsBackendObserver::OnShortcutAddedOrUpdated, - shortcut); -} - -void ShortcutsBackend::DeleteShortcutsWithIdsInternal( - std::vector<std::string> shortcut_ids) { - { - // Update local copy. - base::AutoLock lock(data_access_lock_); - for (size_t i = 0; i < shortcut_ids.size(); ++i) { - shortcuts_provider::GuidToShortcutsIteratorMap::iterator it = - guid_map_.find(shortcut_ids[i]); - if (it != guid_map_.end()) { - shortcuts_map_.erase(it->second); - guid_map_.erase(it); - } - } - } - db_.DeleteShortcutsWithIds(shortcut_ids); - observer_list_->Notify(&ShortcutsBackendObserver::OnShortcutsRemoved, - shortcut_ids); + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &ShortcutsBackend::InitCompleted)); } -void ShortcutsBackend::DeleteShortcutsWithUrlInternal( - std::string shortcut_url) { - std::vector<std::string> shortcut_ids; - { - // Update local copy. - base::AutoLock lock(data_access_lock_); - for (shortcuts_provider::GuidToShortcutsIteratorMap::iterator - it = guid_map_.begin(); - it != guid_map_.end();) { - if (it->second->second.url.spec() == shortcut_url) { - shortcut_ids.push_back(it->first); - shortcuts_map_.erase(it->second); - guid_map_.erase(it++); - } else { - ++it; - } - } - } - db_.DeleteShortcutsWithUrl(shortcut_url); - observer_list_->Notify(&ShortcutsBackendObserver::OnShortcutsRemoved, - shortcut_ids); +void ShortcutsBackend::InitCompleted() { + temp_guid_map_->swap(guid_map_); + temp_shortcuts_map_->swap(shortcuts_map_); + temp_shortcuts_map_.reset(NULL); + temp_guid_map_.reset(NULL); + current_state_ = INITIALIZED; + FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_, + OnShortcutsLoaded()); } // NotificationObserver: void ShortcutsBackend::Observe(int type, const NotificationSource& source, const NotificationDetails& details) { + if (current_state_ != INITIALIZED) + return; if (type == chrome::NOTIFICATION_HISTORY_URLS_DELETED) { + if (Details<const history::URLsDeletedDetails>(details)->all_history) + DeleteAllShortcuts(); const std::set<GURL>& urls = Details<const history::URLsDeletedDetails>(details)->urls; std::vector<std::string> shortcut_ids; - base::AutoLock lock(data_access_lock_); for (shortcuts_provider::GuidToShortcutsIteratorMap::iterator it = guid_map_.begin(); it != guid_map_.end(); ++it) { @@ -200,7 +205,6 @@ void ShortcutsBackend::Observe(int type, int number_of_hits = 1; std::string id; const AutocompleteMatch& match(log->result.match_at(log->selected_index)); - base::AutoLock lock(data_access_lock_); for (shortcuts_provider::ShortcutMap::iterator it = shortcuts_map_.lower_bound(text_lowercase); it != shortcuts_map_.end() && @@ -208,8 +212,6 @@ void ShortcutsBackend::Observe(int type, if (match.destination_url == it->second.url) { number_of_hits = it->second.number_of_hits + 1; id = it->second.id; - // guid_map_ will be updated further down on re-insertion. - shortcuts_map_.erase(it); break; } } @@ -222,9 +224,6 @@ void ShortcutsBackend::Observe(int type, else shortcut.id = id; - guid_map_[shortcut.id] = shortcuts_map_.insert( - std::make_pair(text_lowercase, shortcut)); - if (number_of_hits == 1) AddShortcut(shortcut); else diff --git a/chrome/browser/history/shortcuts_backend.h b/chrome/browser/history/shortcuts_backend.h index abaccd3..67bf64e 100644 --- a/chrome/browser/history/shortcuts_backend.h +++ b/chrome/browser/history/shortcuts_backend.h @@ -10,12 +10,11 @@ #include <string> #include <vector> -#include "base/atomicops.h" #include "base/file_path.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "base/observer_list_threadsafe.h" +#include "base/observer_list.h" #include "base/string16.h" #include "base/synchronization/lock.h" #include "chrome/browser/autocomplete/shortcuts_provider_shortcut.h" @@ -34,7 +33,8 @@ class ShortcutsBackend : public base::RefCountedThreadSafe<ShortcutsBackend>, public NotificationObserver { public: // |profile| is necessary for profile notifications only and can be NULL in - // unit-tests. + // unit-tests. |db_folder_path| could be an empty path only in unit-tests as + // well. It means there is no database created, all things are done in memory. ShortcutsBackend(const FilePath& db_folder_path, Profile* profile); virtual ~ShortcutsBackend(); @@ -44,13 +44,8 @@ class ShortcutsBackend : public base::RefCountedThreadSafe<ShortcutsBackend>, public: // Called after the database is loaded and Init() completed. virtual void OnShortcutsLoaded() = 0; - // This callback is called when addition or change was processed by the - // database. - virtual void OnShortcutAddedOrUpdated( - const shortcuts_provider::Shortcut& shortcut) = 0; - // Called when shortcuts are removed from the database. - virtual void OnShortcutsRemoved( - const std::vector<std::string>& shortcut_ids) = 0; + // Called when shortcuts changed (added/updated/removed) in the database. + virtual void OnShortcutsChanged() {} protected: virtual ~ShortcutsBackendObserver() {} }; @@ -61,11 +56,13 @@ class ShortcutsBackend : public base::RefCountedThreadSafe<ShortcutsBackend>, bool initialized() const { return current_state_ == INITIALIZED; } + // All of the public functions *must* be called on UI thread only! + // Adds the Shortcut to the database. - bool AddShortcut(shortcuts_provider::Shortcut shortcut); + bool AddShortcut(const shortcuts_provider::Shortcut& shortcut); // Updates timing and selection count for the Shortcut. - bool UpdateShortcut(shortcuts_provider::Shortcut shortcut); + bool UpdateShortcut(const shortcuts_provider::Shortcut& shortcut); // Deletes the Shortcuts with the id. bool DeleteShortcutsWithIds(const std::vector<std::string>& shortcut_ids); @@ -73,35 +70,32 @@ class ShortcutsBackend : public base::RefCountedThreadSafe<ShortcutsBackend>, // Deletes the Shortcuts with the url. bool DeleteShortcutsWithUrl(const GURL& shortcut_url); - // Replaces the contents of |shortcuts| with the backend's from the database. - bool GetShortcuts(shortcuts_provider::ShortcutMap* shortcuts); + // Deletes all of the shortcuts. + bool DeleteAllShortcuts(); + + const shortcuts_provider::ShortcutMap& shortcuts_map() const { + return shortcuts_map_; + } + + const shortcuts_provider::GuidToShortcutsIteratorMap& guid_map() const { + return guid_map_; + } void AddObserver(ShortcutsBackendObserver* obs) { - observer_list_->AddObserver(obs); + observer_list_.AddObserver(obs); } void RemoveObserver(ShortcutsBackendObserver* obs) { - observer_list_->RemoveObserver(obs); + observer_list_.RemoveObserver(obs); } private: // Internal initialization of the back-end. Posted by Init() to the DB thread. - // On completion notifies all back-end observers asyncronously on their own - // thread. + // On completion posts InitCompleted() back to UI thread. void InitInternal(); - // Internal addition or update of a shortcut. Posted by AddShortcut() or - // UpdateShortcut() to the DB thread. On completion notifies all back-end - // observers asyncronously on their own thread. - void AddOrUpdateShortcutInternal(shortcuts_provider::Shortcut shortcut, - bool add); - // Internal deletion of shortcuts. Posted by DeleteShortcutsWithIds() to the - // DB thread. On completion notifies all back-end observers asyncronously on - // their own thread. - void DeleteShortcutsWithIdsInternal(std::vector<std::string> shortcut_ids); - // Internal deletion of shortcut with the url. Posted by - // DeleteShortcutsWithUrl() to the DB thread. On completion notifies all - // back-end observers asyncronously on their own thread. - void DeleteShortcutsWithUrlInternal(std::string shortcut_url); + + // Finishes initialization on UI thread, notifies all observers. + void InitCompleted(); // NotificationObserver: virtual void Observe(int type, @@ -114,20 +108,25 @@ class ShortcutsBackend : public base::RefCountedThreadSafe<ShortcutsBackend>, INITIALIZED, // Initialization completed, all accessors can be safely // called. }; - // |current_state_| has values of CurrentState enum. - volatile base::subtle::Atomic32 current_state_; - scoped_refptr<ObserverListThreadSafe<ShortcutsBackendObserver> > - observer_list_; - ShortcutsDatabase db_; + CurrentState current_state_; + ObserverList<ShortcutsBackendObserver> observer_list_; + scoped_refptr<ShortcutsDatabase> db_; + + // The |temp_shortcuts_map_| and |temp_guid_map_| used for temporary storage + // between InitInternal() and InitComplete() to avoid doing a potentially huge + // copy. + scoped_ptr<shortcuts_provider::ShortcutMap> temp_shortcuts_map_; + scoped_ptr<shortcuts_provider::GuidToShortcutsIteratorMap> temp_guid_map_; shortcuts_provider::ShortcutMap shortcuts_map_; // This is a helper map for quick access to a shortcut by guid. shortcuts_provider::GuidToShortcutsIteratorMap guid_map_; - base::Lock data_access_lock_; - NotificationRegistrar notification_registrar_; + // For some unit-test only. + bool no_db_access_; + DISALLOW_COPY_AND_ASSIGN(ShortcutsBackend); }; diff --git a/chrome/browser/history/shortcuts_backend_unittest.cc b/chrome/browser/history/shortcuts_backend_unittest.cc index 0bad07c..cc38425 100644 --- a/chrome/browser/history/shortcuts_backend_unittest.cc +++ b/chrome/browser/history/shortcuts_backend_unittest.cc @@ -36,9 +36,7 @@ class ShortcutsBackendTest : public testing::Test, void TearDown(); virtual void OnShortcutsLoaded() OVERRIDE; - virtual void OnShortcutAddedOrUpdated(const Shortcut& shortcut) OVERRIDE; - virtual void OnShortcutsRemoved( - const std::vector<std::string>& shortcut_ids) OVERRIDE; + virtual void OnShortcutsChanged() OVERRIDE; void InitBackend(); @@ -49,8 +47,6 @@ class ShortcutsBackendTest : public testing::Test, BrowserThread db_thread_; bool load_notified_; - Shortcut notified_shortcut_; - std::vector<std::string> notified_shortcut_ids_; }; void ShortcutsBackendTest::SetUp() { @@ -70,15 +66,7 @@ void ShortcutsBackendTest::OnShortcutsLoaded() { MessageLoop::current()->Quit(); } -void ShortcutsBackendTest::OnShortcutAddedOrUpdated(const Shortcut& shortcut) { - notified_shortcut_ = shortcut; - MessageLoop::current()->Quit(); -} - -void ShortcutsBackendTest::OnShortcutsRemoved( - const std::vector<std::string>& shortcut_ids) { - notified_shortcut_ids_ = shortcut_ids; - MessageLoop::current()->Quit(); +void ShortcutsBackendTest::OnShortcutsChanged() { } void ShortcutsBackendTest::InitBackend() { @@ -90,7 +78,6 @@ void ShortcutsBackendTest::InitBackend() { EXPECT_TRUE(backend_->initialized()); } - TEST_F(ShortcutsBackendTest, AddAndUpdateShortcut) { InitBackend(); Shortcut shortcut("BD85DBA2-8C29-49F9-84AE-48E1E90880DF", @@ -100,14 +87,15 @@ TEST_F(ShortcutsBackendTest, AddAndUpdateShortcut) { base::Time::Now().ToInternalValue(), 100); EXPECT_TRUE(backend_->AddShortcut(shortcut)); - MessageLoop::current()->Run(); - EXPECT_EQ(shortcut.id, notified_shortcut_.id); - EXPECT_EQ(shortcut.contents, notified_shortcut_.contents); + + const ShortcutMap& shortcuts = backend_->shortcuts_map(); + ASSERT_TRUE(shortcuts.end() != shortcuts.find(shortcut.text)); + EXPECT_EQ(shortcut.id, shortcuts.find(shortcut.text)->second.id); + EXPECT_EQ(shortcut.contents, shortcuts.find(shortcut.text)->second.contents); shortcut.contents = ASCIIToUTF16("Google Web Search"); EXPECT_TRUE(backend_->UpdateShortcut(shortcut)); - MessageLoop::current()->Run(); - EXPECT_EQ(shortcut.id, notified_shortcut_.id); - EXPECT_EQ(shortcut.contents, notified_shortcut_.contents); + EXPECT_EQ(shortcut.id, shortcuts.find(shortcut.text)->second.id); + EXPECT_EQ(shortcut.contents, shortcuts.find(shortcut.text)->second.contents); } TEST_F(ShortcutsBackendTest, DeleteShortcuts) { @@ -120,7 +108,6 @@ TEST_F(ShortcutsBackendTest, DeleteShortcuts) { base::Time::Now().ToInternalValue(), 100); EXPECT_TRUE(backend_->AddShortcut(shortcut1)); - MessageLoop::current()->Run(); Shortcut shortcut2("BD85DBA2-8C29-49F9-84AE-48E1E90880E0", ASCIIToUTF16("gle"), ASCIIToUTF16("http://www.google.com"), @@ -129,7 +116,6 @@ TEST_F(ShortcutsBackendTest, DeleteShortcuts) { base::Time::Now().ToInternalValue(), 100); EXPECT_TRUE(backend_->AddShortcut(shortcut2)); - MessageLoop::current()->Run(); Shortcut shortcut3("BD85DBA2-8C29-49F9-84AE-48E1E90880E1", ASCIIToUTF16("sp"), ASCIIToUTF16("http://www.sport.com"), @@ -138,7 +124,6 @@ TEST_F(ShortcutsBackendTest, DeleteShortcuts) { base::Time::Now().ToInternalValue(), 10); EXPECT_TRUE(backend_->AddShortcut(shortcut3)); - MessageLoop::current()->Run(); Shortcut shortcut4("BD85DBA2-8C29-49F9-84AE-48E1E90880E2", ASCIIToUTF16("mov"), ASCIIToUTF16("http://www.film.com"), @@ -147,11 +132,8 @@ TEST_F(ShortcutsBackendTest, DeleteShortcuts) { base::Time::Now().ToInternalValue(), 10); EXPECT_TRUE(backend_->AddShortcut(shortcut4)); - MessageLoop::current()->Run(); - - ShortcutMap shortcuts; - EXPECT_TRUE(backend_->GetShortcuts(&shortcuts)); + const ShortcutMap& shortcuts = backend_->shortcuts_map(); ASSERT_EQ(4U, shortcuts.size()); EXPECT_EQ(shortcut1.id, shortcuts.find(shortcut1.text)->second.id); @@ -160,17 +142,12 @@ TEST_F(ShortcutsBackendTest, DeleteShortcuts) { EXPECT_EQ(shortcut4.id, shortcuts.find(shortcut4.text)->second.id); EXPECT_TRUE(backend_->DeleteShortcutsWithUrl(shortcut1.url)); - MessageLoop::current()->Run(); - - ASSERT_EQ(2U, notified_shortcut_ids_.size()); - EXPECT_TRUE(notified_shortcut_ids_[0] == shortcut1.id || - notified_shortcut_ids_[1] == shortcut1.id); - EXPECT_TRUE(notified_shortcut_ids_[0] == shortcut2.id || - notified_shortcut_ids_[1] == shortcut2.id); - - EXPECT_TRUE(backend_->GetShortcuts(&shortcuts)); ASSERT_EQ(2U, shortcuts.size()); + EXPECT_TRUE(shortcuts.end() == shortcuts.find(shortcut1.text)); + EXPECT_TRUE(shortcuts.end() == shortcuts.find(shortcut2.text)); + ASSERT_TRUE(shortcuts.end() != shortcuts.find(shortcut3.text)); + ASSERT_TRUE(shortcuts.end() != shortcuts.find(shortcut4.text)); EXPECT_EQ(shortcut3.id, shortcuts.find(shortcut3.text)->second.id); EXPECT_EQ(shortcut4.id, shortcuts.find(shortcut4.text)->second.id); @@ -179,13 +156,6 @@ TEST_F(ShortcutsBackendTest, DeleteShortcuts) { deleted_ids.push_back(shortcut4.id); EXPECT_TRUE(backend_->DeleteShortcutsWithIds(deleted_ids)); - MessageLoop::current()->Run(); - - ASSERT_EQ(2U, notified_shortcut_ids_.size()); - EXPECT_EQ(notified_shortcut_ids_[0], deleted_ids[0]); - EXPECT_EQ(notified_shortcut_ids_[1], deleted_ids[1]); - - EXPECT_TRUE(backend_->GetShortcuts(&shortcuts)); ASSERT_EQ(0U, shortcuts.size()); } diff --git a/chrome/browser/history/shortcuts_database.cc b/chrome/browser/history/shortcuts_database.cc index f400e5c..45e11a9 100644 --- a/chrome/browser/history/shortcuts_database.cc +++ b/chrome/browser/history/shortcuts_database.cc @@ -21,7 +21,8 @@ using base::Time; namespace { -const char *kShortcutsDBName = "omni_box_shortcuts"; +// Using define instead of const char, so I could use ## in the statements. +#define kShortcutsDBName "omni_box_shortcuts" // The maximum length allowed for form data. const size_t kMaxDataLength = 2048; // 2K is a hard limit on URLs URI. @@ -103,32 +104,18 @@ bool ShortcutsDatabase::Init() { if (!db_.Open(database_path_)) return false; - if (!db_.DoesTableExist(kShortcutsDBName)) { - if (!db_.Execute(base::StringPrintf( - "CREATE TABLE %s ( " - "id VARCHAR PRIMARY KEY, " - "text VARCHAR, " - "url VARCHAR, " - "contents VARCHAR, " - "contents_class VARCHAR, " - "description VARCHAR, " - "description_class VARCHAR, " - "last_access_time INTEGER, " - "number_of_hits INTEGER)", kShortcutsDBName).c_str())) { - NOTREACHED(); - return false; - } - } + if (!EnsureTable()) + return false; return true; } bool ShortcutsDatabase::AddShortcut( - const shortcuts_provider::Shortcut &shortcut) { - sql::Statement s(db_.GetUniqueStatement(base::StringPrintf( - "INSERT INTO %s" + const shortcuts_provider::Shortcut& shortcut) { + sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, + "INSERT INTO " kShortcutsDBName " (id, text, url, contents, contents_class, description," " description_class, last_access_time, number_of_hits) " - "VALUES (?,?,?,?,?,?,?,?,?)", kShortcutsDBName).c_str())); + "VALUES (?,?,?,?,?,?,?,?,?)")); if (!s) { NOTREACHED(); return false; @@ -143,13 +130,13 @@ bool ShortcutsDatabase::AddShortcut( } bool ShortcutsDatabase::UpdateShortcut( - const shortcuts_provider::Shortcut &shortcut) { - sql::Statement s(db_.GetUniqueStatement(base::StringPrintf( - "UPDATE %s " + const shortcuts_provider::Shortcut& shortcut) { + sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, + "UPDATE " kShortcutsDBName " " "SET id=?, text=?, url=?, contents=?, contents_class=?," " description=?, description_class=?, last_access_time=?," " number_of_hits=? " - "WHERE id=?", kShortcutsDBName).c_str())); + "WHERE id=?")); if (!s) { NOTREACHED() << "Statement prepare failed"; return false; @@ -180,15 +167,29 @@ bool ShortcutsDatabase::DeleteShortcutsWithUrl( return DeleteShortcut("url", shortcut_url_spec, db_); } +bool ShortcutsDatabase::DeleteAllShortcuts() { + sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, + "DROP TABLE " kShortcutsDBName)); + if (!s) { + NOTREACHED() << "Statement prepare failed"; + return false; + } + + if (!s.Run()) + return false; + EnsureTable(); + db_.Execute("VACUUM"); + return true; +} // Loads all of the shortcuts. bool ShortcutsDatabase::LoadShortcuts( std::map<std::string, shortcuts_provider::Shortcut>* shortcuts) { DCHECK(shortcuts); - sql::Statement s(db_.GetUniqueStatement(base::StringPrintf( + sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, "SELECT id, text, url, contents, contents_class, " "description, description_class, last_access_time, number_of_hits " - "FROM %s", kShortcutsDBName).c_str())); + "FROM " kShortcutsDBName)); if (!s) { NOTREACHED() << "Statement prepare failed"; return false; @@ -201,4 +202,24 @@ bool ShortcutsDatabase::LoadShortcuts( return true; } +bool ShortcutsDatabase::EnsureTable() { + if (!db_.DoesTableExist(kShortcutsDBName)) { + if (!db_.Execute(base::StringPrintf( + "CREATE TABLE %s ( " + "id VARCHAR PRIMARY KEY, " + "text VARCHAR, " + "url VARCHAR, " + "contents VARCHAR, " + "contents_class VARCHAR, " + "description VARCHAR, " + "description_class VARCHAR, " + "last_access_time INTEGER, " + "number_of_hits INTEGER)", kShortcutsDBName).c_str())) { + NOTREACHED(); + return false; + } + } + return true; +} + } // namespace history diff --git a/chrome/browser/history/shortcuts_database.h b/chrome/browser/history/shortcuts_database.h index 3cbae58..4cd1fe5 100644 --- a/chrome/browser/history/shortcuts_database.h +++ b/chrome/browser/history/shortcuts_database.h @@ -12,6 +12,7 @@ #include "base/file_path.h" #include "base/gtest_prod_util.h" +#include "base/memory/ref_counted.h" #include "base/string16.h" #include "chrome/browser/autocomplete/shortcuts_provider_shortcut.h" #include "googleurl/src/gurl.h" @@ -37,7 +38,7 @@ namespace history { // last_access_time Time the entry was accessed last, stored in seconds, // UTC. // number_of_hits Number of times that the entry has been selected. -class ShortcutsDatabase { +class ShortcutsDatabase : public base::RefCountedThreadSafe<ShortcutsDatabase> { public: explicit ShortcutsDatabase(const FilePath& folder_path); virtual ~ShortcutsDatabase(); @@ -45,10 +46,10 @@ class ShortcutsDatabase { bool Init(); // Adds the ShortcutsProvider::Shortcut to the database. - bool AddShortcut(const shortcuts_provider::Shortcut &shortcut); + bool AddShortcut(const shortcuts_provider::Shortcut& shortcut); // Updates timing and selection count for the ShortcutsProvider::Shortcut. - bool UpdateShortcut(const shortcuts_provider::Shortcut &shortcut); + bool UpdateShortcut(const shortcuts_provider::Shortcut& shortcut); // Deletes the ShortcutsProvider::Shortcuts with the id. bool DeleteShortcutsWithIds(const std::vector<std::string>& shortcut_ids); @@ -56,11 +57,17 @@ class ShortcutsDatabase { // Deletes the ShortcutsProvider::Shortcuts with the url. bool DeleteShortcutsWithUrl(const std::string& shortcut_url_spec); + // Deletes all of the ShortcutsProvider::Shortcuts. + bool DeleteAllShortcuts(); + // Loads all of the shortcuts. bool LoadShortcuts( std::map<std::string, shortcuts_provider::Shortcut>* shortcuts); private: + // Ensures that the table is present. + bool EnsureTable(); + friend class ShortcutsDatabaseTest; FRIEND_TEST_ALL_PREFIXES(ShortcutsDatabaseTest, AddShortcut); FRIEND_TEST_ALL_PREFIXES(ShortcutsDatabaseTest, UpdateShortcut); diff --git a/chrome/browser/history/shortcuts_database_unittest.cc b/chrome/browser/history/shortcuts_database_unittest.cc index 88c802b..216df83 100644 --- a/chrome/browser/history/shortcuts_database_unittest.cc +++ b/chrome/browser/history/shortcuts_database_unittest.cc @@ -59,18 +59,18 @@ class ShortcutsDatabaseTest : public testing::Test { void AddAll(); ScopedTempDir temp_dir_; - scoped_ptr<ShortcutsDatabase> db_; + scoped_refptr<ShortcutsDatabase> db_; }; void ShortcutsDatabaseTest::SetUp() { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - db_.reset(new ShortcutsDatabase(temp_dir_.path())); + db_ = new ShortcutsDatabase(temp_dir_.path()); ASSERT_TRUE(db_->Init()); ClearDB(); } void ShortcutsDatabaseTest::TearDown() { - db_.reset(); + db_ = NULL; } void ShortcutsDatabaseTest::ClearDB() { @@ -185,4 +185,14 @@ TEST_F(ShortcutsDatabaseTest, LoadShortcuts) { } } +TEST_F(ShortcutsDatabaseTest, DeleteAllShortcuts) { + AddAll(); + std::map<std::string, Shortcut> shortcuts; + EXPECT_TRUE(db_->LoadShortcuts(&shortcuts)); + EXPECT_EQ(arraysize(shortcut_test_db), shortcuts.size()); + EXPECT_TRUE(db_->DeleteAllShortcuts()); + EXPECT_TRUE(db_->LoadShortcuts(&shortcuts)); + EXPECT_EQ(0U, shortcuts.size()); +} + } // namespace history |