diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/history/top_sites.cc | 64 | ||||
-rw-r--r-- | chrome/browser/history/top_sites.h | 23 | ||||
-rw-r--r-- | chrome/browser/history/top_sites_database.cc | 3 | ||||
-rw-r--r-- | chrome/browser/history/top_sites_database.h | 9 | ||||
-rw-r--r-- | chrome/browser/history/top_sites_unittest.cc | 61 | ||||
-rw-r--r-- | chrome/browser/profile.cc | 2 | ||||
-rw-r--r-- | chrome/common/chrome_constants.cc | 1 | ||||
-rw-r--r-- | chrome/common/chrome_constants.h | 1 |
8 files changed, 148 insertions, 16 deletions
diff --git a/chrome/browser/history/top_sites.cc b/chrome/browser/history/top_sites.cc index 2e4a39c..84695d9 100644 --- a/chrome/browser/history/top_sites.cc +++ b/chrome/browser/history/top_sites.cc @@ -4,9 +4,13 @@ #include "chrome/browser/history/top_sites.h" +#include <algorithm> + +#include "base/file_util.h" #include "base/logging.h" #include "chrome/browser/profile.h" #include "chrome/browser/history/top_sites_database.h" +#include "chrome/browser/history/history_notifications.h" #include "chrome/browser/history/page_usage_data.h" #include "gfx/codec/jpeg_codec.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -16,19 +20,30 @@ namespace history { // How many top sites to store in the cache. static const int kTopSitesNumber = 20; static const int kDaysOfHistory = 90; -static const int64 kUpdateIntervalSecs = 15; // TODO(Nik): come up - // with an algorithm for timing. +static const int64 kUpdateIntervalSecs = 15; // Time from startup to DB query. +// Intervals between requests to HistoryService. +static const int64 kMinUpdateIntervalMinutes = 1; +static const int64 kMaxUpdateIntervalMinutes = 60; + TopSites::TopSites(Profile* profile) : profile_(profile), - mock_history_service_(NULL) { + mock_history_service_(NULL), + last_num_urls_changed_(0) { + registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, + Source<Profile>(profile_)); } TopSites::~TopSites() { + timer_.Stop(); } -void TopSites::Init() { - if (db_.get()) - ReadDatabase(); +void TopSites::Init(const FilePath& db_name) { + db_path_ = db_name; + db_.reset(new TopSitesDatabaseImpl()); + if (!db_->Init(db_name)) + return; + + ReadDatabase(); // Start the one-shot timer. timer_.Start(base::TimeDelta::FromSeconds(kUpdateIntervalSecs), this, @@ -140,6 +155,9 @@ void TopSites::UpdateMostVisited(MostVisitedURLList* most_visited) { std::vector<size_t> moved; // Indices into most_visited. DiffMostVisited(top_sites_, *most_visited, &added, &deleted, &moved); + // #added == #deleted; #added + #moved = total. + last_num_urls_changed_ = added.size() + moved.size(); + // Process the diff: delete from images and disk, add to disk. // Delete all the thumbnails associated with URLs that were deleted. for (size_t i = 0; i < deleted.size(); i++) { @@ -262,7 +280,7 @@ void TopSites::DiffMostVisited(const MostVisitedURLList& old_list, void TopSites::StartQueryForMostVisited() { if (mock_history_service_) { // Testing with a mockup. - // QuerySegmentUsageSince is not virtual, so we have to duplicate the code. + // QueryMostVisitedURLs is not virtual, so we have to duplicate the code. mock_history_service_->QueryMostVisitedURLs( kTopSitesNumber, kDaysOfHistory, @@ -281,6 +299,17 @@ void TopSites::StartQueryForMostVisited() { LOG(INFO) << "History Service not available."; } } + + timer_.Stop(); + timer_.Start(GetUpdateDelay(), this, + &TopSites::StartQueryForMostVisited); +} + +base::TimeDelta TopSites::GetUpdateDelay() { + int64 range = kMaxUpdateIntervalMinutes - kMinUpdateIntervalMinutes; + int64 minutes = kMaxUpdateIntervalMinutes - + last_num_urls_changed_ * range / kTopSitesNumber; + return base::TimeDelta::FromMinutes(minutes); } void TopSites::OnTopSitesAvailable( @@ -294,4 +323,25 @@ void TopSites::SetMockHistoryService(MockHistoryService* mhs) { mock_history_service_ = mhs; } +void TopSites::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type != NotificationType::HISTORY_URLS_DELETED) { + NOTREACHED(); + return; + } + + Details<history::URLsDeletedDetails> deleted_details(details); + if (deleted_details->all_history) { + db_.reset(new TopSitesDatabaseImpl()); + // TODO(nshkrob): delete file in background (FILE) thread. + file_util::Delete(db_path_, false); + if (!db_->Init(db_path_)) { + NOTREACHED() << "Failed to initialize database."; + return; + } + } + StartQueryForMostVisited(); +} + } // namespace history diff --git a/chrome/browser/history/top_sites.h b/chrome/browser/history/top_sites.h index d05afb1..b049ab3 100644 --- a/chrome/browser/history/top_sites.h +++ b/chrome/browser/history/top_sites.h @@ -19,6 +19,7 @@ #include "chrome/browser/history/history_types.h" #include "chrome/browser/history/history.h" #include "chrome/browser/history/page_usage_data.h" +#include "chrome/common/notification_service.h" #include "chrome/common/thumbnail_score.h" #include "googleurl/src/gurl.h" @@ -43,7 +44,8 @@ typedef std::vector<MostVisitedURL> MostVisitedURLList; // new tab page requests on the I/O thread without proxying to the UI thread is // a nontrivial performance win, especially when the browser is starting and // the UI thread is busy. -class TopSites : public base::RefCountedThreadSafe<TopSites> { +class TopSites : public NotificationObserver, + public base::RefCountedThreadSafe<TopSites> { public: explicit TopSites(Profile* profile); @@ -66,7 +68,7 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { }; // Initializes TopSites. - void Init(); + void Init(const FilePath& db_name); // Sets the given thumbnail for the given URL. Returns true if the thumbnail // was updated. False means either the URL wasn't known to us, or we felt @@ -88,6 +90,8 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { friend class TopSitesTest_GetMostVisited_Test; friend class TopSitesTest_RealDatabase_Test; friend class TopSitesTest_MockDatabase_Test; + friend class TopSitesTest_DeleteNotifications_Test; + friend class TopSitesTest_GetUpdateDelay_Test; ~TopSites(); @@ -150,6 +154,15 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { // For testing with a HistoryService mock. void SetMockHistoryService(MockHistoryService* mhs); + // Implementation of NotificationObserver. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Returns the delay until the next update of history is needed. + // Uses num_urls_changed + base::TimeDelta GetUpdateDelay(); + Profile* profile_; // A mockup to use for testing. If NULL, use the real HistoryService // from the profile_. See SetMockHistoryService. @@ -174,6 +187,12 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { base::OneShotTimer<TopSites> timer_; scoped_ptr<TopSitesDatabase> db_; + FilePath db_path_; + + NotificationRegistrar registrar_; + + // The number of URLs changed on the last update. + size_t last_num_urls_changed_; // TODO(brettw): use the blacklist. // std::set<GURL> blacklist_; diff --git a/chrome/browser/history/top_sites_database.cc b/chrome/browser/history/top_sites_database.cc index 537b19f..39493f6 100644 --- a/chrome/browser/history/top_sites_database.cc +++ b/chrome/browser/history/top_sites_database.cc @@ -21,7 +21,7 @@ bool TopSitesDatabaseImpl::Init(const FilePath& db_name) { if (!db_.Open(db_name)) { LOG(WARNING) << db_.GetErrorMessage(); - return sql::INIT_FAILURE; + return false; } return InitThumbnailTable(); @@ -247,4 +247,3 @@ bool TopSitesDatabaseImpl::RemoveURL(const MostVisitedURL& url) { } } // namespace history - diff --git a/chrome/browser/history/top_sites_database.h b/chrome/browser/history/top_sites_database.h index 2a664a6..86b053f 100644 --- a/chrome/browser/history/top_sites_database.h +++ b/chrome/browser/history/top_sites_database.h @@ -9,8 +9,6 @@ #include <vector> #include "app/sql/connection.h" -#include "app/sql/init_status.h" -#include "app/sql/meta_table.h" #include "base/ref_counted.h" #include "chrome/browser/history/history_types.h" #include "chrome/browser/history/url_database.h" // For DBCloseScoper. @@ -31,6 +29,9 @@ namespace history { class TopSitesDatabase { public: virtual ~TopSitesDatabase() {} + virtual bool Init(const FilePath& filename) { + return true; + } // Returns a list of all URLs currently in the table. virtual MostVisitedURLList GetTopURLs() = 0; @@ -51,14 +52,14 @@ class TopSitesDatabase { virtual bool RemoveURL(const MostVisitedURL& url) = 0; }; -class TopSitesDatabaseImpl: public TopSitesDatabase { +class TopSitesDatabaseImpl : public TopSitesDatabase { public: TopSitesDatabaseImpl(); ~TopSitesDatabaseImpl() {} // Must be called after creation but before any other methods are called. // Returns true on success. If false, no other functions should be called. - bool Init(const FilePath& db_name); + virtual bool Init(const FilePath& db_name); // Thumbnails ---------------------------------------------------------------- diff --git a/chrome/browser/history/top_sites_unittest.cc b/chrome/browser/history/top_sites_unittest.cc index 0cf282a..698ac1d 100644 --- a/chrome/browser/history/top_sites_unittest.cc +++ b/chrome/browser/history/top_sites_unittest.cc @@ -7,6 +7,7 @@ #include "chrome/browser/history/top_sites.h" #include "chrome/common/chrome_paths.h" #include "chrome/browser/history/top_sites_database.h" +#include "chrome/browser/history/history_notifications.h" #include "chrome/test/testing_profile.h" #include "chrome/tools/profiles/thumbnail-inl.h" #include "gfx/codec/jpeg_codec.h" @@ -28,6 +29,7 @@ class TopSitesTest : public testing::Test { } TopSites& top_sites() { return *top_sites_; } + Profile& profile() {return *profile_;} FilePath& file_name() { return file_name_; } RefCountedBytes* google_thumbnail() { return google_thumbnail_; } RefCountedBytes* random_thumbnail() { return random_thumbnail_; } @@ -88,6 +90,7 @@ class TopSitesTest : public testing::Test { scoped_refptr<RefCountedBytes> google_thumbnail_; scoped_refptr<RefCountedBytes> random_thumbnail_; scoped_refptr<RefCountedBytes> weewar_thumbnail_; + MessageLoop message_loop_; DISALLOW_COPY_AND_ASSIGN(TopSitesTest); }; @@ -117,6 +120,11 @@ class MockHistoryServiceImpl : public TopSites::MockHistoryService { most_visited_urls_.push_back(page); } + // Removes the last URL in the list. + void RemoveMostVisitedURL() { + most_visited_urls_.pop_back(); + } + private: MostVisitedURLList most_visited_urls_; }; @@ -607,4 +615,57 @@ TEST_F(TopSitesTest, RealDatabase) { EXPECT_TRUE(high_score.Equals(out_2.thumbnail_score)); } +TEST_F(TopSitesTest, DeleteNotifications) { + GURL google1_url("http://google.com"); + GURL google2_url("http://google.com/redirect"); + GURL google3_url("http://www.google.com"); + string16 google_title(ASCIIToUTF16("Google")); + GURL news_url("http://news.google.com"); + string16 news_title(ASCIIToUTF16("Google News")); + + MockHistoryServiceImpl hs; + + top_sites().Init(file_name()); + + hs.AppendMockPage(google1_url, google_title); + hs.AppendMockPage(news_url, news_title); + top_sites().SetMockHistoryService(&hs); + + top_sites().StartQueryForMostVisited(); + + MostVisitedURLList result = top_sites().GetMostVisitedURLs(); + ASSERT_EQ(2u, result.size()); + + hs.RemoveMostVisitedURL(); + + history::URLsDeletedDetails details; + details.all_history = false; + top_sites().Observe(NotificationType::HISTORY_URLS_DELETED, + Source<Profile> (&profile()), + (const NotificationDetails&)details); + + result = top_sites().GetMostVisitedURLs(); + ASSERT_EQ(1u, result.size()); + EXPECT_EQ(google_title, result[0].title); + + hs.RemoveMostVisitedURL(); + details.all_history = true; + top_sites().Observe(NotificationType::HISTORY_URLS_DELETED, + Source<Profile> (&profile()), + (const NotificationDetails&)details); + result = top_sites().GetMostVisitedURLs(); + ASSERT_EQ(0u, result.size()); +} + +TEST_F(TopSitesTest, GetUpdateDelay) { + top_sites().last_num_urls_changed_ = 0; + EXPECT_EQ(60, top_sites().GetUpdateDelay().InMinutes()); + + top_sites().last_num_urls_changed_ = 3; + EXPECT_EQ(52, top_sites().GetUpdateDelay().InMinutes()); + + top_sites().last_num_urls_changed_ = 20; + EXPECT_EQ(1, top_sites().GetUpdateDelay().InMinutes()); +} + } // namespace history diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index b2bdf7f..31d794c 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -1424,7 +1424,7 @@ ThumbnailStore* ProfileImpl::GetThumbnailStore() { history::TopSites* ProfileImpl::GetTopSites() { if (!top_sites_.get()) { top_sites_ = new history::TopSites(this); - top_sites_->Init(); + top_sites_->Init(GetPath().Append(chrome::kTopSitesFilename)); } return top_sites_; } diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc index 2250cf5..3fff399 100644 --- a/chrome/common/chrome_constants.cc +++ b/chrome/common/chrome_constants.cc @@ -99,6 +99,7 @@ const FilePath::CharType kSingletonSocketFilename[] = FPL("SingletonSocket"); const FilePath::CharType kSingletonLockFilename[] = FPL("SingletonLock"); const FilePath::CharType kThumbnailsFilename[] = FPL("Thumbnails"); const FilePath::CharType kNewTabThumbnailsFilename[] = FPL("Top Thumbnails"); +const FilePath::CharType kTopSitesFilename[] = FPL("Top Sites"); const wchar_t kUserDataDirname[] = L"User Data"; const FilePath::CharType kUserScriptsDirname[] = FPL("User Scripts"); const FilePath::CharType kWebDataFilename[] = FPL("Web Data"); diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h index 4090b74..8ffe8a5 100644 --- a/chrome/common/chrome_constants.h +++ b/chrome/common/chrome_constants.h @@ -53,6 +53,7 @@ extern const FilePath::CharType kSingletonSocketFilename[]; extern const FilePath::CharType kSingletonLockFilename[]; extern const FilePath::CharType kThumbnailsFilename[]; extern const FilePath::CharType kNewTabThumbnailsFilename[]; +extern const FilePath::CharType kTopSitesFilename[]; extern const wchar_t kUserDataDirname[]; extern const FilePath::CharType kUserScriptsDirname[]; extern const FilePath::CharType kWebDataFilename[]; |