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

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: Remove QueryOptions.body_only 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 // HistoryBackend -------------------------------------------------------------- 164 // HistoryBackend --------------------------------------------------------------
215 165
216 HistoryBackend::HistoryBackend(const base::FilePath& history_dir, 166 HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
217 int id, 167 int id,
218 Delegate* delegate, 168 Delegate* delegate,
219 BookmarkService* bookmark_service) 169 BookmarkService* bookmark_service)
220 : delegate_(delegate), 170 : delegate_(delegate),
221 id_(id), 171 id_(id),
222 history_dir_(history_dir), 172 history_dir_(history_dir),
223 scheduled_kill_db_(false), 173 scheduled_kill_db_(false),
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 // Update the visit_details for this visit. 516 // Update the visit_details for this visit.
567 UpdateVisitDuration(from_visit_id, request.time); 517 UpdateVisitDuration(from_visit_id, request.time);
568 } 518 }
569 519
570 // Subsequent transitions in the redirect list must all be server 520 // Subsequent transitions in the redirect list must all be server
571 // redirects. 521 // redirects.
572 redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT; 522 redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
573 } 523 }
574 524
575 // Last, save this redirect chain for later so we can set titles & favicons 525 // Last, save this redirect chain for later so we can set titles & favicons
576 // on the redirected pages properly. It is indexed by the destination page. 526 // on the redirected pages properly.
577 recent_redirects_.Put(request.url, redirects); 527 recent_redirects_.Put(request.url, redirects);
578 } 528 }
579 529
580 // TODO(brettw) bug 1140015: Add an "add page" notification so the history 530 // TODO(brettw) bug 1140015: Add an "add page" notification so the history
581 // views can keep in sync. 531 // views can keep in sync.
582 532
583 // Add the last visit to the tracker so we can get outgoing transitions. 533 // Add the last visit to the tracker so we can get outgoing transitions.
584 // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe 534 // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
585 // navigation anyway, so last_visit_id is always zero for them. But adding 535 // navigation anyway, so last_visit_id is always zero for them. But adding
586 // them here confuses main frame history, so we skip them for now. 536 // them here confuses main frame history, so we skip them for now.
587 if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME && 537 if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
588 stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME && 538 stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
589 !is_keyword_generated) { 539 !is_keyword_generated) {
590 tracker_.AddVisit(request.id_scope, request.page_id, request.url, 540 tracker_.AddVisit(request.id_scope, request.page_id, request.url,
591 last_ids.second); 541 last_ids.second);
592 } 542 }
593 543
594 if (text_database_) {
595 text_database_->AddPageURL(request.url, last_ids.first, last_ids.second,
596 request.time);
597 }
598
599 ScheduleCommit(); 544 ScheduleCommit();
600 } 545 }
601 546
602 void HistoryBackend::InitImpl(const std::string& languages) { 547 void HistoryBackend::InitImpl(const std::string& languages) {
603 DCHECK(!db_) << "Initializing HistoryBackend twice"; 548 DCHECK(!db_) << "Initializing HistoryBackend twice";
604 // In the rare case where the db fails to initialize a dialog may get shown 549 // In the rare case where the db fails to initialize a dialog may get shown
605 // the blocks the caller, yet allows other messages through. For this reason 550 // the blocks the caller, yet allows other messages through. For this reason
606 // we only set db_ to the created database if creation is successful. That 551 // we only set db_ to the created database if creation is successful. That
607 // way other methods won't do anything as db_ is still NULL. 552 // way other methods won't do anything as db_ is still NULL.
608 553
609 TimeTicks beginning_time = TimeTicks::Now(); 554 TimeTicks beginning_time = TimeTicks::Now();
610 555
611 // Compute the file names. Note that the index file can be removed when the 556 // Compute the file names.
612 // text db manager is finished being hooked up.
613 base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename); 557 base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
614 base::FilePath thumbnail_name = GetThumbnailFileName(); 558 base::FilePath thumbnail_name = GetThumbnailFileName();
615 base::FilePath archived_name = GetArchivedFileName(); 559 base::FilePath archived_name = GetArchivedFileName();
616 560
561 // Delete the old index database files which are no longer used.
562 DeleteFTSIndexDatabases();
563
617 // History database. 564 // History database.
618 db_.reset(new HistoryDatabase()); 565 db_.reset(new HistoryDatabase());
619 566
620 // Unretained to avoid a ref loop with db_. 567 // Unretained to avoid a ref loop with db_.
621 db_->set_error_callback( 568 db_->set_error_callback(
622 base::Bind(&HistoryBackend::DatabaseErrorCallback, 569 base::Bind(&HistoryBackend::DatabaseErrorCallback,
623 base::Unretained(this))); 570 base::Unretained(this)));
624 571
625 sql::InitStatus status = db_->Init(history_name); 572 sql::InitStatus status = db_->Init(history_name);
626 switch (status) { 573 switch (status) {
(...skipping 19 matching lines...) Expand all
646 // Fill the in-memory database and send it back to the history service on the 593 // Fill the in-memory database and send it back to the history service on the
647 // main thread. 594 // main thread.
648 InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend; 595 InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
649 if (mem_backend->Init(history_name, db_.get())) 596 if (mem_backend->Init(history_name, db_.get()))
650 delegate_->SetInMemoryBackend(id_, mem_backend); // Takes ownership of 597 delegate_->SetInMemoryBackend(id_, mem_backend); // Takes ownership of
651 // pointer. 598 // pointer.
652 else 599 else
653 delete mem_backend; // Error case, run without the in-memory DB. 600 delete mem_backend; // Error case, run without the in-memory DB.
654 db_->BeginExclusiveMode(); // Must be after the mem backend read the data. 601 db_->BeginExclusiveMode(); // Must be after the mem backend read the data.
655 602
656 // Create the history publisher which needs to be passed on to the text and 603 // Create the history publisher which needs to be passed on to the thumbnail
657 // thumbnail databases for publishing history. 604 // database for publishing history.
658 history_publisher_.reset(new HistoryPublisher()); 605 history_publisher_.reset(new HistoryPublisher());
659 if (!history_publisher_->Init()) { 606 if (!history_publisher_->Init()) {
660 // The init may fail when there are no indexers wanting our history. 607 // The init may fail when there are no indexers wanting our history.
661 // Hence no need to log the failure. 608 // Hence no need to log the failure.
662 history_publisher_.reset(); 609 history_publisher_.reset();
663 } 610 }
664 611
665 // Full-text database. This has to be first so we can pass it to the
666 // HistoryDatabase for migration.
667 text_database_.reset(new TextDatabaseManager(history_dir_,
668 db_.get(), db_.get()));
669 if (!text_database_->Init(history_publisher_.get())) {
670 LOG(WARNING) << "Text database initialization failed, running without it.";
671 text_database_.reset();
672 }
673 if (db_->needs_version_17_migration()) {
674 // See needs_version_17_migration() decl for more. In this case, we want
675 // to erase all the text database files. This must be done after the text
676 // database manager has been initialized, since it knows about all the
677 // files it manages.
678 text_database_->DeleteAll();
679 }
680
681 // Thumbnail database. 612 // Thumbnail database.
682 thumbnail_db_.reset(new ThumbnailDatabase()); 613 thumbnail_db_.reset(new ThumbnailDatabase());
683 if (!db_->GetNeedsThumbnailMigration()) { 614 if (!db_->GetNeedsThumbnailMigration()) {
684 // No convertion needed - use new filename right away. 615 // No convertion needed - use new filename right away.
685 thumbnail_name = GetFaviconsFileName(); 616 thumbnail_name = GetFaviconsFileName();
686 } 617 }
687 if (thumbnail_db_->Init(thumbnail_name, 618 if (thumbnail_db_->Init(thumbnail_name,
688 history_publisher_.get(), 619 history_publisher_.get(),
689 db_.get()) != sql::INIT_OK) { 620 db_.get()) != sql::INIT_OK) {
690 // Unlike the main database, we don't error out when the database is too 621 // 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
723 } 654 }
724 655
725 // Tell the expiration module about all the nice databases we made. This must 656 // Tell the expiration module about all the nice databases we made. This must
726 // happen before db_->Init() is called since the callback ForceArchiveHistory 657 // happen before db_->Init() is called since the callback ForceArchiveHistory
727 // may need to expire stuff. 658 // may need to expire stuff.
728 // 659 //
729 // *sigh*, this can all be cleaned up when that migration code is removed. 660 // *sigh*, this can all be cleaned up when that migration code is removed.
730 // The main DB initialization should intuitively be first (not that it 661 // The main DB initialization should intuitively be first (not that it
731 // actually matters) and the expirer should be set last. 662 // actually matters) and the expirer should be set last.
732 expirer_.SetDatabases(db_.get(), archived_db_.get(), 663 expirer_.SetDatabases(db_.get(), archived_db_.get(),
733 thumbnail_db_.get(), text_database_.get()); 664 thumbnail_db_.get());
734 665
735 // Open the long-running transaction. 666 // Open the long-running transaction.
736 db_->BeginTransaction(); 667 db_->BeginTransaction();
737 if (thumbnail_db_) 668 if (thumbnail_db_)
738 thumbnail_db_->BeginTransaction(); 669 thumbnail_db_->BeginTransaction();
739 if (archived_db_) 670 if (archived_db_)
740 archived_db_->BeginTransaction(); 671 archived_db_->BeginTransaction();
741 if (text_database_)
742 text_database_->BeginTransaction();
743 672
744 // Get the first item in our database. 673 // Get the first item in our database.
745 db_->GetStartDate(&first_recorded_time_); 674 db_->GetStartDate(&first_recorded_time_);
746 675
747 // Start expiring old stuff. 676 // Start expiring old stuff.
748 expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold)); 677 expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
749 678
750 #if defined(OS_ANDROID) 679 #if defined(OS_ANDROID)
751 if (thumbnail_db_) { 680 if (thumbnail_db_) {
752 android_provider_backend_.reset(new AndroidProviderBackend( 681 android_provider_backend_.reset(new AndroidProviderBackend(
(...skipping 13 matching lines...) Expand all
766 db_.reset(); 695 db_.reset();
767 } 696 }
768 if (thumbnail_db_) { 697 if (thumbnail_db_) {
769 thumbnail_db_->CommitTransaction(); 698 thumbnail_db_->CommitTransaction();
770 thumbnail_db_.reset(); 699 thumbnail_db_.reset();
771 } 700 }
772 if (archived_db_) { 701 if (archived_db_) {
773 archived_db_->CommitTransaction(); 702 archived_db_->CommitTransaction();
774 archived_db_.reset(); 703 archived_db_.reset();
775 } 704 }
776 if (text_database_) {
777 text_database_->CommitTransaction();
778 text_database_.reset();
779 }
780 } 705 }
781 706
782 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit( 707 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
783 const GURL& url, 708 const GURL& url,
784 Time time, 709 Time time,
785 VisitID referring_visit, 710 VisitID referring_visit,
786 content::PageTransition transition, 711 content::PageTransition transition,
787 VisitSource visit_source) { 712 VisitSource visit_source) {
788 // Top-level frame navigations are visible, everything else is hidden 713 // Top-level frame navigations are visible, everything else is hidden
789 bool new_hidden = !content::PageTransitionIsMainFrame(transition); 714 bool new_hidden = !content::PageTransitionIsMainFrame(transition);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
824 url_info.set_typed_count(typed_increment); 749 url_info.set_typed_count(typed_increment);
825 url_info.set_last_visit(time); 750 url_info.set_last_visit(time);
826 url_info.set_hidden(new_hidden); 751 url_info.set_hidden(new_hidden);
827 752
828 url_id = db_->AddURL(url_info); 753 url_id = db_->AddURL(url_info);
829 if (!url_id) { 754 if (!url_id) {
830 NOTREACHED() << "Adding URL failed."; 755 NOTREACHED() << "Adding URL failed.";
831 return std::make_pair(0, 0); 756 return std::make_pair(0, 0);
832 } 757 }
833 url_info.id_ = url_id; 758 url_info.id_ = url_id;
834
835 // We don't actually add the URL to the full text index at this point. It
836 // might be nice to do this so that even if we get no title or body, the
837 // user can search for URL components and get the page.
838 //
839 // However, in most cases, we'll get at least a title and usually contents,
840 // and this add will be redundant, slowing everything down. As a result,
841 // we ignore this edge case.
842 } 759 }
843 760
844 // Add the visit with the time to the database. 761 // Add the visit with the time to the database.
845 VisitRow visit_info(url_id, time, referring_visit, transition, 0); 762 VisitRow visit_info(url_id, time, referring_visit, transition, 0);
846 VisitID visit_id = db_->AddVisit(&visit_info, visit_source); 763 VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
847 NotifyVisitObservers(visit_info); 764 NotifyVisitObservers(visit_info);
848 765
849 if (visit_info.visit_time < first_recorded_time_) 766 if (visit_info.visit_time < first_recorded_time_)
850 first_recorded_time_ = visit_info.visit_time; 767 first_recorded_time_ = visit_info.visit_time;
851 768
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
901 NOTREACHED() << "Could not add row to DB"; 818 NOTREACHED() << "Could not add row to DB";
902 return; 819 return;
903 } 820 }
904 821
905 if (i->typed_count() > 0) { 822 if (i->typed_count() > 0) {
906 modified->changed_urls.push_back(*i); 823 modified->changed_urls.push_back(*i);
907 modified->changed_urls.back().set_id(url_id); // *i likely has |id_| 0. 824 modified->changed_urls.back().set_id(url_id); // *i likely has |id_| 0.
908 } 825 }
909 } 826 }
910 827
911 // Add the page to the full text index. This function is also used for
912 // importing. Even though we don't have page contents, we can at least
913 // add the title and URL to the index so they can be searched. We don't
914 // bother to delete any already-existing FTS entries for the URL, since
915 // this is normally called on import.
916 //
917 // If you ever import *after* first run (selecting import from the menu),
918 // then these additional entries will "shadow" the originals when querying
919 // for the most recent match only, and the user won't get snippets. This is
920 // a very minor issue, and fixing it will make import slower, so we don't
921 // bother.
922 bool has_indexed = false;
923 if (text_database_) {
924 // We do not have to make it update the visit database, below, we will
925 // create the visit entry with the indexed flag set.
926 has_indexed = text_database_->AddPageData(i->url(), url_id, 0,
927 i->last_visit(),
928 i->title(), string16());
929 }
930
931 // Sync code manages the visits itself. 828 // Sync code manages the visits itself.
932 if (visit_source != SOURCE_SYNCED) { 829 if (visit_source != SOURCE_SYNCED) {
933 // Make up a visit to correspond to the last visit to the page. 830 // Make up a visit to correspond to the last visit to the page.
934 VisitRow visit_info(url_id, i->last_visit(), 0, 831 VisitRow visit_info(url_id, i->last_visit(), 0,
935 content::PageTransitionFromInt( 832 content::PageTransitionFromInt(
936 content::PAGE_TRANSITION_LINK | 833 content::PAGE_TRANSITION_LINK |
937 content::PAGE_TRANSITION_CHAIN_START | 834 content::PAGE_TRANSITION_CHAIN_START |
938 content::PAGE_TRANSITION_CHAIN_END), 0); 835 content::PAGE_TRANSITION_CHAIN_END), 0);
939 visit_info.is_indexed = has_indexed;
940 if (!visit_database->AddVisit(&visit_info, visit_source)) { 836 if (!visit_database->AddVisit(&visit_info, visit_source)) {
941 NOTREACHED() << "Adding visit failed."; 837 NOTREACHED() << "Adding visit failed.";
942 return; 838 return;
943 } 839 }
944 NotifyVisitObservers(visit_info); 840 NotifyVisitObservers(visit_info);
945 841
946 if (visit_info.visit_time < first_recorded_time_) 842 if (visit_info.visit_time < first_recorded_time_)
947 first_recorded_time_ = visit_info.visit_time; 843 first_recorded_time_ = visit_info.visit_time;
948 } 844 }
949 } 845 }
(...skipping 14 matching lines...) Expand all
964 860
965 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { 861 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
966 return time < expirer_.GetCurrentArchiveTime(); 862 return time < expirer_.GetCurrentArchiveTime();
967 } 863 }
968 864
969 void HistoryBackend::SetPageTitle(const GURL& url, 865 void HistoryBackend::SetPageTitle(const GURL& url,
970 const string16& title) { 866 const string16& title) {
971 if (!db_) 867 if (!db_)
972 return; 868 return;
973 869
974 // Update the full text index.
975 if (text_database_)
976 text_database_->AddPageTitle(url, title);
977
978 // Search for recent redirects which should get the same title. We make a 870 // Search for recent redirects which should get the same title. We make a
979 // dummy list containing the exact URL visited if there are no redirects so 871 // dummy list containing the exact URL visited if there are no redirects so
980 // the processing below can be the same. 872 // the processing below can be the same.
981 history::RedirectList dummy_list; 873 history::RedirectList dummy_list;
982 history::RedirectList* redirects; 874 history::RedirectList* redirects;
983 RedirectCache::iterator iter = recent_redirects_.Get(url); 875 RedirectCache::iterator iter = recent_redirects_.Get(url);
984 if (iter != recent_redirects_.end()) { 876 if (iter != recent_redirects_.end()) {
985 redirects = &iter->second; 877 redirects = &iter->second;
986 878
987 // This redirect chain should have the destination URL as the last item. 879 // This redirect chain should have the destination URL as the last item.
(...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after
1460 for (std::vector<URLResult>::iterator it = matching_visits.begin(); 1352 for (std::vector<URLResult>::iterator it = matching_visits.begin();
1461 it != matching_visits.end() && result->size() < max_results; ++it) { 1353 it != matching_visits.end() && result->size() < max_results; ++it) {
1462 result->AppendURLBySwapping(&(*it)); 1354 result->AppendURLBySwapping(&(*it));
1463 } 1355 }
1464 1356
1465 if (matching_visits.size() == result->size() && 1357 if (matching_visits.size() == result->size() &&
1466 options.begin_time <= first_recorded_time_) 1358 options.begin_time <= first_recorded_time_)
1467 result->set_reached_beginning(true); 1359 result->set_reached_beginning(true);
1468 } 1360 }
1469 1361
1470 void HistoryBackend::QueryHistoryFTS(const string16& text_query,
1471 const QueryOptions& options,
1472 QueryResults* result) {
1473 if (!text_database_)
1474 return;
1475
1476 // Full text query, first get all the FTS results in the time range.
1477 std::vector<TextDatabase::Match> fts_matches;
1478 Time first_time_searched;
1479 text_database_->GetTextMatches(text_query, options,
1480 &fts_matches, &first_time_searched);
1481
1482 URLQuerier querier(db_.get(), archived_db_.get(), true);
1483
1484 // Now get the row and visit information for each one.
1485 URLResult url_result; // Declare outside loop to prevent re-construction.
1486 for (size_t i = 0; i < fts_matches.size(); i++) {
1487 if (options.max_count != 0 &&
1488 static_cast<int>(result->size()) >= options.max_count)
1489 break; // Got too many items.
1490
1491 // Get the URL, querying the main and archived databases as necessary. If
1492 // this is not found, the history and full text search databases are out
1493 // of sync and we give up with this result.
1494 if (!querier.GetRowForURL(fts_matches[i].url, &url_result))
1495 continue;
1496
1497 if (!url_result.url().is_valid())
1498 continue; // Don't report invalid URLs in case of corruption.
1499
1500 // Copy over the FTS stuff that the URLDatabase doesn't know about.
1501 // We do this with swap() to avoid copying, since we know we don't
1502 // need the original any more. Note that we override the title with the
1503 // one from FTS, since that will match the title_match_positions (the
1504 // FTS title and the history DB title may differ).
1505 url_result.set_title(fts_matches[i].title);
1506 url_result.title_match_positions_.swap(
1507 fts_matches[i].title_match_positions);
1508 url_result.snippet_.Swap(&fts_matches[i].snippet);
1509
1510 // The visit time also comes from the full text search database. Since it
1511 // has the time, we can avoid an extra query of the visits table.
1512 url_result.set_visit_time(fts_matches[i].time);
1513
1514 // Add it to the vector, this will clear our |url_row| object as a
1515 // result of the swap.
1516 result->AppendURLBySwapping(&url_result);
1517 }
1518
1519 if (first_time_searched <= first_recorded_time_)
1520 result->set_reached_beginning(true);
1521 }
1522
1523 // Frontend to GetMostRecentRedirectsFrom from the history thread. 1362 // Frontend to GetMostRecentRedirectsFrom from the history thread.
1524 void HistoryBackend::QueryRedirectsFrom( 1363 void HistoryBackend::QueryRedirectsFrom(
1525 scoped_refptr<QueryRedirectsRequest> request, 1364 scoped_refptr<QueryRedirectsRequest> request,
1526 const GURL& url) { 1365 const GURL& url) {
1527 if (request->canceled()) 1366 if (request->canceled())
1528 return; 1367 return;
1529 bool success = GetMostRecentRedirectsFrom(url, &request->value); 1368 bool success = GetMostRecentRedirectsFrom(url, &request->value);
1530 request->ForwardResult(request->handle(), url, success, &request->value); 1369 request->ForwardResult(request->handle(), url, success, &request->value);
1531 } 1370 }
1532 1371
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
1772 GetRedirectsToSpecificVisit(cur_visit, redirects); 1611 GetRedirectsToSpecificVisit(cur_visit, redirects);
1773 return true; 1612 return true;
1774 } 1613 }
1775 1614
1776 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider, 1615 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
1777 HistoryURLProviderParams* params) { 1616 HistoryURLProviderParams* params) {
1778 // ExecuteWithDB should handle the NULL database case. 1617 // ExecuteWithDB should handle the NULL database case.
1779 provider->ExecuteWithDB(this, db_.get(), params); 1618 provider->ExecuteWithDB(this, db_.get(), params);
1780 } 1619 }
1781 1620
1782 void HistoryBackend::SetPageContents(const GURL& url,
1783 const string16& contents) {
1784 // This is histogrammed in the text database manager.
1785 if (!text_database_)
1786 return;
1787 text_database_->AddPageContents(url, contents);
1788 }
1789
1790 void HistoryBackend::SetPageThumbnail( 1621 void HistoryBackend::SetPageThumbnail(
1791 const GURL& url, 1622 const GURL& url,
1792 const gfx::Image* thumbnail, 1623 const gfx::Image* thumbnail,
1793 const ThumbnailScore& score) { 1624 const ThumbnailScore& score) {
1794 if (!db_ || !thumbnail_db_) 1625 if (!db_ || !thumbnail_db_)
1795 return; 1626 return;
1796 1627
1797 URLRow url_row; 1628 URLRow url_row;
1798 URLID url_id = db_->GetRowForURL(url, &url_row); 1629 URLID url_id = db_->GetRowForURL(url, &url_row);
1799 if (url_id) { 1630 if (url_id) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1863 if (db_) { 1694 if (db_) {
1864 // If there is no thumbnail DB, we can still record a successful migration. 1695 // If there is no thumbnail DB, we can still record a successful migration.
1865 if (thumbnail_db_) { 1696 if (thumbnail_db_) {
1866 thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(), 1697 thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(),
1867 GetFaviconsFileName()); 1698 GetFaviconsFileName());
1868 } 1699 }
1869 db_->ThumbnailMigrationDone(); 1700 db_->ThumbnailMigrationDone();
1870 } 1701 }
1871 } 1702 }
1872 1703
1704 void HistoryBackend::DeleteFTSIndexDatabases() {
1705 // Find files on disk matching the text databases file pattern so we can
1706 // quickly test for and delete them.
1707 base::FilePath::StringType filepattern =
1708 FILE_PATH_LITERAL("History Index *");
1709 base::FileEnumerator enumerator(
1710 history_dir_, false, base::FileEnumerator::FILES, filepattern);
1711 int num_databases_deleted = 0;
1712 base::FilePath current_file;
1713 while (!(current_file = enumerator.Next()).empty()) {
1714 if (sql::Connection::Delete(current_file))
1715 num_databases_deleted++;
1716 }
1717 UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1718 num_databases_deleted);
1719 }
1720
1873 bool HistoryBackend::GetThumbnailFromOlderRedirect( 1721 bool HistoryBackend::GetThumbnailFromOlderRedirect(
1874 const GURL& page_url, 1722 const GURL& page_url,
1875 std::vector<unsigned char>* data) { 1723 std::vector<unsigned char>* data) {
1876 // Look at a few previous visit sessions. 1724 // Look at a few previous visit sessions.
1877 VisitVector older_sessions; 1725 VisitVector older_sessions;
1878 URLID page_url_id = db_->GetRowForURL(page_url, NULL); 1726 URLID page_url_id = db_->GetRowForURL(page_url, NULL);
1879 static const int kVisitsToSearchForThumbnail = 4; 1727 static const int kVisitsToSearchForThumbnail = 4;
1880 db_->GetMostRecentVisitsForURL( 1728 db_->GetMostRecentVisitsForURL(
1881 page_url_id, kVisitsToSearchForThumbnail, &older_sessions); 1729 page_url_id, kVisitsToSearchForThumbnail, &older_sessions);
1882 1730
(...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after
2632 thumbnail_db_->CommitTransaction(); 2480 thumbnail_db_->CommitTransaction();
2633 DCHECK(thumbnail_db_->transaction_nesting() == 0) << 2481 DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
2634 "Somebody left a transaction open"; 2482 "Somebody left a transaction open";
2635 thumbnail_db_->BeginTransaction(); 2483 thumbnail_db_->BeginTransaction();
2636 } 2484 }
2637 2485
2638 if (archived_db_) { 2486 if (archived_db_) {
2639 archived_db_->CommitTransaction(); 2487 archived_db_->CommitTransaction();
2640 archived_db_->BeginTransaction(); 2488 archived_db_->BeginTransaction();
2641 } 2489 }
2642
2643 if (text_database_) {
2644 text_database_->CommitTransaction();
2645 text_database_->BeginTransaction();
2646 }
2647 } 2490 }
2648 2491
2649 void HistoryBackend::ScheduleCommit() { 2492 void HistoryBackend::ScheduleCommit() {
2650 if (scheduled_commit_.get()) 2493 if (scheduled_commit_.get())
2651 return; 2494 return;
2652 scheduled_commit_ = new CommitLaterTask(this); 2495 scheduled_commit_ = new CommitLaterTask(this);
2653 base::MessageLoop::current()->PostDelayedTask( 2496 base::MessageLoop::current()->PostDelayedTask(
2654 FROM_HERE, 2497 FROM_HERE,
2655 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()), 2498 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
2656 base::TimeDelta::FromSeconds(kCommitIntervalSeconds)); 2499 base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
2867 bool success = db_->Raze(); 2710 bool success = db_->Raze();
2868 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success); 2711 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
2869 2712
2870 #if defined(OS_ANDROID) 2713 #if defined(OS_ANDROID)
2871 // Release AndroidProviderBackend before other objects. 2714 // Release AndroidProviderBackend before other objects.
2872 android_provider_backend_.reset(); 2715 android_provider_backend_.reset();
2873 #endif 2716 #endif
2874 2717
2875 // The expirer keeps tabs on the active databases. Tell it about the 2718 // The expirer keeps tabs on the active databases. Tell it about the
2876 // databases which will be closed. 2719 // databases which will be closed.
2877 expirer_.SetDatabases(NULL, NULL, NULL, NULL); 2720 expirer_.SetDatabases(NULL, NULL, NULL);
2878 2721
2879 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases(). 2722 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
2880 db_->BeginTransaction(); 2723 db_->BeginTransaction();
2881 CloseAllDatabases(); 2724 CloseAllDatabases();
2882 } 2725 }
2883 2726
2884 void HistoryBackend::ProcessDBTask( 2727 void HistoryBackend::ProcessDBTask(
2885 scoped_refptr<HistoryDBTaskRequest> request) { 2728 scoped_refptr<HistoryDBTaskRequest> request) {
2886 DCHECK(request.get()); 2729 DCHECK(request.get());
2887 if (request->canceled()) 2730 if (request->canceled())
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
2957 // We continue in this error case. If the user wants to delete their 2800 // We continue in this error case. If the user wants to delete their
2958 // history, we should delete as much as we can. 2801 // history, we should delete as much as we can.
2959 } 2802 }
2960 2803
2961 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore, 2804 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore,
2962 // we clear the list afterwards to make sure nobody uses this invalid data. 2805 // we clear the list afterwards to make sure nobody uses this invalid data.
2963 if (!ClearAllMainHistory(kept_urls)) 2806 if (!ClearAllMainHistory(kept_urls))
2964 LOG(ERROR) << "Main history could not be cleared"; 2807 LOG(ERROR) << "Main history could not be cleared";
2965 kept_urls.clear(); 2808 kept_urls.clear();
2966 2809
2967 // Delete FTS files & archived history. 2810 // Delete archived history.
2968 if (text_database_) {
2969 // We assume that the text database has one transaction on them that we need
2970 // to close & restart (the long-running history transaction).
2971 text_database_->CommitTransaction();
2972 text_database_->DeleteAll();
2973 text_database_->BeginTransaction();
2974 }
2975
2976 if (archived_db_) { 2811 if (archived_db_) {
2977 // Close the database and delete the file. 2812 // Close the database and delete the file.
2978 archived_db_.reset(); 2813 archived_db_.reset();
2979 base::FilePath archived_file_name = GetArchivedFileName(); 2814 base::FilePath archived_file_name = GetArchivedFileName();
2980 file_util::Delete(archived_file_name, false); 2815 file_util::Delete(archived_file_name, false);
2981 2816
2982 // Now re-initialize the database (which may fail). 2817 // Now re-initialize the database (which may fail).
2983 archived_db_.reset(new ArchivedDatabase()); 2818 archived_db_.reset(new ArchivedDatabase());
2984 if (!archived_db_->Init(archived_file_name)) { 2819 if (!archived_db_->Init(archived_file_name)) {
2985 LOG(WARNING) << "Could not initialize the archived database."; 2820 LOG(WARNING) << "Could not initialize the archived database.";
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
3111 info.url_id = visit.url_id; 2946 info.url_id = visit.url_id;
3112 info.time = visit.visit_time; 2947 info.time = visit.visit_time;
3113 info.transition = visit.transition; 2948 info.transition = visit.transition;
3114 // If we don't have a delegate yet during setup or shutdown, we will drop 2949 // If we don't have a delegate yet during setup or shutdown, we will drop
3115 // these notifications. 2950 // these notifications.
3116 if (delegate_) 2951 if (delegate_)
3117 delegate_->NotifyVisitDBObserversOnAddVisit(info); 2952 delegate_->NotifyVisitDBObserversOnAddVisit(info);
3118 } 2953 }
3119 2954
3120 } // namespace history 2955 } // namespace history
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698