OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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/predictors/predictor_database.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/file_util.h" | |
9 #include "base/logging.h" | |
10 #include "base/metrics/histogram.h" | |
11 #include "base/stringprintf.h" | |
12 #include "base/utf_string_conversions.h" | |
13 #include "chrome/browser/profiles/profile.h" | |
14 #include "chrome/common/guid.h" | |
15 #include "content/public/browser/browser_thread.h" | |
16 #include "sql/statement.h" | |
17 | |
18 namespace { | |
19 | |
20 const char kAutocompletePredictorTableName[] = "network_action_predictor"; | |
21 const FilePath::CharType kPredictorDatabaseName[] = | |
22 FILE_PATH_LITERAL("Network Action Predictor"); | |
dominich
2012/03/06 16:42:13
Consider renaming this. Two options: Delete the ol
Shishir
2012/03/14 21:14:37
Adding a todo for this. Once more ppl are ok with
| |
23 | |
24 // The maximum length allowed for strings in the database. | |
25 const size_t kMaxDataLength = 2048; | |
26 | |
27 void LogDatabaseStats(const FilePath& db_path, sql::Connection* db) { | |
28 int64 db_size; | |
29 bool success = file_util::GetFileSize(db_path, &db_size); | |
30 DCHECK(success) << "Failed to get file size for " << db_path.value(); | |
31 UMA_HISTOGRAM_MEMORY_KB("Predictor.DatabaseSizeKB", | |
dominich
2012/03/06 16:42:13
histogram name should be AutocompleteActionPredict
Shishir
2012/03/14 21:14:37
This is the histogram for the overall database so
| |
32 static_cast<int>(db_size / 1024)); | |
33 | |
34 sql::Statement count_statement(db->GetUniqueStatement( | |
35 base::StringPrintf("SELECT count(id) FROM %s", | |
36 kAutocompletePredictorTableName).c_str())); | |
37 if (!count_statement.Step()) | |
38 return; | |
39 UMA_HISTOGRAM_COUNTS("AutocompleteActionPredictor.DatabaseRowCount", | |
40 count_statement.ColumnInt(0)); | |
41 } | |
42 | |
43 } // namespace | |
44 | |
45 namespace predictors { | |
46 | |
47 PredictorTableBase::PredictorTableBase() : db_(NULL) { | |
48 } | |
49 | |
50 PredictorTableBase::~PredictorTableBase() { | |
51 } | |
52 | |
53 void PredictorTableBase::SetCancelled() { | |
54 cancelled_.Set(); | |
55 } | |
56 | |
57 void PredictorTableBase::Initialize(sql::Connection* db) { | |
58 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
59 | |
60 db_ = db; | |
61 CreateTableIfNonExistant(); | |
62 } | |
63 | |
64 | |
65 AutocompleteActionPredictorTable::Row::Row() | |
66 : number_of_hits(0), | |
67 number_of_misses(0) { | |
68 } | |
69 | |
70 AutocompleteActionPredictorTable::Row::Row(const Row::Id& id, | |
71 const string16& user_text, | |
72 const GURL& url, | |
73 int number_of_hits, | |
74 int number_of_misses) | |
75 : id(id), | |
76 user_text(user_text), | |
77 url(url), | |
78 number_of_hits(number_of_hits), | |
79 number_of_misses(number_of_misses) { | |
80 } | |
81 | |
82 AutocompleteActionPredictorTable::Row::Row(const Row& row) | |
83 : id(row.id), | |
84 user_text(row.user_text), | |
85 url(row.url), | |
86 number_of_hits(row.number_of_hits), | |
87 number_of_misses(row.number_of_misses) { | |
88 } | |
89 | |
90 void AutocompleteActionPredictorTable::GetRow(const Row::Id& id, Row* row) { | |
91 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
92 if (cancelled_.IsSet() || !db_) | |
93 return; | |
94 | |
95 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, | |
96 base::StringPrintf("SELECT * FROM %s WHERE id=?", | |
97 kAutocompletePredictorTableName).c_str())); | |
98 statement.BindString(0, id); | |
99 | |
100 bool success = StepAndInitializeRow(&statement, row); | |
101 DCHECK(success) << "Failed to get row " << id << " from " | |
102 << kAutocompletePredictorTableName; | |
103 } | |
104 | |
105 void AutocompleteActionPredictorTable::GetAllRows( | |
106 std::vector<AutocompleteActionPredictorTable::Row>* row_buffer) { | |
107 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
108 if (cancelled_.IsSet() || !db_) | |
109 return; | |
110 | |
111 CHECK(row_buffer); | |
112 row_buffer->clear(); | |
113 | |
114 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, | |
115 base::StringPrintf( | |
116 "SELECT * FROM %s", kAutocompletePredictorTableName).c_str())); | |
117 | |
118 Row row; | |
119 while (StepAndInitializeRow(&statement, &row)) | |
120 row_buffer->push_back(row); | |
121 } | |
122 | |
123 void AutocompleteActionPredictorTable::AddRow( | |
124 const AutocompleteActionPredictorTable::Row& row) { | |
125 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
126 if (cancelled_.IsSet() || !db_) | |
127 return; | |
128 | |
129 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, | |
130 base::StringPrintf( | |
131 "INSERT INTO %s " | |
132 "(id, user_text, url, number_of_hits, number_of_misses) " | |
133 "VALUES (?,?,?,?,?)", kAutocompletePredictorTableName).c_str())); | |
134 BindRowToStatement(row, &statement); | |
135 | |
136 bool success = statement.Run(); | |
137 DCHECK(success) << "Failed to insert row " << row.id << " into " | |
138 << kAutocompletePredictorTableName; | |
139 } | |
140 | |
141 void AutocompleteActionPredictorTable::UpdateRow( | |
142 const AutocompleteActionPredictorTable::Row& row) { | |
143 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
144 if (cancelled_.IsSet() || !db_) | |
145 return; | |
146 | |
147 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, | |
148 base::StringPrintf( | |
149 "UPDATE %s " | |
150 "SET id=?, user_text=?, url=?, number_of_hits=?, number_of_misses=? " | |
151 "WHERE id=?1", kAutocompletePredictorTableName).c_str())); | |
152 BindRowToStatement(row, &statement); | |
153 | |
154 statement.Run(); | |
155 DCHECK_GT(db_->GetLastChangeCount(), 0); | |
156 } | |
157 | |
158 void AutocompleteActionPredictorTable::AddAndUpdateRows( | |
159 const std::vector<Row>& rows_to_add, | |
dominich
2012/03/06 16:42:13
consider a typedef for std::vector<Row>
Shishir
2012/03/14 21:14:37
Done.
| |
160 const std::vector<Row>& rows_to_update) { | |
161 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
162 if (cancelled_.IsSet() || !db_) | |
163 return; | |
164 | |
165 db_->BeginTransaction(); | |
166 for (std::vector<Row>::const_iterator it = rows_to_add.begin(); | |
167 it != rows_to_add.end(); ++it) { | |
168 AddRow(*it); | |
169 } | |
170 for (std::vector<Row>::const_iterator it = rows_to_update.begin(); | |
171 it != rows_to_update.end(); ++it) { | |
172 AddRow(*it); | |
173 } | |
174 db_->CommitTransaction(); | |
175 } | |
176 | |
177 void AutocompleteActionPredictorTable::DeleteRow(const Row::Id& id) { | |
178 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
179 if (cancelled_.IsSet() || !db_) | |
180 return; | |
181 | |
182 DeleteRows(std::vector<Row::Id>(1, id)); | |
183 } | |
184 | |
185 void AutocompleteActionPredictorTable::DeleteRows( | |
186 const std::vector<Row::Id>& id_list) { | |
187 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
188 if (cancelled_.IsSet() || !db_) | |
189 return; | |
190 | |
191 sql::Statement statement(db_->GetUniqueStatement(base::StringPrintf( | |
192 "DELETE FROM %s WHERE id=?", | |
193 kAutocompletePredictorTableName).c_str())); | |
194 | |
195 db_->BeginTransaction(); | |
196 for (std::vector<Row::Id>::const_iterator it = id_list.begin(); | |
197 it != id_list.end(); ++it) { | |
198 statement.BindString(0, *it); | |
199 statement.Run(); | |
200 statement.Reset(); | |
201 } | |
202 db_->CommitTransaction(); | |
203 } | |
204 | |
205 void AutocompleteActionPredictorTable::DeleteAllRows() { | |
206 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
207 if (cancelled_.IsSet() || !db_) | |
208 return; | |
209 | |
210 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, | |
211 base::StringPrintf("DELETE FROM %s", | |
212 kAutocompletePredictorTableName).c_str())); | |
213 | |
214 statement.Run(); | |
215 } | |
216 | |
217 AutocompleteActionPredictorTable::AutocompleteActionPredictorTable() | |
218 : PredictorTableBase() { | |
219 } | |
220 | |
221 AutocompleteActionPredictorTable::~AutocompleteActionPredictorTable() { | |
222 } | |
223 | |
224 void AutocompleteActionPredictorTable::CreateTableIfNonExistant() { | |
225 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
226 if (cancelled_.IsSet() || !db_) | |
227 return; | |
228 | |
229 if (db_->DoesTableExist(kAutocompletePredictorTableName)) | |
230 return; | |
231 | |
232 bool success = db_->Execute(base::StringPrintf( | |
233 "CREATE TABLE %s ( " | |
234 "id TEXT PRIMARY KEY, " | |
235 "user_text TEXT, " | |
236 "url TEXT, " | |
237 "number_of_hits INTEGER, " | |
238 "number_of_misses INTEGER)", kAutocompletePredictorTableName).c_str()); | |
239 DCHECK(success) << "Failed to create " << kAutocompletePredictorTableName | |
240 << " table."; | |
241 } | |
242 | |
243 void AutocompleteActionPredictorTable::BindRowToStatement( | |
244 const Row& row, | |
245 sql::Statement* statement) { | |
246 DCHECK(guid::IsValidGUID(row.id)); | |
247 statement->BindString(0, row.id); | |
248 statement->BindString16(1, row.user_text.substr(0, kMaxDataLength)); | |
249 statement->BindString(2, row.url.spec().substr(0, kMaxDataLength)); | |
250 statement->BindInt(3, row.number_of_hits); | |
251 statement->BindInt(4, row.number_of_misses); | |
252 } | |
253 | |
254 bool AutocompleteActionPredictorTable::StepAndInitializeRow( | |
255 sql::Statement* statement, | |
256 Row* row) { | |
257 if (!statement->Step()) | |
258 return false; | |
259 | |
260 row->id = statement->ColumnString(0); | |
261 row->user_text = statement->ColumnString16(1); | |
262 row->url = GURL(statement->ColumnString(2)); | |
263 row->number_of_hits = statement->ColumnInt(3); | |
264 row->number_of_misses = statement->ColumnInt(4); | |
265 return true; | |
266 } | |
267 | |
268 | |
269 PredictorDatabase::PredictorDatabase(Profile* profile) | |
270 : db_path_(profile->GetPath().Append(kPredictorDatabaseName)), | |
271 autocomplete_table_(new AutocompleteActionPredictorTable()) { | |
272 } | |
273 | |
274 PredictorDatabase::~PredictorDatabase() { | |
275 } | |
276 | |
277 void PredictorDatabase::Initialize() { | |
278 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); | |
279 | |
280 db_.set_exclusive_locking(); | |
281 bool success = db_.Open(db_path_); | |
282 | |
283 if (!success) { | |
284 LOG(ERROR) << "Could not open predictor database @ " | |
285 << db_path_.AsUTF8Unsafe(); | |
286 return; | |
287 } | |
288 | |
289 autocomplete_table_->Initialize(&db_); | |
290 | |
291 LogDatabaseStats(db_path_, &db_); | |
292 } | |
293 | |
294 void PredictorDatabase::ShutdownOnUIThread() { | |
295 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
296 | |
297 autocomplete_table_->SetCancelled(); | |
dominich
2012/03/06 16:42:13
why do you need a method for this? cancelled_ is a
Shishir
2012/03/14 21:14:37
Done.
| |
298 } | |
299 | |
300 } // namespace predictors | |
OLD | NEW |