• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/history/core/browser/in_memory_database.h"
6 
7 #include "base/files/file_path.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/time/time.h"
12 #include "build/build_config.h"
13 
14 namespace history {
15 
InMemoryDatabase()16 InMemoryDatabase::InMemoryDatabase() : URLDatabase() {
17 }
18 
~InMemoryDatabase()19 InMemoryDatabase::~InMemoryDatabase() {
20 }
21 
InitDB()22 bool InMemoryDatabase::InitDB() {
23   // Set the database page size to 4K for better performance.
24   db_.set_page_size(4096);
25 
26   if (!db_.OpenInMemory()) {
27     NOTREACHED() << "Cannot open databse " << GetDB().GetErrorMessage();
28     return false;
29   }
30 
31   // No reason to leave data behind in memory when rows are removed.
32   ignore_result(db_.Execute("PRAGMA auto_vacuum=1"));
33 
34   // Ensure this is really an in-memory-only cache.
35   ignore_result(db_.Execute("PRAGMA temp_store=MEMORY"));
36 
37   // Create the URL table, but leave it empty for now.
38   if (!CreateURLTable(false)) {
39     NOTREACHED() << "Unable to create table";
40     db_.Close();
41     return false;
42   }
43 
44   // Create the keyword search terms table.
45   if (!InitKeywordSearchTermsTable()) {
46     NOTREACHED() << "Unable to create keyword search terms";
47     db_.Close();
48     return false;
49   }
50 
51   return true;
52 }
53 
InitFromScratch()54 bool InMemoryDatabase::InitFromScratch() {
55   if (!InitDB())
56     return false;
57 
58   // InitDB doesn't create the index so in the disk-loading case, it can be
59   // added afterwards.
60   CreateMainURLIndex();
61   CreateKeywordSearchTermsIndices();
62   return true;
63 }
64 
InitFromDisk(const base::FilePath & history_name)65 bool InMemoryDatabase::InitFromDisk(const base::FilePath& history_name) {
66   if (!InitDB())
67     return false;
68 
69   // Attach to the history database on disk.  (We can't ATTACH in the middle of
70   // a transaction.)
71   sql::Statement attach(GetDB().GetUniqueStatement("ATTACH ? AS history"));
72 #if defined(OS_POSIX)
73   attach.BindString(0, history_name.value());
74 #else
75   attach.BindString(0, base::WideToUTF8(history_name.value()));
76 #endif
77   if (!attach.Run())
78     return false;
79 
80   // Copy URL data to memory.
81   base::TimeTicks begin_load = base::TimeTicks::Now();
82   if (!db_.Execute(
83       "INSERT INTO urls SELECT * FROM history.urls WHERE typed_count > 0")) {
84     // Unable to get data from the history database. This is OK, the file may
85     // just not exist yet.
86   }
87   base::TimeTicks end_load = base::TimeTicks::Now();
88   UMA_HISTOGRAM_MEDIUM_TIMES("History.InMemoryDBPopulate",
89                              end_load - begin_load);
90   UMA_HISTOGRAM_COUNTS("History.InMemoryDBItemCount", db_.GetLastChangeCount());
91 
92   {
93     // This calculation should be fast (since it's on an in-memory DB with
94     // an average of only 35 rows).
95     sql::Statement visit_count(db_.GetUniqueStatement(
96         "SELECT sum(visit_count) FROM urls"));
97     if (visit_count.Step()) {
98       UMA_HISTOGRAM_COUNTS("History.InMemoryTypedUrlVisitCount",
99                            visit_count.ColumnInt(0));
100     }
101   }
102 
103   // Insert keyword search related URLs.
104   begin_load = base::TimeTicks::Now();
105   if (!db_.Execute(
106       "INSERT OR IGNORE INTO urls SELECT u.id, u.url, u.title, u.visit_count, "
107       "u.typed_count, u.last_visit_time, u.hidden, u.favicon_id "
108       "FROM history.urls u JOIN history.keyword_search_terms kst "
109       "WHERE u.typed_count = 0 AND u.id = kst.url_id")) {
110     // Unable to get data from the history database. This is OK, the file may
111     // just not exist yet.
112   }
113   end_load = base::TimeTicks::Now();
114   UMA_HISTOGRAM_MEDIUM_TIMES("History.InMemoryDBKeywordURLPopulate",
115                              end_load - begin_load);
116   UMA_HISTOGRAM_COUNTS("History.InMemoryDBKeywordURLItemCount",
117                        db_.GetLastChangeCount());
118 
119   // Copy search terms to memory.
120   begin_load = base::TimeTicks::Now();
121   if (!db_.Execute(
122       "INSERT INTO keyword_search_terms SELECT * FROM "
123       "history.keyword_search_terms")) {
124     // Unable to get data from the history database. This is OK, the file may
125     // just not exist yet.
126   }
127   end_load = base::TimeTicks::Now();
128   UMA_HISTOGRAM_MEDIUM_TIMES("History.InMemoryDBKeywordTermsPopulate",
129                              end_load - begin_load);
130   UMA_HISTOGRAM_COUNTS("History.InMemoryDBKeywordTermsCount",
131                        db_.GetLastChangeCount());
132 
133   // Detach from the history database on disk.
134   if (!db_.Execute("DETACH history")) {
135     NOTREACHED() << "Unable to detach from history database.";
136     return false;
137   }
138 
139   // Index the table, this is faster than creating the index first and then
140   // inserting into it.
141   CreateMainURLIndex();
142   CreateKeywordSearchTermsIndices();
143 
144   return true;
145 }
146 
GetDB()147 sql::Connection& InMemoryDatabase::GetDB() {
148   return db_;
149 }
150 
151 }  // namespace history
152