1 // Copyright (c) 2009 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 "chrome/browser/history/in_memory_database.h"
6
7 #include "base/file_path.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/time.h"
11 #include "base/utf_string_conversions.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 db_.Execute("PRAGMA auto_vacuum=1");
33
34 // Ensure this is really an in-memory-only cache.
35 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 FilePath & history_name)65 bool InMemoryDatabase::InitFromDisk(const 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 (!attach) {
73 NOTREACHED() << "Unable to attach to history database.";
74 return false;
75 }
76 #if defined(OS_POSIX)
77 attach.BindString(0, history_name.value());
78 #else
79 attach.BindString(0, WideToUTF8(history_name.value()));
80 #endif
81 if (!attach.Run()) {
82 NOTREACHED() << GetDB().GetErrorMessage();
83 return false;
84 }
85
86 // Copy URL data to memory.
87 base::TimeTicks begin_load = base::TimeTicks::Now();
88 if (!db_.Execute(
89 "INSERT INTO urls SELECT * FROM history.urls WHERE typed_count > 0")) {
90 // Unable to get data from the history database. This is OK, the file may
91 // just not exist yet.
92 }
93 base::TimeTicks end_load = base::TimeTicks::Now();
94 UMA_HISTOGRAM_MEDIUM_TIMES("History.InMemoryDBPopulate",
95 end_load - begin_load);
96 UMA_HISTOGRAM_COUNTS("History.InMemoryDBItemCount", db_.GetLastChangeCount());
97
98 // Insert keyword search related URLs.
99 begin_load = base::TimeTicks::Now();
100 if (!db_.Execute(
101 "INSERT INTO urls SELECT u.id, u.url, u.title, u.visit_count, "
102 "u.typed_count, u.last_visit_time, u.hidden, u.favicon_id "
103 "FROM history.urls u JOIN history.keyword_search_terms kst "
104 "WHERE u.typed_count = 0 AND u.id = kst.url_id")) {
105 // Unable to get data from the history database. This is OK, the file may
106 // just not exist yet.
107 }
108 end_load = base::TimeTicks::Now();
109 UMA_HISTOGRAM_MEDIUM_TIMES("History.InMemoryDBKeywordURLPopulate",
110 end_load - begin_load);
111 UMA_HISTOGRAM_COUNTS("History.InMemoryDBKeywordURLItemCount",
112 db_.GetLastChangeCount());
113
114 // Copy search terms to memory.
115 begin_load = base::TimeTicks::Now();
116 if (!db_.Execute(
117 "INSERT INTO keyword_search_terms SELECT * FROM "
118 "history.keyword_search_terms")) {
119 // Unable to get data from the history database. This is OK, the file may
120 // just not exist yet.
121 }
122 end_load = base::TimeTicks::Now();
123 UMA_HISTOGRAM_MEDIUM_TIMES("History.InMemoryDBKeywordTermsPopulate",
124 end_load - begin_load);
125 UMA_HISTOGRAM_COUNTS("History.InMemoryDBKeywordTermsCount",
126 db_.GetLastChangeCount());
127
128 // Detach from the history database on disk.
129 if (!db_.Execute("DETACH history")) {
130 NOTREACHED() << "Unable to detach from history database.";
131 return false;
132 }
133
134 // Index the table, this is faster than creating the index first and then
135 // inserting into it.
136 CreateMainURLIndex();
137 CreateKeywordSearchTermsIndices();
138
139 return true;
140 }
141
GetDB()142 sql::Connection& InMemoryDatabase::GetDB() {
143 return db_;
144 }
145
146 } // namespace history
147