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

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: Sync and rebase. Created 7 years, 5 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/files/file_enumerator.h"
17 #include "base/memory/scoped_ptr.h" 18 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/scoped_vector.h" 19 #include "base/memory/scoped_vector.h"
19 #include "base/message_loop/message_loop.h" 20 #include "base/message_loop/message_loop.h"
20 #include "base/metrics/histogram.h" 21 #include "base/metrics/histogram.h"
21 #include "base/rand_util.h" 22 #include "base/rand_util.h"
22 #include "base/strings/string_util.h" 23 #include "base/strings/string_util.h"
23 #include "base/strings/utf_string_conversions.h" 24 #include "base/strings/utf_string_conversions.h"
24 #include "base/time/time.h" 25 #include "base/time/time.h"
25 #include "chrome/browser/autocomplete/history_url_provider.h" 26 #include "chrome/browser/autocomplete/history_url_provider.h"
26 #include "chrome/browser/bookmarks/bookmark_service.h" 27 #include "chrome/browser/bookmarks/bookmark_service.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 VisitDatabase (stores a list of visits for the URLs) 62 VisitDatabase (stores a list of visits for the URLs)
62 VisitSegmentDatabase (stores groups of URLs for the most visited view). 63 VisitSegmentDatabase (stores groups of URLs for the most visited view).
63 64
64 ArchivedDatabase (stores history older than 3 months) 65 ArchivedDatabase (stores history older than 3 months)
65 URLDatabase (stores a list of URLs) 66 URLDatabase (stores a list of URLs)
66 DownloadDatabase (stores a list of downloads) 67 DownloadDatabase (stores a list of downloads)
67 VisitDatabase (stores a list of visits for the URLs) 68 VisitDatabase (stores a list of visits for the URLs)
68 69
69 (this does not store visit segments as they expire after 3 mos.) 70 (this does not store visit segments as they expire after 3 mos.)
70 71
71 TextDatabaseManager (manages multiple text database for different times)
72 TextDatabase (represents a single month of full-text index).
73 ...more TextDatabase objects...
74
75 ExpireHistoryBackend (manages moving things from HistoryDatabase to 72 ExpireHistoryBackend (manages moving things from HistoryDatabase to
76 the ArchivedDatabase and deleting) 73 the ArchivedDatabase and deleting)
77 */ 74 */
78 75
79 namespace history { 76 namespace history {
80 77
81 // How long we keep segment data for in days. Currently 3 months. 78 // How long we keep segment data for in days. Currently 3 months.
82 // This value needs to be greater or equal to 79 // This value needs to be greater or equal to
83 // MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct 80 // MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
84 // dependency between MostVisitedModel and the history backend. 81 // dependency between MostVisitedModel and the history backend.
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 } 158 }
162 159
163 private: 160 private:
164 friend class base::RefCounted<CommitLaterTask>; 161 friend class base::RefCounted<CommitLaterTask>;
165 162
166 ~CommitLaterTask() {} 163 ~CommitLaterTask() {}
167 164
168 scoped_refptr<HistoryBackend> history_backend_; 165 scoped_refptr<HistoryBackend> history_backend_;
169 }; 166 };
170 167
171 // Handles querying first the main database, then the full text database if that
172 // fails. It will optionally keep track of all URLs seen so duplicates can be
173 // eliminated. This is used by the querying sub-functions.
174 //
175 // TODO(brettw): This class may be able to be simplified or eliminated. After
176 // this was written, QueryResults can efficiently look up by URL, so the need
177 // for this extra set of previously queried URLs is less important.
178 class HistoryBackend::URLQuerier {
179 public:
180 URLQuerier(URLDatabase* main_db, URLDatabase* archived_db, bool track_unique)
181 : main_db_(main_db),
182 archived_db_(archived_db),
183 track_unique_(track_unique) {
184 }
185
186 // When we're tracking unique URLs, returns true if this URL has been
187 // previously queried. Only call when tracking unique URLs.
188 bool HasURL(const GURL& url) {
189 DCHECK(track_unique_);
190 return unique_urls_.find(url) != unique_urls_.end();
191 }
192
193 bool GetRowForURL(const GURL& url, URLRow* row) {
194 if (!main_db_->GetRowForURL(url, row)) {
195 if (!archived_db_ || !archived_db_->GetRowForURL(url, row)) {
196 // This row is neither in the main nor the archived DB.
197 return false;
198 }
199 }
200
201 if (track_unique_)
202 unique_urls_.insert(url);
203 return true;
204 }
205
206 private:
207 URLDatabase* main_db_; // Guaranteed non-NULL.
208 URLDatabase* archived_db_; // Possibly NULL.
209
210 bool track_unique_;
211
212 // When track_unique_ is set, this is updated with every URL seen so far.
213 std::set<GURL> unique_urls_;
214
215 DISALLOW_COPY_AND_ASSIGN(URLQuerier);
216 };
217
218 // HistoryBackend -------------------------------------------------------------- 168 // HistoryBackend --------------------------------------------------------------
219 169
220 HistoryBackend::HistoryBackend(const base::FilePath& history_dir, 170 HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
221 int id, 171 int id,
222 Delegate* delegate, 172 Delegate* delegate,
223 BookmarkService* bookmark_service) 173 BookmarkService* bookmark_service)
224 : delegate_(delegate), 174 : delegate_(delegate),
225 id_(id), 175 id_(id),
226 history_dir_(history_dir), 176 history_dir_(history_dir),
227 scheduled_kill_db_(false), 177 scheduled_kill_db_(false),
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after
575 // Update the visit_details for this visit. 525 // Update the visit_details for this visit.
576 UpdateVisitDuration(from_visit_id, request.time); 526 UpdateVisitDuration(from_visit_id, request.time);
577 } 527 }
578 528
579 // Subsequent transitions in the redirect list must all be server 529 // Subsequent transitions in the redirect list must all be server
580 // redirects. 530 // redirects.
581 redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT; 531 redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
582 } 532 }
583 533
584 // Last, save this redirect chain for later so we can set titles & favicons 534 // Last, save this redirect chain for later so we can set titles & favicons
585 // on the redirected pages properly. It is indexed by the destination page. 535 // on the redirected pages properly.
586 recent_redirects_.Put(request.url, redirects); 536 recent_redirects_.Put(request.url, redirects);
587 } 537 }
588 538
589 // TODO(brettw) bug 1140015: Add an "add page" notification so the history 539 // TODO(brettw) bug 1140015: Add an "add page" notification so the history
590 // views can keep in sync. 540 // views can keep in sync.
591 541
592 // Add the last visit to the tracker so we can get outgoing transitions. 542 // Add the last visit to the tracker so we can get outgoing transitions.
593 // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe 543 // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
594 // navigation anyway, so last_visit_id is always zero for them. But adding 544 // navigation anyway, so last_visit_id is always zero for them. But adding
595 // them here confuses main frame history, so we skip them for now. 545 // them here confuses main frame history, so we skip them for now.
596 if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME && 546 if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
597 stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME && 547 stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
598 !is_keyword_generated) { 548 !is_keyword_generated) {
599 tracker_.AddVisit(request.id_scope, request.page_id, request.url, 549 tracker_.AddVisit(request.id_scope, request.page_id, request.url,
600 last_ids.second); 550 last_ids.second);
601 } 551 }
602 552
603 if (text_database_) {
604 text_database_->AddPageURL(request.url, last_ids.first, last_ids.second,
605 request.time);
606 }
607
608 ScheduleCommit(); 553 ScheduleCommit();
609 } 554 }
610 555
611 void HistoryBackend::InitImpl(const std::string& languages) { 556 void HistoryBackend::InitImpl(const std::string& languages) {
612 DCHECK(!db_) << "Initializing HistoryBackend twice"; 557 DCHECK(!db_) << "Initializing HistoryBackend twice";
613 // In the rare case where the db fails to initialize a dialog may get shown 558 // In the rare case where the db fails to initialize a dialog may get shown
614 // the blocks the caller, yet allows other messages through. For this reason 559 // the blocks the caller, yet allows other messages through. For this reason
615 // we only set db_ to the created database if creation is successful. That 560 // we only set db_ to the created database if creation is successful. That
616 // way other methods won't do anything as db_ is still NULL. 561 // way other methods won't do anything as db_ is still NULL.
617 562
618 TimeTicks beginning_time = TimeTicks::Now(); 563 TimeTicks beginning_time = TimeTicks::Now();
619 564
620 // Compute the file names. Note that the index file can be removed when the 565 // Compute the file names.
621 // text db manager is finished being hooked up.
622 base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename); 566 base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
623 base::FilePath thumbnail_name = GetThumbnailFileName(); 567 base::FilePath thumbnail_name = GetThumbnailFileName();
624 base::FilePath archived_name = GetArchivedFileName(); 568 base::FilePath archived_name = GetArchivedFileName();
625 569
570 // Delete the old index database files which are no longer used.
571 DeleteFTSIndexDatabases();
572
626 // History database. 573 // History database.
627 db_.reset(new HistoryDatabase()); 574 db_.reset(new HistoryDatabase());
628 575
629 // Unretained to avoid a ref loop with db_. 576 // Unretained to avoid a ref loop with db_.
630 db_->set_error_callback( 577 db_->set_error_callback(
631 base::Bind(&HistoryBackend::DatabaseErrorCallback, 578 base::Bind(&HistoryBackend::DatabaseErrorCallback,
632 base::Unretained(this))); 579 base::Unretained(this)));
633 580
634 sql::InitStatus status = db_->Init(history_name); 581 sql::InitStatus status = db_->Init(history_name);
635 switch (status) { 582 switch (status) {
(...skipping 19 matching lines...) Expand all
655 // Fill the in-memory database and send it back to the history service on the 602 // Fill the in-memory database and send it back to the history service on the
656 // main thread. 603 // main thread.
657 InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend; 604 InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
658 if (mem_backend->Init(history_name, db_.get())) 605 if (mem_backend->Init(history_name, db_.get()))
659 delegate_->SetInMemoryBackend(id_, mem_backend); // Takes ownership of 606 delegate_->SetInMemoryBackend(id_, mem_backend); // Takes ownership of
660 // pointer. 607 // pointer.
661 else 608 else
662 delete mem_backend; // Error case, run without the in-memory DB. 609 delete mem_backend; // Error case, run without the in-memory DB.
663 db_->BeginExclusiveMode(); // Must be after the mem backend read the data. 610 db_->BeginExclusiveMode(); // Must be after the mem backend read the data.
664 611
665 // Create the history publisher which needs to be passed on to the text and 612 // Create the history publisher which needs to be passed on to the thumbnail
666 // thumbnail databases for publishing history. 613 // database for publishing history.
667 history_publisher_.reset(new HistoryPublisher()); 614 history_publisher_.reset(new HistoryPublisher());
668 if (!history_publisher_->Init()) { 615 if (!history_publisher_->Init()) {
669 // The init may fail when there are no indexers wanting our history. 616 // The init may fail when there are no indexers wanting our history.
670 // Hence no need to log the failure. 617 // Hence no need to log the failure.
671 history_publisher_.reset(); 618 history_publisher_.reset();
672 } 619 }
673 620
674 // Full-text database. This has to be first so we can pass it to the
675 // HistoryDatabase for migration.
676 text_database_.reset(new TextDatabaseManager(history_dir_,
677 db_.get(), db_.get()));
678 if (!text_database_->Init(history_publisher_.get())) {
679 LOG(WARNING) << "Text database initialization failed, running without it.";
680 text_database_.reset();
681 }
682 if (db_->needs_version_17_migration()) {
683 // See needs_version_17_migration() decl for more. In this case, we want
684 // to erase all the text database files. This must be done after the text
685 // database manager has been initialized, since it knows about all the
686 // files it manages.
687 text_database_->DeleteAll();
688 }
689
690 // Thumbnail database. 621 // Thumbnail database.
691 thumbnail_db_.reset(new ThumbnailDatabase()); 622 thumbnail_db_.reset(new ThumbnailDatabase());
692 if (!db_->GetNeedsThumbnailMigration()) { 623 if (!db_->GetNeedsThumbnailMigration()) {
693 // No convertion needed - use new filename right away. 624 // No convertion needed - use new filename right away.
694 thumbnail_name = GetFaviconsFileName(); 625 thumbnail_name = GetFaviconsFileName();
695 } 626 }
696 if (thumbnail_db_->Init(thumbnail_name, 627 if (thumbnail_db_->Init(thumbnail_name,
697 history_publisher_.get(), 628 history_publisher_.get(),
698 db_.get()) != sql::INIT_OK) { 629 db_.get()) != sql::INIT_OK) {
699 // Unlike the main database, we don't error out when the database is too 630 // 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
732 } 663 }
733 664
734 // Tell the expiration module about all the nice databases we made. This must 665 // Tell the expiration module about all the nice databases we made. This must
735 // happen before db_->Init() is called since the callback ForceArchiveHistory 666 // happen before db_->Init() is called since the callback ForceArchiveHistory
736 // may need to expire stuff. 667 // may need to expire stuff.
737 // 668 //
738 // *sigh*, this can all be cleaned up when that migration code is removed. 669 // *sigh*, this can all be cleaned up when that migration code is removed.
739 // The main DB initialization should intuitively be first (not that it 670 // The main DB initialization should intuitively be first (not that it
740 // actually matters) and the expirer should be set last. 671 // actually matters) and the expirer should be set last.
741 expirer_.SetDatabases(db_.get(), archived_db_.get(), 672 expirer_.SetDatabases(db_.get(), archived_db_.get(),
742 thumbnail_db_.get(), text_database_.get()); 673 thumbnail_db_.get());
743 674
744 // Open the long-running transaction. 675 // Open the long-running transaction.
745 db_->BeginTransaction(); 676 db_->BeginTransaction();
746 if (thumbnail_db_) 677 if (thumbnail_db_)
747 thumbnail_db_->BeginTransaction(); 678 thumbnail_db_->BeginTransaction();
748 if (archived_db_) 679 if (archived_db_)
749 archived_db_->BeginTransaction(); 680 archived_db_->BeginTransaction();
750 if (text_database_)
751 text_database_->BeginTransaction();
752 681
753 // Get the first item in our database. 682 // Get the first item in our database.
754 db_->GetStartDate(&first_recorded_time_); 683 db_->GetStartDate(&first_recorded_time_);
755 684
756 // Start expiring old stuff. 685 // Start expiring old stuff.
757 expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold)); 686 expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
758 687
759 #if defined(OS_ANDROID) 688 #if defined(OS_ANDROID)
760 if (thumbnail_db_) { 689 if (thumbnail_db_) {
761 android_provider_backend_.reset(new AndroidProviderBackend( 690 android_provider_backend_.reset(new AndroidProviderBackend(
(...skipping 25 matching lines...) Expand all
787 db_.reset(); 716 db_.reset();
788 } 717 }
789 if (thumbnail_db_) { 718 if (thumbnail_db_) {
790 thumbnail_db_->CommitTransaction(); 719 thumbnail_db_->CommitTransaction();
791 thumbnail_db_.reset(); 720 thumbnail_db_.reset();
792 } 721 }
793 if (archived_db_) { 722 if (archived_db_) {
794 archived_db_->CommitTransaction(); 723 archived_db_->CommitTransaction();
795 archived_db_.reset(); 724 archived_db_.reset();
796 } 725 }
797 if (text_database_) {
798 text_database_->CommitTransaction();
799 text_database_.reset();
800 }
801 } 726 }
802 727
803 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit( 728 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
804 const GURL& url, 729 const GURL& url,
805 Time time, 730 Time time,
806 VisitID referring_visit, 731 VisitID referring_visit,
807 content::PageTransition transition, 732 content::PageTransition transition,
808 VisitSource visit_source) { 733 VisitSource visit_source) {
809 // Top-level frame navigations are visible, everything else is hidden 734 // Top-level frame navigations are visible, everything else is hidden
810 bool new_hidden = !content::PageTransitionIsMainFrame(transition); 735 bool new_hidden = !content::PageTransitionIsMainFrame(transition);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
854 url_info.set_typed_count(typed_increment); 779 url_info.set_typed_count(typed_increment);
855 url_info.set_last_visit(time); 780 url_info.set_last_visit(time);
856 url_info.set_hidden(new_hidden); 781 url_info.set_hidden(new_hidden);
857 782
858 url_id = db_->AddURL(url_info); 783 url_id = db_->AddURL(url_info);
859 if (!url_id) { 784 if (!url_id) {
860 NOTREACHED() << "Adding URL failed."; 785 NOTREACHED() << "Adding URL failed.";
861 return std::make_pair(0, 0); 786 return std::make_pair(0, 0);
862 } 787 }
863 url_info.id_ = url_id; 788 url_info.id_ = url_id;
864
865 // We don't actually add the URL to the full text index at this point. It
866 // might be nice to do this so that even if we get no title or body, the
867 // user can search for URL components and get the page.
868 //
869 // However, in most cases, we'll get at least a title and usually contents,
870 // and this add will be redundant, slowing everything down. As a result,
871 // we ignore this edge case.
872 } 789 }
873 790
874 // Add the visit with the time to the database. 791 // Add the visit with the time to the database.
875 VisitRow visit_info(url_id, time, referring_visit, transition, 0); 792 VisitRow visit_info(url_id, time, referring_visit, transition, 0);
876 VisitID visit_id = db_->AddVisit(&visit_info, visit_source); 793 VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
877 NotifyVisitObservers(visit_info); 794 NotifyVisitObservers(visit_info);
878 795
879 if (visit_info.visit_time < first_recorded_time_) 796 if (visit_info.visit_time < first_recorded_time_)
880 first_recorded_time_ = visit_info.visit_time; 797 first_recorded_time_ = visit_info.visit_time;
881 798
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
931 NOTREACHED() << "Could not add row to DB"; 848 NOTREACHED() << "Could not add row to DB";
932 return; 849 return;
933 } 850 }
934 851
935 if (i->typed_count() > 0) { 852 if (i->typed_count() > 0) {
936 modified->changed_urls.push_back(*i); 853 modified->changed_urls.push_back(*i);
937 modified->changed_urls.back().set_id(url_id); // *i likely has |id_| 0. 854 modified->changed_urls.back().set_id(url_id); // *i likely has |id_| 0.
938 } 855 }
939 } 856 }
940 857
941 // Add the page to the full text index. This function is also used for
942 // importing. Even though we don't have page contents, we can at least
943 // add the title and URL to the index so they can be searched. We don't
944 // bother to delete any already-existing FTS entries for the URL, since
945 // this is normally called on import.
946 //
947 // If you ever import *after* first run (selecting import from the menu),
948 // then these additional entries will "shadow" the originals when querying
949 // for the most recent match only, and the user won't get snippets. This is
950 // a very minor issue, and fixing it will make import slower, so we don't
951 // bother.
952 bool has_indexed = false;
953 if (text_database_) {
954 // We do not have to make it update the visit database, below, we will
955 // create the visit entry with the indexed flag set.
956 has_indexed = text_database_->AddPageData(i->url(), url_id, 0,
957 i->last_visit(),
958 i->title(), string16());
959 }
960
961 // Sync code manages the visits itself. 858 // Sync code manages the visits itself.
962 if (visit_source != SOURCE_SYNCED) { 859 if (visit_source != SOURCE_SYNCED) {
963 // Make up a visit to correspond to the last visit to the page. 860 // Make up a visit to correspond to the last visit to the page.
964 VisitRow visit_info(url_id, i->last_visit(), 0, 861 VisitRow visit_info(url_id, i->last_visit(), 0,
965 content::PageTransitionFromInt( 862 content::PageTransitionFromInt(
966 content::PAGE_TRANSITION_LINK | 863 content::PAGE_TRANSITION_LINK |
967 content::PAGE_TRANSITION_CHAIN_START | 864 content::PAGE_TRANSITION_CHAIN_START |
968 content::PAGE_TRANSITION_CHAIN_END), 0); 865 content::PAGE_TRANSITION_CHAIN_END), 0);
969 visit_info.is_indexed = has_indexed;
970 if (!visit_database->AddVisit(&visit_info, visit_source)) { 866 if (!visit_database->AddVisit(&visit_info, visit_source)) {
971 NOTREACHED() << "Adding visit failed."; 867 NOTREACHED() << "Adding visit failed.";
972 return; 868 return;
973 } 869 }
974 NotifyVisitObservers(visit_info); 870 NotifyVisitObservers(visit_info);
975 871
976 if (visit_info.visit_time < first_recorded_time_) 872 if (visit_info.visit_time < first_recorded_time_)
977 first_recorded_time_ = visit_info.visit_time; 873 first_recorded_time_ = visit_info.visit_time;
978 } 874 }
979 } 875 }
(...skipping 14 matching lines...) Expand all
994 890
995 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { 891 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
996 return time < expirer_.GetCurrentArchiveTime(); 892 return time < expirer_.GetCurrentArchiveTime();
997 } 893 }
998 894
999 void HistoryBackend::SetPageTitle(const GURL& url, 895 void HistoryBackend::SetPageTitle(const GURL& url,
1000 const string16& title) { 896 const string16& title) {
1001 if (!db_) 897 if (!db_)
1002 return; 898 return;
1003 899
1004 // Update the full text index.
1005 if (text_database_)
1006 text_database_->AddPageTitle(url, title);
1007
1008 // Search for recent redirects which should get the same title. We make a 900 // Search for recent redirects which should get the same title. We make a
1009 // dummy list containing the exact URL visited if there are no redirects so 901 // dummy list containing the exact URL visited if there are no redirects so
1010 // the processing below can be the same. 902 // the processing below can be the same.
1011 history::RedirectList dummy_list; 903 history::RedirectList dummy_list;
1012 history::RedirectList* redirects; 904 history::RedirectList* redirects;
1013 RedirectCache::iterator iter = recent_redirects_.Get(url); 905 RedirectCache::iterator iter = recent_redirects_.Get(url);
1014 if (iter != recent_redirects_.end()) { 906 if (iter != recent_redirects_.end()) {
1015 redirects = &iter->second; 907 redirects = &iter->second;
1016 908
1017 // This redirect chain should have the destination URL as the last item. 909 // This redirect chain should have the destination URL as the last item.
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after
1492 for (std::vector<URLResult>::iterator it = matching_visits.begin(); 1384 for (std::vector<URLResult>::iterator it = matching_visits.begin();
1493 it != matching_visits.end() && result->size() < max_results; ++it) { 1385 it != matching_visits.end() && result->size() < max_results; ++it) {
1494 result->AppendURLBySwapping(&(*it)); 1386 result->AppendURLBySwapping(&(*it));
1495 } 1387 }
1496 1388
1497 if (matching_visits.size() == result->size() && 1389 if (matching_visits.size() == result->size() &&
1498 options.begin_time <= first_recorded_time_) 1390 options.begin_time <= first_recorded_time_)
1499 result->set_reached_beginning(true); 1391 result->set_reached_beginning(true);
1500 } 1392 }
1501 1393
1502 void HistoryBackend::QueryHistoryFTS(const string16& text_query,
1503 const QueryOptions& options,
1504 QueryResults* result) {
1505 if (!text_database_)
1506 return;
1507
1508 // Full text query, first get all the FTS results in the time range.
1509 std::vector<TextDatabase::Match> fts_matches;
1510 Time first_time_searched;
1511 text_database_->GetTextMatches(text_query, options,
1512 &fts_matches, &first_time_searched);
1513
1514 URLQuerier querier(db_.get(), archived_db_.get(), true);
1515
1516 // Now get the row and visit information for each one.
1517 URLResult url_result; // Declare outside loop to prevent re-construction.
1518 for (size_t i = 0; i < fts_matches.size(); i++) {
1519 if (options.max_count != 0 &&
1520 static_cast<int>(result->size()) >= options.max_count)
1521 break; // Got too many items.
1522
1523 // Get the URL, querying the main and archived databases as necessary. If
1524 // this is not found, the history and full text search databases are out
1525 // of sync and we give up with this result.
1526 if (!querier.GetRowForURL(fts_matches[i].url, &url_result))
1527 continue;
1528
1529 if (!url_result.url().is_valid())
1530 continue; // Don't report invalid URLs in case of corruption.
1531
1532 // Copy over the FTS stuff that the URLDatabase doesn't know about.
1533 // We do this with swap() to avoid copying, since we know we don't
1534 // need the original any more. Note that we override the title with the
1535 // one from FTS, since that will match the title_match_positions (the
1536 // FTS title and the history DB title may differ).
1537 url_result.set_title(fts_matches[i].title);
1538 url_result.title_match_positions_.swap(
1539 fts_matches[i].title_match_positions);
1540 url_result.snippet_.Swap(&fts_matches[i].snippet);
1541
1542 // The visit time also comes from the full text search database. Since it
1543 // has the time, we can avoid an extra query of the visits table.
1544 url_result.set_visit_time(fts_matches[i].time);
1545
1546 // Add it to the vector, this will clear our |url_row| object as a
1547 // result of the swap.
1548 result->AppendURLBySwapping(&url_result);
1549 }
1550
1551 if (first_time_searched <= first_recorded_time_)
1552 result->set_reached_beginning(true);
1553 }
1554
1555 // Frontend to GetMostRecentRedirectsFrom from the history thread. 1394 // Frontend to GetMostRecentRedirectsFrom from the history thread.
1556 void HistoryBackend::QueryRedirectsFrom( 1395 void HistoryBackend::QueryRedirectsFrom(
1557 scoped_refptr<QueryRedirectsRequest> request, 1396 scoped_refptr<QueryRedirectsRequest> request,
1558 const GURL& url) { 1397 const GURL& url) {
1559 if (request->canceled()) 1398 if (request->canceled())
1560 return; 1399 return;
1561 bool success = GetMostRecentRedirectsFrom(url, &request->value); 1400 bool success = GetMostRecentRedirectsFrom(url, &request->value);
1562 request->ForwardResult(request->handle(), url, success, &request->value); 1401 request->ForwardResult(request->handle(), url, success, &request->value);
1563 } 1402 }
1564 1403
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
1804 GetRedirectsToSpecificVisit(cur_visit, redirects); 1643 GetRedirectsToSpecificVisit(cur_visit, redirects);
1805 return true; 1644 return true;
1806 } 1645 }
1807 1646
1808 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider, 1647 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
1809 HistoryURLProviderParams* params) { 1648 HistoryURLProviderParams* params) {
1810 // ExecuteWithDB should handle the NULL database case. 1649 // ExecuteWithDB should handle the NULL database case.
1811 provider->ExecuteWithDB(this, db_.get(), params); 1650 provider->ExecuteWithDB(this, db_.get(), params);
1812 } 1651 }
1813 1652
1814 void HistoryBackend::SetPageContents(const GURL& url,
1815 const string16& contents) {
1816 // This is histogrammed in the text database manager.
1817 if (!text_database_)
1818 return;
1819 text_database_->AddPageContents(url, contents);
1820 }
1821
1822 void HistoryBackend::SetPageThumbnail( 1653 void HistoryBackend::SetPageThumbnail(
1823 const GURL& url, 1654 const GURL& url,
1824 const gfx::Image* thumbnail, 1655 const gfx::Image* thumbnail,
1825 const ThumbnailScore& score) { 1656 const ThumbnailScore& score) {
1826 if (!db_ || !thumbnail_db_) 1657 if (!db_ || !thumbnail_db_)
1827 return; 1658 return;
1828 1659
1829 URLRow url_row; 1660 URLRow url_row;
1830 URLID url_id = db_->GetRowForURL(url, &url_row); 1661 URLID url_id = db_->GetRowForURL(url, &url_row);
1831 if (url_id) { 1662 if (url_id) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1895 if (db_) { 1726 if (db_) {
1896 // If there is no thumbnail DB, we can still record a successful migration. 1727 // If there is no thumbnail DB, we can still record a successful migration.
1897 if (thumbnail_db_) { 1728 if (thumbnail_db_) {
1898 thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(), 1729 thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(),
1899 GetFaviconsFileName()); 1730 GetFaviconsFileName());
1900 } 1731 }
1901 db_->ThumbnailMigrationDone(); 1732 db_->ThumbnailMigrationDone();
1902 } 1733 }
1903 } 1734 }
1904 1735
1736 void HistoryBackend::DeleteFTSIndexDatabases() {
1737 // Find files on disk matching the text databases file pattern so we can
1738 // quickly test for and delete them.
1739 base::FilePath::StringType filepattern =
1740 FILE_PATH_LITERAL("History Index *");
1741 base::FileEnumerator enumerator(
1742 history_dir_, false, base::FileEnumerator::FILES, filepattern);
1743 int num_databases_deleted = 0;
1744 base::FilePath current_file;
1745 while (!(current_file = enumerator.Next()).empty()) {
1746 if (sql::Connection::Delete(current_file))
1747 num_databases_deleted++;
1748 }
1749 UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1750 num_databases_deleted);
1751 }
1752
1905 bool HistoryBackend::GetThumbnailFromOlderRedirect( 1753 bool HistoryBackend::GetThumbnailFromOlderRedirect(
1906 const GURL& page_url, 1754 const GURL& page_url,
1907 std::vector<unsigned char>* data) { 1755 std::vector<unsigned char>* data) {
1908 // Look at a few previous visit sessions. 1756 // Look at a few previous visit sessions.
1909 VisitVector older_sessions; 1757 VisitVector older_sessions;
1910 URLID page_url_id = db_->GetRowForURL(page_url, NULL); 1758 URLID page_url_id = db_->GetRowForURL(page_url, NULL);
1911 static const int kVisitsToSearchForThumbnail = 4; 1759 static const int kVisitsToSearchForThumbnail = 4;
1912 db_->GetMostRecentVisitsForURL( 1760 db_->GetMostRecentVisitsForURL(
1913 page_url_id, kVisitsToSearchForThumbnail, &older_sessions); 1761 page_url_id, kVisitsToSearchForThumbnail, &older_sessions);
1914 1762
(...skipping 746 matching lines...) Expand 10 before | Expand all | Expand 10 after
2661 thumbnail_db_->CommitTransaction(); 2509 thumbnail_db_->CommitTransaction();
2662 DCHECK(thumbnail_db_->transaction_nesting() == 0) << 2510 DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
2663 "Somebody left a transaction open"; 2511 "Somebody left a transaction open";
2664 thumbnail_db_->BeginTransaction(); 2512 thumbnail_db_->BeginTransaction();
2665 } 2513 }
2666 2514
2667 if (archived_db_) { 2515 if (archived_db_) {
2668 archived_db_->CommitTransaction(); 2516 archived_db_->CommitTransaction();
2669 archived_db_->BeginTransaction(); 2517 archived_db_->BeginTransaction();
2670 } 2518 }
2671
2672 if (text_database_) {
2673 text_database_->CommitTransaction();
2674 text_database_->BeginTransaction();
2675 }
2676 } 2519 }
2677 2520
2678 void HistoryBackend::ScheduleCommit() { 2521 void HistoryBackend::ScheduleCommit() {
2679 if (scheduled_commit_.get()) 2522 if (scheduled_commit_.get())
2680 return; 2523 return;
2681 scheduled_commit_ = new CommitLaterTask(this); 2524 scheduled_commit_ = new CommitLaterTask(this);
2682 base::MessageLoop::current()->PostDelayedTask( 2525 base::MessageLoop::current()->PostDelayedTask(
2683 FROM_HERE, 2526 FROM_HERE,
2684 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()), 2527 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
2685 base::TimeDelta::FromSeconds(kCommitIntervalSeconds)); 2528 base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
2896 bool success = db_->Raze(); 2739 bool success = db_->Raze();
2897 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success); 2740 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
2898 2741
2899 #if defined(OS_ANDROID) 2742 #if defined(OS_ANDROID)
2900 // Release AndroidProviderBackend before other objects. 2743 // Release AndroidProviderBackend before other objects.
2901 android_provider_backend_.reset(); 2744 android_provider_backend_.reset();
2902 #endif 2745 #endif
2903 2746
2904 // The expirer keeps tabs on the active databases. Tell it about the 2747 // The expirer keeps tabs on the active databases. Tell it about the
2905 // databases which will be closed. 2748 // databases which will be closed.
2906 expirer_.SetDatabases(NULL, NULL, NULL, NULL); 2749 expirer_.SetDatabases(NULL, NULL, NULL);
2907 2750
2908 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases(). 2751 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
2909 db_->BeginTransaction(); 2752 db_->BeginTransaction();
2910 CloseAllDatabases(); 2753 CloseAllDatabases();
2911 } 2754 }
2912 2755
2913 void HistoryBackend::ProcessDBTask( 2756 void HistoryBackend::ProcessDBTask(
2914 scoped_refptr<HistoryDBTaskRequest> request) { 2757 scoped_refptr<HistoryDBTaskRequest> request) {
2915 DCHECK(request.get()); 2758 DCHECK(request.get());
2916 if (request->canceled()) 2759 if (request->canceled())
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
2986 // We continue in this error case. If the user wants to delete their 2829 // We continue in this error case. If the user wants to delete their
2987 // history, we should delete as much as we can. 2830 // history, we should delete as much as we can.
2988 } 2831 }
2989 2832
2990 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore, 2833 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore,
2991 // we clear the list afterwards to make sure nobody uses this invalid data. 2834 // we clear the list afterwards to make sure nobody uses this invalid data.
2992 if (!ClearAllMainHistory(kept_urls)) 2835 if (!ClearAllMainHistory(kept_urls))
2993 LOG(ERROR) << "Main history could not be cleared"; 2836 LOG(ERROR) << "Main history could not be cleared";
2994 kept_urls.clear(); 2837 kept_urls.clear();
2995 2838
2996 // Delete FTS files & archived history. 2839 // Delete archived history.
2997 if (text_database_) {
2998 // We assume that the text database has one transaction on them that we need
2999 // to close & restart (the long-running history transaction).
3000 text_database_->CommitTransaction();
3001 text_database_->DeleteAll();
3002 text_database_->BeginTransaction();
3003 }
3004
3005 if (archived_db_) { 2840 if (archived_db_) {
3006 // Close the database and delete the file. 2841 // Close the database and delete the file.
3007 archived_db_.reset(); 2842 archived_db_.reset();
3008 base::FilePath archived_file_name = GetArchivedFileName(); 2843 base::FilePath archived_file_name = GetArchivedFileName();
3009 sql::Connection::Delete(archived_file_name); 2844 sql::Connection::Delete(archived_file_name);
3010 2845
3011 // Now re-initialize the database (which may fail). 2846 // Now re-initialize the database (which may fail).
3012 archived_db_.reset(new ArchivedDatabase()); 2847 archived_db_.reset(new ArchivedDatabase());
3013 if (!archived_db_->Init(archived_file_name)) { 2848 if (!archived_db_->Init(archived_file_name)) {
3014 LOG(WARNING) << "Could not initialize the archived database."; 2849 LOG(WARNING) << "Could not initialize the archived database.";
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
3164 int rank = kPageVisitStatsMaxTopSites; 2999 int rank = kPageVisitStatsMaxTopSites;
3165 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url); 3000 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
3166 if (it != most_visited_urls_map_.end()) 3001 if (it != most_visited_urls_map_.end())
3167 rank = (*it).second; 3002 rank = (*it).second;
3168 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank", 3003 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
3169 rank, kPageVisitStatsMaxTopSites + 1); 3004 rank, kPageVisitStatsMaxTopSites + 1);
3170 } 3005 }
3171 #endif 3006 #endif
3172 3007
3173 } // namespace history 3008 } // namespace history
OLDNEW
« no previous file with comments | « chrome/browser/history/history_backend.h ('k') | chrome/browser/history/history_backend_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698