summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/history/top_sites.cc64
-rw-r--r--chrome/browser/history/top_sites.h23
-rw-r--r--chrome/browser/history/top_sites_database.cc3
-rw-r--r--chrome/browser/history/top_sites_database.h9
-rw-r--r--chrome/browser/history/top_sites_unittest.cc61
-rw-r--r--chrome/browser/profile.cc2
-rw-r--r--chrome/common/chrome_constants.cc1
-rw-r--r--chrome/common/chrome_constants.h1
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[];