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 <algorithm> 6 #include <string> 7 8 #include "app/sql/transaction.h" 9 #include "base/string_util.h" 10 #include "chrome/browser/history/archived_database.h" 11 12 namespace history { 13 14 namespace { 15 16 static const int kCurrentVersionNumber = 3; 17 static const int kCompatibleVersionNumber = 2; 18 19 } // namespace 20 21 ArchivedDatabase::ArchivedDatabase() { 22 } 23 24 ArchivedDatabase::~ArchivedDatabase() { 25 } 26 27 bool ArchivedDatabase::Init(const FilePath& file_name) { 28 // Set the database page size to something a little larger to give us 29 // better performance (we're typically seek rather than bandwidth limited). 30 // This only has an effect before any tables have been created, otherwise 31 // this is a NOP. Must be a power of 2 and a max of 8192. 32 db_.set_page_size(4096); 33 34 // Don't use very much memory caching this database. We seldom use it for 35 // anything important. 36 db_.set_cache_size(64); 37 38 // Run the database in exclusive mode. Nobody else should be accessing the 39 // database while we're running, and this will give somewhat improved perf. 40 db_.set_exclusive_locking(); 41 42 if (!db_.Open(file_name)) 43 return false; 44 45 sql::Transaction transaction(&db_); 46 if (!transaction.Begin()) { 47 db_.Close(); 48 return false; 49 } 50 51 // Version check. 52 if (!meta_table_.Init(&db_, kCurrentVersionNumber, 53 kCompatibleVersionNumber)) { 54 db_.Close(); 55 return false; 56 } 57 58 // Create the tables. 59 if (!CreateURLTable(false) || !InitVisitTable() || 60 !InitKeywordSearchTermsTable()) { 61 db_.Close(); 62 return false; 63 } 64 CreateMainURLIndex(); 65 CreateKeywordSearchTermsIndices(); 66 67 if (EnsureCurrentVersion() != sql::INIT_OK) { 68 db_.Close(); 69 return false; 70 } 71 72 return transaction.Commit(); 73 } 74 75 void ArchivedDatabase::BeginTransaction() { 76 db_.BeginTransaction(); 77 } 78 79 void ArchivedDatabase::CommitTransaction() { 80 db_.CommitTransaction(); 81 } 82 83 sql::Connection& ArchivedDatabase::GetDB() { 84 return db_; 85 } 86 87 // Migration ------------------------------------------------------------------- 88 89 sql::InitStatus ArchivedDatabase::EnsureCurrentVersion() { 90 // We can't read databases newer than we were designed for. 91 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { 92 LOG(WARNING) << "Archived database is too new."; 93 return sql::INIT_TOO_NEW; 94 } 95 96 // NOTICE: If you are changing structures for things shared with the archived 97 // history file like URLs, visits, or downloads, that will need migration as 98 // well. Instead of putting such migration code in this class, it should be 99 // in the corresponding file (url_database.cc, etc.) and called from here and 100 // from the archived_database.cc. 101 102 int cur_version = meta_table_.GetVersionNumber(); 103 if (cur_version == 1) { 104 if (!DropStarredIDFromURLs()) { 105 LOG(WARNING) << "Unable to update archived database to version 2."; 106 return sql::INIT_FAILURE; 107 } 108 ++cur_version; 109 meta_table_.SetVersionNumber(cur_version); 110 meta_table_.SetCompatibleVersionNumber( 111 std::min(cur_version, kCompatibleVersionNumber)); 112 } 113 114 if (cur_version == 2) { 115 // This is the version prior to adding visit_source table. 116 ++cur_version; 117 meta_table_.SetVersionNumber(cur_version); 118 } 119 120 // Put future migration cases here. 121 122 // When the version is too old, we just try to continue anyway, there should 123 // not be a released product that makes a database too old for us to handle. 124 LOG_IF(WARNING, cur_version < kCurrentVersionNumber) << 125 "Archived database version " << cur_version << " is too old to handle."; 126 127 return sql::INIT_OK; 128 } 129 } // namespace history 130