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 3// found in the LICENSE file. 4 5#include <algorithm> 6#include <string> 7 8#include "base/strings/string_util.h" 9#include "chrome/browser/history/archived_database.h" 10#include "sql/transaction.h" 11 12namespace history { 13 14namespace { 15 16static const int kCurrentVersionNumber = 4; 17static const int kCompatibleVersionNumber = 2; 18 19} // namespace 20 21ArchivedDatabase::ArchivedDatabase() { 22} 23 24ArchivedDatabase::~ArchivedDatabase() { 25} 26 27bool ArchivedDatabase::Init(const base::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 if (!InitTables()) { 46 db_.Close(); 47 return false; 48 } 49 50 return true; 51} 52 53bool ArchivedDatabase::InitTables() { 54 sql::Transaction transaction(&db_); 55 if (!transaction.Begin()) 56 return false; 57 58 // Version check. 59 if (!meta_table_.Init(&db_, kCurrentVersionNumber, 60 kCompatibleVersionNumber)) 61 return false; 62 63 // Create the tables. 64 if (!CreateURLTable(false) || !InitVisitTable() || 65 !InitKeywordSearchTermsTable()) 66 return false; 67 68 CreateMainURLIndex(); 69 CreateKeywordSearchTermsIndices(); 70 71 if (EnsureCurrentVersion() != sql::INIT_OK) 72 return false; 73 74 return transaction.Commit(); 75} 76 77void ArchivedDatabase::TrimMemory(bool aggressively) { 78 db_.TrimMemory(aggressively); 79} 80 81void ArchivedDatabase::BeginTransaction() { 82 db_.BeginTransaction(); 83} 84 85void ArchivedDatabase::CommitTransaction() { 86 db_.CommitTransaction(); 87} 88 89sql::Connection& ArchivedDatabase::GetDB() { 90 return db_; 91} 92 93// static 94int ArchivedDatabase::GetCurrentVersion() { 95 return kCurrentVersionNumber; 96} 97 98// Migration ------------------------------------------------------------------- 99 100sql::InitStatus ArchivedDatabase::EnsureCurrentVersion() { 101 // We can't read databases newer than we were designed for. 102 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { 103 LOG(WARNING) << "Archived database is too new."; 104 return sql::INIT_TOO_NEW; 105 } 106 107 // NOTICE: If you are changing structures for things shared with the archived 108 // history file like URLs, visits, or downloads, that will need migration as 109 // well. Instead of putting such migration code in this class, it should be 110 // in the corresponding file (url_database.cc, etc.) and called from here and 111 // from the archived_database.cc. 112 113 int cur_version = meta_table_.GetVersionNumber(); 114 if (cur_version == 1) { 115 if (!DropStarredIDFromURLs()) { 116 LOG(WARNING) << "Unable to update archived database to version 2."; 117 return sql::INIT_FAILURE; 118 } 119 ++cur_version; 120 meta_table_.SetVersionNumber(cur_version); 121 meta_table_.SetCompatibleVersionNumber( 122 std::min(cur_version, kCompatibleVersionNumber)); 123 } 124 125 if (cur_version == 2) { 126 // This is the version prior to adding visit_source table. 127 ++cur_version; 128 meta_table_.SetVersionNumber(cur_version); 129 } 130 131 if (cur_version == 3) { 132 // This is the version prior to adding the visit_duration field in visits 133 // database. We need to migrate the database. 134 if (!MigrateVisitsWithoutDuration()) { 135 LOG(WARNING) << "Unable to update archived database to version 4."; 136 return sql::INIT_FAILURE; 137 } 138 ++cur_version; 139 meta_table_.SetVersionNumber(cur_version); 140 } 141 142 // Put future migration cases here. 143 144 // When the version is too old, we just try to continue anyway, there should 145 // not be a released product that makes a database too old for us to handle. 146 LOG_IF(WARNING, cur_version < kCurrentVersionNumber) << 147 "Archived database version " << cur_version << " is too old to handle."; 148 149 return sql::INIT_OK; 150} 151} // namespace history 152