Home | History | Annotate | Download | only in history
      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 
     12 namespace history {
     13 
     14 namespace {
     15 
     16 static const int kCurrentVersionNumber = 4;
     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 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 
     53 bool 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 
     77 void ArchivedDatabase::TrimMemory(bool aggressively) {
     78   db_.TrimMemory(aggressively);
     79 }
     80 
     81 void ArchivedDatabase::BeginTransaction() {
     82   db_.BeginTransaction();
     83 }
     84 
     85 void ArchivedDatabase::CommitTransaction() {
     86   db_.CommitTransaction();
     87 }
     88 
     89 sql::Connection& ArchivedDatabase::GetDB() {
     90   return db_;
     91 }
     92 
     93 // static
     94 int ArchivedDatabase::GetCurrentVersion() {
     95   return kCurrentVersionNumber;
     96 }
     97 
     98 // Migration -------------------------------------------------------------------
     99 
    100 sql::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