blob: 05c69af477a4bf04189d42df293c083e7bed387c [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/activity_log/database_string_table.h"
#include <stddef.h>
#include "base/strings/stringprintf.h"
#include "sql/database.h"
#include "sql/statement.h"
using base::StringPrintf;
namespace extensions {
// A target maximum size (in number of entries) for the mapping tables. If the
// cache would grow larger than this, the size should be reduced.
static const size_t kMaximumCacheSize = 1000;
DatabaseStringTable::DatabaseStringTable(const std::string& table)
: table_(table) {}
DatabaseStringTable::~DatabaseStringTable() {}
bool DatabaseStringTable::Initialize(sql::Database* connection) {
if (!connection->DoesTableExist(table_.c_str())) {
return connection->Execute(StringPrintf(
"CREATE TABLE %s (id INTEGER PRIMARY KEY, value TEXT NOT NULL); "
"CREATE UNIQUE INDEX %s_index ON %s(value)",
table_.c_str(),
table_.c_str(),
table_.c_str()).c_str());
} else {
return true;
}
}
bool DatabaseStringTable::StringToInt(sql::Database* connection,
const std::string& value,
int64_t* id) {
std::map<std::string, int64_t>::const_iterator lookup =
value_to_id_.find(value);
if (lookup != value_to_id_.end()) {
*id = lookup->second;
return true;
}
// We will be adding data to the cache below--check the cache size now and
// reduce it if needed.
PruneCache();
// Operate on the assumption that the cache does a good job on
// frequently-used strings--if there is a cache miss, first act on the
// assumption that the string is not in the database either.
sql::Statement update(connection->GetUniqueStatement(
StringPrintf("INSERT OR IGNORE INTO %s(value) VALUES (?)", table_.c_str())
.c_str()));
update.BindString(0, value);
if (!update.Run())
return false;
if (connection->GetLastChangeCount() == 1) {
*id = connection->GetLastInsertRowId();
id_to_value_[*id] = value;
value_to_id_[value] = *id;
return true;
}
// The specified string may have already existed in the database, in which
// case the insert above will have been ignored. If this happens, do a
// lookup to find the old value.
sql::Statement query(connection->GetUniqueStatement(
StringPrintf("SELECT id FROM %s WHERE value = ?", table_.c_str())
.c_str()));
query.BindString(0, value);
if (!query.Step())
return false;
*id = query.ColumnInt64(0);
id_to_value_[*id] = value;
value_to_id_[value] = *id;
return true;
}
bool DatabaseStringTable::IntToString(sql::Database* connection,
int64_t id,
std::string* value) {
std::map<int64_t, std::string>::const_iterator lookup = id_to_value_.find(id);
if (lookup != id_to_value_.end()) {
*value = lookup->second;
return true;
}
// We will be adding data to the cache below--check the cache size now and
// reduce it if needed.
PruneCache();
sql::Statement query(connection->GetUniqueStatement(
StringPrintf("SELECT value FROM %s WHERE id = ?", table_.c_str())
.c_str()));
query.BindInt64(0, id);
if (!query.Step())
return false;
*value = query.ColumnString(0);
id_to_value_[id] = *value;
value_to_id_[*value] = id;
return true;
}
void DatabaseStringTable::ClearCache() {
id_to_value_.clear();
value_to_id_.clear();
}
void DatabaseStringTable::PruneCache() {
if (id_to_value_.size() <= kMaximumCacheSize &&
value_to_id_.size() <= kMaximumCacheSize)
return;
// TODO(mvrable): Perhaps implement a more intelligent caching policy. For
// now, to limit memory usage we simply clear the entire cache when it would
// become too large. Data will be brought back in from the database as
// needed.
ClearCache();
}
} // namespace extensions