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 16 InMemoryDatabase::InMemoryDatabase() : URLDatabase() { 17 } 18 19 InMemoryDatabase::~InMemoryDatabase() { 20 } 21 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 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 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 147 sql::Connection& InMemoryDatabase::GetDB() { 148 return db_; 149 } 150 151 } // namespace history 152