Chromium Code Reviews| 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, these were not |
| 622 // See needs_version_17_migration() decl for more. In this case, we want | 615 // really used for much, therefore the feature has been removed as of M36. |
| 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 M36, we no longer retain expired records in an archived database, |
| 809 // the date of the added visit. | 785 // so forget about old visits. |
| 810 URLDatabase* url_database = NULL; | 786 if (IsExpiredVisitTime(i->last_visit())) |
| 811 VisitDatabase* visit_database = NULL; | 787 continue; |
| 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 | 788 |
| 822 URLRow existing_url; | 789 URLRow existing_url; |
| 823 URLID url_id = url_database->GetRowForURL(i->url(), &existing_url); | 790 URLID url_id = db_->GetRowForURL(i->url(), &existing_url); |
| 824 if (!url_id) { | 791 if (!url_id) { |
| 825 // Add the page if it doesn't exist. | 792 // Add the page if it doesn't exist. |
| 826 url_id = url_database->AddURL(*i); | 793 url_id = db_->AddURL(*i); |
| 827 if (!url_id) { | 794 if (!url_id) { |
| 828 NOTREACHED() << "Could not add row to DB"; | 795 NOTREACHED() << "Could not add row to DB"; |
| 829 return; | 796 return; |
| 830 } | 797 } |
| 831 | 798 |
| 832 if (i->typed_count() > 0) { | 799 if (i->typed_count() > 0) { |
| 833 // Collect expired URLs that belong to |archived_db_| separately; we | 800 modified->changed_urls.push_back(*i); |
| 834 // want to fire NOTIFICATION_HISTORY_URLS_MODIFIED only for changes that | 801 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 } | 802 } |
| 844 } | 803 } |
| 845 | 804 |
| 846 // Sync code manages the visits itself. | 805 // Sync code manages the visits itself. |
| 847 if (visit_source != SOURCE_SYNCED) { | 806 if (visit_source != SOURCE_SYNCED) { |
| 848 // Make up a visit to correspond to the last visit to the page. | 807 // Make up a visit to correspond to the last visit to the page. |
| 849 VisitRow visit_info(url_id, i->last_visit(), 0, | 808 VisitRow visit_info(url_id, i->last_visit(), 0, |
| 850 content::PageTransitionFromInt( | 809 content::PageTransitionFromInt( |
| 851 content::PAGE_TRANSITION_LINK | | 810 content::PAGE_TRANSITION_LINK | |
| 852 content::PAGE_TRANSITION_CHAIN_START | | 811 content::PAGE_TRANSITION_CHAIN_START | |
| 853 content::PAGE_TRANSITION_CHAIN_END), 0); | 812 content::PAGE_TRANSITION_CHAIN_END), 0); |
| 854 if (!visit_database->AddVisit(&visit_info, visit_source)) { | 813 if (!db_->AddVisit(&visit_info, visit_source)) { |
| 855 NOTREACHED() << "Adding visit failed."; | 814 NOTREACHED() << "Adding visit failed."; |
| 856 return; | 815 return; |
| 857 } | 816 } |
| 858 NotifyVisitObservers(visit_info); | 817 NotifyVisitObservers(visit_info); |
| 859 | 818 |
| 860 if (visit_info.visit_time < first_recorded_time_) | 819 if (visit_info.visit_time < first_recorded_time_) |
| 861 first_recorded_time_ = visit_info.visit_time; | 820 first_recorded_time_ = visit_info.visit_time; |
| 862 } | 821 } |
| 863 } | 822 } |
| 864 | 823 |
| 865 if (typed_url_syncable_service_.get()) { | 824 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); | 825 typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls); |
| 869 } | |
| 870 | 826 |
| 871 // Broadcast a notification for typed URLs that have been modified. This | 827 // 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. | 828 // will be picked up by the in-memory URL database on the main thread. |
| 873 // | 829 // |
| 874 // TODO(brettw) bug 1140015: Add an "add page" notification so the history | 830 // TODO(brettw) bug 1140015: Add an "add page" notification so the history |
| 875 // views can keep in sync. | 831 // views can keep in sync. |
| 876 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, | 832 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, |
| 877 modified.PassAs<HistoryDetails>()); | 833 modified.PassAs<HistoryDetails>()); |
| 878 | 834 |
| 879 ScheduleCommit(); | 835 ScheduleCommit(); |
| 880 } | 836 } |
| 881 | 837 |
| 882 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { | 838 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { |
| 883 return time < expirer_.GetCurrentArchiveTime(); | 839 return time < expirer_.GetCurrentExpirationTime(); |
| 884 } | 840 } |
| 885 | 841 |
| 886 void HistoryBackend::SetPageTitle(const GURL& url, | 842 void HistoryBackend::SetPageTitle(const GURL& url, |
| 887 const base::string16& title) { | 843 const base::string16& title) { |
| 888 if (!db_) | 844 if (!db_) |
| 889 return; | 845 return; |
| 890 | 846 |
| 891 // Search for recent redirects which should get the same title. We make a | 847 // 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 | 848 // dummy list containing the exact URL visited if there are no redirects so |
| 893 // the processing below can be the same. | 849 // the processing below can be the same. |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1119 new KeywordSearchUpdatedDetails(url, keyword_id, term))); | 1075 new KeywordSearchUpdatedDetails(url, keyword_id, term))); |
| 1120 ScheduleCommit(); | 1076 ScheduleCommit(); |
| 1121 } | 1077 } |
| 1122 | 1078 |
| 1123 void HistoryBackend::DeleteAllSearchTermsForKeyword( | 1079 void HistoryBackend::DeleteAllSearchTermsForKeyword( |
| 1124 TemplateURLID keyword_id) { | 1080 TemplateURLID keyword_id) { |
| 1125 if (!db_) | 1081 if (!db_) |
| 1126 return; | 1082 return; |
| 1127 | 1083 |
| 1128 db_->DeleteAllSearchTermsForKeyword(keyword_id); | 1084 db_->DeleteAllSearchTermsForKeyword(keyword_id); |
| 1129 // TODO(sky): bug 1168470. Need to move from archive dbs too. | |
| 1130 ScheduleCommit(); | 1085 ScheduleCommit(); |
| 1131 } | 1086 } |
| 1132 | 1087 |
| 1133 void HistoryBackend::GetMostRecentKeywordSearchTerms( | 1088 void HistoryBackend::GetMostRecentKeywordSearchTerms( |
| 1134 scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request, | 1089 scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request, |
| 1135 TemplateURLID keyword_id, | 1090 TemplateURLID keyword_id, |
| 1136 const base::string16& prefix, | 1091 const base::string16& prefix, |
| 1137 int max_count) { | 1092 int max_count) { |
| 1138 if (request->canceled()) | 1093 if (request->canceled()) |
| 1139 return; | 1094 return; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1244 const base::string16& text_query, | 1199 const base::string16& text_query, |
| 1245 const QueryOptions& options) { | 1200 const QueryOptions& options) { |
| 1246 if (request->canceled()) | 1201 if (request->canceled()) |
| 1247 return; | 1202 return; |
| 1248 | 1203 |
| 1249 TimeTicks beginning_time = TimeTicks::Now(); | 1204 TimeTicks beginning_time = TimeTicks::Now(); |
| 1250 | 1205 |
| 1251 if (db_) { | 1206 if (db_) { |
| 1252 if (text_query.empty()) { | 1207 if (text_query.empty()) { |
| 1253 // Basic history query for the main database. | 1208 // Basic history query for the main database. |
| 1254 QueryHistoryBasic(db_.get(), db_.get(), options, &request->value); | 1209 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 { | 1210 } else { |
| 1264 // Text history query. | 1211 // Text history query. |
| 1265 QueryHistoryText(db_.get(), db_.get(), text_query, options, | 1212 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 } | 1213 } |
| 1273 } | 1214 } |
| 1274 | 1215 |
| 1275 request->ForwardResult(request->handle(), &request->value); | 1216 request->ForwardResult(request->handle(), &request->value); |
| 1276 | 1217 |
| 1277 UMA_HISTOGRAM_TIMES("History.QueryHistory", | 1218 UMA_HISTOGRAM_TIMES("History.QueryHistory", |
| 1278 TimeTicks::Now() - beginning_time); | 1219 TimeTicks::Now() - beginning_time); |
| 1279 } | 1220 } |
| 1280 | 1221 |
| 1281 // Basic time-based querying of history. | 1222 // Basic time-based querying of history. |
| 1282 void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db, | 1223 void HistoryBackend::QueryHistoryBasic(const QueryOptions& options, |
| 1283 VisitDatabase* visit_db, | |
| 1284 const QueryOptions& options, | |
| 1285 QueryResults* result) { | 1224 QueryResults* result) { |
| 1286 // First get all visits. | 1225 // First get all visits. |
| 1287 VisitVector visits; | 1226 VisitVector visits; |
| 1288 bool has_more_results = visit_db->GetVisibleVisitsInRange(options, &visits); | 1227 bool has_more_results = db_->GetVisibleVisitsInRange(options, &visits); |
| 1289 DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount()); | 1228 DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount()); |
| 1290 | 1229 |
| 1291 // Now add them and the URL rows to the results. | 1230 // Now add them and the URL rows to the results. |
| 1292 URLResult url_result; | 1231 URLResult url_result; |
| 1293 for (size_t i = 0; i < visits.size(); i++) { | 1232 for (size_t i = 0; i < visits.size(); i++) { |
| 1294 const VisitRow visit = visits[i]; | 1233 const VisitRow visit = visits[i]; |
| 1295 | 1234 |
| 1296 // Add a result row for this visit, get the URL info from the DB. | 1235 // Add a result row for this visit, get the URL info from the DB. |
| 1297 if (!url_db->GetURLRow(visit.url_id, &url_result)) { | 1236 if (!db_->GetURLRow(visit.url_id, &url_result)) { |
| 1298 VLOG(0) << "Failed to get id " << visit.url_id | 1237 VLOG(0) << "Failed to get id " << visit.url_id |
| 1299 << " from history.urls."; | 1238 << " from history.urls."; |
| 1300 continue; // DB out of sync and URL doesn't exist, try to recover. | 1239 continue; // DB out of sync and URL doesn't exist, try to recover. |
| 1301 } | 1240 } |
| 1302 | 1241 |
| 1303 if (!url_result.url().is_valid()) { | 1242 if (!url_result.url().is_valid()) { |
| 1304 VLOG(0) << "Got invalid URL from history.urls with id " | 1243 VLOG(0) << "Got invalid URL from history.urls with id " |
| 1305 << visit.url_id << ": " | 1244 << visit.url_id << ": " |
| 1306 << url_result.url().possibly_invalid_spec(); | 1245 << url_result.url().possibly_invalid_spec(); |
| 1307 continue; // Don't report invalid URLs in case of corruption. | 1246 continue; // Don't report invalid URLs in case of corruption. |
| 1308 } | 1247 } |
| 1309 | 1248 |
| 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()) { | |
|
engedy
2014/04/16 18:08:10
Note: I think this should have been a non-equality
| |
| 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); | 1249 url_result.set_visit_time(visit.visit_time); |
| 1321 | 1250 |
| 1322 // Set whether the visit was blocked for a managed user by looking at the | 1251 // Set whether the visit was blocked for a managed user by looking at the |
| 1323 // transition type. | 1252 // transition type. |
| 1324 url_result.set_blocked_visit( | 1253 url_result.set_blocked_visit( |
| 1325 (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0); | 1254 (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0); |
| 1326 | 1255 |
| 1327 // We don't set any of the query-specific parts of the URLResult, since | 1256 // We don't set any of the query-specific parts of the URLResult, since |
| 1328 // snippets and stuff don't apply to basic querying. | 1257 // snippets and stuff don't apply to basic querying. |
| 1329 result->AppendURLBySwapping(&url_result); | 1258 result->AppendURLBySwapping(&url_result); |
| 1330 } | 1259 } |
| 1331 | 1260 |
| 1332 if (!has_more_results && options.begin_time <= first_recorded_time_) | 1261 if (!has_more_results && options.begin_time <= first_recorded_time_) |
| 1333 result->set_reached_beginning(true); | 1262 result->set_reached_beginning(true); |
| 1334 } | 1263 } |
| 1335 | 1264 |
| 1336 // Text-based querying of history. | 1265 // Text-based querying of history. |
| 1337 void HistoryBackend::QueryHistoryText(URLDatabase* url_db, | 1266 void HistoryBackend::QueryHistoryText(const base::string16& text_query, |
| 1338 VisitDatabase* visit_db, | |
| 1339 const base::string16& text_query, | |
| 1340 const QueryOptions& options, | 1267 const QueryOptions& options, |
| 1341 QueryResults* result) { | 1268 QueryResults* result) { |
| 1342 URLRows text_matches; | 1269 URLRows text_matches; |
| 1343 url_db->GetTextMatches(text_query, &text_matches); | 1270 db_->GetTextMatches(text_query, &text_matches); |
| 1344 | 1271 |
| 1345 std::vector<URLResult> matching_visits; | 1272 std::vector<URLResult> matching_visits; |
| 1346 VisitVector visits; // Declare outside loop to prevent re-construction. | 1273 VisitVector visits; // Declare outside loop to prevent re-construction. |
| 1347 for (size_t i = 0; i < text_matches.size(); i++) { | 1274 for (size_t i = 0; i < text_matches.size(); i++) { |
| 1348 const URLRow& text_match = text_matches[i]; | 1275 const URLRow& text_match = text_matches[i]; |
| 1349 // Get all visits for given URL match. | 1276 // Get all visits for given URL match. |
| 1350 visit_db->GetVisibleVisitsForURL(text_match.id(), options, &visits); | 1277 db_->GetVisibleVisitsForURL(text_match.id(), options, &visits); |
| 1351 for (size_t j = 0; j < visits.size(); j++) { | 1278 for (size_t j = 0; j < visits.size(); j++) { |
| 1352 URLResult url_result(text_match); | 1279 URLResult url_result(text_match); |
| 1353 url_result.set_visit_time(visits[j].visit_time); | 1280 url_result.set_visit_time(visits[j].visit_time); |
| 1354 matching_visits.push_back(url_result); | 1281 matching_visits.push_back(url_result); |
| 1355 } | 1282 } |
| 1356 } | 1283 } |
| 1357 | 1284 |
| 1358 std::sort(matching_visits.begin(), matching_visits.end(), | 1285 std::sort(matching_visits.begin(), matching_visits.end(), |
| 1359 URLResult::CompareVisitTime); | 1286 URLResult::CompareVisitTime); |
| 1360 | 1287 |
| (...skipping 1103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2464 db_->CommitTransaction(); | 2391 db_->CommitTransaction(); |
| 2465 DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open"; | 2392 DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open"; |
| 2466 db_->BeginTransaction(); | 2393 db_->BeginTransaction(); |
| 2467 | 2394 |
| 2468 if (thumbnail_db_) { | 2395 if (thumbnail_db_) { |
| 2469 thumbnail_db_->CommitTransaction(); | 2396 thumbnail_db_->CommitTransaction(); |
| 2470 DCHECK(thumbnail_db_->transaction_nesting() == 0) << | 2397 DCHECK(thumbnail_db_->transaction_nesting() == 0) << |
| 2471 "Somebody left a transaction open"; | 2398 "Somebody left a transaction open"; |
| 2472 thumbnail_db_->BeginTransaction(); | 2399 thumbnail_db_->BeginTransaction(); |
| 2473 } | 2400 } |
| 2474 | |
| 2475 if (archived_db_) { | |
| 2476 archived_db_->CommitTransaction(); | |
| 2477 archived_db_->BeginTransaction(); | |
| 2478 } | |
| 2479 } | 2401 } |
| 2480 | 2402 |
| 2481 void HistoryBackend::ScheduleCommit() { | 2403 void HistoryBackend::ScheduleCommit() { |
| 2482 if (scheduled_commit_.get()) | 2404 if (scheduled_commit_.get()) |
| 2483 return; | 2405 return; |
| 2484 scheduled_commit_ = new CommitLaterTask(this); | 2406 scheduled_commit_ = new CommitLaterTask(this); |
| 2485 base::MessageLoop::current()->PostDelayedTask( | 2407 base::MessageLoop::current()->PostDelayedTask( |
| 2486 FROM_HERE, | 2408 FROM_HERE, |
| 2487 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()), | 2409 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()), |
| 2488 base::TimeDelta::FromSeconds(kCommitIntervalSeconds)); | 2410 base::TimeDelta::FromSeconds(kCommitIntervalSeconds)); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2595 << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime(); | 2517 << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime(); |
| 2596 DCHECK(*times.rbegin() < end_time) | 2518 DCHECK(*times.rbegin() < end_time) |
| 2597 << "Max time is after end time: " | 2519 << "Max time is after end time: " |
| 2598 << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime(); | 2520 << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime(); |
| 2599 | 2521 |
| 2600 history::QueryOptions options; | 2522 history::QueryOptions options; |
| 2601 options.begin_time = begin_time; | 2523 options.begin_time = begin_time; |
| 2602 options.end_time = end_time; | 2524 options.end_time = end_time; |
| 2603 options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES; | 2525 options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES; |
| 2604 QueryResults results; | 2526 QueryResults results; |
| 2605 QueryHistoryBasic(db_.get(), db_.get(), options, &results); | 2527 QueryHistoryBasic(options, &results); |
| 2606 | 2528 |
| 2607 // 1st pass: find URLs that are visited at one of |times|. | 2529 // 1st pass: find URLs that are visited at one of |times|. |
| 2608 std::set<GURL> urls; | 2530 std::set<GURL> urls; |
| 2609 for (size_t i = 0; i < results.size(); ++i) { | 2531 for (size_t i = 0; i < results.size(); ++i) { |
| 2610 if (times.count(results[i].visit_time()) > 0) | 2532 if (times.count(results[i].visit_time()) > 0) |
| 2611 urls.insert(results[i].url()); | 2533 urls.insert(results[i].url()); |
| 2612 } | 2534 } |
| 2613 if (urls.empty()) | 2535 if (urls.empty()) |
| 2614 return; | 2536 return; |
| 2615 | 2537 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2700 bool success = db_->Raze(); | 2622 bool success = db_->Raze(); |
| 2701 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success); | 2623 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success); |
| 2702 | 2624 |
| 2703 #if defined(OS_ANDROID) | 2625 #if defined(OS_ANDROID) |
| 2704 // Release AndroidProviderBackend before other objects. | 2626 // Release AndroidProviderBackend before other objects. |
| 2705 android_provider_backend_.reset(); | 2627 android_provider_backend_.reset(); |
| 2706 #endif | 2628 #endif |
| 2707 | 2629 |
| 2708 // The expirer keeps tabs on the active databases. Tell it about the | 2630 // The expirer keeps tabs on the active databases. Tell it about the |
| 2709 // databases which will be closed. | 2631 // databases which will be closed. |
| 2710 expirer_.SetDatabases(NULL, NULL, NULL); | 2632 expirer_.SetDatabases(NULL, NULL); |
| 2711 | 2633 |
| 2712 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases(). | 2634 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases(). |
| 2713 db_->BeginTransaction(); | 2635 db_->BeginTransaction(); |
| 2714 CloseAllDatabases(); | 2636 CloseAllDatabases(); |
| 2715 } | 2637 } |
| 2716 | 2638 |
| 2717 void HistoryBackend::ProcessDBTask( | 2639 void HistoryBackend::ProcessDBTask( |
| 2718 scoped_refptr<HistoryDBTaskRequest> request) { | 2640 scoped_refptr<HistoryDBTaskRequest> request) { |
| 2719 DCHECK(request.get()); | 2641 DCHECK(request.get()); |
| 2720 if (request->canceled()) | 2642 if (request->canceled()) |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2789 // history, we should delete as much as we can. | 2711 // history, we should delete as much as we can. |
| 2790 } | 2712 } |
| 2791 | 2713 |
| 2792 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. | 2714 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. |
| 2793 // Therefore, we clear the list afterwards to make sure nobody uses this | 2715 // Therefore, we clear the list afterwards to make sure nobody uses this |
| 2794 // invalid data. | 2716 // invalid data. |
| 2795 if (!ClearAllMainHistory(kept_urls)) | 2717 if (!ClearAllMainHistory(kept_urls)) |
| 2796 LOG(ERROR) << "Main history could not be cleared"; | 2718 LOG(ERROR) << "Main history could not be cleared"; |
| 2797 kept_urls.clear(); | 2719 kept_urls.clear(); |
| 2798 | 2720 |
| 2799 // Delete archived history. | |
| 2800 if (archived_db_) { | |
| 2801 // Close the database and delete the file. | |
| 2802 archived_db_.reset(); | |
| 2803 base::FilePath archived_file_name = GetArchivedFileName(); | |
| 2804 sql::Connection::Delete(archived_file_name); | |
| 2805 | |
| 2806 // Now re-initialize the database (which may fail). | |
| 2807 archived_db_.reset(new ArchivedDatabase()); | |
| 2808 if (!archived_db_->Init(archived_file_name)) { | |
| 2809 LOG(WARNING) << "Could not initialize the archived database."; | |
| 2810 archived_db_.reset(); | |
| 2811 } else { | |
| 2812 // Open our long-running transaction on this database. | |
| 2813 archived_db_->BeginTransaction(); | |
| 2814 } | |
| 2815 } | |
| 2816 | |
| 2817 db_->GetStartDate(&first_recorded_time_); | 2721 db_->GetStartDate(&first_recorded_time_); |
| 2818 | 2722 |
| 2819 // Send out the notification that history is cleared. The in-memory database | 2723 // Send out the notification that history is cleared. The in-memory database |
| 2820 // will pick this up and clear itself. | 2724 // will pick this up and clear itself. |
| 2821 scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails); | 2725 scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails); |
| 2822 details->all_history = true; | 2726 details->all_history = true; |
| 2823 NotifySyncURLsDeleted(true, false, NULL); | 2727 NotifySyncURLsDeleted(true, false, NULL); |
| 2824 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, | 2728 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, |
| 2825 details.PassAs<HistoryDetails>()); | 2729 details.PassAs<HistoryDetails>()); |
| 2826 } | 2730 } |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2937 int rank = kPageVisitStatsMaxTopSites; | 2841 int rank = kPageVisitStatsMaxTopSites; |
| 2938 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url); | 2842 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url); |
| 2939 if (it != most_visited_urls_map_.end()) | 2843 if (it != most_visited_urls_map_.end()) |
| 2940 rank = (*it).second; | 2844 rank = (*it).second; |
| 2941 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank", | 2845 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank", |
| 2942 rank, kPageVisitStatsMaxTopSites + 1); | 2846 rank, kPageVisitStatsMaxTopSites + 1); |
| 2943 } | 2847 } |
| 2944 #endif | 2848 #endif |
| 2945 | 2849 |
| 2946 } // namespace history | 2850 } // namespace history |
| OLD | NEW |