Home | History | Annotate | Download | only in activity_log
      1 // Copyright 2013 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/extensions/activity_log/database_string_table.h"
      6 
      7 #include "base/strings/stringprintf.h"
      8 #include "sql/connection.h"
      9 #include "sql/statement.h"
     10 
     11 using base::StringPrintf;
     12 
     13 namespace extensions {
     14 
     15 // A target maximum size (in number of entries) for the mapping tables.  If the
     16 // cache would grow larger than this, the size should be reduced.
     17 static const size_t kMaximumCacheSize = 1000;
     18 
     19 DatabaseStringTable::DatabaseStringTable(const std::string& table)
     20     : table_(table) {}
     21 
     22 DatabaseStringTable::~DatabaseStringTable() {}
     23 
     24 bool DatabaseStringTable::Initialize(sql::Connection* connection) {
     25   if (!connection->DoesTableExist(table_.c_str())) {
     26     return connection->Execute(StringPrintf(
     27         "CREATE TABLE %s (id INTEGER PRIMARY KEY, value TEXT NOT NULL); "
     28         "CREATE UNIQUE INDEX %s_index ON %s(value)",
     29         table_.c_str(),
     30         table_.c_str(),
     31         table_.c_str()).c_str());
     32   } else {
     33     return true;
     34   }
     35 }
     36 
     37 bool DatabaseStringTable::StringToInt(sql::Connection* connection,
     38                                       const std::string& value,
     39                                       int64* id) {
     40   std::map<std::string, int64>::const_iterator lookup =
     41       value_to_id_.find(value);
     42   if (lookup != value_to_id_.end()) {
     43     *id = lookup->second;
     44     return true;
     45   }
     46 
     47   // We will be adding data to the cache below--check the cache size now and
     48   // reduce it if needed.
     49   PruneCache();
     50 
     51   // Operate on the assumption that the cache does a good job on
     52   // frequently-used strings--if there is a cache miss, first act on the
     53   // assumption that the string is not in the database either.
     54   sql::Statement update(connection->GetUniqueStatement(
     55       StringPrintf("INSERT OR IGNORE INTO %s(value) VALUES (?)", table_.c_str())
     56           .c_str()));
     57   update.BindString(0, value);
     58   if (!update.Run())
     59     return false;
     60 
     61   if (connection->GetLastChangeCount() == 1) {
     62     *id = connection->GetLastInsertRowId();
     63     id_to_value_[*id] = value;
     64     value_to_id_[value] = *id;
     65     return true;
     66   }
     67 
     68   // The specified string may have already existed in the database, in which
     69   // case the insert above will have been ignored.  If this happens, do a
     70   // lookup to find the old value.
     71   sql::Statement query(connection->GetUniqueStatement(
     72       StringPrintf("SELECT id FROM %s WHERE value = ?", table_.c_str())
     73           .c_str()));
     74   query.BindString(0, value);
     75   if (!query.Step())
     76     return false;
     77   *id = query.ColumnInt64(0);
     78   id_to_value_[*id] = value;
     79   value_to_id_[value] = *id;
     80   return true;
     81 }
     82 
     83 bool DatabaseStringTable::IntToString(sql::Connection* connection,
     84                                       int64 id,
     85                                       std::string* value) {
     86   std::map<int64, std::string>::const_iterator lookup =
     87       id_to_value_.find(id);
     88   if (lookup != id_to_value_.end()) {
     89     *value = lookup->second;
     90     return true;
     91   }
     92 
     93   // We will be adding data to the cache below--check the cache size now and
     94   // reduce it if needed.
     95   PruneCache();
     96 
     97   sql::Statement query(connection->GetUniqueStatement(
     98       StringPrintf("SELECT value FROM %s WHERE id = ?", table_.c_str())
     99           .c_str()));
    100   query.BindInt64(0, id);
    101   if (!query.Step())
    102     return false;
    103 
    104   *value = query.ColumnString(0);
    105   id_to_value_[id] = *value;
    106   value_to_id_[*value] = id;
    107   return true;
    108 }
    109 
    110 void DatabaseStringTable::ClearCache() {
    111   id_to_value_.clear();
    112   value_to_id_.clear();
    113 }
    114 
    115 void DatabaseStringTable::PruneCache() {
    116   if (id_to_value_.size() <= kMaximumCacheSize &&
    117       value_to_id_.size() <= kMaximumCacheSize)
    118     return;
    119 
    120   // TODO(mvrable): Perhaps implement a more intelligent caching policy.  For
    121   // now, to limit memory usage we simply clear the entire cache when it would
    122   // become too large.  Data will be brought back in from the database as
    123   // needed.
    124   ClearCache();
    125 }
    126 
    127 }  // namespace extensions
    128