summaryrefslogtreecommitdiffstats
path: root/chrome/browser/history
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/history')
-rw-r--r--chrome/browser/history/archived_database.cc8
-rw-r--r--chrome/browser/history/expire_history_backend.cc12
-rw-r--r--chrome/browser/history/expire_history_backend.h1
-rw-r--r--chrome/browser/history/expire_history_backend_unittest.cc83
-rw-r--r--chrome/browser/history/history.cc18
-rw-r--r--chrome/browser/history/history.h14
-rw-r--r--chrome/browser/history/history_backend.cc20
-rw-r--r--chrome/browser/history/history_backend.h16
-rw-r--r--chrome/browser/history/history_backend_unittest.cc233
-rw-r--r--chrome/browser/history/history_database.cc23
-rw-r--r--chrome/browser/history/history_marshaling.h3
-rw-r--r--chrome/browser/history/history_querying_unittest.cc4
-rw-r--r--chrome/browser/history/history_types.h20
-rw-r--r--chrome/browser/history/history_unittest.cc56
-rw-r--r--chrome/browser/history/text_database_manager_unittest.cc16
-rw-r--r--chrome/browser/history/thumbnail_database.cc3
-rw-r--r--chrome/browser/history/visit_database.cc77
-rw-r--r--chrome/browser/history/visit_database.h9
-rw-r--r--chrome/browser/history/visit_database_unittest.cc57
19 files changed, 580 insertions, 93 deletions
diff --git a/chrome/browser/history/archived_database.cc b/chrome/browser/history/archived_database.cc
index 777ee4d..72fa998 100644
--- a/chrome/browser/history/archived_database.cc
+++ b/chrome/browser/history/archived_database.cc
@@ -13,7 +13,7 @@ namespace history {
namespace {
-static const int kCurrentVersionNumber = 2;
+static const int kCurrentVersionNumber = 3;
static const int kCompatibleVersionNumber = 2;
} // namespace
@@ -110,6 +110,12 @@ sql::InitStatus ArchivedDatabase::EnsureCurrentVersion() {
std::min(cur_version, kCompatibleVersionNumber));
}
+ if (cur_version == 2) {
+ // This is the version prior to adding visit_source table.
+ ++cur_version;
+ meta_table_.SetVersionNumber(cur_version);
+ }
+
// Put future migration cases here.
// When the version is too old, we just try to continue anyway, there should
diff --git a/chrome/browser/history/expire_history_backend.cc b/chrome/browser/history/expire_history_backend.cc
index bd471ad..294c0e6 100644
--- a/chrome/browser/history/expire_history_backend.cc
+++ b/chrome/browser/history/expire_history_backend.cc
@@ -512,7 +512,7 @@ void ExpireHistoryBackend::ExpireURLsForVisits(
void ExpireHistoryBackend::ArchiveURLsAndVisits(
const VisitVector& visits,
DeleteDependencies* dependencies) {
- if (!archived_db_)
+ if (!archived_db_ || !main_db_)
return;
// Make sure all unique URL rows are added to the dependency list and the
@@ -539,6 +539,12 @@ void ExpireHistoryBackend::ArchiveURLsAndVisits(
}
}
+ // Retrieve the sources for all the archived visits before archiving.
+ // The returned visit_sources vector should contain the source for each visit
+ // from visits at the same index.
+ VisitSourceMap visit_sources;
+ main_db_->GetVisitsSource(visits, &visit_sources);
+
// Now archive the visits since we know the URL ID to make them reference.
// The source visit list should still reference the visits in the main DB, but
// we will update it to reflect only the visits that were successfully
@@ -550,7 +556,9 @@ void ExpireHistoryBackend::ArchiveURLsAndVisits(
VisitRow cur_visit(visits[i]);
cur_visit.url_id = main_id_to_archived_id[cur_visit.url_id];
cur_visit.referring_visit = 0;
- archived_db_->AddVisit(&cur_visit);
+ VisitSourceMap::iterator iter = visit_sources.find(visits[i].visit_id);
+ archived_db_->AddVisit(&cur_visit,
+ iter == visit_sources.end() ? SOURCE_BROWSED : iter->second);
// Ignore failures, we will delete it from the main DB no matter what.
}
}
diff --git a/chrome/browser/history/expire_history_backend.h b/chrome/browser/history/expire_history_backend.h
index 4bd18b0..96e2e9a 100644
--- a/chrome/browser/history/expire_history_backend.h
+++ b/chrome/browser/history/expire_history_backend.h
@@ -106,6 +106,7 @@ class ExpireHistoryBackend {
FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, DeleteFaviconsIfPossible);
FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ArchiveSomeOldHistory);
FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpiringVisitsReader);
+ FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ArchiveSomeOldHistoryWithSource);
friend class ::TestingProfile;
struct DeleteDependencies;
diff --git a/chrome/browser/history/expire_history_backend_unittest.cc b/chrome/browser/history/expire_history_backend_unittest.cc
index 60c783d..ef65eab 100644
--- a/chrome/browser/history/expire_history_backend_unittest.cc
+++ b/chrome/browser/history/expire_history_backend_unittest.cc
@@ -56,6 +56,8 @@ class ExpireHistoryTest : public testing::Test,
protected:
// Called by individual tests when they want data populated.
void AddExampleData(URLID url_ids[3], Time visit_times[4]);
+ // Add visits with source information.
+ void AddExampleSourceData(const GURL& url, URLID* id);
// Returns true if the given favicon/thumanil has an entry in the DB.
bool HasFavIcon(FavIconID favicon_id);
@@ -227,26 +229,26 @@ void ExpireHistoryTest::AddExampleData(URLID url_ids[3], Time visit_times[4]) {
visit_row1.url_id = url_ids[0];
visit_row1.visit_time = visit_times[0];
visit_row1.is_indexed = true;
- main_db_->AddVisit(&visit_row1);
+ main_db_->AddVisit(&visit_row1, SOURCE_BROWSED);
VisitRow visit_row2;
visit_row2.url_id = url_ids[1];
visit_row2.visit_time = visit_times[1];
visit_row2.is_indexed = true;
- main_db_->AddVisit(&visit_row2);
+ main_db_->AddVisit(&visit_row2, SOURCE_BROWSED);
VisitRow visit_row3;
visit_row3.url_id = url_ids[1];
visit_row3.visit_time = visit_times[2];
visit_row3.is_indexed = true;
visit_row3.transition = PageTransition::TYPED;
- main_db_->AddVisit(&visit_row3);
+ main_db_->AddVisit(&visit_row3, SOURCE_BROWSED);
VisitRow visit_row4;
visit_row4.url_id = url_ids[2];
visit_row4.visit_time = visit_times[3];
visit_row4.is_indexed = true;
- main_db_->AddVisit(&visit_row4);
+ main_db_->AddVisit(&visit_row4, SOURCE_BROWSED);
// Full text index for each visit.
text_db_->AddPageData(url_row1.url(), visit_row1.url_id, visit_row1.visit_id,
@@ -267,6 +269,35 @@ void ExpireHistoryTest::AddExampleData(URLID url_ids[3], Time visit_times[4]) {
UTF8ToUTF16("goats body"));
}
+void ExpireHistoryTest::AddExampleSourceData(const GURL& url, URLID* id) {
+ if (!main_db_.get())
+ return;
+
+ Time last_visit_time = Time::Now();
+ // Add one URL.
+ URLRow url_row1(url);
+ url_row1.set_last_visit(last_visit_time);
+ url_row1.set_visit_count(4);
+ URLID url_id = main_db_->AddURL(url_row1);
+ *id = url_id;
+
+ // Four times for each visit.
+ VisitRow visit_row1(url_id, last_visit_time - TimeDelta::FromDays(4), 0,
+ PageTransition::TYPED, 0);
+ main_db_->AddVisit(&visit_row1, SOURCE_SYNCED);
+
+ VisitRow visit_row2(url_id, last_visit_time - TimeDelta::FromDays(3), 0,
+ PageTransition::TYPED, 0);
+ main_db_->AddVisit(&visit_row2, SOURCE_BROWSED);
+
+ VisitRow visit_row3(url_id, last_visit_time - TimeDelta::FromDays(2), 0,
+ PageTransition::TYPED, 0);
+ main_db_->AddVisit(&visit_row3, SOURCE_EXTENSION);
+
+ VisitRow visit_row4(url_id, last_visit_time, 0, PageTransition::TYPED, 0);
+ main_db_->AddVisit(&visit_row4, SOURCE_FIREFOX_IMPORTED);
+}
+
bool ExpireHistoryTest::HasFavIcon(FavIconID favicon_id) {
if (!thumb_db_.get())
return false;
@@ -815,6 +846,50 @@ TEST_F(ExpireHistoryTest, ExpiringVisitsReader) {
EXPECT_EQ(1U, visits.size());
}
+// Tests how ArchiveSomeOldHistory treats source information.
+TEST_F(ExpireHistoryTest, ArchiveSomeOldHistoryWithSource) {
+ const GURL url("www.testsource.com");
+ URLID url_id;
+ AddExampleSourceData(url, &url_id);
+ const ExpiringVisitsReader* reader = expirer_.GetAllVisitsReader();
+
+ // Archiving all the visits we added.
+ ASSERT_FALSE(expirer_.ArchiveSomeOldHistory(Time::Now(), reader, 10));
+
+ URLRow archived_row;
+ ASSERT_TRUE(archived_db_->GetRowForURL(url, &archived_row));
+ VisitVector archived_visits;
+ archived_db_->GetVisitsForURL(archived_row.id(), &archived_visits);
+ ASSERT_EQ(4U, archived_visits.size());
+ VisitSourceMap sources;
+ archived_db_->GetVisitsSource(archived_visits, &sources);
+ ASSERT_EQ(3U, sources.size());
+ int result = 0;
+ VisitSourceMap::iterator iter;
+ for (int i = 0; i < 4; i++) {
+ iter = sources.find(archived_visits[i].visit_id);
+ if (iter == sources.end())
+ continue;
+ switch (iter->second) {
+ case history::SOURCE_EXTENSION:
+ result |= 0x1;
+ break;
+ case history::SOURCE_FIREFOX_IMPORTED:
+ result |= 0x2;
+ break;
+ case history::SOURCE_SYNCED:
+ result |= 0x4;
+ default:
+ break;
+ }
+ }
+ EXPECT_EQ(0x7, result);
+ main_db_->GetVisitsSource(archived_visits, &sources);
+ EXPECT_EQ(0U, sources.size());
+ main_db_->GetVisitsForURL(url_id, &archived_visits);
+ EXPECT_EQ(0U, archived_visits.size());
+}
+
// TODO(brettw) add some visits with no URL to make sure everything is updated
// properly. Have the visits also refer to nonexistant FTS rows.
//
diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc
index 156f9da..eb27b97 100644
--- a/chrome/browser/history/history.cc
+++ b/chrome/browser/history/history.cc
@@ -301,9 +301,10 @@ void HistoryService::AddPage(const GURL& url,
const GURL& referrer,
PageTransition::Type transition,
const history::RedirectList& redirects,
+ history::VisitSource visit_source,
bool did_replace_entry) {
AddPage(url, Time::Now(), id_scope, page_id, referrer, transition, redirects,
- did_replace_entry);
+ visit_source, did_replace_entry);
}
void HistoryService::AddPage(const GURL& url,
@@ -313,6 +314,7 @@ void HistoryService::AddPage(const GURL& url,
const GURL& referrer,
PageTransition::Type transition,
const history::RedirectList& redirects,
+ history::VisitSource visit_source,
bool did_replace_entry) {
DCHECK(thread_) << "History service being called after cleanup";
@@ -340,8 +342,8 @@ void HistoryService::AddPage(const GURL& url,
}
scoped_refptr<history::HistoryAddPageArgs> request(
- new history::HistoryAddPageArgs(url, time, id_scope, page_id,
- referrer, redirects, transition,
+ new history::HistoryAddPageArgs(url, time, id_scope, page_id, referrer,
+ redirects, transition, visit_source,
did_replace_entry));
ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage, request);
}
@@ -356,7 +358,8 @@ void HistoryService::AddPageWithDetails(const GURL& url,
int visit_count,
int typed_count,
Time last_visit,
- bool hidden) {
+ bool hidden,
+ history::VisitSource visit_source) {
// Filter out unwanted URLs.
if (!CanAddURL(url))
return;
@@ -377,11 +380,12 @@ void HistoryService::AddPageWithDetails(const GURL& url,
rows.push_back(row);
ScheduleAndForget(PRIORITY_NORMAL,
- &HistoryBackend::AddPagesWithDetails, rows);
+ &HistoryBackend::AddPagesWithDetails, rows, visit_source);
}
void HistoryService::AddPagesWithDetails(
- const std::vector<history::URLRow>& info) {
+ const std::vector<history::URLRow>& info,
+ history::VisitSource visit_source) {
// Add to the visited links system.
VisitedLinkMaster* visited_links;
@@ -397,7 +401,7 @@ void HistoryService::AddPagesWithDetails(
}
ScheduleAndForget(PRIORITY_NORMAL,
- &HistoryBackend::AddPagesWithDetails, info);
+ &HistoryBackend::AddPagesWithDetails, info, visit_source);
}
void HistoryService::SetPageContents(const GURL& url,
diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h
index c142c97..5bc3b7f 100644
--- a/chrome/browser/history/history.h
+++ b/chrome/browser/history/history.h
@@ -185,6 +185,7 @@ class HistoryService : public CancelableRequestProvider,
const GURL& referrer,
PageTransition::Type transition,
const history::RedirectList& redirects,
+ history::VisitSource visit_source,
bool did_replace_entry);
// For adding pages to history with a specific time. This is for testing
@@ -196,12 +197,13 @@ class HistoryService : public CancelableRequestProvider,
const GURL& referrer,
PageTransition::Type transition,
const history::RedirectList& redirects,
+ history::VisitSource visit_source,
bool did_replace_entry);
// For adding pages to history where no tracking information can be done.
- void AddPage(const GURL& url) {
- AddPage(url, NULL, 0, GURL(), PageTransition::LINK, history::RedirectList(),
- false);
+ void AddPage(const GURL& url, history::VisitSource visit_source) {
+ AddPage(url, NULL, 0, GURL(), PageTransition::LINK,
+ history::RedirectList(), visit_source, false);
}
// Sets the title for the given page. The page should be in history. If it
@@ -535,10 +537,12 @@ class HistoryService : public CancelableRequestProvider,
int visit_count,
int typed_count,
base::Time last_visit,
- bool hidden);
+ bool hidden,
+ history::VisitSource visit_source);
// The same as AddPageWithDetails() but takes a vector.
- void AddPagesWithDetails(const std::vector<history::URLRow>& info);
+ void AddPagesWithDetails(const std::vector<history::URLRow>& info,
+ history::VisitSource visit_source);
// Starts the TopSites migration in the HistoryThread. Called by the
// BackendDelegate.
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index 91aba75..847dc6e 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -405,7 +405,7 @@ void HistoryBackend::AddPage(scoped_refptr<HistoryAddPageArgs> request) {
// No redirect case (one element means just the page itself).
last_ids = AddPageVisit(request->url, last_recorded_time_,
- last_ids.second, t);
+ last_ids.second, t, request->visit_source);
// Update the segment for this visit. KEYWORD_GENERATED visits should not
// result in changing most visited, so we don't update segments (most
@@ -471,7 +471,8 @@ void HistoryBackend::AddPage(scoped_refptr<HistoryAddPageArgs> request) {
// them anyway, and if we ever decide to, we can reconstruct their order
// from the redirect chain.
last_ids = AddPageVisit(request->redirects[redirect_index],
- last_recorded_time_, last_ids.second, t);
+ last_recorded_time_, last_ids.second,
+ t, request->visit_source);
if (t & PageTransition::CHAIN_START) {
// Update the segment for this visit.
UpdateSegments(request->redirects[redirect_index],
@@ -651,7 +652,8 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
const GURL& url,
Time time,
VisitID referring_visit,
- PageTransition::Type transition) {
+ PageTransition::Type transition,
+ VisitSource visit_source) {
// Top-level frame navigations are visible, everything else is hidden
bool new_hidden = !PageTransition::IsMainFrame(transition);
@@ -708,7 +710,7 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
// Add the visit with the time to the database.
VisitRow visit_info(url_id, time, referring_visit, transition, 0);
- VisitID visit_id = db_->AddVisit(&visit_info);
+ VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
if (visit_info.visit_time < first_recorded_time_)
first_recorded_time_ = visit_info.visit_time;
@@ -727,7 +729,8 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
return std::make_pair(url_id, visit_id);
}
-void HistoryBackend::AddPagesWithDetails(const std::vector<URLRow>& urls) {
+void HistoryBackend::AddPagesWithDetails(const std::vector<URLRow>& urls,
+ VisitSource visit_source) {
if (!db_.get())
return;
@@ -789,7 +792,7 @@ void HistoryBackend::AddPagesWithDetails(const std::vector<URLRow>& urls) {
PageTransition::LINK | PageTransition::CHAIN_START |
PageTransition::CHAIN_END, 0);
visit_info.is_indexed = has_indexed;
- if (!visit_database->AddVisit(&visit_info)) {
+ if (!visit_database->AddVisit(&visit_info, visit_source)) {
NOTREACHED() << "Adding visit failed.";
return;
}
@@ -906,11 +909,12 @@ bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
}
bool HistoryBackend::AddVisits(const GURL& url,
- const std::vector<base::Time>& visits) {
+ const std::vector<base::Time>& visits,
+ VisitSource visit_source) {
if (db_.get()) {
for (std::vector<base::Time>::const_iterator visit = visits.begin();
visit != visits.end(); ++visit) {
- if (!AddPageVisit(url, *visit, 0, 0).first) {
+ if (!AddPageVisit(url, *visit, 0, 0, visit_source).first) {
return false;
}
}
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index 4d333f3..1965bc5 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -258,8 +258,10 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
virtual bool UpdateURL(URLID id, const history::URLRow& url);
+ // While adding visits in batch, the source needs to be provided.
virtual bool AddVisits(const GURL& url,
- const std::vector<base::Time>& visits);
+ const std::vector<base::Time>& visits,
+ VisitSource visit_source);
virtual bool RemoveVisits(const VisitVector& visits);
@@ -292,7 +294,9 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// Adds the given rows to the database if it doesn't exist. A visit will be
// added for each given URL at the last visit time in the URLRow.
- void AddPagesWithDetails(const std::vector<URLRow>& info);
+ // Each visit will have the visit_source type set.
+ void AddPagesWithDetails(const std::vector<URLRow>& info,
+ VisitSource visit_source);
#if defined(UNIT_TEST)
HistoryDatabase* db() const { return db_.get(); }
@@ -312,6 +316,11 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, URLsNoLongerBookmarked);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, StripUsernamePasswordTest);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, DeleteThumbnailsDatabaseTest);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, AddPageVisitSource);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, AddPageArgsSource);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, AddVisitsSource);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, RemoveVisitsSource);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, MigrationVisitSource);
friend class ::TestingProfile;
// Computes the name of the specified database on disk.
@@ -339,7 +348,8 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
std::pair<URLID, VisitID> AddPageVisit(const GURL& url,
base::Time time,
VisitID referring_visit,
- PageTransition::Type transition);
+ PageTransition::Type transition,
+ VisitSource visit_source);
// Returns a redirect chain in |redirects| for the VisitID
// |cur_visit|. |cur_visit| is assumed to be valid. Assumes that
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc
index ff91c53..68fd2e2 100644
--- a/chrome/browser/history/history_backend_unittest.cc
+++ b/chrome/browser/history/history_backend_unittest.cc
@@ -15,6 +15,8 @@
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/history/in_memory_history_backend.h"
#include "chrome/browser/history/in_memory_database.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/thumbnail_score.h"
@@ -75,7 +77,7 @@ class HistoryBackendTest : public testing::Test {
scoped_refptr<history::HistoryAddPageArgs> request(
new history::HistoryAddPageArgs(
redirects.back(), Time::Now(), scope, page_id, GURL(),
- redirects, PageTransition::LINK, true));
+ redirects, PageTransition::LINK, history::SOURCE_BROWSED, true));
backend_->AddPage(request);
}
@@ -95,7 +97,8 @@ class HistoryBackendTest : public testing::Test {
redirects.push_back(url2);
scoped_refptr<HistoryAddPageArgs> request(
new HistoryAddPageArgs(url2, base::Time(), dummy_scope, 0, url1,
- redirects, PageTransition::CLIENT_REDIRECT, did_replace));
+ redirects, PageTransition::CLIENT_REDIRECT,
+ history::SOURCE_BROWSED, did_replace));
backend_->AddPage(request);
*transition1 = getTransition(url1);
@@ -112,6 +115,10 @@ class HistoryBackendTest : public testing::Test {
return visits[0].transition;
}
+ FilePath getTestDir() {
+ return test_dir_;
+ }
+
BookmarkModel bookmark_model_;
protected:
@@ -215,7 +222,7 @@ TEST_F(HistoryBackendTest, DeleteAll) {
std::vector<URLRow> rows;
rows.push_back(row2); // Reversed order for the same reason as favicons.
rows.push_back(row1);
- backend_->AddPagesWithDetails(rows);
+ backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL);
URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL);
@@ -345,7 +352,7 @@ TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
std::vector<URLRow> rows;
rows.push_back(row2); // Reversed order for the same reason as favicons.
rows.push_back(row1);
- backend_->AddPagesWithDetails(rows);
+ backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL);
URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL);
@@ -454,7 +461,8 @@ TEST_F(HistoryBackendTest, KeywordGenerated) {
scoped_refptr<HistoryAddPageArgs> request(
new HistoryAddPageArgs(url, visit_time, NULL, 0, GURL(),
history::RedirectList(),
- PageTransition::KEYWORD_GENERATED, false));
+ PageTransition::KEYWORD_GENERATED,
+ history::SOURCE_BROWSED, false));
backend_->AddPage(request);
// A row should have been added for the url.
@@ -537,7 +545,7 @@ TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
std::vector<URLRow> rows;
rows.push_back(row1);
rows.push_back(row2);
- backend_->AddPagesWithDetails(rows);
+ backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
URLRow url_row1, url_row2;
EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
@@ -592,7 +600,8 @@ TEST_F(HistoryBackendTest, StripUsernamePasswordTest) {
// Visit the url with username, password.
backend_->AddPageVisit(url, base::Time::Now(), 0,
- PageTransition::GetQualifier(PageTransition::TYPED));
+ PageTransition::GetQualifier(PageTransition::TYPED),
+ history::SOURCE_BROWSED);
// Fetch the row information about stripped url from history db.
VisitVector visits;
@@ -612,4 +621,214 @@ TEST_F(HistoryBackendTest, DeleteThumbnailsDatabaseTest) {
EXPECT_FALSE(backend_->thumbnail_db_->NeedsMigrationToTopSites());
}
+TEST_F(HistoryBackendTest, AddPageVisitSource) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url("http://www.google.com");
+
+ // Clear all history.
+ backend_->DeleteAllHistory();
+
+ // Assume visiting the url from an externsion.
+ backend_->AddPageVisit(url, base::Time::Now(), 0, PageTransition::TYPED,
+ history::SOURCE_EXTENSION);
+ // Assume the url is imported from Firefox.
+ backend_->AddPageVisit(url, base::Time::Now(), 0, PageTransition::TYPED,
+ history::SOURCE_FIREFOX_IMPORTED);
+ // Assume this url is also synced.
+ backend_->AddPageVisit(url, base::Time::Now(), 0, PageTransition::TYPED,
+ history::SOURCE_SYNCED);
+
+ // Fetch the row information about the url from history db.
+ VisitVector visits;
+ URLID row_id = backend_->db_->GetRowForURL(url, NULL);
+ backend_->db_->GetVisitsForURL(row_id, &visits);
+
+ // Check if all the visits to the url are stored in database.
+ ASSERT_EQ(3U, visits.size());
+ VisitSourceMap visit_sources;
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(3U, visit_sources.size());
+ int sources = 0;
+ for (int i = 0; i < 3; i++) {
+ switch (visit_sources[visits[i].visit_id]) {
+ case history::SOURCE_EXTENSION:
+ sources |= 0x1;
+ break;
+ case history::SOURCE_FIREFOX_IMPORTED:
+ sources |= 0x2;
+ break;
+ case history::SOURCE_SYNCED:
+ sources |= 0x4;
+ default:
+ break;
+ }
+ }
+ EXPECT_EQ(0x7, sources);
+}
+
+TEST_F(HistoryBackendTest, AddPageArgsSource) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url("http://testpageargs.com");
+
+ // Assume this page is browsed by user.
+ scoped_refptr<HistoryAddPageArgs> request1(
+ new HistoryAddPageArgs(url, base::Time::Now(), NULL, 0, GURL(),
+ history::RedirectList(),
+ PageTransition::KEYWORD_GENERATED,
+ history::SOURCE_BROWSED, false));
+ backend_->AddPage(request1);
+ // Assume this page is synced.
+ scoped_refptr<HistoryAddPageArgs> request2(
+ new HistoryAddPageArgs(url, base::Time::Now(), NULL, 0, GURL(),
+ history::RedirectList(),
+ PageTransition::LINK,
+ history::SOURCE_SYNCED, false));
+ backend_->AddPage(request2);
+ // Assume this page is browsed again.
+ scoped_refptr<HistoryAddPageArgs> request3(
+ new HistoryAddPageArgs(url, base::Time::Now(), NULL, 0, GURL(),
+ history::RedirectList(),
+ PageTransition::TYPED,
+ history::SOURCE_BROWSED, false));
+ backend_->AddPage(request3);
+
+ // Three visits should be added with proper sources.
+ VisitVector visits;
+ URLRow row;
+ URLID id = backend_->db()->GetRowForURL(url, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(3U, visits.size());
+ VisitSourceMap visit_sources;
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(1U, visit_sources.size());
+ EXPECT_EQ(history::SOURCE_SYNCED, visit_sources.begin()->second);
+}
+
+TEST_F(HistoryBackendTest, AddVisitsSource) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url1("http://www.cnn.com");
+ std::vector<base::Time> visits1;
+ visits1.push_back(Time::Now() - base::TimeDelta::FromDays(5));
+ visits1.push_back(Time::Now() - base::TimeDelta::FromDays(1));
+ visits1.push_back(Time::Now());
+
+ GURL url2("http://www.example.com");
+ std::vector<base::Time> visits2;
+ visits2.push_back(Time::Now() - base::TimeDelta::FromDays(10));
+ visits2.push_back(Time::Now());
+
+ // Clear all history.
+ backend_->DeleteAllHistory();
+
+ // Add the visits.
+ backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
+ backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
+
+ // Verify the visits were added with their sources.
+ VisitVector visits;
+ URLRow row;
+ URLID id = backend_->db()->GetRowForURL(url1, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(3U, visits.size());
+ VisitSourceMap visit_sources;
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(3U, visit_sources.size());
+ for (int i = 0; i < 3; i++)
+ EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_sources[visits[i].visit_id]);
+ id = backend_->db()->GetRowForURL(url2, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(2U, visits.size());
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(2U, visit_sources.size());
+ for (int i = 0; i < 2; i++)
+ EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
+}
+
+TEST_F(HistoryBackendTest, RemoveVisitsSource) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url1("http://www.cnn.com");
+ std::vector<base::Time> visits1;
+ visits1.push_back(Time::Now() - base::TimeDelta::FromDays(5));
+ visits1.push_back(Time::Now());
+
+ GURL url2("http://www.example.com");
+ std::vector<base::Time> visits2;
+ visits2.push_back(Time::Now() - base::TimeDelta::FromDays(10));
+ visits2.push_back(Time::Now());
+
+ // Clear all history.
+ backend_->DeleteAllHistory();
+
+ // Add the visits.
+ backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
+ backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
+
+ // Verify the visits of url1 were added.
+ VisitVector visits;
+ URLRow row;
+ URLID id = backend_->db()->GetRowForURL(url1, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(2U, visits.size());
+ // Remove these visits.
+ ASSERT_TRUE(backend_->RemoveVisits(visits));
+
+ // Now check only url2's source in visit_source table.
+ VisitSourceMap visit_sources;
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(0U, visit_sources.size());
+ id = backend_->db()->GetRowForURL(url2, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(2U, visits.size());
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(2U, visit_sources.size());
+ for (int i = 0; i < 2; i++)
+ EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
+}
+
+// Test for migration of adding visit_source table.
+TEST_F(HistoryBackendTest, MigrationVisitSource) {
+ ASSERT_TRUE(backend_.get());
+
+ FilePath old_history_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path));
+ old_history_path = old_history_path.AppendASCII("History");
+ old_history_path = old_history_path.AppendASCII("HistoryNoSource");
+
+ // Copy history database file to current directory so that it will be deleted
+ // in Teardown.
+ FilePath new_history_path(getTestDir());
+ file_util::Delete(new_history_path, true);
+ file_util::CreateDirectory(new_history_path);
+ FilePath new_history_file = new_history_path.Append(chrome::kHistoryFilename);
+ ASSERT_TRUE(file_util::CopyFile(old_history_path, new_history_file));
+
+ backend_->Closing();
+ backend_ = new HistoryBackend(new_history_path,
+ new HistoryBackendTestDelegate(this),
+ &bookmark_model_);
+ backend_->Init(false);
+
+ // Now the database should already be migrated.
+ // Check version first.
+ int cur_version = HistoryDatabase::GetCurrentVersion();
+ sql::Connection db;
+ ASSERT_TRUE(db.Open(new_history_file));
+ sql::Statement s(db.GetUniqueStatement(
+ "SELECT value FROM meta WHERE key = 'version'"));
+ ASSERT_TRUE(s.Step());
+ int file_version = s.ColumnInt(0);
+ EXPECT_EQ(cur_version, file_version);
+
+ // Check visit_source table is created and empty.
+ s.Assign(db.GetUniqueStatement(
+ "SELECT name FROM sqlite_master WHERE name=\"visit_source\""));
+ ASSERT_TRUE(s.Step());
+ s.Assign(db.GetUniqueStatement("SELECT * FROM visit_source LIMIT 10"));
+ EXPECT_FALSE(s.Step());
+}
+
} // namespace history
diff --git a/chrome/browser/history/history_database.cc b/chrome/browser/history/history_database.cc
index 7869fcc..4fab291 100644
--- a/chrome/browser/history/history_database.cc
+++ b/chrome/browser/history/history_database.cc
@@ -26,7 +26,7 @@ namespace {
// Current version number. We write databases at the "current" version number,
// but any previous version that can read the "compatible" one can make do with
// or database without *too* many bad effects.
-static const int kCurrentVersionNumber = 18;
+static const int kCurrentVersionNumber = 19;
static const int kCompatibleVersionNumber = 16;
static const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
@@ -134,7 +134,7 @@ void HistoryDatabase::BeginExclusiveMode() {
// static
int HistoryDatabase::GetCurrentVersion() {
- // If we don't use TopSites, we are one version number behind.
+ // If we don't use TopSites, we stay at the last pre-TopSites version.
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoTopSites))
return 17; // Last pre-TopSites version.
else
@@ -284,12 +284,19 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion(
needs_version_18_migration_ = true;
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoTopSites) &&
- cur_version == 18) {
+ (cur_version == 18 || cur_version == 19)) {
// Set DB version back to pre-top sites.
cur_version = 17;
meta_table_.SetVersionNumber(cur_version);
}
+ if (needs_version_18_migration_ || cur_version == 18) {
+ // This is the version prior to adding url_source column. We need to
+ // migrate the database.
+ cur_version = 19;
+ meta_table_.SetVersionNumber(cur_version);
+ }
+
// When the version is too old, we just try to continue anyway, there should
// not be a released product that makes a database too old for us to handle.
LOG_IF(WARNING, (cur_version < GetCurrentVersion() &&
@@ -325,9 +332,13 @@ void HistoryDatabase::MigrateTimeEpoch() {
#endif
void HistoryDatabase::MigrationToTopSitesDone() {
- // We should be migrating from 17 to 18.
- DCHECK_EQ(17, meta_table_.GetVersionNumber());
- meta_table_.SetVersionNumber(18);
+ // Migration should only happen for version 17 and 19.
+ int version = meta_table_.GetVersionNumber();
+ DCHECK(17 == version || 19 == version);
+ if (17 == version) {
+ // We should be migrating from 17 to 18.
+ meta_table_.SetVersionNumber(18);
+ }
needs_version_18_migration_ = false;
}
diff --git a/chrome/browser/history/history_marshaling.h b/chrome/browser/history/history_marshaling.h
index 64cde29..e746d20 100644
--- a/chrome/browser/history/history_marshaling.h
+++ b/chrome/browser/history/history_marshaling.h
@@ -30,6 +30,7 @@ class HistoryAddPageArgs
const GURL& arg_referrer,
const history::RedirectList& arg_redirects,
PageTransition::Type arg_transition,
+ VisitSource arg_source,
bool arg_did_replace_entry)
: url(arg_url),
time(arg_time),
@@ -38,6 +39,7 @@ class HistoryAddPageArgs
referrer(arg_referrer),
redirects(arg_redirects),
transition(arg_transition),
+ visit_source(arg_source),
did_replace_entry(arg_did_replace_entry) {
}
@@ -50,6 +52,7 @@ class HistoryAddPageArgs
GURL referrer;
history::RedirectList redirects;
PageTransition::Type transition;
+ VisitSource visit_source;
bool did_replace_entry;
private:
diff --git a/chrome/browser/history/history_querying_unittest.cc b/chrome/browser/history/history_querying_unittest.cc
index 7512786..7dbf5d1 100644
--- a/chrome/browser/history/history_querying_unittest.cc
+++ b/chrome/browser/history/history_querying_unittest.cc
@@ -111,7 +111,7 @@ class HistoryQueryTest : public testing::Test {
history_->AddPage(url, test_entries[i].time, id_scope, page_id, GURL(),
PageTransition::LINK, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history_->SetPageTitle(url, UTF8ToUTF16(test_entries[i].title));
history_->SetPageContents(url, UTF8ToUTF16(test_entries[i].body));
}
@@ -314,7 +314,7 @@ TEST_F(HistoryQueryTest, FTSArchived) {
row2.set_last_visit(Time::Now());
urls_to_add.push_back(row2);
- history_->AddPagesWithDetails(urls_to_add);
+ history_->AddPagesWithDetails(urls_to_add, history::SOURCE_BROWSED);
QueryOptions options;
QueryResults results;
diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h
index 21e8067..de4b88c 100644
--- a/chrome/browser/history/history_types.h
+++ b/chrome/browser/history/history_types.h
@@ -176,9 +176,27 @@ class URLRow {
// We support the implicit copy constuctor and operator=.
};
-// VisitRow -------------------------------------------------------------------
+// The enumeration of all possible sources of visits is listed below.
+// The source will be propogated along with a URL or a visit item
+// and eventually be stored in the history database,
+// visit_source table specifically.
+// Different from page transition types, they describe the origins of visits.
+// (Warning): Please don't change any existing values while it is ok to add
+// new values when needed.
+typedef enum {
+ SOURCE_SYNCED = 0, // Synchronized from somewhere else.
+ SOURCE_BROWSED = 1, // User browsed.
+ SOURCE_EXTENSION = 2, // Added by an externsion.
+ SOURCE_FIREFOX_IMPORTED = 3,
+ SOURCE_IE_IMPORTED = 4,
+ SOURCE_SAFARI_IMPORTED = 5,
+} VisitSource;
typedef int64 VisitID;
+// Structure to hold the mapping between each visit's id and its source.
+typedef std::map<VisitID, VisitSource> VisitSourceMap;
+
+// VisitRow -------------------------------------------------------------------
// Holds all information associated with a specific visit. A visit holds time
// and referrer information for one time a URL is visited.
diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc
index 063414f..255e466 100644
--- a/chrome/browser/history/history_unittest.cc
+++ b/chrome/browser/history/history_unittest.cc
@@ -415,7 +415,8 @@ TEST_F(HistoryTest, AddPage) {
const GURL test_url("http://www.google.com/");
history->AddPage(test_url, NULL, 0, GURL(),
PageTransition::MANUAL_SUBFRAME,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
EXPECT_EQ(1, query_url_row_.visit_count());
EXPECT_EQ(0, query_url_row_.typed_count());
@@ -423,7 +424,8 @@ TEST_F(HistoryTest, AddPage) {
// Add the page once from the main frame (should unhide it).
history->AddPage(test_url, NULL, 0, GURL(), PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
EXPECT_EQ(2, query_url_row_.visit_count()); // Added twice.
EXPECT_EQ(0, query_url_row_.typed_count()); // Never typed.
@@ -446,14 +448,16 @@ TEST_F(HistoryTest, AddPageSameTimes) {
// additions have different timestamps.
history->AddPage(test_urls[0], now, NULL, 0, GURL(),
PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_urls[0]));
EXPECT_EQ(1, query_url_row_.visit_count());
EXPECT_TRUE(now == query_url_row_.last_visit()); // gtest doesn't like Time
history->AddPage(test_urls[1], now, NULL, 0, GURL(),
PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_urls[1]));
EXPECT_EQ(1, query_url_row_.visit_count());
EXPECT_TRUE(now + TimeDelta::FromMicroseconds(1) ==
@@ -463,7 +467,8 @@ TEST_F(HistoryTest, AddPageSameTimes) {
history->AddPage(test_urls[2], now + TimeDelta::FromMinutes(1),
NULL, 0, GURL(),
PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_urls[2]));
EXPECT_EQ(1, query_url_row_.visit_count());
EXPECT_TRUE(now + TimeDelta::FromMinutes(1) ==
@@ -486,7 +491,8 @@ TEST_F(HistoryTest, AddRedirect) {
// Add the sequence of pages as a server with no referrer. Note that we need
// to have a non-NULL page ID scope.
history->AddPage(first_redirects.back(), MakeFakeHost(1), 0, GURL(),
- PageTransition::LINK, first_redirects, true);
+ PageTransition::LINK, first_redirects,
+ history::SOURCE_BROWSED, true);
// The first page should be added once with a link visit type (because we set
// LINK when we added the original URL, and a referrer of nowhere (0).
@@ -524,7 +530,7 @@ TEST_F(HistoryTest, AddRedirect) {
second_redirects[0],
static_cast<PageTransition::Type>(PageTransition::LINK |
PageTransition::CLIENT_REDIRECT),
- second_redirects, true);
+ second_redirects, history::SOURCE_BROWSED, true);
// The last page (source of the client redirect) should NOT have an
// additional visit added, because it was a client redirect (normally it
@@ -549,7 +555,8 @@ TEST_F(HistoryTest, Typed) {
// Add the page once as typed.
const GURL test_url("http://www.google.com/");
history->AddPage(test_url, NULL, 0, GURL(), PageTransition::TYPED,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
// We should have the same typed & visit count.
@@ -558,7 +565,8 @@ TEST_F(HistoryTest, Typed) {
// Add the page again not typed.
history->AddPage(test_url, NULL, 0, GURL(), PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
// The second time should not have updated the typed count.
@@ -568,7 +576,7 @@ TEST_F(HistoryTest, Typed) {
// Add the page again as a generated URL.
history->AddPage(test_url, NULL, 0, GURL(),
PageTransition::GENERATED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
// This should have worked like a link click.
@@ -578,7 +586,7 @@ TEST_F(HistoryTest, Typed) {
// Add the page again as a reload.
history->AddPage(test_url, NULL, 0, GURL(),
PageTransition::RELOAD, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
// This should not have incremented any visit counts.
@@ -593,7 +601,7 @@ TEST_F(HistoryTest, SetTitle) {
// Add a URL.
const GURL existing_url("http://www.google.com/");
- history->AddPage(existing_url);
+ history->AddPage(existing_url, history::SOURCE_BROWSED);
// Set some title.
const string16 existing_title = UTF8ToUTF16("Google");
@@ -628,7 +636,7 @@ TEST_F(HistoryTest, Segments) {
const GURL existing_url("http://www.google.com/");
history->AddPage(existing_url, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
// Make sure a segment was created.
history->QuerySegmentUsageSince(
@@ -647,7 +655,7 @@ TEST_F(HistoryTest, Segments) {
const GURL link_url("http://yahoo.com/");
history->AddPage(link_url, scope, 0, GURL(),
PageTransition::LINK, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
// Query again
history->QuerySegmentUsageSince(
@@ -665,7 +673,7 @@ TEST_F(HistoryTest, Segments) {
// Add a page linked from existing_url.
history->AddPage(GURL("http://www.google.com/foo"), scope, 3, existing_url,
PageTransition::LINK, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
// Query again
history->QuerySegmentUsageSince(
@@ -699,7 +707,8 @@ TEST_F(HistoryTest, Thumbnails) {
static const double boringness = 0.25;
const GURL url("http://www.google.com/thumbnail_test/");
- history->AddPage(url); // Must be visited before adding a thumbnail.
+ // Must be visited before adding a thumbnail.
+ history->AddPage(url, history::SOURCE_BROWSED);
history->SetPageThumbnail(url, *thumbnail,
ThumbnailScore(boringness, true, true));
@@ -766,10 +775,10 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Add two pages.
history->AddPage(url0, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->AddPage(url1, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -782,7 +791,7 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Add another page.
history->AddPage(url2, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -796,7 +805,7 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Revisit url2, making it the top URL.
history->AddPage(url2, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -810,7 +819,7 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Revisit url1, making it the top URL.
history->AddPage(url1, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -829,7 +838,7 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Visit url4 using redirects.
history->AddPage(url4, scope, 0, GURL(),
PageTransition::TYPED, redirects,
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -887,7 +896,8 @@ HistoryAddPageArgs* MakeAddArgs(const GURL& url) {
0,
GURL(),
history::RedirectList(),
- PageTransition::TYPED, false);
+ PageTransition::TYPED,
+ history::SOURCE_BROWSED, false);
}
// Convenience version of the above to convert a char string.
diff --git a/chrome/browser/history/text_database_manager_unittest.cc b/chrome/browser/history/text_database_manager_unittest.cc
index 8e7f27e..1ec7744 100644
--- a/chrome/browser/history/text_database_manager_unittest.cc
+++ b/chrome/browser/history/text_database_manager_unittest.cc
@@ -79,7 +79,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
visit_row.transition = 0;
visit_row.segment_id = 0;
visit_row.is_indexed = false;
- VisitID visit_id = visit_db->AddVisit(&visit_row);
+ VisitID visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL1), visit_row.url_id, visit_row.visit_id,
@@ -89,7 +89,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.day_of_month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL2), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle2),
@@ -98,7 +98,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.day_of_month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL3), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle3),
@@ -108,7 +108,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL4), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle4),
@@ -117,7 +117,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.day_of_month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL5), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle5),
@@ -127,7 +127,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.day_of_month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL1), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle1),
@@ -242,7 +242,7 @@ TEST_F(TextDatabaseManagerTest, InsertCompleteVisit) {
visit.transition = PageTransition::LINK;
visit.segment_id = 0;
visit.is_indexed = false;
- visit_db.AddVisit(&visit);
+ visit_db.AddVisit(&visit, SOURCE_BROWSED);
// Add a full text indexed entry for that visit.
const GURL url(kURL2);
@@ -335,7 +335,7 @@ TEST_F(TextDatabaseManagerTest, PartialComplete) {
VisitRow visit_row;
visit_row.url_id = url_id;
visit_row.visit_time = added_time;
- visit_db.AddVisit(&visit_row);
+ visit_db.AddVisit(&visit_row, SOURCE_BROWSED);
// Add a URL with no title or body, and say that it expired.
manager.AddPageURL(url, 0, 0, added_time);
diff --git a/chrome/browser/history/thumbnail_database.cc b/chrome/browser/history/thumbnail_database.cc
index 979accf..ecc7a3c 100644
--- a/chrome/browser/history/thumbnail_database.cc
+++ b/chrome/browser/history/thumbnail_database.cc
@@ -499,7 +499,8 @@ bool ThumbnailDatabase::RenameAndDropThumbnails(const FilePath& old_db_file,
favicons.Close();
// Can't attach within a transaction.
- CommitTransaction();
+ if (transaction_nesting())
+ CommitTransaction();
// Attach new DB.
{
diff --git a/chrome/browser/history/visit_database.cc b/chrome/browser/history/visit_database.cc
index 75c91ee..d0156c2 100644
--- a/chrome/browser/history/visit_database.cc
+++ b/chrome/browser/history/visit_database.cc
@@ -11,6 +11,7 @@
#include "app/sql/statement.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/history/url_database.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/url_constants.h"
@@ -50,6 +51,17 @@ bool VisitDatabase::InitVisitTable() {
return false;
}
+ // Visit source table contains the source information for all the visits. To
+ // save space, we do not record those user browsed visits which would be the
+ // majority in this table. Only other sources are recorded.
+ // Due to the tight relationship between visit_source and visits table, they
+ // should be created and dropped at the same time.
+ if (!GetDB().DoesTableExist("visit_source")) {
+ if (!GetDB().Execute("CREATE TABLE visit_source("
+ "id INTEGER PRIMARY KEY,source INTEGER NOT NULL)"))
+ return false;
+ }
+
// Index over url so we can quickly find visits for a page. This will just
// fail if it already exists and we'll ignore it.
GetDB().Execute("CREATE INDEX visits_url_index ON visits (url)");
@@ -67,6 +79,7 @@ bool VisitDatabase::InitVisitTable() {
}
bool VisitDatabase::DropVisitTable() {
+ GetDB().Execute("DROP TABLE visit_source");
// This will also drop the indices over the table.
return GetDB().Execute("DROP TABLE visits");
}
@@ -93,7 +106,7 @@ void VisitDatabase::FillVisitVector(sql::Statement& statement,
}
}
-VisitID VisitDatabase::AddVisit(VisitRow* visit) {
+VisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) {
sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
"INSERT INTO visits "
"(url, visit_time, from_visit, transition, segment_id, is_indexed) "
@@ -111,6 +124,20 @@ VisitID VisitDatabase::AddVisit(VisitRow* visit) {
return 0;
visit->visit_id = GetDB().GetLastInsertRowId();
+
+ if (source != SOURCE_BROWSED) {
+ // Record the source of this visit when it is not browsed.
+ sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE,
+ "INSERT INTO visit_source (id, source) VALUES (?,?)"));
+ if (!statement1.is_valid())
+ return 0;
+
+ statement1.BindInt64(0, visit->visit_id);
+ statement1.BindInt64(1, source);
+ if (!statement1.Run())
+ return 0;
+ }
+
return visit->visit_id;
}
@@ -132,6 +159,16 @@ void VisitDatabase::DeleteVisit(const VisitRow& visit) {
return;
del.BindInt64(0, visit.visit_id);
del.Run();
+
+ // Try to delete the entry in visit_source table as well.
+ // If the visit was browsed, there is no corresponding entry in visit_source
+ // table, and nothing will be deleted.
+ del.Assign(GetDB().GetCachedStatement(SQL_FROM_HERE,
+ "DELETE FROM visit_source WHERE id=?"));
+ if (!del.is_valid())
+ return;
+ del.BindInt64(0, visit.visit_id);
+ del.Run();
}
bool VisitDatabase::GetRowForVisit(VisitID visit_id, VisitRow* out_visit) {
@@ -436,4 +473,42 @@ bool VisitDatabase::GetStartDate(base::Time* first_visit) {
return true;
}
+void VisitDatabase::GetVisitsSource(const VisitVector& visits,
+ VisitSourceMap* sources) {
+ DCHECK(sources);
+ sources->clear();
+
+ // We query the source in batch. Here defines the batch size.
+ const size_t batch_size = 500;
+ size_t visits_size = visits.size();
+
+ size_t start_index = 0, end_index = 0;
+ while (end_index < visits_size) {
+ start_index = end_index;
+ end_index = end_index + batch_size < visits_size ? end_index + batch_size
+ : visits_size;
+
+ // Compose the sql statement with a list of ids.
+ std::string sql = "SELECT id,source FROM visit_source ";
+ sql.append("WHERE id IN (");
+ // Append all the ids in the statement.
+ for (size_t j = start_index; j < end_index; j++) {
+ if (j != start_index)
+ sql.push_back(',');
+ sql.append(base::Int64ToString(visits[j].visit_id));
+ }
+ sql.append(") ORDER BY id");
+ sql::Statement statement(GetDB().GetUniqueStatement(sql.c_str()));
+ if (!statement)
+ return;
+
+ // Get the source entries out of the query result.
+ while (statement.Step()) {
+ std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0),
+ static_cast<VisitSource>(statement.ColumnInt(1)));
+ sources->insert(source_entry);
+ }
+ }
+}
+
} // namespace history
diff --git a/chrome/browser/history/visit_database.h b/chrome/browser/history/visit_database.h
index 3731c4a..0e97cac 100644
--- a/chrome/browser/history/visit_database.h
+++ b/chrome/browser/history/visit_database.h
@@ -34,8 +34,9 @@ class VisitDatabase {
// Adds a line to the visit database with the given information, returning
// the added row ID on success, 0 on failure. The given visit is updated with
- // the new row ID on success.
- VisitID AddVisit(VisitRow* visit);
+ // the new row ID on success. In addition, adds its source into visit_source
+ // table.
+ VisitID AddVisit(VisitRow* visit, VisitSource source);
// Deletes the given visit from the database. If a visit with the given ID
// doesn't exist, it will not do anything.
@@ -144,6 +145,10 @@ class VisitDatabase {
// Get the time of the first item in our database.
bool GetStartDate(base::Time* first_visit);
+ // Get the source information about the given visits.
+ void GetVisitsSource(const VisitVector& visits,
+ VisitSourceMap* sources);
+
protected:
// Returns the database for the functions in this interface.
virtual sql::Connection& GetDB() = 0;
diff --git a/chrome/browser/history/visit_database_unittest.cc b/chrome/browser/history/visit_database_unittest.cc
index ebc2e1b..28a0e15 100644
--- a/chrome/browser/history/visit_database_unittest.cc
+++ b/chrome/browser/history/visit_database_unittest.cc
@@ -73,19 +73,19 @@ class VisitDatabaseTest : public PlatformTest,
TEST_F(VisitDatabaseTest, Add) {
// Add one visit.
VisitRow visit_info1(1, Time::Now(), 0, PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info1));
+ EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
// Add second visit for the same page.
VisitRow visit_info2(visit_info1.url_id,
visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
PageTransition::TYPED, 0);
- EXPECT_TRUE(AddVisit(&visit_info2));
+ EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
// Add third visit for a different page.
VisitRow visit_info3(2,
visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info3));
+ EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
// Query the first two.
std::vector<VisitRow> matches;
@@ -104,17 +104,17 @@ TEST_F(VisitDatabaseTest, Delete) {
static const int kTime1 = 1000;
VisitRow visit_info1(1, Time::FromInternalValue(kTime1), 0,
PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info1));
+ EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
static const int kTime2 = kTime1 + 1;
VisitRow visit_info2(1, Time::FromInternalValue(kTime2),
visit_info1.visit_id, PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info2));
+ EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
static const int kTime3 = kTime2 + 1;
VisitRow visit_info3(1, Time::FromInternalValue(kTime3),
visit_info2.visit_id, PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info3));
+ EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
// First make sure all the visits are there.
std::vector<VisitRow> matches;
@@ -140,7 +140,7 @@ TEST_F(VisitDatabaseTest, Delete) {
TEST_F(VisitDatabaseTest, Update) {
// Make something in the database.
VisitRow original(1, Time::Now(), 23, 22, 19);
- AddVisit(&original);
+ AddVisit(&original, SOURCE_BROWSED);
// Mutate that row.
VisitRow modification(original);
@@ -167,7 +167,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_END),
0);
visit_info1.visit_id = 1;
- EXPECT_TRUE(AddVisit(&visit_info1));
+ EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
// Add second visit for the same page.
VisitRow visit_info2(visit_info1.url_id,
@@ -177,7 +177,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_END),
0);
visit_info2.visit_id = 2;
- EXPECT_TRUE(AddVisit(&visit_info2));
+ EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
// Add third visit for a different page.
VisitRow visit_info3(2,
@@ -186,7 +186,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_START),
0);
visit_info3.visit_id = 3;
- EXPECT_TRUE(AddVisit(&visit_info3));
+ EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
// Add a redirect visit from the last page.
VisitRow visit_info4(3,
@@ -195,7 +195,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_END),
0);
visit_info4.visit_id = 4;
- EXPECT_TRUE(AddVisit(&visit_info4));
+ EXPECT_TRUE(AddVisit(&visit_info4, SOURCE_BROWSED));
// Add a subframe visit.
VisitRow visit_info5(4,
@@ -205,7 +205,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_END),
0);
visit_info5.visit_id = 5;
- EXPECT_TRUE(AddVisit(&visit_info5));
+ EXPECT_TRUE(AddVisit(&visit_info5, SOURCE_BROWSED));
// Query the visits for all time, we should not get the first (duplicate of
// the second) or the redirect or subframe visits.
@@ -227,4 +227,37 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
ASSERT_EQ(static_cast<size_t>(1), results.size());
EXPECT_TRUE(IsVisitInfoEqual(results[0], visit_info4));
}
+
+TEST_F(VisitDatabaseTest, VisitSource) {
+ // Add visits.
+ VisitRow visit_info1(111, Time::Now(), 0, PageTransition::LINK, 0);
+ ASSERT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
+
+ VisitRow visit_info2(112, Time::Now(), 1, PageTransition::TYPED, 0);
+ ASSERT_TRUE(AddVisit(&visit_info2, SOURCE_SYNCED));
+
+ VisitRow visit_info3(113, Time::Now(), 0, PageTransition::TYPED, 0);
+ ASSERT_TRUE(AddVisit(&visit_info3, SOURCE_EXTENSION));
+
+ // Query each visit.
+ std::vector<VisitRow> matches;
+ ASSERT_TRUE(GetVisitsForURL(111, &matches));
+ ASSERT_EQ(1U, matches.size());
+ VisitSourceMap sources;
+ GetVisitsSource(matches, &sources);
+ EXPECT_EQ(0U, sources.size());
+
+ ASSERT_TRUE(GetVisitsForURL(112, &matches));
+ ASSERT_EQ(1U, matches.size());
+ GetVisitsSource(matches, &sources);
+ ASSERT_EQ(1U, sources.size());
+ EXPECT_EQ(SOURCE_SYNCED, sources[matches[0].visit_id]);
+
+ ASSERT_TRUE(GetVisitsForURL(113, &matches));
+ ASSERT_EQ(1U, matches.size());
+ GetVisitsSource(matches, &sources);
+ ASSERT_EQ(1U, sources.size());
+ EXPECT_EQ(SOURCE_EXTENSION, sources[matches[0].visit_id]);
+}
+
} // namespace history