• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DatabaseStringTable(const std::string & table)19 DatabaseStringTable::DatabaseStringTable(const std::string& table)
20     : table_(table) {}
21 
~DatabaseStringTable()22 DatabaseStringTable::~DatabaseStringTable() {}
23 
Initialize(sql::Connection * connection)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 
StringToInt(sql::Connection * connection,const std::string & value,int64 * id)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 
IntToString(sql::Connection * connection,int64 id,std::string * value)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 
ClearCache()110 void DatabaseStringTable::ClearCache() {
111   id_to_value_.clear();
112   value_to_id_.clear();
113 }
114 
PruneCache()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