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 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
797 // Add the visit with the time to the database. | 797 // Add the visit with the time to the database. |
798 VisitRow visit_info(url_id, time, referring_visit, transition, 0); | 798 VisitRow visit_info(url_id, time, referring_visit, transition, 0); |
799 VisitID visit_id = db_->AddVisit(&visit_info, visit_source); | 799 VisitID visit_id = db_->AddVisit(&visit_info, visit_source); |
800 NotifyVisitObservers(visit_info); | 800 NotifyVisitObservers(visit_info); |
801 | 801 |
802 if (visit_info.visit_time < first_recorded_time_) | 802 if (visit_info.visit_time < first_recorded_time_) |
803 first_recorded_time_ = visit_info.visit_time; | 803 first_recorded_time_ = visit_info.visit_time; |
804 | 804 |
805 // Broadcast a notification of the visit. | 805 // Broadcast a notification of the visit. |
806 if (visit_id) { | 806 if (visit_id) { |
807 if (typed_url_syncable_service_.get()) | |
808 typed_url_syncable_service_->OnUrlVisited(transition, &url_info); | |
809 | |
810 RedirectList redirects; | 807 RedirectList redirects; |
811 // TODO(meelapshah) Disabled due to potential PageCycler regression. | 808 // TODO(meelapshah) Disabled due to potential PageCycler regression. |
812 // Re-enable this. | 809 // Re-enable this. |
813 // QueryRedirectsTo(url, &redirects); | 810 // QueryRedirectsTo(url, &redirects); |
814 NotifyURLVisited(transition, url_info, redirects, time); | 811 NotifyURLVisited(transition, url_info, redirects, time); |
815 | |
816 // TODO(sdefresne): turn HistoryBackend::Delegate from HistoryService into | |
817 // an HistoryBackendObserver and register it so that we can remove this | |
818 // method. | |
819 if (delegate_) | |
820 delegate_->NotifyURLVisited(transition, url_info, redirects, time); | |
821 } else { | 812 } else { |
822 VLOG(0) << "Failed to build visit insert statement: " | 813 VLOG(0) << "Failed to build visit insert statement: " |
823 << "url_id = " << url_id; | 814 << "url_id = " << url_id; |
824 } | 815 } |
825 | 816 |
826 return std::make_pair(url_id, visit_id); | 817 return std::make_pair(url_id, visit_id); |
827 } | 818 } |
828 | 819 |
829 void HistoryBackend::NotifyURLVisited(ui::PageTransition transition, | |
830 const URLRow& row, | |
831 const RedirectList& redirects, | |
832 base::Time visit_time) { | |
833 FOR_EACH_OBSERVER( | |
834 HistoryBackendObserver, | |
835 observers_, | |
836 OnURLVisited(this, transition, row, redirects, visit_time)); | |
837 } | |
838 | |
839 void HistoryBackend::AddPagesWithDetails(const URLRows& urls, | 820 void HistoryBackend::AddPagesWithDetails(const URLRows& urls, |
840 VisitSource visit_source) { | 821 VisitSource visit_source) { |
841 if (!db_) | 822 if (!db_) |
842 return; | 823 return; |
843 | 824 |
844 scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails); | 825 URLRows changed_urls; |
845 for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) { | 826 for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) { |
846 DCHECK(!i->last_visit().is_null()); | 827 DCHECK(!i->last_visit().is_null()); |
847 | 828 |
848 // As of M37, we no longer maintain an archived database, ignore old visits. | 829 // As of M37, we no longer maintain an archived database, ignore old visits. |
849 if (IsExpiredVisitTime(i->last_visit())) | 830 if (IsExpiredVisitTime(i->last_visit())) |
850 continue; | 831 continue; |
851 | 832 |
852 URLRow existing_url; | 833 URLRow existing_url; |
853 URLID url_id = db_->GetRowForURL(i->url(), &existing_url); | 834 URLID url_id = db_->GetRowForURL(i->url(), &existing_url); |
854 if (!url_id) { | 835 if (!url_id) { |
855 // Add the page if it doesn't exist. | 836 // Add the page if it doesn't exist. |
856 url_id = db_->AddURL(*i); | 837 url_id = db_->AddURL(*i); |
857 if (!url_id) { | 838 if (!url_id) { |
858 NOTREACHED() << "Could not add row to DB"; | 839 NOTREACHED() << "Could not add row to DB"; |
859 return; | 840 return; |
860 } | 841 } |
861 | 842 |
862 modified->changed_urls.push_back(*i); | 843 changed_urls.push_back(*i); |
863 modified->changed_urls.back().set_id(url_id); // i->id_ is likely 0. | 844 changed_urls.back().set_id(url_id); // i->id_ is likely 0. |
864 } | 845 } |
865 | 846 |
866 // Sync code manages the visits itself. | 847 // Sync code manages the visits itself. |
867 if (visit_source != SOURCE_SYNCED) { | 848 if (visit_source != SOURCE_SYNCED) { |
868 // Make up a visit to correspond to the last visit to the page. | 849 // Make up a visit to correspond to the last visit to the page. |
869 VisitRow visit_info(url_id, i->last_visit(), 0, | 850 VisitRow visit_info(url_id, i->last_visit(), 0, |
870 ui::PageTransitionFromInt( | 851 ui::PageTransitionFromInt( |
871 ui::PAGE_TRANSITION_LINK | | 852 ui::PAGE_TRANSITION_LINK | |
872 ui::PAGE_TRANSITION_CHAIN_START | | 853 ui::PAGE_TRANSITION_CHAIN_START | |
873 ui::PAGE_TRANSITION_CHAIN_END), 0); | 854 ui::PAGE_TRANSITION_CHAIN_END), 0); |
874 if (!db_->AddVisit(&visit_info, visit_source)) { | 855 if (!db_->AddVisit(&visit_info, visit_source)) { |
875 NOTREACHED() << "Adding visit failed."; | 856 NOTREACHED() << "Adding visit failed."; |
876 return; | 857 return; |
877 } | 858 } |
878 NotifyVisitObservers(visit_info); | 859 NotifyVisitObservers(visit_info); |
879 | 860 |
880 if (visit_info.visit_time < first_recorded_time_) | 861 if (visit_info.visit_time < first_recorded_time_) |
881 first_recorded_time_ = visit_info.visit_time; | 862 first_recorded_time_ = visit_info.visit_time; |
882 } | 863 } |
883 } | 864 } |
884 | 865 |
885 if (typed_url_syncable_service_.get()) | |
886 typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls); | |
887 | |
888 // Broadcast a notification for typed URLs that have been modified. This | 866 // Broadcast a notification for typed URLs that have been modified. This |
889 // will be picked up by the in-memory URL database on the main thread. | 867 // will be picked up by the in-memory URL database on the main thread. |
890 // | 868 // |
891 // TODO(brettw) bug 1140015: Add an "add page" notification so the history | 869 // TODO(brettw) bug 1140015: Add an "add page" notification so the history |
892 // views can keep in sync. | 870 // views can keep in sync. |
893 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, | 871 NotifyURLsModified(changed_urls); |
894 modified.Pass()); | |
895 | |
896 ScheduleCommit(); | 872 ScheduleCommit(); |
897 } | 873 } |
898 | 874 |
899 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { | 875 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { |
900 return time < expirer_.GetCurrentExpirationTime(); | 876 return time < expirer_.GetCurrentExpirationTime(); |
901 } | 877 } |
902 | 878 |
903 void HistoryBackend::SetPageTitle(const GURL& url, | 879 void HistoryBackend::SetPageTitle(const GURL& url, |
904 const base::string16& title) { | 880 const base::string16& title) { |
905 if (!db_) | 881 if (!db_) |
(...skipping 11 matching lines...) Expand all Loading... |
917 // This redirect chain should have the destination URL as the last item. | 893 // This redirect chain should have the destination URL as the last item. |
918 DCHECK(!redirects->empty()); | 894 DCHECK(!redirects->empty()); |
919 DCHECK(redirects->back() == url); | 895 DCHECK(redirects->back() == url); |
920 } else { | 896 } else { |
921 // No redirect chain stored, make up one containing the URL we want so we | 897 // No redirect chain stored, make up one containing the URL we want so we |
922 // can use the same logic below. | 898 // can use the same logic below. |
923 dummy_list.push_back(url); | 899 dummy_list.push_back(url); |
924 redirects = &dummy_list; | 900 redirects = &dummy_list; |
925 } | 901 } |
926 | 902 |
927 scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails); | 903 URLRows changed_urls; |
928 for (size_t i = 0; i < redirects->size(); i++) { | 904 for (size_t i = 0; i < redirects->size(); i++) { |
929 URLRow row; | 905 URLRow row; |
930 URLID row_id = db_->GetRowForURL(redirects->at(i), &row); | 906 URLID row_id = db_->GetRowForURL(redirects->at(i), &row); |
931 if (row_id && row.title() != title) { | 907 if (row_id && row.title() != title) { |
932 row.set_title(title); | 908 row.set_title(title); |
933 db_->UpdateURLRow(row_id, row); | 909 db_->UpdateURLRow(row_id, row); |
934 details->changed_urls.push_back(row); | 910 changed_urls.push_back(row); |
935 } | 911 } |
936 } | 912 } |
937 | 913 |
938 // Broadcast notifications for any URLs that have changed. This will | 914 // Broadcast notifications for any URLs that have changed. This will |
939 // update the in-memory database and the InMemoryURLIndex. | 915 // update the in-memory database and the InMemoryURLIndex. |
940 if (!details->changed_urls.empty()) { | 916 if (!changed_urls.empty()) { |
941 if (typed_url_syncable_service_.get()) | 917 NotifyURLsModified(changed_urls); |
942 typed_url_syncable_service_->OnUrlsModified(&details->changed_urls); | |
943 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, | |
944 details.Pass()); | |
945 ScheduleCommit(); | 918 ScheduleCommit(); |
946 } | 919 } |
947 } | 920 } |
948 | 921 |
949 void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url, | 922 void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url, |
950 const base::string16& title) { | 923 const base::string16& title) { |
951 if (!db_) | 924 if (!db_) |
952 return; | 925 return; |
953 | 926 |
954 URLRow url_info(url); | 927 URLRow url_info(url); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1005 VisitVector* visits) { | 978 VisitVector* visits) { |
1006 if (db_) | 979 if (db_) |
1007 return db_->GetMostRecentVisitsForURL(id, max_visits, visits); | 980 return db_->GetMostRecentVisitsForURL(id, max_visits, visits); |
1008 return false; | 981 return false; |
1009 } | 982 } |
1010 | 983 |
1011 size_t HistoryBackend::UpdateURLs(const history::URLRows& urls) { | 984 size_t HistoryBackend::UpdateURLs(const history::URLRows& urls) { |
1012 if (!db_) | 985 if (!db_) |
1013 return 0; | 986 return 0; |
1014 | 987 |
1015 scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails); | 988 URLRows changed_urls; |
1016 for (history::URLRows::const_iterator it = urls.begin(); it != urls.end(); | 989 for (history::URLRows::const_iterator it = urls.begin(); it != urls.end(); |
1017 ++it) { | 990 ++it) { |
1018 DCHECK(it->id()); | 991 DCHECK(it->id()); |
1019 if (db_->UpdateURLRow(it->id(), *it)) | 992 if (db_->UpdateURLRow(it->id(), *it)) |
1020 details->changed_urls.push_back(*it); | 993 changed_urls.push_back(*it); |
1021 } | 994 } |
1022 | 995 |
1023 // Broadcast notifications for any URLs that have actually been changed. This | 996 // Broadcast notifications for any URLs that have actually been changed. This |
1024 // will update the in-memory database and the InMemoryURLIndex. | 997 // will update the in-memory database and the InMemoryURLIndex. |
1025 size_t num_updated_records = details->changed_urls.size(); | 998 size_t num_updated_records = changed_urls.size(); |
1026 if (num_updated_records) { | 999 if (num_updated_records) { |
1027 if (typed_url_syncable_service_) | 1000 NotifyURLsModified(changed_urls); |
1028 typed_url_syncable_service_->OnUrlsModified(&details->changed_urls); | |
1029 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, | |
1030 details.Pass()); | |
1031 ScheduleCommit(); | 1001 ScheduleCommit(); |
1032 } | 1002 } |
1033 return num_updated_records; | 1003 return num_updated_records; |
1034 } | 1004 } |
1035 | 1005 |
1036 bool HistoryBackend::AddVisits(const GURL& url, | 1006 bool HistoryBackend::AddVisits(const GURL& url, |
1037 const std::vector<VisitInfo>& visits, | 1007 const std::vector<VisitInfo>& visits, |
1038 VisitSource visit_source) { | 1008 VisitSource visit_source) { |
1039 if (db_) { | 1009 if (db_) { |
1040 for (std::vector<VisitInfo>::const_iterator visit = visits.begin(); | 1010 for (std::vector<VisitInfo>::const_iterator visit = visits.begin(); |
(...skipping 1494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2535 | 2505 |
2536 void HistoryBackend::BroadcastNotifications( | 2506 void HistoryBackend::BroadcastNotifications( |
2537 int type, | 2507 int type, |
2538 scoped_ptr<HistoryDetails> details) { | 2508 scoped_ptr<HistoryDetails> details) { |
2539 // |delegate_| may be NULL if |this| is in the process of closing (closed by | 2509 // |delegate_| may be NULL if |this| is in the process of closing (closed by |
2540 // HistoryService -> HistoryBackend::Closing(). | 2510 // HistoryService -> HistoryBackend::Closing(). |
2541 if (delegate_) | 2511 if (delegate_) |
2542 delegate_->BroadcastNotifications(type, details.Pass()); | 2512 delegate_->BroadcastNotifications(type, details.Pass()); |
2543 } | 2513 } |
2544 | 2514 |
2545 void HistoryBackend::NotifySyncURLsModified(URLRows* rows) { | 2515 void HistoryBackend::NotifyURLVisited(ui::PageTransition transition, |
| 2516 const URLRow& row, |
| 2517 const RedirectList& redirects, |
| 2518 base::Time visit_time) { |
| 2519 URLRow url_info(row); |
2546 if (typed_url_syncable_service_.get()) | 2520 if (typed_url_syncable_service_.get()) |
2547 typed_url_syncable_service_->OnUrlsModified(rows); | 2521 typed_url_syncable_service_->OnUrlVisited(transition, &url_info); |
| 2522 |
| 2523 FOR_EACH_OBSERVER( |
| 2524 HistoryBackendObserver, |
| 2525 observers_, |
| 2526 OnURLVisited(this, transition, url_info, redirects, visit_time)); |
| 2527 |
| 2528 // TODO(sdefresne): turn HistoryBackend::Delegate from HistoryService into |
| 2529 // an HistoryBackendObserver and register it so that we can remove this |
| 2530 // method. |
| 2531 if (delegate_) |
| 2532 delegate_->NotifyURLVisited(transition, url_info, redirects, visit_time); |
2548 } | 2533 } |
2549 | 2534 |
2550 void HistoryBackend::NotifySyncURLsDeleted(bool all_history, | 2535 void HistoryBackend::NotifyURLsModified(const URLRows& rows) { |
2551 bool expired, | 2536 scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails); |
2552 URLRows* rows) { | 2537 details->changed_urls = rows; |
| 2538 |
2553 if (typed_url_syncable_service_.get()) | 2539 if (typed_url_syncable_service_.get()) |
2554 typed_url_syncable_service_->OnUrlsDeleted(all_history, expired, rows); | 2540 typed_url_syncable_service_->OnUrlsModified(&details->changed_urls); |
| 2541 |
| 2542 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, |
| 2543 details.Pass()); |
| 2544 } |
| 2545 |
| 2546 void HistoryBackend::NotifyURLsDeleted(bool all_history, |
| 2547 bool expired, |
| 2548 const URLRows& rows, |
| 2549 const std::set<GURL>& favicon_urls) { |
| 2550 scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails); |
| 2551 details->all_history = all_history; |
| 2552 details->expired = expired; |
| 2553 details->rows = rows; |
| 2554 details->favicon_urls = favicon_urls; |
| 2555 |
| 2556 if (typed_url_syncable_service_.get()) { |
| 2557 typed_url_syncable_service_->OnUrlsDeleted( |
| 2558 all_history, expired, &details->rows); |
| 2559 } |
| 2560 |
| 2561 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, |
| 2562 details.Pass()); |
2555 } | 2563 } |
2556 | 2564 |
2557 // Deleting -------------------------------------------------------------------- | 2565 // Deleting -------------------------------------------------------------------- |
2558 | 2566 |
2559 void HistoryBackend::DeleteAllHistory() { | 2567 void HistoryBackend::DeleteAllHistory() { |
2560 // Our approach to deleting all history is: | 2568 // Our approach to deleting all history is: |
2561 // 1. Copy the bookmarks and their dependencies to new tables with temporary | 2569 // 1. Copy the bookmarks and their dependencies to new tables with temporary |
2562 // names. | 2570 // names. |
2563 // 2. Delete the original tables. Since tables can not share pages, we know | 2571 // 2. Delete the original tables. Since tables can not share pages, we know |
2564 // that any data we don't want to keep is now in an unused page. | 2572 // that any data we don't want to keep is now in an unused page. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2600 // Therefore, we clear the list afterwards to make sure nobody uses this | 2608 // Therefore, we clear the list afterwards to make sure nobody uses this |
2601 // invalid data. | 2609 // invalid data. |
2602 if (!ClearAllMainHistory(kept_urls)) | 2610 if (!ClearAllMainHistory(kept_urls)) |
2603 LOG(ERROR) << "Main history could not be cleared"; | 2611 LOG(ERROR) << "Main history could not be cleared"; |
2604 kept_urls.clear(); | 2612 kept_urls.clear(); |
2605 | 2613 |
2606 db_->GetStartDate(&first_recorded_time_); | 2614 db_->GetStartDate(&first_recorded_time_); |
2607 | 2615 |
2608 // Send out the notification that history is cleared. The in-memory database | 2616 // Send out the notification that history is cleared. The in-memory database |
2609 // will pick this up and clear itself. | 2617 // will pick this up and clear itself. |
2610 scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails); | 2618 NotifyURLsDeleted(true, false, URLRows(), std::set<GURL>()); |
2611 details->all_history = true; | |
2612 NotifySyncURLsDeleted(true, false, NULL); | |
2613 BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, | |
2614 details.Pass()); | |
2615 } | 2619 } |
2616 | 2620 |
2617 bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) { | 2621 bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) { |
2618 if (!thumbnail_db_) { | 2622 if (!thumbnail_db_) { |
2619 // When we have no reference to the thumbnail database, maybe there was an | 2623 // When we have no reference to the thumbnail database, maybe there was an |
2620 // error opening it. In this case, we just try to blow it away to try to | 2624 // error opening it. In this case, we just try to blow it away to try to |
2621 // fix the error if it exists. This may fail, in which case either the | 2625 // fix the error if it exists. This may fail, in which case either the |
2622 // file doesn't exist or there's no more we can do. | 2626 // file doesn't exist or there's no more we can do. |
2623 sql::Connection::Delete(GetFaviconsFileName()); | 2627 sql::Connection::Delete(GetFaviconsFileName()); |
2624 | 2628 |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2726 int rank = kPageVisitStatsMaxTopSites; | 2730 int rank = kPageVisitStatsMaxTopSites; |
2727 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url); | 2731 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url); |
2728 if (it != most_visited_urls_map_.end()) | 2732 if (it != most_visited_urls_map_.end()) |
2729 rank = (*it).second; | 2733 rank = (*it).second; |
2730 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank", | 2734 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank", |
2731 rank, kPageVisitStatsMaxTopSites + 1); | 2735 rank, kPageVisitStatsMaxTopSites + 1); |
2732 } | 2736 } |
2733 #endif | 2737 #endif |
2734 | 2738 |
2735 } // namespace history | 2739 } // namespace history |
OLD | NEW |