1ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// found in the LICENSE file. 4ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 5ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chrome/browser/extensions/activity_log/database_string_table.h" 6ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 7ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/strings/stringprintf.h" 8ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "sql/connection.h" 9ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "sql/statement.h" 10ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 11ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochusing base::StringPrintf; 12ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 13ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochnamespace extensions { 14ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// A target maximum size (in number of entries) for the mapping tables. If the 16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// cache would grow larger than this, the size should be reduced. 17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)static const size_t kMaximumCacheSize = 1000; 18424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 19ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochDatabaseStringTable::DatabaseStringTable(const std::string& table) 20ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch : table_(table) {} 21ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 22ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochDatabaseStringTable::~DatabaseStringTable() {} 23ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 24ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochbool DatabaseStringTable::Initialize(sql::Connection* connection) { 25ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!connection->DoesTableExist(table_.c_str())) { 26ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return connection->Execute(StringPrintf( 27ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch "CREATE TABLE %s (id INTEGER PRIMARY KEY, value TEXT NOT NULL); " 28ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch "CREATE UNIQUE INDEX %s_index ON %s(value)", 29ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch table_.c_str(), 30ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch table_.c_str(), 31ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch table_.c_str()).c_str()); 32ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } else { 33ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return true; 34ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 35ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 36ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 37ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochbool DatabaseStringTable::StringToInt(sql::Connection* connection, 38ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch const std::string& value, 39ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch int64* id) { 40ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch std::map<std::string, int64>::const_iterator lookup = 41ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch value_to_id_.find(value); 42ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (lookup != value_to_id_.end()) { 43ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch *id = lookup->second; 44ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return true; 45ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 46ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 47424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // We will be adding data to the cache below--check the cache size now and 48424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // reduce it if needed. 49424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) PruneCache(); 50424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 51ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // Operate on the assumption that the cache does a good job on 52ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // frequently-used strings--if there is a cache miss, first act on the 53ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // assumption that the string is not in the database either. 54ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch sql::Statement update(connection->GetUniqueStatement( 55ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch StringPrintf("INSERT OR IGNORE INTO %s(value) VALUES (?)", table_.c_str()) 56ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch .c_str())); 57ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch update.BindString(0, value); 58ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!update.Run()) 59ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return false; 60ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 61ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (connection->GetLastChangeCount() == 1) { 62ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch *id = connection->GetLastInsertRowId(); 63ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch id_to_value_[*id] = value; 64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch value_to_id_[value] = *id; 65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return true; 66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 67ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 68ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // The specified string may have already existed in the database, in which 69ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // case the insert above will have been ignored. If this happens, do a 70ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // lookup to find the old value. 71ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch sql::Statement query(connection->GetUniqueStatement( 72ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch StringPrintf("SELECT id FROM %s WHERE value = ?", table_.c_str()) 73ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch .c_str())); 74ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch query.BindString(0, value); 75ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!query.Step()) 76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return false; 77ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch *id = query.ColumnInt64(0); 78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch id_to_value_[*id] = value; 79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch value_to_id_[value] = *id; 80ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return true; 81ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 82ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 83ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochbool DatabaseStringTable::IntToString(sql::Connection* connection, 84ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch int64 id, 85ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch std::string* value) { 86ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch std::map<int64, std::string>::const_iterator lookup = 87ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch id_to_value_.find(id); 88ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (lookup != id_to_value_.end()) { 89ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch *value = lookup->second; 90ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return true; 91ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 92ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 93424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // We will be adding data to the cache below--check the cache size now and 94424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // reduce it if needed. 95424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) PruneCache(); 96424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 97ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch sql::Statement query(connection->GetUniqueStatement( 98ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch StringPrintf("SELECT value FROM %s WHERE id = ?", table_.c_str()) 99ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch .c_str())); 100ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch query.BindInt64(0, id); 101ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!query.Step()) 102ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return false; 103ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 104ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch *value = query.ColumnString(0); 105ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch id_to_value_[id] = *value; 106ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch value_to_id_[*value] = id; 107ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return true; 108ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 109ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 110ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid DatabaseStringTable::ClearCache() { 111ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch id_to_value_.clear(); 112ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch value_to_id_.clear(); 113ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 114ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 115424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void DatabaseStringTable::PruneCache() { 116424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (id_to_value_.size() <= kMaximumCacheSize && 117424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) value_to_id_.size() <= kMaximumCacheSize) 118424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return; 119424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 120424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // TODO(mvrable): Perhaps implement a more intelligent caching policy. For 121424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // now, to limit memory usage we simply clear the entire cache when it would 122424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // become too large. Data will be brought back in from the database as 123424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // needed. 124424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ClearCache(); 125424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 126424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 127ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} // namespace extensions 128