1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
// 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/connection.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::Connection* 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::Connection* 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::Connection* 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
|