OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/history/history_backend.h" | 5 #include "chrome/browser/history/history_backend.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <list> | 9 #include <list> |
10 #include <map> | 10 #include <map> |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
46 #include "url/gurl.h" | 46 #include "url/gurl.h" |
47 | 47 |
48 #if defined(OS_ANDROID) | 48 #if defined(OS_ANDROID) |
49 #include "chrome/browser/history/android/android_provider_backend.h" | 49 #include "chrome/browser/history/android/android_provider_backend.h" |
50 #endif | 50 #endif |
51 | 51 |
52 using base::Time; | 52 using base::Time; |
53 using base::TimeDelta; | 53 using base::TimeDelta; |
54 using base::TimeTicks; | 54 using base::TimeTicks; |
55 | 55 |
56 /* The HistoryBackend consists of a number of components: | 56 /* The HistoryBackend consists of two components: |
57 | 57 |
58 HistoryDatabase (stores past 3 months of history) | 58 HistoryDatabase (stores past 3 months of history) |
59 URLDatabase (stores a list of URLs) | 59 URLDatabase (stores a list of URLs) |
60 DownloadDatabase (stores a list of downloads) | 60 DownloadDatabase (stores a list of downloads) |
61 VisitDatabase (stores a list of visits for the URLs) | 61 VisitDatabase (stores a list of visits for the URLs) |
62 VisitSegmentDatabase (stores groups of URLs for the most visited view). | 62 VisitSegmentDatabase (stores groups of URLs for the most visited view). |
63 | 63 |
64 ArchivedDatabase (stores history older than 3 months) | |
65 URLDatabase (stores a list of URLs) | |
66 DownloadDatabase (stores a list of downloads) | |
67 VisitDatabase (stores a list of visits for the URLs) | |
68 | |
69 (this does not store visit segments as they expire after 3 mos.) | |
70 | |
71 ExpireHistoryBackend (manages moving things from HistoryDatabase to | 64 ExpireHistoryBackend (manages moving things from HistoryDatabase to |
72 the ArchivedDatabase and deleting) | 65 the ArchivedDatabase and deleting) |
73 */ | 66 */ |
74 | 67 |
75 namespace history { | 68 namespace history { |
76 | 69 |
77 // How long we keep segment data for in days. Currently 3 months. | 70 // How long we keep segment data for in days. Currently 3 months. |
78 // This value needs to be greater or equal to | 71 // This value needs to be greater or equal to |
79 // MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct | 72 // MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct |
80 // dependency between MostVisitedModel and the history backend. | 73 // dependency between MostVisitedModel and the history backend. |
81 const int kSegmentDataRetention = 90; | 74 const int kSegmentDataRetention = 90; |
82 | 75 |
83 // How long we'll wait to do a commit, so that things are batched together. | 76 // How long we'll wait to do a commit, so that things are batched together. |
84 const int kCommitIntervalSeconds = 10; | 77 const int kCommitIntervalSeconds = 10; |
85 | 78 |
86 // The amount of time before we re-fetch the favicon. | 79 // The amount of time before we re-fetch the favicon. |
87 const int kFaviconRefetchDays = 7; | 80 const int kFaviconRefetchDays = 7; |
88 | 81 |
89 // The maximum number of items we'll allow in the redirect list before | 82 // The maximum number of items we'll allow in the redirect list before |
90 // deleting some. | 83 // deleting some. |
91 const int kMaxRedirectCount = 32; | 84 const int kMaxRedirectCount = 32; |
92 | 85 |
93 // The number of days old a history entry can be before it is considered "old" | 86 // The number of days old a history entry can be before it is considered "old" |
94 // and is archived. | 87 // and is deleted. |
95 const int kArchiveDaysThreshold = 90; | 88 const int kArchiveDaysThreshold = 90; |
96 | 89 |
97 #if defined(OS_ANDROID) | 90 #if defined(OS_ANDROID) |
98 // The maximum number of top sites to track when recording top page visit stats. | 91 // The maximum number of top sites to track when recording top page visit stats. |
99 const size_t kPageVisitStatsMaxTopSites = 50; | 92 const size_t kPageVisitStatsMaxTopSites = 50; |
100 #endif | 93 #endif |
101 | 94 |
102 // Converts from PageUsageData to MostVisitedURL. |redirects| is a | 95 // Converts from PageUsageData to MostVisitedURL. |redirects| is a |
103 // list of redirects for this URL. Empty list means no redirects. | 96 // list of redirects for this URL. Empty list means no redirects. |
104 MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data, | 97 MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data, |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
610 if (thumbnail_db_->Init(thumbnail_name) != sql::INIT_OK) { | 603 if (thumbnail_db_->Init(thumbnail_name) != sql::INIT_OK) { |
611 // Unlike the main database, we don't error out when the database is too | 604 // Unlike the main database, we don't error out when the database is too |
612 // new because this error is much less severe. Generally, this shouldn't | 605 // new because this error is much less severe. Generally, this shouldn't |
613 // happen since the thumbnail and main database versions should be in sync. | 606 // happen since the thumbnail and main database versions should be in sync. |
614 // We'll just continue without thumbnails & favicons in this case or any | 607 // We'll just continue without thumbnails & favicons in this case or any |
615 // other error. | 608 // other error. |
616 LOG(WARNING) << "Could not initialize the thumbnail database."; | 609 LOG(WARNING) << "Could not initialize the thumbnail database."; |
617 thumbnail_db_.reset(); | 610 thumbnail_db_.reset(); |
618 } | 611 } |
619 | 612 |
620 // Archived database. | 613 // Nuke the remnants of the legacy Archived Database. This used to retain |
621 if (db_->needs_version_17_migration()) { | 614 // expired (> 3 months old) history entries, but in the end, was not really |
622 // See needs_version_17_migration() decl for more. In this case, we want | 615 // used for much, and consequently has been removed as of M37. |
brettw
2014/06/03 17:08:26
Can you add a bug and TODO here to remove this cod
engedy
2014/06/05 10:52:56
Done.
| |
623 // to delete the archived database and need to do so before we try to | 616 sql::Connection::Delete(archived_name); |
624 // open the file. We can ignore any error (maybe the file doesn't exist). | |
625 sql::Connection::Delete(archived_name); | |
626 } | |
627 archived_db_.reset(new ArchivedDatabase()); | |
628 if (!archived_db_->Init(archived_name)) { | |
629 LOG(WARNING) << "Could not initialize the archived database."; | |
630 archived_db_.reset(); | |
631 } | |
632 | 617 |
633 // Generate the history and thumbnail database metrics only after performing | 618 // Generate the history and thumbnail database metrics only after performing |
634 // any migration work. | 619 // any migration work. |
635 if (base::RandInt(1, 100) == 50) { | 620 if (base::RandInt(1, 100) == 50) { |
636 // Only do this computation sometimes since it can be expensive. | 621 // Only do this computation sometimes since it can be expensive. |
637 db_->ComputeDatabaseMetrics(history_name); | 622 db_->ComputeDatabaseMetrics(history_name); |
638 if (thumbnail_db_) | 623 if (thumbnail_db_) |
639 thumbnail_db_->ComputeDatabaseMetrics(); | 624 thumbnail_db_->ComputeDatabaseMetrics(); |
640 } | 625 } |
641 | 626 |
642 // Tell the expiration module about all the nice databases we made. This must | 627 // Tell the expiration module about all the nice databases we made. This must |
643 // happen before db_->Init() is called since the callback ForceArchiveHistory | 628 // happen before db_->Init() is called since the callback ForceArchiveHistory |
644 // may need to expire stuff. | 629 // may need to expire stuff. |
645 // | 630 // |
646 // *sigh*, this can all be cleaned up when that migration code is removed. | 631 // *sigh*, this can all be cleaned up when that migration code is removed. |
647 // The main DB initialization should intuitively be first (not that it | 632 // The main DB initialization should intuitively be first (not that it |
648 // actually matters) and the expirer should be set last. | 633 // actually matters) and the expirer should be set last. |
649 expirer_.SetDatabases(db_.get(), archived_db_.get(), thumbnail_db_.get()); | 634 expirer_.SetDatabases(db_.get(), thumbnail_db_.get()); |
650 | 635 |
651 // Open the long-running transaction. | 636 // Open the long-running transaction. |
652 db_->BeginTransaction(); | 637 db_->BeginTransaction(); |
653 if (thumbnail_db_) | 638 if (thumbnail_db_) |
654 thumbnail_db_->BeginTransaction(); | 639 thumbnail_db_->BeginTransaction(); |
655 if (archived_db_) | |
656 archived_db_->BeginTransaction(); | |
657 | 640 |
658 // Get the first item in our database. | 641 // Get the first item in our database. |
659 db_->GetStartDate(&first_recorded_time_); | 642 db_->GetStartDate(&first_recorded_time_); |
660 | 643 |
661 // Start expiring old stuff. | 644 // Start expiring old stuff. |
662 expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold)); | 645 expirer_.StartExpiringOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold)); |
663 | 646 |
664 #if defined(OS_ANDROID) | 647 #if defined(OS_ANDROID) |
665 if (thumbnail_db_) { | 648 if (thumbnail_db_) { |
666 android_provider_backend_.reset(new AndroidProviderBackend( | 649 android_provider_backend_.reset(new AndroidProviderBackend( |
667 GetAndroidCacheFileName(), db_.get(), thumbnail_db_.get(), | 650 GetAndroidCacheFileName(), db_.get(), thumbnail_db_.get(), |
668 bookmark_service_, delegate_.get())); | 651 bookmark_service_, delegate_.get())); |
669 } | 652 } |
670 #endif | 653 #endif |
671 | 654 |
672 HISTOGRAM_TIMES("History.InitTime", | 655 HISTOGRAM_TIMES("History.InitTime", |
673 TimeTicks::Now() - beginning_time); | 656 TimeTicks::Now() - beginning_time); |
674 } | 657 } |
675 | 658 |
676 void HistoryBackend::OnMemoryPressure( | 659 void HistoryBackend::OnMemoryPressure( |
677 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { | 660 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { |
678 bool trim_aggressively = memory_pressure_level == | 661 bool trim_aggressively = memory_pressure_level == |
679 base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL; | 662 base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL; |
680 if (db_) | 663 if (db_) |
681 db_->TrimMemory(trim_aggressively); | 664 db_->TrimMemory(trim_aggressively); |
682 if (thumbnail_db_) | 665 if (thumbnail_db_) |
683 thumbnail_db_->TrimMemory(trim_aggressively); | 666 thumbnail_db_->TrimMemory(trim_aggressively); |
684 if (archived_db_) | |
685 archived_db_->TrimMemory(trim_aggressively); | |
686 } | 667 } |
687 | 668 |
688 void HistoryBackend::CloseAllDatabases() { | 669 void HistoryBackend::CloseAllDatabases() { |
689 if (db_) { | 670 if (db_) { |
690 // Commit the long-running transaction. | 671 // Commit the long-running transaction. |
691 db_->CommitTransaction(); | 672 db_->CommitTransaction(); |
692 db_.reset(); | 673 db_.reset(); |
693 // Forget the first recorded time since the database is closed. | 674 // Forget the first recorded time since the database is closed. |
694 first_recorded_time_ = base::Time(); | 675 first_recorded_time_ = base::Time(); |
695 } | 676 } |
696 if (thumbnail_db_) { | 677 if (thumbnail_db_) { |
697 thumbnail_db_->CommitTransaction(); | 678 thumbnail_db_->CommitTransaction(); |
698 thumbnail_db_.reset(); | 679 thumbnail_db_.reset(); |
699 } | 680 } |
700 if (archived_db_) { | |
701 archived_db_->CommitTransaction(); | |
702 archived_db_.reset(); | |
703 } | |
704 } | 681 } |
705 | 682 |
706 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit( | 683 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit( |
707 const GURL& url, | 684 const GURL& url, |
708 Time time, | 685 Time time, |
709 VisitID referring_visit, | 686 VisitID referring_visit, |
710 content::PageTransition transition, | 687 content::PageTransition transition, |
711 VisitSource visit_source) { | 688 VisitSource visit_source) { |
712 // Top-level frame navigations are visible, everything else is hidden | 689 // Top-level frame navigations are visible, everything else is hidden |
713 bool new_hidden = !content::PageTransitionIsMainFrame(transition); | 690 bool new_hidden = !content::PageTransitionIsMainFrame(transition); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
794 | 771 |
795 return std::make_pair(url_id, visit_id); | 772 return std::make_pair(url_id, visit_id); |
796 } | 773 } |
797 | 774 |
798 void HistoryBackend::AddPagesWithDetails(const URLRows& urls, | 775 void HistoryBackend::AddPagesWithDetails(const URLRows& urls, |
799 VisitSource visit_source) { | 776 VisitSource visit_source) { |
800 if (!db_) | 777 if (!db_) |
801 return; | 778 return; |
802 | 779 |
803 scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails); | 780 scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails); |
804 scoped_ptr<URLsModifiedDetails> modified_in_archive(new URLsModifiedDetails); | |
805 for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) { | 781 for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) { |
806 DCHECK(!i->last_visit().is_null()); | 782 DCHECK(!i->last_visit().is_null()); |
807 | 783 |
808 // We will add to either the archived database or the main one depending on | 784 // As of M37, we no longer maintain an archived database, ignore old visits. |
809 // the date of the added visit. | 785 if (IsExpiredVisitTime(i->last_visit())) |
810 URLDatabase* url_database = NULL; | 786 continue; |
811 VisitDatabase* visit_database = NULL; | |
812 if (IsExpiredVisitTime(i->last_visit())) { | |
813 if (!archived_db_) | |
814 return; // No archived database to save it to, just forget this. | |
815 url_database = archived_db_.get(); | |
816 visit_database = archived_db_.get(); | |
817 } else { | |
818 url_database = db_.get(); | |
819 visit_database = db_.get(); | |
820 } | |
821 | 787 |
822 URLRow existing_url; | 788 URLRow existing_url; |
823 URLID url_id = url_database->GetRowForURL(i->url(), &existing_url); | 789 URLID url_id = db_->GetRowForURL(i->url(), &existing_url); |
824 if (!url_id) { | 790 if (!url_id) { |
825 // Add the page if it doesn't exist. | 791 // Add the page if it doesn't exist. |
826 url_id = url_database->AddURL(*i); | 792 url_id = db_->AddURL(*i); |
827 if (!url_id) { | 793 if (!url_id) { |
828 NOTREACHED() << "Could not add row to DB"; | 794 NOTREACHED() << "Could not add row to DB"; |
829 return; | 795 return; |
830 } | 796 } |
831 | 797 |
832 if (i->typed_count() > 0) { | 798 if (i->typed_count() > 0) { |
833 // Collect expired URLs that belong to |archived_db_| separately; we | 799 modified->changed_urls.push_back(*i); |
834 // want to fire NOTIFICATION_HISTORY_URLS_MODIFIED only for changes that | 800 modified->changed_urls.back().set_id(url_id); // i->id_ is likely 0. |
835 // take place in the main |db_|. | |
836 if (url_database == db_.get()) { | |
837 modified->changed_urls.push_back(*i); | |
838 modified->changed_urls.back().set_id(url_id); // i->id_ is likely 0. | |
839 } else { | |
840 modified_in_archive->changed_urls.push_back(*i); | |
841 modified_in_archive->changed_urls.back().set_id(url_id); | |
842 } | |
843 } | 801 } |
844 } | 802 } |
845 | 803 |
846 // Sync code manages the visits itself. | 804 // Sync code manages the visits itself. |
847 if (visit_source != SOURCE_SYNCED) { | 805 if (visit_source != SOURCE_SYNCED) { |
848 // Make up a visit to correspond to the last visit to the page. | 806 // Make up a visit to correspond to the last visit to the page. |
849 VisitRow visit_info(url_id, i->last_visit(), 0, | 807 VisitRow visit_info(url_id, i->last_visit(), 0, |
850 content::PageTransitionFromInt( | 808 content::PageTransitionFromInt( |
851 content::PAGE_TRANSITION_LINK | | 809 content::PAGE_TRANSITION_LINK | |
852 content::PAGE_TRANSITION_CHAIN_START | | 810 content::PAGE_TRANSITION_CHAIN_START | |
853 content::PAGE_TRANSITION_CHAIN_END), 0); | 811 content::PAGE_TRANSITION_CHAIN_END), 0); |
854 if (!visit_database->AddVisit(&visit_info, visit_source)) { | 812 if (!db_->AddVisit(&visit_info, visit_source)) { |
855 NOTREACHED() << "Adding visit failed."; | 813 NOTREACHED() << "Adding visit failed."; |
856 return; | 814 return; |
857 } | 815 } |
858 NotifyVisitObservers(visit_info); | 816 NotifyVisitObservers(visit_info); |
859 | 817 |
860 if (visit_info.visit_time < first_recorded_time_) | 818 if (visit_info.visit_time < first_recorded_time_) |
861 first_recorded_time_ = visit_info.visit_time; | 819 first_recorded_time_ = visit_info.visit_time; |
862 } | 820 } |
863 } | 821 } |
864 | 822 |
865 if (typed_url_syncable_service_.get()) { | 823 if (typed_url_syncable_service_.get()) |
866 typed_url_syncable_service_->OnUrlsModified( | |
867 &modified_in_archive->changed_urls); | |
868 typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls); | 824 typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls); |
869 } | |
870 | 825 |
871 // Broadcast a notification for typed URLs that have been modified. This | 826 // Broadcast a notification for typed URLs that have been modified. This |
872 // will be picked up by the in-memory URL database on the main thread. | 827 // will be picked up by the in-memory URL database on the main thread. |
873 // | 828 // |
874 // TODO(brettw) bug 1140015: Add an "add page" notification so the history | 829 // TODO(brettw) bug 1140015: Add an "add page" notification so the history |
875 // views can keep in sync. | 830 // views can keep in sync. |
876 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, | 831 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, |
877 modified.PassAs<HistoryDetails>()); | 832 modified.PassAs<HistoryDetails>()); |
878 | 833 |
879 ScheduleCommit(); | 834 ScheduleCommit(); |
880 } | 835 } |
881 | 836 |
882 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { | 837 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { |
883 return time < expirer_.GetCurrentArchiveTime(); | 838 return time < expirer_.GetCurrentExpirationTime(); |
884 } | 839 } |
885 | 840 |
886 void HistoryBackend::SetPageTitle(const GURL& url, | 841 void HistoryBackend::SetPageTitle(const GURL& url, |
887 const base::string16& title) { | 842 const base::string16& title) { |
888 if (!db_) | 843 if (!db_) |
889 return; | 844 return; |
890 | 845 |
891 // Search for recent redirects which should get the same title. We make a | 846 // Search for recent redirects which should get the same title. We make a |
892 // dummy list containing the exact URL visited if there are no redirects so | 847 // dummy list containing the exact URL visited if there are no redirects so |
893 // the processing below can be the same. | 848 // the processing below can be the same. |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1119 new KeywordSearchUpdatedDetails(row, keyword_id, term))); | 1074 new KeywordSearchUpdatedDetails(row, keyword_id, term))); |
1120 ScheduleCommit(); | 1075 ScheduleCommit(); |
1121 } | 1076 } |
1122 | 1077 |
1123 void HistoryBackend::DeleteAllSearchTermsForKeyword( | 1078 void HistoryBackend::DeleteAllSearchTermsForKeyword( |
1124 TemplateURLID keyword_id) { | 1079 TemplateURLID keyword_id) { |
1125 if (!db_) | 1080 if (!db_) |
1126 return; | 1081 return; |
1127 | 1082 |
1128 db_->DeleteAllSearchTermsForKeyword(keyword_id); | 1083 db_->DeleteAllSearchTermsForKeyword(keyword_id); |
1129 // TODO(sky): bug 1168470. Need to move from archive dbs too. | |
1130 ScheduleCommit(); | 1084 ScheduleCommit(); |
1131 } | 1085 } |
1132 | 1086 |
1133 void HistoryBackend::GetMostRecentKeywordSearchTerms( | 1087 void HistoryBackend::GetMostRecentKeywordSearchTerms( |
1134 scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request, | 1088 scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request, |
1135 TemplateURLID keyword_id, | 1089 TemplateURLID keyword_id, |
1136 const base::string16& prefix, | 1090 const base::string16& prefix, |
1137 int max_count) { | 1091 int max_count) { |
1138 if (request->canceled()) | 1092 if (request->canceled()) |
1139 return; | 1093 return; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1244 const base::string16& text_query, | 1198 const base::string16& text_query, |
1245 const QueryOptions& options) { | 1199 const QueryOptions& options) { |
1246 if (request->canceled()) | 1200 if (request->canceled()) |
1247 return; | 1201 return; |
1248 | 1202 |
1249 TimeTicks beginning_time = TimeTicks::Now(); | 1203 TimeTicks beginning_time = TimeTicks::Now(); |
1250 | 1204 |
1251 if (db_) { | 1205 if (db_) { |
1252 if (text_query.empty()) { | 1206 if (text_query.empty()) { |
1253 // Basic history query for the main database. | 1207 // Basic history query for the main database. |
1254 QueryHistoryBasic(db_.get(), db_.get(), options, &request->value); | 1208 QueryHistoryBasic(options, &request->value); |
1255 | |
1256 // Now query the archived database. This is a bit tricky because we don't | |
1257 // want to query it if the queried time range isn't going to find anything | |
1258 // in it. | |
1259 // TODO(brettw) bug 1171036: do blimpie querying for the archived database | |
1260 // as well. | |
1261 // if (archived_db_.get() && | |
1262 // expirer_.GetCurrentArchiveTime() - TimeDelta::FromDays(7)) { | |
1263 } else { | 1209 } else { |
1264 // Text history query. | 1210 // Text history query. |
1265 QueryHistoryText(db_.get(), db_.get(), text_query, options, | 1211 QueryHistoryText(text_query, options, &request->value); |
1266 &request->value); | |
1267 if (archived_db_.get() && | |
1268 expirer_.GetCurrentArchiveTime() >= options.begin_time) { | |
1269 QueryHistoryText(archived_db_.get(), archived_db_.get(), text_query, | |
1270 options, &request->value); | |
1271 } | |
1272 } | 1212 } |
1273 } | 1213 } |
1274 | 1214 |
1275 request->ForwardResult(request->handle(), &request->value); | 1215 request->ForwardResult(request->handle(), &request->value); |
1276 | 1216 |
1277 UMA_HISTOGRAM_TIMES("History.QueryHistory", | 1217 UMA_HISTOGRAM_TIMES("History.QueryHistory", |
1278 TimeTicks::Now() - beginning_time); | 1218 TimeTicks::Now() - beginning_time); |
1279 } | 1219 } |
1280 | 1220 |
1281 // Basic time-based querying of history. | 1221 // Basic time-based querying of history. |
1282 void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db, | 1222 void HistoryBackend::QueryHistoryBasic(const QueryOptions& options, |
1283 VisitDatabase* visit_db, | |
1284 const QueryOptions& options, | |
1285 QueryResults* result) { | 1223 QueryResults* result) { |
1286 // First get all visits. | 1224 // First get all visits. |
1287 VisitVector visits; | 1225 VisitVector visits; |
1288 bool has_more_results = visit_db->GetVisibleVisitsInRange(options, &visits); | 1226 bool has_more_results = db_->GetVisibleVisitsInRange(options, &visits); |
1289 DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount()); | 1227 DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount()); |
1290 | 1228 |
1291 // Now add them and the URL rows to the results. | 1229 // Now add them and the URL rows to the results. |
1292 URLResult url_result; | 1230 URLResult url_result; |
1293 for (size_t i = 0; i < visits.size(); i++) { | 1231 for (size_t i = 0; i < visits.size(); i++) { |
1294 const VisitRow visit = visits[i]; | 1232 const VisitRow visit = visits[i]; |
1295 | 1233 |
1296 // Add a result row for this visit, get the URL info from the DB. | 1234 // Add a result row for this visit, get the URL info from the DB. |
1297 if (!url_db->GetURLRow(visit.url_id, &url_result)) { | 1235 if (!db_->GetURLRow(visit.url_id, &url_result)) { |
1298 VLOG(0) << "Failed to get id " << visit.url_id | 1236 VLOG(0) << "Failed to get id " << visit.url_id |
1299 << " from history.urls."; | 1237 << " from history.urls."; |
1300 continue; // DB out of sync and URL doesn't exist, try to recover. | 1238 continue; // DB out of sync and URL doesn't exist, try to recover. |
1301 } | 1239 } |
1302 | 1240 |
1303 if (!url_result.url().is_valid()) { | 1241 if (!url_result.url().is_valid()) { |
1304 VLOG(0) << "Got invalid URL from history.urls with id " | 1242 VLOG(0) << "Got invalid URL from history.urls with id " |
1305 << visit.url_id << ": " | 1243 << visit.url_id << ": " |
1306 << url_result.url().possibly_invalid_spec(); | 1244 << url_result.url().possibly_invalid_spec(); |
1307 continue; // Don't report invalid URLs in case of corruption. | 1245 continue; // Don't report invalid URLs in case of corruption. |
1308 } | 1246 } |
1309 | 1247 |
1310 // The archived database may be out of sync with respect to starring, | |
1311 // titles, last visit date, etc. Therefore, we query the main DB if the | |
1312 // current URL database is not the main one. | |
1313 if (url_db == db_.get()) { | |
1314 // Currently querying the archived DB, update with the main database to | |
1315 // catch any interesting stuff. This will update it if it exists in the | |
1316 // main DB, and do nothing otherwise. | |
1317 db_->GetRowForURL(url_result.url(), &url_result); | |
1318 } | |
1319 | |
1320 url_result.set_visit_time(visit.visit_time); | 1248 url_result.set_visit_time(visit.visit_time); |
1321 | 1249 |
1322 // Set whether the visit was blocked for a managed user by looking at the | 1250 // Set whether the visit was blocked for a managed user by looking at the |
1323 // transition type. | 1251 // transition type. |
1324 url_result.set_blocked_visit( | 1252 url_result.set_blocked_visit( |
1325 (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0); | 1253 (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0); |
1326 | 1254 |
1327 // We don't set any of the query-specific parts of the URLResult, since | 1255 // We don't set any of the query-specific parts of the URLResult, since |
1328 // snippets and stuff don't apply to basic querying. | 1256 // snippets and stuff don't apply to basic querying. |
1329 result->AppendURLBySwapping(&url_result); | 1257 result->AppendURLBySwapping(&url_result); |
1330 } | 1258 } |
1331 | 1259 |
1332 if (!has_more_results && options.begin_time <= first_recorded_time_) | 1260 if (!has_more_results && options.begin_time <= first_recorded_time_) |
1333 result->set_reached_beginning(true); | 1261 result->set_reached_beginning(true); |
1334 } | 1262 } |
1335 | 1263 |
1336 // Text-based querying of history. | 1264 // Text-based querying of history. |
1337 void HistoryBackend::QueryHistoryText(URLDatabase* url_db, | 1265 void HistoryBackend::QueryHistoryText(const base::string16& text_query, |
1338 VisitDatabase* visit_db, | |
1339 const base::string16& text_query, | |
1340 const QueryOptions& options, | 1266 const QueryOptions& options, |
1341 QueryResults* result) { | 1267 QueryResults* result) { |
1342 URLRows text_matches; | 1268 URLRows text_matches; |
1343 url_db->GetTextMatches(text_query, &text_matches); | 1269 db_->GetTextMatches(text_query, &text_matches); |
1344 | 1270 |
1345 std::vector<URLResult> matching_visits; | 1271 std::vector<URLResult> matching_visits; |
1346 VisitVector visits; // Declare outside loop to prevent re-construction. | 1272 VisitVector visits; // Declare outside loop to prevent re-construction. |
1347 for (size_t i = 0; i < text_matches.size(); i++) { | 1273 for (size_t i = 0; i < text_matches.size(); i++) { |
1348 const URLRow& text_match = text_matches[i]; | 1274 const URLRow& text_match = text_matches[i]; |
1349 // Get all visits for given URL match. | 1275 // Get all visits for given URL match. |
1350 visit_db->GetVisibleVisitsForURL(text_match.id(), options, &visits); | 1276 db_->GetVisibleVisitsForURL(text_match.id(), options, &visits); |
1351 for (size_t j = 0; j < visits.size(); j++) { | 1277 for (size_t j = 0; j < visits.size(); j++) { |
1352 URLResult url_result(text_match); | 1278 URLResult url_result(text_match); |
1353 url_result.set_visit_time(visits[j].visit_time); | 1279 url_result.set_visit_time(visits[j].visit_time); |
1354 matching_visits.push_back(url_result); | 1280 matching_visits.push_back(url_result); |
1355 } | 1281 } |
1356 } | 1282 } |
1357 | 1283 |
1358 std::sort(matching_visits.begin(), matching_visits.end(), | 1284 std::sort(matching_visits.begin(), matching_visits.end(), |
1359 URLResult::CompareVisitTime); | 1285 URLResult::CompareVisitTime); |
1360 | 1286 |
(...skipping 1109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2470 db_->CommitTransaction(); | 2396 db_->CommitTransaction(); |
2471 DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open"; | 2397 DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open"; |
2472 db_->BeginTransaction(); | 2398 db_->BeginTransaction(); |
2473 | 2399 |
2474 if (thumbnail_db_) { | 2400 if (thumbnail_db_) { |
2475 thumbnail_db_->CommitTransaction(); | 2401 thumbnail_db_->CommitTransaction(); |
2476 DCHECK(thumbnail_db_->transaction_nesting() == 0) << | 2402 DCHECK(thumbnail_db_->transaction_nesting() == 0) << |
2477 "Somebody left a transaction open"; | 2403 "Somebody left a transaction open"; |
2478 thumbnail_db_->BeginTransaction(); | 2404 thumbnail_db_->BeginTransaction(); |
2479 } | 2405 } |
2480 | |
2481 if (archived_db_) { | |
2482 archived_db_->CommitTransaction(); | |
2483 archived_db_->BeginTransaction(); | |
2484 } | |
2485 } | 2406 } |
2486 | 2407 |
2487 void HistoryBackend::ScheduleCommit() { | 2408 void HistoryBackend::ScheduleCommit() { |
2488 if (scheduled_commit_.get()) | 2409 if (scheduled_commit_.get()) |
2489 return; | 2410 return; |
2490 scheduled_commit_ = new CommitLaterTask(this); | 2411 scheduled_commit_ = new CommitLaterTask(this); |
2491 base::MessageLoop::current()->PostDelayedTask( | 2412 base::MessageLoop::current()->PostDelayedTask( |
2492 FROM_HERE, | 2413 FROM_HERE, |
2493 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()), | 2414 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()), |
2494 base::TimeDelta::FromSeconds(kCommitIntervalSeconds)); | 2415 base::TimeDelta::FromSeconds(kCommitIntervalSeconds)); |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2601 << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime(); | 2522 << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime(); |
2602 DCHECK(*times.rbegin() < end_time) | 2523 DCHECK(*times.rbegin() < end_time) |
2603 << "Max time is after end time: " | 2524 << "Max time is after end time: " |
2604 << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime(); | 2525 << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime(); |
2605 | 2526 |
2606 history::QueryOptions options; | 2527 history::QueryOptions options; |
2607 options.begin_time = begin_time; | 2528 options.begin_time = begin_time; |
2608 options.end_time = end_time; | 2529 options.end_time = end_time; |
2609 options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES; | 2530 options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES; |
2610 QueryResults results; | 2531 QueryResults results; |
2611 QueryHistoryBasic(db_.get(), db_.get(), options, &results); | 2532 QueryHistoryBasic(options, &results); |
2612 | 2533 |
2613 // 1st pass: find URLs that are visited at one of |times|. | 2534 // 1st pass: find URLs that are visited at one of |times|. |
2614 std::set<GURL> urls; | 2535 std::set<GURL> urls; |
2615 for (size_t i = 0; i < results.size(); ++i) { | 2536 for (size_t i = 0; i < results.size(); ++i) { |
2616 if (times.count(results[i].visit_time()) > 0) | 2537 if (times.count(results[i].visit_time()) > 0) |
2617 urls.insert(results[i].url()); | 2538 urls.insert(results[i].url()); |
2618 } | 2539 } |
2619 if (urls.empty()) | 2540 if (urls.empty()) |
2620 return; | 2541 return; |
2621 | 2542 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2706 bool success = db_->Raze(); | 2627 bool success = db_->Raze(); |
2707 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success); | 2628 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success); |
2708 | 2629 |
2709 #if defined(OS_ANDROID) | 2630 #if defined(OS_ANDROID) |
2710 // Release AndroidProviderBackend before other objects. | 2631 // Release AndroidProviderBackend before other objects. |
2711 android_provider_backend_.reset(); | 2632 android_provider_backend_.reset(); |
2712 #endif | 2633 #endif |
2713 | 2634 |
2714 // The expirer keeps tabs on the active databases. Tell it about the | 2635 // The expirer keeps tabs on the active databases. Tell it about the |
2715 // databases which will be closed. | 2636 // databases which will be closed. |
2716 expirer_.SetDatabases(NULL, NULL, NULL); | 2637 expirer_.SetDatabases(NULL, NULL); |
2717 | 2638 |
2718 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases(). | 2639 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases(). |
2719 db_->BeginTransaction(); | 2640 db_->BeginTransaction(); |
2720 CloseAllDatabases(); | 2641 CloseAllDatabases(); |
2721 } | 2642 } |
2722 | 2643 |
2723 void HistoryBackend::ProcessDBTask( | 2644 void HistoryBackend::ProcessDBTask( |
2724 scoped_refptr<HistoryDBTaskRequest> request) { | 2645 scoped_refptr<HistoryDBTaskRequest> request) { |
2725 DCHECK(request.get()); | 2646 DCHECK(request.get()); |
2726 if (request->canceled()) | 2647 if (request->canceled()) |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2800 // history, we should delete as much as we can. | 2721 // history, we should delete as much as we can. |
2801 } | 2722 } |
2802 | 2723 |
2803 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. | 2724 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. |
2804 // Therefore, we clear the list afterwards to make sure nobody uses this | 2725 // Therefore, we clear the list afterwards to make sure nobody uses this |
2805 // invalid data. | 2726 // invalid data. |
2806 if (!ClearAllMainHistory(kept_urls)) | 2727 if (!ClearAllMainHistory(kept_urls)) |
2807 LOG(ERROR) << "Main history could not be cleared"; | 2728 LOG(ERROR) << "Main history could not be cleared"; |
2808 kept_urls.clear(); | 2729 kept_urls.clear(); |
2809 | 2730 |
2810 // Delete archived history. | |
2811 if (archived_db_) { | |
2812 // Close the database and delete the file. | |
2813 archived_db_.reset(); | |
2814 base::FilePath archived_file_name = GetArchivedFileName(); | |
2815 sql::Connection::Delete(archived_file_name); | |
2816 | |
2817 // Now re-initialize the database (which may fail). | |
2818 archived_db_.reset(new ArchivedDatabase()); | |
2819 if (!archived_db_->Init(archived_file_name)) { | |
2820 LOG(WARNING) << "Could not initialize the archived database."; | |
2821 archived_db_.reset(); | |
2822 } else { | |
2823 // Open our long-running transaction on this database. | |
2824 archived_db_->BeginTransaction(); | |
2825 } | |
2826 } | |
2827 | |
2828 db_->GetStartDate(&first_recorded_time_); | 2731 db_->GetStartDate(&first_recorded_time_); |
2829 | 2732 |
2830 // Send out the notification that history is cleared. The in-memory database | 2733 // Send out the notification that history is cleared. The in-memory database |
2831 // will pick this up and clear itself. | 2734 // will pick this up and clear itself. |
2832 scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails); | 2735 scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails); |
2833 details->all_history = true; | 2736 details->all_history = true; |
2834 NotifySyncURLsDeleted(true, false, NULL); | 2737 NotifySyncURLsDeleted(true, false, NULL); |
2835 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, | 2738 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, |
2836 details.PassAs<HistoryDetails>()); | 2739 details.PassAs<HistoryDetails>()); |
2837 } | 2740 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2948 int rank = kPageVisitStatsMaxTopSites; | 2851 int rank = kPageVisitStatsMaxTopSites; |
2949 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url); | 2852 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url); |
2950 if (it != most_visited_urls_map_.end()) | 2853 if (it != most_visited_urls_map_.end()) |
2951 rank = (*it).second; | 2854 rank = (*it).second; |
2952 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank", | 2855 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank", |
2953 rank, kPageVisitStatsMaxTopSites + 1); | 2856 rank, kPageVisitStatsMaxTopSites + 1); |
2954 } | 2857 } |
2955 #endif | 2858 #endif |
2956 | 2859 |
2957 } // namespace history | 2860 } // namespace history |
OLD | NEW |