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

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: Fix unit test for Windows. 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.h" 20 #include "base/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 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 // Update the visit_details for this visit. 523 // Update the visit_details for this visit.
574 UpdateVisitDuration(from_visit_id, request.time); 524 UpdateVisitDuration(from_visit_id, request.time);
575 } 525 }
576 526
577 // Subsequent transitions in the redirect list must all be server 527 // Subsequent transitions in the redirect list must all be server
578 // redirects. 528 // redirects.
579 redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT; 529 redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
580 } 530 }
581 531
582 // Last, save this redirect chain for later so we can set titles & favicons 532 // Last, save this redirect chain for later so we can set titles & favicons
583 // on the redirected pages properly. It is indexed by the destination page. 533 // on the redirected pages properly.
584 recent_redirects_.Put(request.url, redirects); 534 recent_redirects_.Put(request.url, redirects);
585 } 535 }
586 536
587 // TODO(brettw) bug 1140015: Add an "add page" notification so the history 537 // TODO(brettw) bug 1140015: Add an "add page" notification so the history
588 // views can keep in sync. 538 // views can keep in sync.
589 539
590 // Add the last visit to the tracker so we can get outgoing transitions. 540 // Add the last visit to the tracker so we can get outgoing transitions.
591 // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe 541 // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
592 // navigation anyway, so last_visit_id is always zero for them. But adding 542 // navigation anyway, so last_visit_id is always zero for them. But adding
593 // them here confuses main frame history, so we skip them for now. 543 // them here confuses main frame history, so we skip them for now.
594 if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME && 544 if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
595 stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME && 545 stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
596 !is_keyword_generated) { 546 !is_keyword_generated) {
597 tracker_.AddVisit(request.id_scope, request.page_id, request.url, 547 tracker_.AddVisit(request.id_scope, request.page_id, request.url,
598 last_ids.second); 548 last_ids.second);
599 } 549 }
600 550
601 if (text_database_) {
602 text_database_->AddPageURL(request.url, last_ids.first, last_ids.second,
603 request.time);
604 }
605
606 ScheduleCommit(); 551 ScheduleCommit();
607 } 552 }
608 553
609 void HistoryBackend::InitImpl(const std::string& languages) { 554 void HistoryBackend::InitImpl(const std::string& languages) {
610 DCHECK(!db_) << "Initializing HistoryBackend twice"; 555 DCHECK(!db_) << "Initializing HistoryBackend twice";
611 // In the rare case where the db fails to initialize a dialog may get shown 556 // In the rare case where the db fails to initialize a dialog may get shown
612 // the blocks the caller, yet allows other messages through. For this reason 557 // the blocks the caller, yet allows other messages through. For this reason
613 // we only set db_ to the created database if creation is successful. That 558 // we only set db_ to the created database if creation is successful. That
614 // way other methods won't do anything as db_ is still NULL. 559 // way other methods won't do anything as db_ is still NULL.
615 560
616 TimeTicks beginning_time = TimeTicks::Now(); 561 TimeTicks beginning_time = TimeTicks::Now();
617 562
618 // Compute the file names. Note that the index file can be removed when the 563 // Compute the file names.
619 // text db manager is finished being hooked up.
620 base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename); 564 base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
621 base::FilePath thumbnail_name = GetThumbnailFileName(); 565 base::FilePath thumbnail_name = GetThumbnailFileName();
622 base::FilePath archived_name = GetArchivedFileName(); 566 base::FilePath archived_name = GetArchivedFileName();
623 567
568 // Delete the old index database files which are no longer used.
569 DeleteFTSIndexDatabases();
570
624 // History database. 571 // History database.
625 db_.reset(new HistoryDatabase()); 572 db_.reset(new HistoryDatabase());
626 573
627 // Unretained to avoid a ref loop with db_. 574 // Unretained to avoid a ref loop with db_.
628 db_->set_error_callback( 575 db_->set_error_callback(
629 base::Bind(&HistoryBackend::DatabaseErrorCallback, 576 base::Bind(&HistoryBackend::DatabaseErrorCallback,
630 base::Unretained(this))); 577 base::Unretained(this)));
631 578
632 sql::InitStatus status = db_->Init(history_name); 579 sql::InitStatus status = db_->Init(history_name);
633 switch (status) { 580 switch (status) {
(...skipping 19 matching lines...) Expand all
653 // Fill the in-memory database and send it back to the history service on the 600 // Fill the in-memory database and send it back to the history service on the
654 // main thread. 601 // main thread.
655 InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend; 602 InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
656 if (mem_backend->Init(history_name, db_.get())) 603 if (mem_backend->Init(history_name, db_.get()))
657 delegate_->SetInMemoryBackend(id_, mem_backend); // Takes ownership of 604 delegate_->SetInMemoryBackend(id_, mem_backend); // Takes ownership of
658 // pointer. 605 // pointer.
659 else 606 else
660 delete mem_backend; // Error case, run without the in-memory DB. 607 delete mem_backend; // Error case, run without the in-memory DB.
661 db_->BeginExclusiveMode(); // Must be after the mem backend read the data. 608 db_->BeginExclusiveMode(); // Must be after the mem backend read the data.
662 609
663 // Create the history publisher which needs to be passed on to the text and 610 // Create the history publisher which needs to be passed on to the thumbnail
664 // thumbnail databases for publishing history. 611 // database for publishing history.
665 history_publisher_.reset(new HistoryPublisher()); 612 history_publisher_.reset(new HistoryPublisher());
666 if (!history_publisher_->Init()) { 613 if (!history_publisher_->Init()) {
667 // The init may fail when there are no indexers wanting our history. 614 // The init may fail when there are no indexers wanting our history.
668 // Hence no need to log the failure. 615 // Hence no need to log the failure.
669 history_publisher_.reset(); 616 history_publisher_.reset();
670 } 617 }
671 618
672 // Full-text database. This has to be first so we can pass it to the
673 // HistoryDatabase for migration.
674 text_database_.reset(new TextDatabaseManager(history_dir_,
675 db_.get(), db_.get()));
676 if (!text_database_->Init(history_publisher_.get())) {
677 LOG(WARNING) << "Text database initialization failed, running without it.";
678 text_database_.reset();
679 }
680 if (db_->needs_version_17_migration()) {
681 // See needs_version_17_migration() decl for more. In this case, we want
682 // to erase all the text database files. This must be done after the text
683 // database manager has been initialized, since it knows about all the
684 // files it manages.
685 text_database_->DeleteAll();
686 }
687
688 // Thumbnail database. 619 // Thumbnail database.
689 thumbnail_db_.reset(new ThumbnailDatabase()); 620 thumbnail_db_.reset(new ThumbnailDatabase());
690 if (!db_->GetNeedsThumbnailMigration()) { 621 if (!db_->GetNeedsThumbnailMigration()) {
691 // No convertion needed - use new filename right away. 622 // No convertion needed - use new filename right away.
692 thumbnail_name = GetFaviconsFileName(); 623 thumbnail_name = GetFaviconsFileName();
693 } 624 }
694 if (thumbnail_db_->Init(thumbnail_name, 625 if (thumbnail_db_->Init(thumbnail_name,
695 history_publisher_.get(), 626 history_publisher_.get(),
696 db_.get()) != sql::INIT_OK) { 627 db_.get()) != sql::INIT_OK) {
697 // Unlike the main database, we don't error out when the database is too 628 // 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
730 } 661 }
731 662
732 // Tell the expiration module about all the nice databases we made. This must 663 // Tell the expiration module about all the nice databases we made. This must
733 // happen before db_->Init() is called since the callback ForceArchiveHistory 664 // happen before db_->Init() is called since the callback ForceArchiveHistory
734 // may need to expire stuff. 665 // may need to expire stuff.
735 // 666 //
736 // *sigh*, this can all be cleaned up when that migration code is removed. 667 // *sigh*, this can all be cleaned up when that migration code is removed.
737 // The main DB initialization should intuitively be first (not that it 668 // The main DB initialization should intuitively be first (not that it
738 // actually matters) and the expirer should be set last. 669 // actually matters) and the expirer should be set last.
739 expirer_.SetDatabases(db_.get(), archived_db_.get(), 670 expirer_.SetDatabases(db_.get(), archived_db_.get(),
740 thumbnail_db_.get(), text_database_.get()); 671 thumbnail_db_.get());
741 672
742 // Open the long-running transaction. 673 // Open the long-running transaction.
743 db_->BeginTransaction(); 674 db_->BeginTransaction();
744 if (thumbnail_db_) 675 if (thumbnail_db_)
745 thumbnail_db_->BeginTransaction(); 676 thumbnail_db_->BeginTransaction();
746 if (archived_db_) 677 if (archived_db_)
747 archived_db_->BeginTransaction(); 678 archived_db_->BeginTransaction();
748 if (text_database_)
749 text_database_->BeginTransaction();
750 679
751 // Get the first item in our database. 680 // Get the first item in our database.
752 db_->GetStartDate(&first_recorded_time_); 681 db_->GetStartDate(&first_recorded_time_);
753 682
754 // Start expiring old stuff. 683 // Start expiring old stuff.
755 expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold)); 684 expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
756 685
757 #if defined(OS_ANDROID) 686 #if defined(OS_ANDROID)
758 if (thumbnail_db_) { 687 if (thumbnail_db_) {
759 android_provider_backend_.reset(new AndroidProviderBackend( 688 android_provider_backend_.reset(new AndroidProviderBackend(
(...skipping 13 matching lines...) Expand all
773 db_.reset(); 702 db_.reset();
774 } 703 }
775 if (thumbnail_db_) { 704 if (thumbnail_db_) {
776 thumbnail_db_->CommitTransaction(); 705 thumbnail_db_->CommitTransaction();
777 thumbnail_db_.reset(); 706 thumbnail_db_.reset();
778 } 707 }
779 if (archived_db_) { 708 if (archived_db_) {
780 archived_db_->CommitTransaction(); 709 archived_db_->CommitTransaction();
781 archived_db_.reset(); 710 archived_db_.reset();
782 } 711 }
783 if (text_database_) {
784 text_database_->CommitTransaction();
785 text_database_.reset();
786 }
787 } 712 }
788 713
789 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit( 714 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
790 const GURL& url, 715 const GURL& url,
791 Time time, 716 Time time,
792 VisitID referring_visit, 717 VisitID referring_visit,
793 content::PageTransition transition, 718 content::PageTransition transition,
794 VisitSource visit_source) { 719 VisitSource visit_source) {
795 // Top-level frame navigations are visible, everything else is hidden 720 // Top-level frame navigations are visible, everything else is hidden
796 bool new_hidden = !content::PageTransitionIsMainFrame(transition); 721 bool new_hidden = !content::PageTransitionIsMainFrame(transition);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
840 url_info.set_typed_count(typed_increment); 765 url_info.set_typed_count(typed_increment);
841 url_info.set_last_visit(time); 766 url_info.set_last_visit(time);
842 url_info.set_hidden(new_hidden); 767 url_info.set_hidden(new_hidden);
843 768
844 url_id = db_->AddURL(url_info); 769 url_id = db_->AddURL(url_info);
845 if (!url_id) { 770 if (!url_id) {
846 NOTREACHED() << "Adding URL failed."; 771 NOTREACHED() << "Adding URL failed.";
847 return std::make_pair(0, 0); 772 return std::make_pair(0, 0);
848 } 773 }
849 url_info.id_ = url_id; 774 url_info.id_ = url_id;
850
851 // We don't actually add the URL to the full text index at this point. It
852 // might be nice to do this so that even if we get no title or body, the
853 // user can search for URL components and get the page.
854 //
855 // However, in most cases, we'll get at least a title and usually contents,
856 // and this add will be redundant, slowing everything down. As a result,
857 // we ignore this edge case.
858 } 775 }
859 776
860 // Add the visit with the time to the database. 777 // Add the visit with the time to the database.
861 VisitRow visit_info(url_id, time, referring_visit, transition, 0); 778 VisitRow visit_info(url_id, time, referring_visit, transition, 0);
862 VisitID visit_id = db_->AddVisit(&visit_info, visit_source); 779 VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
863 NotifyVisitObservers(visit_info); 780 NotifyVisitObservers(visit_info);
864 781
865 if (visit_info.visit_time < first_recorded_time_) 782 if (visit_info.visit_time < first_recorded_time_)
866 first_recorded_time_ = visit_info.visit_time; 783 first_recorded_time_ = visit_info.visit_time;
867 784
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
917 NOTREACHED() << "Could not add row to DB"; 834 NOTREACHED() << "Could not add row to DB";
918 return; 835 return;
919 } 836 }
920 837
921 if (i->typed_count() > 0) { 838 if (i->typed_count() > 0) {
922 modified->changed_urls.push_back(*i); 839 modified->changed_urls.push_back(*i);
923 modified->changed_urls.back().set_id(url_id); // *i likely has |id_| 0. 840 modified->changed_urls.back().set_id(url_id); // *i likely has |id_| 0.
924 } 841 }
925 } 842 }
926 843
927 // Add the page to the full text index. This function is also used for
928 // importing. Even though we don't have page contents, we can at least
929 // add the title and URL to the index so they can be searched. We don't
930 // bother to delete any already-existing FTS entries for the URL, since
931 // this is normally called on import.
932 //
933 // If you ever import *after* first run (selecting import from the menu),
934 // then these additional entries will "shadow" the originals when querying
935 // for the most recent match only, and the user won't get snippets. This is
936 // a very minor issue, and fixing it will make import slower, so we don't
937 // bother.
938 bool has_indexed = false;
939 if (text_database_) {
940 // We do not have to make it update the visit database, below, we will
941 // create the visit entry with the indexed flag set.
942 has_indexed = text_database_->AddPageData(i->url(), url_id, 0,
943 i->last_visit(),
944 i->title(), string16());
945 }
946
947 // Sync code manages the visits itself. 844 // Sync code manages the visits itself.
948 if (visit_source != SOURCE_SYNCED) { 845 if (visit_source != SOURCE_SYNCED) {
949 // Make up a visit to correspond to the last visit to the page. 846 // Make up a visit to correspond to the last visit to the page.
950 VisitRow visit_info(url_id, i->last_visit(), 0, 847 VisitRow visit_info(url_id, i->last_visit(), 0,
951 content::PageTransitionFromInt( 848 content::PageTransitionFromInt(
952 content::PAGE_TRANSITION_LINK | 849 content::PAGE_TRANSITION_LINK |
953 content::PAGE_TRANSITION_CHAIN_START | 850 content::PAGE_TRANSITION_CHAIN_START |
954 content::PAGE_TRANSITION_CHAIN_END), 0); 851 content::PAGE_TRANSITION_CHAIN_END), 0);
955 visit_info.is_indexed = has_indexed;
956 if (!visit_database->AddVisit(&visit_info, visit_source)) { 852 if (!visit_database->AddVisit(&visit_info, visit_source)) {
957 NOTREACHED() << "Adding visit failed."; 853 NOTREACHED() << "Adding visit failed.";
958 return; 854 return;
959 } 855 }
960 NotifyVisitObservers(visit_info); 856 NotifyVisitObservers(visit_info);
961 857
962 if (visit_info.visit_time < first_recorded_time_) 858 if (visit_info.visit_time < first_recorded_time_)
963 first_recorded_time_ = visit_info.visit_time; 859 first_recorded_time_ = visit_info.visit_time;
964 } 860 }
965 } 861 }
(...skipping 14 matching lines...) Expand all
980 876
981 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) { 877 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
982 return time < expirer_.GetCurrentArchiveTime(); 878 return time < expirer_.GetCurrentArchiveTime();
983 } 879 }
984 880
985 void HistoryBackend::SetPageTitle(const GURL& url, 881 void HistoryBackend::SetPageTitle(const GURL& url,
986 const string16& title) { 882 const string16& title) {
987 if (!db_) 883 if (!db_)
988 return; 884 return;
989 885
990 // Update the full text index.
991 if (text_database_)
992 text_database_->AddPageTitle(url, title);
993
994 // Search for recent redirects which should get the same title. We make a 886 // Search for recent redirects which should get the same title. We make a
995 // dummy list containing the exact URL visited if there are no redirects so 887 // dummy list containing the exact URL visited if there are no redirects so
996 // the processing below can be the same. 888 // the processing below can be the same.
997 history::RedirectList dummy_list; 889 history::RedirectList dummy_list;
998 history::RedirectList* redirects; 890 history::RedirectList* redirects;
999 RedirectCache::iterator iter = recent_redirects_.Get(url); 891 RedirectCache::iterator iter = recent_redirects_.Get(url);
1000 if (iter != recent_redirects_.end()) { 892 if (iter != recent_redirects_.end()) {
1001 redirects = &iter->second; 893 redirects = &iter->second;
1002 894
1003 // This redirect chain should have the destination URL as the last item. 895 // This redirect chain should have the destination URL as the last item.
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after
1478 for (std::vector<URLResult>::iterator it = matching_visits.begin(); 1370 for (std::vector<URLResult>::iterator it = matching_visits.begin();
1479 it != matching_visits.end() && result->size() < max_results; ++it) { 1371 it != matching_visits.end() && result->size() < max_results; ++it) {
1480 result->AppendURLBySwapping(&(*it)); 1372 result->AppendURLBySwapping(&(*it));
1481 } 1373 }
1482 1374
1483 if (matching_visits.size() == result->size() && 1375 if (matching_visits.size() == result->size() &&
1484 options.begin_time <= first_recorded_time_) 1376 options.begin_time <= first_recorded_time_)
1485 result->set_reached_beginning(true); 1377 result->set_reached_beginning(true);
1486 } 1378 }
1487 1379
1488 void HistoryBackend::QueryHistoryFTS(const string16& text_query,
1489 const QueryOptions& options,
1490 QueryResults* result) {
1491 if (!text_database_)
1492 return;
1493
1494 // Full text query, first get all the FTS results in the time range.
1495 std::vector<TextDatabase::Match> fts_matches;
1496 Time first_time_searched;
1497 text_database_->GetTextMatches(text_query, options,
1498 &fts_matches, &first_time_searched);
1499
1500 URLQuerier querier(db_.get(), archived_db_.get(), true);
1501
1502 // Now get the row and visit information for each one.
1503 URLResult url_result; // Declare outside loop to prevent re-construction.
1504 for (size_t i = 0; i < fts_matches.size(); i++) {
1505 if (options.max_count != 0 &&
1506 static_cast<int>(result->size()) >= options.max_count)
1507 break; // Got too many items.
1508
1509 // Get the URL, querying the main and archived databases as necessary. If
1510 // this is not found, the history and full text search databases are out
1511 // of sync and we give up with this result.
1512 if (!querier.GetRowForURL(fts_matches[i].url, &url_result))
1513 continue;
1514
1515 if (!url_result.url().is_valid())
1516 continue; // Don't report invalid URLs in case of corruption.
1517
1518 // Copy over the FTS stuff that the URLDatabase doesn't know about.
1519 // We do this with swap() to avoid copying, since we know we don't
1520 // need the original any more. Note that we override the title with the
1521 // one from FTS, since that will match the title_match_positions (the
1522 // FTS title and the history DB title may differ).
1523 url_result.set_title(fts_matches[i].title);
1524 url_result.title_match_positions_.swap(
1525 fts_matches[i].title_match_positions);
1526 url_result.snippet_.Swap(&fts_matches[i].snippet);
1527
1528 // The visit time also comes from the full text search database. Since it
1529 // has the time, we can avoid an extra query of the visits table.
1530 url_result.set_visit_time(fts_matches[i].time);
1531
1532 // Add it to the vector, this will clear our |url_row| object as a
1533 // result of the swap.
1534 result->AppendURLBySwapping(&url_result);
1535 }
1536
1537 if (first_time_searched <= first_recorded_time_)
1538 result->set_reached_beginning(true);
1539 }
1540
1541 // Frontend to GetMostRecentRedirectsFrom from the history thread. 1380 // Frontend to GetMostRecentRedirectsFrom from the history thread.
1542 void HistoryBackend::QueryRedirectsFrom( 1381 void HistoryBackend::QueryRedirectsFrom(
1543 scoped_refptr<QueryRedirectsRequest> request, 1382 scoped_refptr<QueryRedirectsRequest> request,
1544 const GURL& url) { 1383 const GURL& url) {
1545 if (request->canceled()) 1384 if (request->canceled())
1546 return; 1385 return;
1547 bool success = GetMostRecentRedirectsFrom(url, &request->value); 1386 bool success = GetMostRecentRedirectsFrom(url, &request->value);
1548 request->ForwardResult(request->handle(), url, success, &request->value); 1387 request->ForwardResult(request->handle(), url, success, &request->value);
1549 } 1388 }
1550 1389
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
1790 GetRedirectsToSpecificVisit(cur_visit, redirects); 1629 GetRedirectsToSpecificVisit(cur_visit, redirects);
1791 return true; 1630 return true;
1792 } 1631 }
1793 1632
1794 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider, 1633 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
1795 HistoryURLProviderParams* params) { 1634 HistoryURLProviderParams* params) {
1796 // ExecuteWithDB should handle the NULL database case. 1635 // ExecuteWithDB should handle the NULL database case.
1797 provider->ExecuteWithDB(this, db_.get(), params); 1636 provider->ExecuteWithDB(this, db_.get(), params);
1798 } 1637 }
1799 1638
1800 void HistoryBackend::SetPageContents(const GURL& url,
1801 const string16& contents) {
1802 // This is histogrammed in the text database manager.
1803 if (!text_database_)
1804 return;
1805 text_database_->AddPageContents(url, contents);
1806 }
1807
1808 void HistoryBackend::SetPageThumbnail( 1639 void HistoryBackend::SetPageThumbnail(
1809 const GURL& url, 1640 const GURL& url,
1810 const gfx::Image* thumbnail, 1641 const gfx::Image* thumbnail,
1811 const ThumbnailScore& score) { 1642 const ThumbnailScore& score) {
1812 if (!db_ || !thumbnail_db_) 1643 if (!db_ || !thumbnail_db_)
1813 return; 1644 return;
1814 1645
1815 URLRow url_row; 1646 URLRow url_row;
1816 URLID url_id = db_->GetRowForURL(url, &url_row); 1647 URLID url_id = db_->GetRowForURL(url, &url_row);
1817 if (url_id) { 1648 if (url_id) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1881 if (db_) { 1712 if (db_) {
1882 // If there is no thumbnail DB, we can still record a successful migration. 1713 // If there is no thumbnail DB, we can still record a successful migration.
1883 if (thumbnail_db_) { 1714 if (thumbnail_db_) {
1884 thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(), 1715 thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(),
1885 GetFaviconsFileName()); 1716 GetFaviconsFileName());
1886 } 1717 }
1887 db_->ThumbnailMigrationDone(); 1718 db_->ThumbnailMigrationDone();
1888 } 1719 }
1889 } 1720 }
1890 1721
1722 void HistoryBackend::DeleteFTSIndexDatabases() {
1723 // Find files on disk matching the text databases file pattern so we can
1724 // quickly test for and delete them.
1725 base::FilePath::StringType filepattern =
1726 FILE_PATH_LITERAL("History Index *");
1727 base::FileEnumerator enumerator(
1728 history_dir_, false, base::FileEnumerator::FILES, filepattern);
1729 int num_databases_deleted = 0;
1730 base::FilePath current_file;
1731 while (!(current_file = enumerator.Next()).empty()) {
1732 if (sql::Connection::Delete(current_file))
1733 num_databases_deleted++;
1734 }
1735 UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1736 num_databases_deleted);
1737 }
1738
1891 bool HistoryBackend::GetThumbnailFromOlderRedirect( 1739 bool HistoryBackend::GetThumbnailFromOlderRedirect(
1892 const GURL& page_url, 1740 const GURL& page_url,
1893 std::vector<unsigned char>* data) { 1741 std::vector<unsigned char>* data) {
1894 // Look at a few previous visit sessions. 1742 // Look at a few previous visit sessions.
1895 VisitVector older_sessions; 1743 VisitVector older_sessions;
1896 URLID page_url_id = db_->GetRowForURL(page_url, NULL); 1744 URLID page_url_id = db_->GetRowForURL(page_url, NULL);
1897 static const int kVisitsToSearchForThumbnail = 4; 1745 static const int kVisitsToSearchForThumbnail = 4;
1898 db_->GetMostRecentVisitsForURL( 1746 db_->GetMostRecentVisitsForURL(
1899 page_url_id, kVisitsToSearchForThumbnail, &older_sessions); 1747 page_url_id, kVisitsToSearchForThumbnail, &older_sessions);
1900 1748
(...skipping 746 matching lines...) Expand 10 before | Expand all | Expand 10 after
2647 thumbnail_db_->CommitTransaction(); 2495 thumbnail_db_->CommitTransaction();
2648 DCHECK(thumbnail_db_->transaction_nesting() == 0) << 2496 DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
2649 "Somebody left a transaction open"; 2497 "Somebody left a transaction open";
2650 thumbnail_db_->BeginTransaction(); 2498 thumbnail_db_->BeginTransaction();
2651 } 2499 }
2652 2500
2653 if (archived_db_) { 2501 if (archived_db_) {
2654 archived_db_->CommitTransaction(); 2502 archived_db_->CommitTransaction();
2655 archived_db_->BeginTransaction(); 2503 archived_db_->BeginTransaction();
2656 } 2504 }
2657
2658 if (text_database_) {
2659 text_database_->CommitTransaction();
2660 text_database_->BeginTransaction();
2661 }
2662 } 2505 }
2663 2506
2664 void HistoryBackend::ScheduleCommit() { 2507 void HistoryBackend::ScheduleCommit() {
2665 if (scheduled_commit_.get()) 2508 if (scheduled_commit_.get())
2666 return; 2509 return;
2667 scheduled_commit_ = new CommitLaterTask(this); 2510 scheduled_commit_ = new CommitLaterTask(this);
2668 base::MessageLoop::current()->PostDelayedTask( 2511 base::MessageLoop::current()->PostDelayedTask(
2669 FROM_HERE, 2512 FROM_HERE,
2670 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()), 2513 base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
2671 base::TimeDelta::FromSeconds(kCommitIntervalSeconds)); 2514 base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
2882 bool success = db_->Raze(); 2725 bool success = db_->Raze();
2883 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success); 2726 UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
2884 2727
2885 #if defined(OS_ANDROID) 2728 #if defined(OS_ANDROID)
2886 // Release AndroidProviderBackend before other objects. 2729 // Release AndroidProviderBackend before other objects.
2887 android_provider_backend_.reset(); 2730 android_provider_backend_.reset();
2888 #endif 2731 #endif
2889 2732
2890 // The expirer keeps tabs on the active databases. Tell it about the 2733 // The expirer keeps tabs on the active databases. Tell it about the
2891 // databases which will be closed. 2734 // databases which will be closed.
2892 expirer_.SetDatabases(NULL, NULL, NULL, NULL); 2735 expirer_.SetDatabases(NULL, NULL, NULL);
2893 2736
2894 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases(). 2737 // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
2895 db_->BeginTransaction(); 2738 db_->BeginTransaction();
2896 CloseAllDatabases(); 2739 CloseAllDatabases();
2897 } 2740 }
2898 2741
2899 void HistoryBackend::ProcessDBTask( 2742 void HistoryBackend::ProcessDBTask(
2900 scoped_refptr<HistoryDBTaskRequest> request) { 2743 scoped_refptr<HistoryDBTaskRequest> request) {
2901 DCHECK(request.get()); 2744 DCHECK(request.get());
2902 if (request->canceled()) 2745 if (request->canceled())
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
2972 // We continue in this error case. If the user wants to delete their 2815 // We continue in this error case. If the user wants to delete their
2973 // history, we should delete as much as we can. 2816 // history, we should delete as much as we can.
2974 } 2817 }
2975 2818
2976 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore, 2819 // ClearAllMainHistory will change the IDs of the URLs in kept_urls. Therfore,
2977 // we clear the list afterwards to make sure nobody uses this invalid data. 2820 // we clear the list afterwards to make sure nobody uses this invalid data.
2978 if (!ClearAllMainHistory(kept_urls)) 2821 if (!ClearAllMainHistory(kept_urls))
2979 LOG(ERROR) << "Main history could not be cleared"; 2822 LOG(ERROR) << "Main history could not be cleared";
2980 kept_urls.clear(); 2823 kept_urls.clear();
2981 2824
2982 // Delete FTS files & archived history. 2825 // Delete archived history.
2983 if (text_database_) {
2984 // We assume that the text database has one transaction on them that we need
2985 // to close & restart (the long-running history transaction).
2986 text_database_->CommitTransaction();
2987 text_database_->DeleteAll();
2988 text_database_->BeginTransaction();
2989 }
2990
2991 if (archived_db_) { 2826 if (archived_db_) {
2992 // Close the database and delete the file. 2827 // Close the database and delete the file.
2993 archived_db_.reset(); 2828 archived_db_.reset();
2994 base::FilePath archived_file_name = GetArchivedFileName(); 2829 base::FilePath archived_file_name = GetArchivedFileName();
2995 sql::Connection::Delete(archived_file_name); 2830 sql::Connection::Delete(archived_file_name);
2996 2831
2997 // Now re-initialize the database (which may fail). 2832 // Now re-initialize the database (which may fail).
2998 archived_db_.reset(new ArchivedDatabase()); 2833 archived_db_.reset(new ArchivedDatabase());
2999 if (!archived_db_->Init(archived_file_name)) { 2834 if (!archived_db_->Init(archived_file_name)) {
3000 LOG(WARNING) << "Could not initialize the archived database."; 2835 LOG(WARNING) << "Could not initialize the archived database.";
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
3150 int rank = kPageVisitStatsMaxTopSites; 2985 int rank = kPageVisitStatsMaxTopSites;
3151 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url); 2986 std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
3152 if (it != most_visited_urls_map_.end()) 2987 if (it != most_visited_urls_map_.end())
3153 rank = (*it).second; 2988 rank = (*it).second;
3154 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank", 2989 UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
3155 rank, kPageVisitStatsMaxTopSites + 1); 2990 rank, kPageVisitStatsMaxTopSites + 1);
3156 } 2991 }
3157 #endif 2992 #endif
3158 2993
3159 } // namespace history 2994 } // namespace history
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698