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