Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: chrome/browser/history/history_backend.cc

Issue 16951015: Remove TextDatabase from the history service. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@replace_fts
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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>
11 #include <set> 11 #include <set>
12 #include <vector> 12 #include <vector>
13 13
14 #include "base/basictypes.h" 14 #include "base/basictypes.h"
15 #include "base/bind.h" 15 #include "base/bind.h"
16 #include "base/compiler_specific.h" 16 #include "base/compiler_specific.h"
17 #include "base/file_util.h" 17 #include "base/file_util.h"
18 #include "base/files/file_enumerator.h"
18 #include "base/memory/scoped_ptr.h" 19 #include "base/memory/scoped_ptr.h"
19 #include "base/memory/scoped_vector.h" 20 #include "base/memory/scoped_vector.h"
20 #include "base/message_loop.h" 21 #include "base/message_loop.h"
21 #include "base/metrics/histogram.h" 22 #include "base/metrics/histogram.h"
22 #include "base/rand_util.h" 23 #include "base/rand_util.h"
23 #include "base/strings/string_util.h" 24 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h" 25 #include "base/strings/utf_string_conversions.h"
25 #include "base/time.h" 26 #include "base/time.h"
26 #include "chrome/browser/autocomplete/history_url_provider.h" 27 #include "chrome/browser/autocomplete/history_url_provider.h"
27 #include "chrome/browser/bookmarks/bookmark_service.h" 28 #include "chrome/browser/bookmarks/bookmark_service.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 VisitDatabase (stores a list of visits for the URLs) 63 VisitDatabase (stores a list of visits for the URLs)
63 VisitSegmentDatabase (stores groups of URLs for the most visited view). 64 VisitSegmentDatabase (stores groups of URLs for the most visited view).
64 65
65 ArchivedDatabase (stores history older than 3 months) 66 ArchivedDatabase (stores history older than 3 months)
66 URLDatabase (stores a list of URLs) 67 URLDatabase (stores a list of URLs)
67 DownloadDatabase (stores a list of downloads) 68 DownloadDatabase (stores a list of downloads)
68 VisitDatabase (stores a list of visits for the URLs) 69 VisitDatabase (stores a list of visits for the URLs)
69 70
70 (this does not store visit segments as they expire after 3 mos.) 71 (this does not store visit segments as they expire after 3 mos.)
71 72
72 TextDatabaseManager (manages multiple text database for different times)
73 TextDatabase (represents a single month of full-text index).
74 ...more TextDatabase objects...
75
76 ExpireHistoryBackend (manages moving things from HistoryDatabase to 73 ExpireHistoryBackend (manages moving things from HistoryDatabase to
77 the ArchivedDatabase and deleting) 74 the ArchivedDatabase and deleting)
78 */ 75 */
79 76
80 namespace history { 77 namespace history {
81 78
82 // How long we keep segment data for in days. Currently 3 months. 79 // How long we keep segment data for in days. Currently 3 months.
83 // This value needs to be greater or equal to 80 // This value needs to be greater or equal to
84 // MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct 81 // MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
85 // dependency between MostVisitedModel and the history backend. 82 // dependency between MostVisitedModel and the history backend.
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 } 154 }
158 155
159 private: 156 private:
160 friend class base::RefCounted<CommitLaterTask>; 157 friend class base::RefCounted<CommitLaterTask>;
161 158
162 ~CommitLaterTask() {} 159 ~CommitLaterTask() {}
163 160
164 scoped_refptr<HistoryBackend> history_backend_; 161 scoped_refptr<HistoryBackend> history_backend_;
165 }; 162 };
166 163
167 // Handles querying first the main database, then the full text database if that
168 // fails. It will optionally keep track of all URLs seen so duplicates can be
169 // eliminated. This is used by the querying sub-functions.
170 //
171 // TODO(brettw): This class may be able to be simplified or eliminated. After
172 // this was written, QueryResults can efficiently look up by URL, so the need
173 // for this extra set of previously queried URLs is less important.
174 class HistoryBackend::URLQuerier {
175 public:
176 URLQuerier(URLDatabase* main_db, URLDatabase* archived_db, bool track_unique)
177 : main_db_(main_db),
178 archived_db_(archived_db),
179 track_unique_(track_unique) {
180 }
181
182 // When we're tracking unique URLs, returns true if this URL has been
183 // previously queried. Only call when tracking unique URLs.
184 bool HasURL(const GURL& url) {
185 DCHECK(track_unique_);
186 return unique_urls_.find(url) != unique_urls_.end();
187 }
188
189 bool GetRowForURL(const GURL& url, URLRow* row) {
190 if (!main_db_->GetRowForURL(url, row)) {
191 if (!archived_db_ || !archived_db_->GetRowForURL(url, row)) {
192 // This row is neither in the main nor the archived DB.
193 return false;
194 }
195 }
196
197 if (track_unique_)
198 unique_urls_.insert(url);
199 return true;
200 }
201
202 private:
203 URLDatabase* main_db_; // Guaranteed non-NULL.
204 URLDatabase* archived_db_; // Possibly NULL.
205
206 bool track_unique_;
207
208 // When track_unique_ is set, this is updated with every URL seen so far.
209 std::set<GURL> unique_urls_;
210
211 DISALLOW_COPY_AND_ASSIGN(URLQuerier);
212 };
213
214 // KillHistoryDatabaseErrorDelegate ------------------------------------------- 164 // KillHistoryDatabaseErrorDelegate -------------------------------------------
215 165
216 class KillHistoryDatabaseErrorDelegate : public sql::ErrorDelegate { 166 class KillHistoryDatabaseErrorDelegate : public sql::ErrorDelegate {
217 public: 167 public:
218 explicit KillHistoryDatabaseErrorDelegate(HistoryBackend* backend) 168 explicit KillHistoryDatabaseErrorDelegate(HistoryBackend* backend)
219 : backend_(backend), 169 : backend_(backend),
220 scheduled_killing_database_(false) { 170 scheduled_killing_database_(false) {
221 } 171 }
222 172
223 // sql::ErrorDelegate implementation. 173 // sql::ErrorDelegate implementation.
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 // Update the visit_details for this visit. 560 // Update the visit_details for this visit.
611 UpdateVisitDuration(from_visit_id, request.time); 561 UpdateVisitDuration(from_visit_id, request.time);
612 } 562 }
613 563
614 // Subsequent transitions in the redirect list must all be server 564 // Subsequent transitions in the redirect list must all be server
615 // redirects. 565 // redirects.
616 redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT; 566 redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
617 } 567 }
618 568
619 // Last, save this redirect chain for later so we can set titles & favicons 569 // Last, save this redirect chain for later so we can set titles & favicons
620 // on the redirected pages properly. It is indexed by the destination page. 570 // on the redirected pages properly.
621 recent_redirects_.Put(request.url, redirects); 571 recent_redirects_.Put(request.url, redirects);
622 } 572 }
623 573
624 // TODO(brettw) bug 1140015: Add an "add page" notification so the history 574 // TODO(brettw) bug 1140015: Add an "add page" notification so the history
625 // views can keep in sync. 575 // views can keep in sync.
626 576
627 // Add the last visit to the tracker so we can get outgoing transitions. 577 // Add the last visit to the tracker so we can get outgoing transitions.
628 // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe 578 // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
629 // navigation anyway, so last_visit_id is always zero for them. But adding 579 // navigation anyway, so last_visit_id is always zero for them. But adding
630 // them here confuses main frame history, so we skip them for now. 580 // them here confuses main frame history, so we skip them for now.
631 if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME && 581 if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
632 stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME && 582 stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
633 !is_keyword_generated) { 583 !is_keyword_generated) {
634 tracker_.AddVisit(request.id_scope, request.page_id, request.url, 584 tracker_.AddVisit(request.id_scope, request.page_id, request.url,
635 last_ids.second); 585 last_ids.second);
636 } 586 }
637 587
638 if (text_database_) {
639 text_database_->AddPageURL(request.url, last_ids.first, last_ids.second,
640 request.time);
641 }
642
643 ScheduleCommit(); 588 ScheduleCommit();
644 } 589 }
645 590
646 void HistoryBackend::InitImpl(const std::string& languages) { 591 void HistoryBackend::InitImpl(const std::string& languages) {
647 DCHECK(!db_) << "Initializing HistoryBackend twice"; 592 DCHECK(!db_) << "Initializing HistoryBackend twice";
648 // In the rare case where the db fails to initialize a dialog may get shown 593 // In the rare case where the db fails to initialize a dialog may get shown
649 // the blocks the caller, yet allows other messages through. For this reason 594 // the blocks the caller, yet allows other messages through. For this reason
650 // we only set db_ to the created database if creation is successful. That 595 // we only set db_ to the created database if creation is successful. That
651 // way other methods won't do anything as db_ is still NULL. 596 // way other methods won't do anything as db_ is still NULL.
652 597
653 TimeTicks beginning_time = TimeTicks::Now(); 598 TimeTicks beginning_time = TimeTicks::Now();
654 599
655 // Compute the file names. Note that the index file can be removed when the 600 // Compute the file names.
656 // text db manager is finished being hooked up.
657 base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename); 601 base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
658 base::FilePath thumbnail_name = GetThumbnailFileName(); 602 base::FilePath thumbnail_name = GetThumbnailFileName();
659 base::FilePath archived_name = GetArchivedFileName(); 603 base::FilePath archived_name = GetArchivedFileName();
660 604
605 // Delete the old index database files which are no longer used.
606 DeleteFTSIndexDatabases();
607
661 // History database. 608 // History database.
662 db_.reset(new HistoryDatabase()); 609 db_.reset(new HistoryDatabase());
663 610
664 // |HistoryDatabase::Init| takes ownership of |error_delegate|. 611 // |HistoryDatabase::Init| takes ownership of |error_delegate|.
665 KillHistoryDatabaseErrorDelegate* error_delegate = 612 KillHistoryDatabaseErrorDelegate* error_delegate =
666 new KillHistoryDatabaseErrorDelegate(this); 613 new KillHistoryDatabaseErrorDelegate(this);
667 614
668 sql::InitStatus status = db_->Init(history_name, error_delegate); 615 sql::InitStatus status = db_->Init(history_name, error_delegate);
669 switch (status) { 616 switch (status) {
670 case sql::INIT_OK: 617 case sql::INIT_OK:
(...skipping 19 matching lines...) Expand all
690 // Fill the in-memory database and send it back to the history service on the 637 // Fill the in-memory database and send it back to the history service on the
691 // main thread. 638 // main thread.
692 InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend; 639 InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
693 if (mem_backend->Init(history_name, db_.get())) 640 if (mem_backend->Init(history_name, db_.get()))
694 delegate_->SetInMemoryBackend(id_, mem_backend); // Takes ownership of 641 delegate_->SetInMemoryBackend(id_, mem_backend); // Takes ownership of
695 // pointer. 642 // pointer.
696 else 643 else
697 delete mem_backend; // Error case, run without the in-memory DB. 644 delete mem_backend; // Error case, run without the in-memory DB.
698 db_->BeginExclusiveMode(); // Must be after the mem backend read the data. 645 db_->BeginExclusiveMode(); // Must be after the mem backend read the data.
699 646
700 // Create the history publisher which needs to be passed on to the text and 647 // Create the history publisher which needs to be passed on to the thumbnail
701 // thumbnail databases for publishing history. 648 // database for publishing history.
702 history_publisher_.reset(new HistoryPublisher()); 649 history_publisher_.reset(new HistoryPublisher());
703 if (!history_publisher_->Init()) { 650 if (!history_publisher_->Init()) {
704 // The init may fail when there are no indexers wanting our history. 651 // The init may fail when there are no indexers wanting our history.
705 // Hence no need to log the failure. 652 // Hence no need to log the failure.
706 history_publisher_.reset(); 653 history_publisher_.reset();
707 } 654 }
708 655
709 // Full-text database. This has to be first so we can pass it to the
710 // HistoryDatabase for migration.
711 text_database_.reset(new TextDatabaseManager(history_dir_,
712 db_.get(), db_.get()));
713 if (!text_database_->Init(history_publisher_.get())) {
714 LOG(WARNING) << "Text database initialization failed, running without it.";
715 text_database_.reset();
716 }
717 if (db_->needs_version_17_migration()) {
718 // See needs_version_17_migration() decl for more. In this case, we want
719 // to erase all the text database files. This must be done after the text
720 // database manager has been initialized, since it knows about all the
721 // files it manages.
722 text_database_->DeleteAll();
723 }
724
725 // Thumbnail database. 656 // Thumbnail database.
726 thumbnail_db_.reset(new ThumbnailDatabase()); 657 thumbnail_db_.reset(new ThumbnailDatabase());
727 if (!db_->GetNeedsThumbnailMigration()) { 658 if (!db_->GetNeedsThumbnailMigration()) {
728 // No convertion needed - use new filename right away. 659 // No convertion needed - use new filename right away.
729 thumbnail_name = GetFaviconsFileName(); 660 thumbnail_name = GetFaviconsFileName();
730 } 661 }
731 if (thumbnail_db_->Init(thumbnail_name, 662 if (thumbnail_db_->Init(thumbnail_name,
732 history_publisher_.get(), 663 history_publisher_.get(),
733 db_.get()) != sql::INIT_OK) { 664 db_.get()) != sql::INIT_OK) {
734 // Unlike the main database, we don't error out when the database is too 665 // Unlike the main database, we don't error out when the database is too
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
767 } 698 }
768 699
769 // Tell the expiration module about all the nice databases we made. This must 700 // Tell the expiration module about all the nice databases we made. This must
770 // happen before db_->Init() is called since the callback ForceArchiveHistory 701 // happen before db_->Init() is called since the callback ForceArchiveHistory
771 // may need to expire stuff. 702 // may need to expire stuff.
772 // 703 //
773 // *sigh*, this can all be cleaned up when that migration code is removed. 704 // *sigh*, this can all be cleaned up when that migration code is removed.
774 // The main DB initialization should intuitively be first (not that it 705 // The main DB initialization should intuitively be first (not that it
775 // actually matters) and the expirer should be set last. 706 // actually matters) and the expirer should be set last.
776 expirer_.SetDatabases(db_.get(), archived_db_.get(), 707 expirer_.SetDatabases(db_.get(), archived_db_.get(),
777 thumbnail_db_.get(), text_database_.get()); 708 thumbnail_db_.get());
778 709
779 // Open the long-running transaction. 710 // Open the long-running transaction.
780 db_->BeginTransaction(); 711 db_->BeginTransaction();
781 if (thumbnail_db_) 712 if (thumbnail_db_)
782 thumbnail_db_->BeginTransaction(); 713 thumbnail_db_->BeginTransaction();
783 if (archived_db_) 714 if (archived_db_)
784 archived_db_->BeginTransaction(); 715 archived_db_->BeginTransaction();
785 if (text_database_)
786 text_database_->BeginTransaction();
787 716
788 // Get the first item in our database. 717 // Get the first item in our database.
789 db_->GetStartDate(&first_recorded_time_); 718 db_->GetStartDate(&first_recorded_time_);
790 719
791 // Start expiring old stuff. 720 // Start expiring old stuff.
792 expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold)); 721 expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
793 722
794 #if defined(OS_ANDROID) 723 #if defined(OS_ANDROID)
795 if (thumbnail_db_) { 724 if (thumbnail_db_) {
796 android_provider_backend_.reset(new AndroidProviderBackend( 725 android_provider_backend_.reset(new AndroidProviderBackend(
(...skipping 13 matching lines...) Expand all
810 db_.reset(); 739 db_.reset();
811 } 740 }
812 if (thumbnail_db_) { 741 if (thumbnail_db_) {
813 thumbnail_db_->CommitTransaction(); 742 thumbnail_db_->CommitTransaction();
814 thumbnail_db_.reset(); 743 thumbnail_db_.reset();
815 } 744 }
816 if (archived_db_) { 745 if (archived_db_) {
817 archived_db_->CommitTransaction(); 746 archived_db_->CommitTransaction();
818 archived_db_.reset(); 747 archived_db_.reset();
819 } 748 }
820 if (text_database_) {
821 text_database_->CommitTransaction();
822 text_database_.reset();
823 }
824 } 749 }
825 750
826 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit( 751 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
827 const GURL& url, 752 const GURL& url,
828 Time time, 753 Time time,
829 VisitID referring_visit, 754 VisitID referring_visit,
830 content::PageTransition transition, 755 content::PageTransition transition,
831 VisitSource visit_source) { 756 VisitSource visit_source) {
832 // Top-level frame navigations are visible, everything else is hidden 757 // Top-level frame navigations are visible, everything else is hidden
833 bool new_hidden = !content::PageTransitionIsMainFrame(transition); 758 bool new_hidden = !content::PageTransitionIsMainFrame(transition);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
868 url_info.set_typed_count(typed_increment); 793 url_info.set_typed_count(typed_increment);
869 url_info.set_last_visit(time); 794 url_info.set_last_visit(time);
870 url_info.set_hidden(new_hidden); 795 url_info.set_hidden(new_hidden);
871 796
872 url_id = db_->AddURL(url_info); 797 url_id = db_->AddURL(url_info);
873 if (!url_id) { 798 if (!url_id) {
874 NOTREACHED() << "Adding URL failed."; 799 NOTREACHED() << "Adding URL failed.";
875 return std::make_pair(0, 0); 800 return std::make_pair(0, 0);
876 } 801 }
877 url_info.id_ = url_id; 802 url_info.id_ = url_id;
878
879 // We don't actually add the URL to the full text index at this point. It
880 // might be nice to do this so that even if we get no title or body, the
881 // user can search for URL components and get the page.
882 //
883 // However, in most cases, we'll get at least a title and usually contents,
884 // and this add will be redundant, slowing everything down. As a result,
885 // we ignore this edge case.
886 } 803 }
887 804
888 // Add the visit with the time to the database. 805 // Add the visit with the time to the database.
889 VisitRow visit_info(url_id, time, referring_visit, transition, 0); 806 VisitRow visit_info(url_id, time, referring_visit, transition, 0);
890 VisitID visit_id = db_->AddVisit(&visit_info, visit_source); 807 VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
891 NotifyVisitObservers(visit_info); 808 NotifyVisitObservers(visit_info);
892 809
893 if (visit_info.visit_time < first_recorded_time_) 810 if (visit_info.visit_time < first_recorded_time_)
894 first_recorded_time_ = visit_info.visit_time; 811 first_recorded_time_ = visit_info.visit_time;
895 812
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 NOTREACHED() << "Could not add row to DB"; 862 NOTREACHED() << "Could not add row to DB";
946 return; 863 return;
947 } 864 }
948 865
949 if (i->typed_count() > 0) { 866 if (i->typed_count() > 0) {
950 modified->changed_urls.push_back(*i); 867 modified->changed_urls.push_back(*i);
951 modified->changed_urls.back().set_id(url_id); // *i likely has |id_| 0. 868 modified->changed_urls.back().set_id(url_id); // *i likely has |id_| 0.
952 } 869 }
953 } 870 }
954 871
955 // Add the page to the full text index. This function is also used for
956 // importing. Even though we don't have page contents, we can at least
957 // add the title and URL to the index so they can be searched. We don't
958 // bother to delete any already-existing FTS entries for the URL, since
959 // this is normally called on import.
960 //
961 // If you ever import *after* first run (selecting import from the menu),
962 // then these additional entries will "shadow" the originals when querying
963 // for the most recent match only, and the user won't get snippets. This is
964 // a very minor issue, and fixing it will make import slower, so we don't
965 // bother.
966 bool has_indexed = false;
967 if (text_database_) {
968 // We do not have to make it update the visit database, below, we will
969 // create the visit entry with the indexed flag set.
970 has_indexed = text_database_->AddPageData(i->url(), url_id, 0,
971 i->last_visit(),
972 i->title(), string16());
973 }
974
975 // Sync code manages the visits itself. 872 // Sync code manages the visits itself.
976 if (visit_source != SOURCE_SYNCED) { 873 if (visit_source != SOURCE_SYNCED) {
977 // Make up a visit to correspond to the last visit to the page. 874 // Make up a visit to correspond to the last visit to the page.
978 VisitRow visit_info(url_id, i->last_visit(), 0, 875 VisitRow visit_info(url_id, i->last_visit(), 0,
979 content::PageTransitionFromInt( 876 content::PageTransitionFromInt(
980 content::PAGE_TRANSITION_LINK | 877 content::PAGE_TRANSITION_LINK |
981 content::PAGE_TRANSITION_CHAIN_START | 878 content::PAGE_TRANSITION_CHAIN_START |
982 content::PAGE_TRANSITION_CHAIN_END), 0); 879 content::PAGE_TRANSITION_CHAIN_END), 0);
983 visit_info.is_indexed = has_indexed;
984 if (!visit_database->AddVisit(&visit_info, visit_source)) { 880 if (!visit_database->AddVisit(&visit_info, visit_source)) {
985 NOTREACHED() << "Adding visit failed."; 881 NOTREACHED() << "Adding visit failed.";
986 return; 882 return;
987 } 883 }
988 NotifyVisitObservers(visit_info); 884 NotifyVisitObservers(visit_info);
989 885
990 if (visit_info.visit_time < first_recorded_time_) 886 if (visit_info.visit_time < first_recorded_time_)
991 first_recorded_time_ = visit_info.visit_time; 887 first_recorded_time_ = visit_info.visit_time;
992 } 888 }
993 } 889 }
(...skipping 14 matching lines...) Expand all
1008 904
1009 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { 905 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
1010 return time < expirer_.GetCurrentArchiveTime(); 906 return time < expirer_.GetCurrentArchiveTime();
1011 } 907 }
1012 908
1013 void HistoryBackend::SetPageTitle(const GURL& url, 909 void HistoryBackend::SetPageTitle(const GURL& url,
1014 const string16& title) { 910 const string16& title) {
1015 if (!db_) 911 if (!db_)
1016 return; 912 return;
1017 913
1018 // Update the full text index.
1019 if (text_database_)
1020 text_database_->AddPageTitle(url, title);
1021
1022 // Search for recent redirects which should get the same title. We make a 914 // Search for recent redirects which should get the same title. We make a
1023 // dummy list containing the exact URL visited if there are no redirects so 915 // dummy list containing the exact URL visited if there are no redirects so
1024 // the processing below can be the same. 916 // the processing below can be the same.
1025 history::RedirectList dummy_list; 917 history::RedirectList dummy_list;
1026 history::RedirectList* redirects; 918 history::RedirectList* redirects;
1027 RedirectCache::iterator iter = recent_redirects_.Get(url); 919 RedirectCache::iterator iter = recent_redirects_.Get(url);
1028 if (iter != recent_redirects_.end()) { 920 if (iter != recent_redirects_.end()) {
1029 redirects = &iter->second; 921 redirects = &iter->second;
1030 922
1031 // This redirect chain should have the destination URL as the last item. 923 // This redirect chain should have the destination URL as the last item.
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after
1512 for (std::vector<URLResult>::iterator it = matching_visits.begin(); 1404 for (std::vector<URLResult>::iterator it = matching_visits.begin();
1513 it != matching_visits.end() && result->size() < max_results; ++it) { 1405 it != matching_visits.end() && result->size() < max_results; ++it) {
1514 result->AppendURLBySwapping(&(*it)); 1406 result->AppendURLBySwapping(&(*it));
1515 } 1407 }
1516 1408
1517 if (matching_visits.size() == result->size() && 1409 if (matching_visits.size() == result->size() &&
1518 options.begin_time <= first_recorded_time_) 1410 options.begin_time <= first_recorded_time_)
1519 result->set_reached_beginning(true); 1411 result->set_reached_beginning(true);
1520 } 1412 }
1521 1413
1522 void HistoryBackend::QueryHistoryFTS(const string16& text_query,
1523 const QueryOptions& options,
1524 QueryResults* result) {
1525 if (!text_database_)
1526 return;
1527
1528 // Full text query, first get all the FTS results in the time range.
1529 std::vector<TextDatabase::Match> fts_matches;
1530 Time first_time_searched;
1531 text_database_->GetTextMatches(text_query, options,
1532 &fts_matches, &first_time_searched);
1533
1534 URLQuerier querier(db_.get(), archived_db_.get(), true);
1535
1536 // Now get the row and visit information for each one.
1537 URLResult url_result; // Declare outside loop to prevent re-construction.
1538 for (size_t i = 0; i < fts_matches.size(); i++) {
1539 if (options.max_count != 0 &&
1540 static_cast<int>(result->size()) >= options.max_count)
1541 break; // Got too many items.
1542
1543 // Get the URL, querying the main and archived databases as necessary. If
1544 // this is not found, the history and full text search databases are out
1545 // of sync and we give up with this result.
1546 if (!querier.GetRowForURL(fts_matches[i].url, &url_result))
1547 continue;
1548
1549 if (!url_result.url().is_valid())
1550 continue; // Don't report invalid URLs in case of corruption.
1551
1552 // Copy over the FTS stuff that the URLDatabase doesn't know about.
1553 // We do this with swap() to avoid copying, since we know we don't
1554 // need the original any more. Note that we override the title with the
1555 // one from FTS, since that will match the title_match_positions (the
1556 // FTS title and the history DB title may differ).
1557 url_result.set_title(fts_matches[i].title);
1558 url_result.title_match_positions_.swap(
1559 fts_matches[i].title_match_positions);
1560 url_result.snippet_.Swap(&fts_matches[i].snippet);
1561
1562 // The visit time also comes from the full text search database. Since it
1563 // has the time, we can avoid an extra query of the visits table.
1564 url_result.set_visit_time(fts_matches[i].time);
1565
1566 // Add it to the vector, this will clear our |url_row| object as a
1567 // result of the swap.
1568 result->AppendURLBySwapping(&url_result);
1569 }
1570
1571 if (first_time_searched <= first_recorded_time_)
1572 result->set_reached_beginning(true);
1573 }
1574
1575 // Frontend to GetMostRecentRedirectsFrom from the history thread. 1414 // Frontend to GetMostRecentRedirectsFrom from the history thread.
1576 void HistoryBackend::QueryRedirectsFrom( 1415 void HistoryBackend::QueryRedirectsFrom(
1577 scoped_refptr<QueryRedirectsRequest> request, 1416 scoped_refptr<QueryRedirectsRequest> request,
1578 const GURL& url) { 1417 const GURL& url) {
1579 if (request->canceled()) 1418 if (request->canceled())
1580 return; 1419 return;
1581 bool success = GetMostRecentRedirectsFrom(url, &request->value); 1420 bool success = GetMostRecentRedirectsFrom(url, &request->value);
1582 request->ForwardResult(request->handle(), url, success, &request->value); 1421 request->ForwardResult(request->handle(), url, success, &request->value);
1583 } 1422 }
1584 1423
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
1824 GetRedirectsToSpecificVisit(cur_visit, redirects); 1663 GetRedirectsToSpecificVisit(cur_visit, redirects);
1825 return true; 1664 return true;
1826 } 1665 }
1827 1666
1828 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider, 1667 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
1829 HistoryURLProviderParams* params) { 1668 HistoryURLProviderParams* params) {
1830 // ExecuteWithDB should handle the NULL database case. 1669 // ExecuteWithDB should handle the NULL database case.
1831 provider->ExecuteWithDB(this, db_.get(), params); 1670 provider->ExecuteWithDB(this, db_.get(), params);
1832 } 1671 }
1833 1672
1834 void HistoryBackend::SetPageContents(const GURL& url,
1835 const string16& contents) {
1836 // This is histogrammed in the text database manager.
1837 if (!text_database_)
1838 return;
1839 text_database_->AddPageContents(url, contents);
1840 }
1841
1842 void HistoryBackend::SetPageThumbnail( 1673 void HistoryBackend::SetPageThumbnail(
1843 const GURL& url, 1674 const GURL& url,
1844 const gfx::Image* thumbnail, 1675 const gfx::Image* thumbnail,
1845 const ThumbnailScore& score) { 1676 const ThumbnailScore& score) {
1846 if (!db_ || !thumbnail_db_) 1677 if (!db_ || !thumbnail_db_)
1847 return; 1678 return;
1848 1679
1849 URLRow url_row; 1680 URLRow url_row;
1850 URLID url_id = db_->GetRowForURL(url, &url_row); 1681 URLID url_id = db_->GetRowForURL(url, &url_row);
1851 if (url_id) { 1682 if (url_id) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1915 if (db_) { 1746 if (db_) {
1916 // If there is no thumbnail DB, we can still record a successful migration. 1747 // If there is no thumbnail DB, we can still record a successful migration.
1917 if (thumbnail_db_) { 1748 if (thumbnail_db_) {
1918 thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(), 1749 thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(),
1919 GetFaviconsFileName()); 1750 GetFaviconsFileName());
1920 } 1751 }
1921 db_->ThumbnailMigrationDone(); 1752 db_->ThumbnailMigrationDone();
1922 } 1753 }
1923 } 1754 }
1924 1755
1756 void HistoryBackend::DeleteFTSIndexDatabases() {
1757 // Find files on disk matching the text databases file pattern so we can
1758 // quickly test for and delete them.
1759 base::FilePath::StringType filepattern =
1760 FILE_PATH_LITERAL("History Index *");
1761 base::FileEnumerator enumerator(
1762 history_dir_, false, base::FileEnumerator::FILES, filepattern);
1763 base::FilePath current_file;
1764 while (!(current_file = enumerator.Next()).empty()) {
1765 file_util::Delete(current_file, false);
Scott Hess - ex-Googler 2013/06/14 19:39:56 This will potentially leave junk files. Please us
rmcilroy 2013/06/17 14:11:49 Done.
1766 }
Scott Hess - ex-Googler 2013/06/14 19:39:56 I think it would be reasonable to have this histog
rmcilroy 2013/06/17 14:11:49 Done.
1767 }
1768
1925 bool HistoryBackend::GetThumbnailFromOlderRedirect( 1769 bool HistoryBackend::GetThumbnailFromOlderRedirect(
1926 const GURL& page_url, 1770 const GURL& page_url,
1927 std::vector<unsigned char>* data) { 1771 std::vector<unsigned char>* data) {
1928 // Look at a few previous visit sessions. 1772 // Look at a few previous visit sessions.
1929 VisitVector older_sessions; 1773 VisitVector older_sessions;
1930 URLID page_url_id = db_->GetRowForURL(page_url, NULL); 1774 URLID page_url_id = db_->GetRowForURL(page_url, NULL);
1931 static const int kVisitsToSearchForThumbnail = 4; 1775 static const int kVisitsToSearchForThumbnail = 4;
1932 db_->GetMostRecentVisitsForURL( 1776 db_->GetMostRecentVisitsForURL(
1933 page_url_id, kVisitsToSearchForThumbnail, &older_sessions); 1777 page_url_id, kVisitsToSearchForThumbnail, &older_sessions);
1934 1778
(...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after
2684 thumbnail_db_->CommitTransaction(); 2528 thumbnail_db_->CommitTransaction();
2685 DCHECK(thumbnail_db_->transaction_nesting() == 0) << 2529 DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
2686 "Somebody left a transaction open"; 2530 "Somebody left a transaction open";
2687 thumbnail_db_->BeginTransaction(); 2531 thumbnail_db_->BeginTransaction();
2688 } 2532 }
2689 2533
2690 if (archived_db_) { 2534 if (archived_db_) {
2691 archived_db_->CommitTransaction(); 2535 archived_db_->CommitTransaction();
2692 archived_db_->BeginTransaction(); 2536 archived_db_->BeginTransaction();
2693 } 2537 }
2694
2695 if (text_database_) {
2696 text_database_->CommitTransaction();
2697 text_database_->BeginTransaction();
2698 }
2699 } 2538 }
2700 2539
2701 void HistoryBackend::ScheduleCommit() { 2540 void HistoryBackend::ScheduleCommit() {
2702 if (scheduled_commit_.get()) 2541 if (scheduled_commit_.get())
2703 return; 2542 return;
2704 scheduled_commit_ = new CommitLaterTask(this); 2543 scheduled_commit_ = new CommitLaterTask(this);
2705 base::MessageLoop::current()->PostDelayedTask( 2544 base::MessageLoop::current()->PostDelayedTask(
2706 FROM_HERE, 2545 FROM_HERE,
2707 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()), 2546 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
2708 base::TimeDelta::FromSeconds(kCommitIntervalSeconds)); 2547 base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
2905 bool success = db_->Raze(); 2744 bool success = db_->Raze();
2906 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success); 2745 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
2907 2746
2908 #if defined(OS_ANDROID) 2747 #if defined(OS_ANDROID)
2909 // Release AndroidProviderBackend before other objects. 2748 // Release AndroidProviderBackend before other objects.
2910 android_provider_backend_.reset(); 2749 android_provider_backend_.reset();
2911 #endif 2750 #endif
2912 2751
2913 // The expirer keeps tabs on the active databases. Tell it about the 2752 // The expirer keeps tabs on the active databases. Tell it about the
2914 // databases which will be closed. 2753 // databases which will be closed.
2915 expirer_.SetDatabases(NULL, NULL, NULL, NULL); 2754 expirer_.SetDatabases(NULL, NULL, NULL);
2916 2755
2917 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases(). 2756 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
2918 db_->BeginTransaction(); 2757 db_->BeginTransaction();
2919 CloseAllDatabases(); 2758 CloseAllDatabases();
2920 } 2759 }
2921 2760
2922 void HistoryBackend::ProcessDBTask( 2761 void HistoryBackend::ProcessDBTask(
2923 scoped_refptr<HistoryDBTaskRequest> request) { 2762 scoped_refptr<HistoryDBTaskRequest> request) {
2924 DCHECK(request.get()); 2763 DCHECK(request.get());
2925 if (request->canceled()) 2764 if (request->canceled())
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
2995 // We continue in this error case. If the user wants to delete their 2834 // We continue in this error case. If the user wants to delete their
2996 // history, we should delete as much as we can. 2835 // history, we should delete as much as we can.
2997 } 2836 }
2998 2837
2999 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore, 2838 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore,
3000 // we clear the list afterwards to make sure nobody uses this invalid data. 2839 // we clear the list afterwards to make sure nobody uses this invalid data.
3001 if (!ClearAllMainHistory(kept_urls)) 2840 if (!ClearAllMainHistory(kept_urls))
3002 LOG(ERROR) << "Main history could not be cleared"; 2841 LOG(ERROR) << "Main history could not be cleared";
3003 kept_urls.clear(); 2842 kept_urls.clear();
3004 2843
3005 // Delete FTS files & archived history. 2844 // Delete archived history.
3006 if (text_database_) {
3007 // We assume that the text database has one transaction on them that we need
3008 // to close & restart (the long-running history transaction).
3009 text_database_->CommitTransaction();
3010 text_database_->DeleteAll();
3011 text_database_->BeginTransaction();
3012 }
3013
3014 if (archived_db_) { 2845 if (archived_db_) {
3015 // Close the database and delete the file. 2846 // Close the database and delete the file.
3016 archived_db_.reset(); 2847 archived_db_.reset();
3017 base::FilePath archived_file_name = GetArchivedFileName(); 2848 base::FilePath archived_file_name = GetArchivedFileName();
3018 file_util::Delete(archived_file_name, false); 2849 file_util::Delete(archived_file_name, false);
3019 2850
3020 // Now re-initialize the database (which may fail). 2851 // Now re-initialize the database (which may fail).
3021 archived_db_.reset(new ArchivedDatabase()); 2852 archived_db_.reset(new ArchivedDatabase());
3022 if (!archived_db_->Init(archived_file_name)) { 2853 if (!archived_db_->Init(archived_file_name)) {
3023 LOG(WARNING) << "Could not initialize the archived database."; 2854 LOG(WARNING) << "Could not initialize the archived database.";
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
3149 info.url_id = visit.url_id; 2980 info.url_id = visit.url_id;
3150 info.time = visit.visit_time; 2981 info.time = visit.visit_time;
3151 info.transition = visit.transition; 2982 info.transition = visit.transition;
3152 // If we don't have a delegate yet during setup or shutdown, we will drop 2983 // If we don't have a delegate yet during setup or shutdown, we will drop
3153 // these notifications. 2984 // these notifications.
3154 if (delegate_) 2985 if (delegate_)
3155 delegate_->NotifyVisitDBObserversOnAddVisit(info); 2986 delegate_->NotifyVisitDBObserversOnAddVisit(info);
3156 } 2987 }
3157 2988
3158 } // namespace history 2989 } // namespace history
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698