| 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 |