blob: ee755d3dde0d75fe073f853e0380fe2b913a5fa2 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// 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/strcat.h"
#include "extensions/buildflags/buildflags.h"
#include "sql/database.h"
#include "sql/statement.h"
static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
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() = default;
bool DatabaseStringTable::Initialize(sql::Database* connection) {
if (!connection->DoesTableExist(table_.c_str())) {
return connection->Execute(base::StrCat(
{"CREATE TABLE ", table_,
"(id INTEGER PRIMARY KEY, value TEXT NOT NULL)"})) &&
connection->Execute(base::StrCat({"CREATE UNIQUE INDEX ", table_,
"_index ON ", table_, "(value)"}));
}
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(
base::StrCat({"INSERT OR IGNORE INTO ", table_, "(value) VALUES (?)"})));
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(
base::StrCat({"SELECT id FROM ", table_, " WHERE value = ?"})));
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(
base::StrCat({"SELECT value FROM ", table_, " WHERE id = ?"})));
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