Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(57)

Side by Side Diff: chrome/browser/history/in_memory_url_cache_database.cc

Issue 10837244: Replace HistoryQuickProvider protobuf-based caching with an SQLite-based database. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Tweak suppression. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(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/history/in_memory_url_cache_database.h"
6
7 #include <algorithm>
8 #include <functional>
9 #include <iterator>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/file_path.h"
14 #include "base/string_util.h"
15 #include "base/stringprintf.h"
16 #include "base/time.h"
17 #include "chrome/browser/diagnostics/sqlite_diagnostics.h"
18 #include "chrome/browser/history/url_database.h"
19 #include "chrome/browser/history/url_index_private_data.h"
20 #include "chrome/common/chrome_notification_types.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/notification_service.h"
23 #include "sql/diagnostic_error_delegate.h"
24 #include "sql/statement.h"
25 #include "sql/transaction.h"
26 #include "third_party/sqlite/sqlite3.h"
27
28 using content::BrowserThread;
29
30 namespace history {
31
32 namespace {
33
34 static const int kCurrentVersionNumber = 1;
35 static const int kCompatibleVersionNumber = 1;
36
37 const char* kWordsTableName = "words";
38 const char* kCharWordsTableName = "char_words";
39 const char* kWordHistoryTableName = "word_history";
40 const char* kURLsTableName = "urls";
41 const char* kURLWordStartsTableName = "url_word_starts";
42 const char* kTitleWordStartsTableName = "title_word_starts";
43
44 } // namespace
45
46 // Public Methods --------------------------------------------------------------
47
48 InMemoryURLCacheDatabase::InMemoryURLCacheDatabase()
49 : update_error_(SQLITE_OK),
50 shutdown_(false) {
51 }
52
53 InMemoryURLCacheDatabase::~InMemoryURLCacheDatabase() {}
54
55 bool InMemoryURLCacheDatabase::Init(
56 const FilePath& file_path,
57 const base::SequencedWorkerPool::SequenceToken& sequence_token) {
58 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
59 !BrowserThread::CurrentlyOn(BrowserThread::UI));
60 if (shutdown_)
61 return false;
62 sequence_token_ = sequence_token;
63 db_.set_error_delegate(GetErrorHandlerForHQPCacheDb());
64 // Don't use very much memory caching this database. We primarily use it
65 // as a backing store for existing in-memory data.
66 db_.set_cache_size(64);
67 db_.set_exclusive_locking();
68 if (!db_.Open(file_path)) {
69 UMA_HISTOGRAM_ENUMERATION("Sqlite.HQPCacheOpen.Error", db_.GetErrorCode(),
70 sql::kMaxSqliteError);
71 return false;
72 }
73 if (!InitDatabase()) {
74 db_.Close();
75 return false;
76 }
77 return true;
78 }
79
80 void InMemoryURLCacheDatabase::Shutdown() {
81 shutdown_ = true;
82 // Allow all outstanding sequenced database operations to complete.
83 PostSequencedDBTask(FROM_HERE,
84 base::Bind(&InMemoryURLCacheDatabase::ShutdownTask, this));
85 }
86
87 bool InMemoryURLCacheDatabase::RestorePrivateData(URLIndexPrivateData* data) {
88 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
89 !BrowserThread::CurrentlyOn(BrowserThread::UI));
90 return RestoreWords(data) && RestoreCharWords(data) &&
91 RestoreWordHistory(data) && RestoreURLs(data) && RestoreWordStarts(data);
92 }
93
94 bool InMemoryURLCacheDatabase::Reset() {
95 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
96 !BrowserThread::CurrentlyOn(BrowserThread::UI));
97 if (db_.Raze() && CreateTables())
98 return true;
99 UMA_HISTOGRAM_ENUMERATION("Sqlite.HQPCacheCreate.Error", db_.GetErrorCode(),
100 sql::kMaxSqliteError);
101 return false;
102 }
103
104 // Database Updating -----------------------------------------------------------
105
106 void InMemoryURLCacheDatabase::AddHistoryToURLs(history::HistoryID history_id,
107 const history::URLRow& row) {
108 PostSequencedDBTask(FROM_HERE,
109 base::Bind(&InMemoryURLCacheDatabase::AddHistoryToURLsTask, this,
110 history_id, row));
111 }
112
113 void InMemoryURLCacheDatabase::AddHistoryToWordHistory(WordID word_id,
114 HistoryID history_id) {
115 PostSequencedDBTask(FROM_HERE,
116 base::Bind(&InMemoryURLCacheDatabase::AddHistoryToWordHistoryTask, this,
117 word_id, history_id));
118 }
119
120 void InMemoryURLCacheDatabase::AddWordToWords(WordID word_id,
121 const string16& uni_word) {
122 PostSequencedDBTask(FROM_HERE,
123 base::Bind(&InMemoryURLCacheDatabase::AddWordToWordsTask, this, word_id,
124 uni_word));
125 }
126
127 void InMemoryURLCacheDatabase::AddWordToCharWords(char16 uni_char,
128 WordID word_id) {
129 PostSequencedDBTask(FROM_HERE,
130 base::Bind(&InMemoryURLCacheDatabase::AddWordToCharWordsTask, this,
131 uni_char, word_id));
132 }
133
134 void InMemoryURLCacheDatabase::AddRowWordStarts(
135 HistoryID history_id,
136 const RowWordStarts& row_word_starts) {
137 PostSequencedDBTask(FROM_HERE,
138 base::Bind(&InMemoryURLCacheDatabase::AddRowWordStartsTask, this,
139 history_id, row_word_starts));
140 }
141
142 void InMemoryURLCacheDatabase::RemoveHistoryIDFromURLs(HistoryID history_id) {
143 PostSequencedDBTask(FROM_HERE,
144 base::Bind(&InMemoryURLCacheDatabase::RemoveHistoryIDFromURLsTask, this,
145 history_id));
146 }
147
148 void InMemoryURLCacheDatabase::RemoveHistoryIDFromWordHistory(
149 HistoryID history_id) {
150 PostSequencedDBTask(FROM_HERE,
151 base::Bind(&InMemoryURLCacheDatabase::RemoveHistoryIDFromWordHistoryTask,
152 this, history_id));
153 }
154
155 void InMemoryURLCacheDatabase::RemoveWordFromWords(WordID word_id) {
156 PostSequencedDBTask(FROM_HERE,
157 base::Bind(&InMemoryURLCacheDatabase::RemoveWordFromWordsTask, this,
158 word_id));
159 }
160
161 void InMemoryURLCacheDatabase::RemoveWordStarts(HistoryID history_id) {
162 PostSequencedDBTask(FROM_HERE,
163 base::Bind(&InMemoryURLCacheDatabase::RemoveWordStartsTask, this,
164 history_id));
165 }
166
167 void InMemoryURLCacheDatabase::BeginTransaction() {
168 PostSequencedDBTask(FROM_HERE,
169 base::Bind(&InMemoryURLCacheDatabase::BeginTransactionTask, this));
170 }
171
172 void InMemoryURLCacheDatabase::CommitTransaction() {
173 PostSequencedDBTask(FROM_HERE,
174 base::Bind(&InMemoryURLCacheDatabase::CommitTransactionTask, this));
175 }
176
177 bool InMemoryURLCacheDatabase::Refresh(const URLIndexPrivateData& data) {
178 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
179 !BrowserThread::CurrentlyOn(BrowserThread::UI));
180 return RefreshWords(data) && RefreshCharWords(data) &&
181 RefreshWordHistory(data) && RefreshURLs(data) && RefreshWordStarts(data);
182 }
183
184 // Private Methods -------------------------------------------------------------
185
186 bool InMemoryURLCacheDatabase::InitDatabase() {
187 db_.Preload(); // Prime the cache.
188 if (EnsureCurrentVersion() != sql::INIT_OK)
189 return false;
190
191 // Create the tables if any do not already exist.
192 return VerifyTables() || Reset();
193 }
194
195 void InMemoryURLCacheDatabase::PostSequencedDBTask(
196 const tracked_objects::Location& from_here,
197 const base::Closure& task) {
198 BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
199 sequence_token_, from_here, task);
200 }
201
202 void InMemoryURLCacheDatabase::ShutdownTask() {
203 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
204 !BrowserThread::CurrentlyOn(BrowserThread::UI));
205 db_.Close();
206 }
207
208 sql::InitStatus InMemoryURLCacheDatabase::EnsureCurrentVersion() {
209 // We can't read databases newer than we were designed for.
210 if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
211 return sql::INIT_FAILURE;
212 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
213 LOG(WARNING) << "In-memory URL Cache database is too new.";
214 return sql::INIT_TOO_NEW;
215 }
216
217 // NOTE: Add migration code here as required.
218
219 return sql::INIT_OK;
220 }
221
222 void InMemoryURLCacheDatabase::BeginTransactionTask() {
223 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
224 !BrowserThread::CurrentlyOn(BrowserThread::UI));
225 db_.BeginTransaction();
226 }
227
228 void InMemoryURLCacheDatabase::CommitTransactionTask() {
229 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
230 !BrowserThread::CurrentlyOn(BrowserThread::UI));
231 if (update_error_ != SQLITE_OK) {
232 db_.RollbackTransaction();
233 BrowserThread::PostTask(
234 BrowserThread::UI, FROM_HERE,
235 base::Bind(&InMemoryURLCacheDatabase::NotifyDatabaseFailure,
236 base::Unretained(this)));
237 return;
238 }
239 db_.CommitTransaction();
240 }
241
242 bool InMemoryURLCacheDatabase::VerifyTables() {
243 if (db_.DoesTableExist(kWordsTableName) &&
244 db_.DoesTableExist(kCharWordsTableName) &&
245 db_.DoesTableExist(kWordHistoryTableName) &&
246 db_.DoesTableExist(kURLsTableName) &&
247 db_.DoesTableExist(kURLWordStartsTableName) &&
248 db_.DoesTableExist(kTitleWordStartsTableName))
249 return true;
250 UMA_HISTOGRAM_ENUMERATION("Sqlite.HQPCacheVerify.Error", db_.GetErrorCode(),
251 sql::kMaxSqliteError);
252 return false;
253 }
254
255 bool InMemoryURLCacheDatabase::CreateTables() {
256 std::string sql(StringPrintf(
257 "CREATE TABLE %s (word_id INTEGER PRIMARY KEY, word TEXT)",
258 kWordsTableName));
259 if (!db_.Execute(sql.c_str()))
260 return false;
261 sql = StringPrintf("CREATE INDEX %s_index ON %s (word_id)",
262 kWordsTableName, kWordsTableName);
263 if (!db_.Execute(sql.c_str()))
264 return false;
265
266 sql = StringPrintf("CREATE TABLE %s (char LONGCHAR, word_id INTEGER)",
267 kCharWordsTableName);
268 if (!db_.Execute(sql.c_str()))
269 return false;
270 sql = StringPrintf("CREATE INDEX %s_index ON %s (char)",
271 kCharWordsTableName, kCharWordsTableName);
272 if (!db_.Execute(sql.c_str()))
273 return false;
274
275 sql = StringPrintf("CREATE TABLE %s (word_id INTEGER, history_id INTEGER)",
276 kWordHistoryTableName);
277 if (!db_.Execute(sql.c_str()))
278 return false;
279 sql = StringPrintf("CREATE INDEX %s_history_index ON %s (history_id)",
280 kWordHistoryTableName, kWordHistoryTableName);
281 if (!db_.Execute(sql.c_str()))
282 return false;
283
284 sql = StringPrintf(
285 "CREATE TABLE %s (history_id INTEGER PRIMARY KEY, url TEXT, "
286 "title TEXT, visit_count INTEGER, typed_count INTEGER, "
287 "last_visit_time INTEGER, hidden INTEGER)", kURLsTableName);
288 if (!db_.Execute(sql.c_str()))
289 return false;
290 sql = StringPrintf("CREATE INDEX %s_index ON %s (history_id)",
291 kURLsTableName, kURLsTableName);
292 if (!db_.Execute(sql.c_str()))
293 return false;
294
295 sql = StringPrintf("CREATE TABLE %s (history_id INTEGER, word_start INTEGER)",
296 kURLWordStartsTableName);
297 if (!db_.Execute(sql.c_str()))
298 return false;
299 sql = StringPrintf("CREATE INDEX %s_index ON %s (history_id)",
300 kURLWordStartsTableName, kURLWordStartsTableName);
301 if (!db_.Execute(sql.c_str()))
302 return false;
303
304 sql = StringPrintf("CREATE TABLE %s (history_id INTEGER, word_start INTEGER)",
305 kTitleWordStartsTableName);
306 if (!db_.Execute(sql.c_str()))
307 return false;
308 sql = StringPrintf("CREATE INDEX %s_index ON %s (history_id)",
309 kTitleWordStartsTableName, kTitleWordStartsTableName);
310 return db_.Execute(sql.c_str());
311 }
312
313 void InMemoryURLCacheDatabase::NotifyDatabaseFailure() {
314 content::NotificationService::current()->Notify(
315 chrome::NOTIFICATION_IN_MEMORY_URL_CACHE_DATABASE_FAILURE,
316 content::Source<InMemoryURLCacheDatabase>(this),
317 content::NotificationService::NoDetails());
318 }
319
320 bool InMemoryURLCacheDatabase::RunStatement(sql::Statement* statement) {
321 if (statement->Run())
322 return true;
323 // If a failure has already occurred don't spew more histograms and don't
324 // forget the very first failure code.
325 if (update_error_ != SQLITE_OK)
326 return false;
327 update_error_ = db_.GetErrorCode();
328 UMA_HISTOGRAM_ENUMERATION("Sqlite.HQPCacheUpdate.Error", update_error_,
329 sql::kMaxSqliteError);
330 return false;
331 }
332
333 // Database Additions ----------------------------------------------------------
334
335 void InMemoryURLCacheDatabase::AddHistoryToURLsTask(
336 history::HistoryID history_id,
337 const history::URLRow& row) {
338 std::string sql(StringPrintf(
339 "INSERT INTO %s (history_id, url, title, visit_count, typed_count, "
340 "last_visit_time, hidden) VALUES (?,?,?,?,?,?,?)",
341 kURLsTableName));
342 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
343 statement.BindInt(0, history_id);
344 statement.BindString(1, URLDatabase::GURLToDatabaseURL(row.url()));
345 statement.BindString16(2, row.title());
346 statement.BindInt(3, row.visit_count());
347 statement.BindInt(4, row.typed_count());
348 statement.BindInt64(5, row.last_visit().ToInternalValue());
349 statement.BindBool(6, row.hidden());
350 RunStatement(&statement);
351 }
352
353 void InMemoryURLCacheDatabase::AddHistoryToWordHistoryTask(
354 WordID word_id,
355 HistoryID history_id) {
356 std::string sql(StringPrintf(
357 "INSERT INTO %s (word_id, history_id) VALUES (?,?)",
358 kWordHistoryTableName));
359 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
360 statement.BindInt(0, word_id);
361 statement.BindInt(1, history_id);
362 RunStatement(&statement);
363 }
364
365 void InMemoryURLCacheDatabase::AddWordToWordsTask(WordID word_id,
366 const string16& uni_word) {
367 std::string sql(StringPrintf(
368 "INSERT INTO %s (word_id, word) VALUES (?,?)",
369 kWordsTableName));
370 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
371 statement.BindInt(0, word_id);
372 statement.BindString16(1, uni_word);
373 RunStatement(&statement);
374 }
375
376 void InMemoryURLCacheDatabase::AddWordToCharWordsTask(char16 uni_char,
377 WordID word_id) {
378 std::string sql(StringPrintf("INSERT INTO %s (char, word_id) VALUES (?,?)",
379 kCharWordsTableName));
380 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
381 statement.BindInt(0, uni_char);
382 statement.BindInt(1, word_id);
383 RunStatement(&statement);
384 }
385
386 void InMemoryURLCacheDatabase::AddRowWordStartsTask(
387 HistoryID history_id,
388 const RowWordStarts& row_word_starts) {
389 std::string sql_1(StringPrintf(
390 "INSERT INTO %s (history_id, word_start) VALUES (?,?)",
391 kURLWordStartsTableName));
392 sql::Statement url_statement(db_.GetCachedStatement(SQL_FROM_HERE,
393 sql_1.c_str()));
394 for (WordStarts::const_iterator i = row_word_starts.url_word_starts_.begin();
395 i != row_word_starts.url_word_starts_.end(); ++i) {
396 url_statement.Reset(true);
397 url_statement.BindInt(0, history_id);
398 url_statement.BindInt(1, *i);
399 RunStatement(&url_statement);
400 }
401 std::string sql_2(StringPrintf(
402 "INSERT INTO %s (history_id, word_start) VALUES (?,?)",
403 kTitleWordStartsTableName));
404 sql::Statement title_statement(db_.GetCachedStatement(SQL_FROM_HERE,
405 sql_2.c_str()));
406 for (WordStarts::const_iterator i =
407 row_word_starts.title_word_starts_.begin();
408 i != row_word_starts.title_word_starts_.end(); ++i) {
409 title_statement.Reset(true);
410 title_statement.BindInt(0, history_id);
411 title_statement.BindInt(1, *i);
412 RunStatement(&title_statement);
413 }
414 }
415
416 // Database Removals -----------------------------------------------------------
417
418 void InMemoryURLCacheDatabase::RemoveHistoryIDFromURLsTask(
419 HistoryID history_id) {
420 std::string sql(StringPrintf("DELETE FROM %s WHERE history_id = ?",
421 kURLsTableName));
422 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
423 statement.BindInt(0, history_id);
424 RunStatement(&statement);
425 }
426
427 void InMemoryURLCacheDatabase::RemoveHistoryIDFromWordHistoryTask(
428 HistoryID history_id) {
429 std::string sql(StringPrintf("DELETE FROM %s WHERE history_id = ?",
430 kWordHistoryTableName));
431 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
432 statement.BindInt(0, history_id);
433 RunStatement(&statement);
434 }
435
436 void InMemoryURLCacheDatabase::RemoveWordFromWordsTask(WordID word_id) {
437 std::string sql_1(StringPrintf("DELETE FROM %s WHERE word_id = ?",
438 kWordsTableName));
439 sql::Statement statement_1(db_.GetCachedStatement(SQL_FROM_HERE,
440 sql_1.c_str()));
441 statement_1.BindInt(0, word_id);
442 RunStatement(&statement_1);
443
444 std::string sql_2(StringPrintf("DELETE FROM %s WHERE word_id = ?",
445 kCharWordsTableName));
446 sql::Statement statement_2(db_.GetCachedStatement(SQL_FROM_HERE,
447 sql_2.c_str()));
448 statement_2.BindInt(0, word_id);
449 RunStatement(&statement_2);
450 }
451
452 void InMemoryURLCacheDatabase::RemoveWordStartsTask(HistoryID history_id) {
453 std::string url_sql(StringPrintf("DELETE FROM %s WHERE history_id = ?",
454 kURLWordStartsTableName));
455 sql::Statement url_statement(db_.GetCachedStatement(SQL_FROM_HERE,
456 url_sql.c_str()));
457 url_statement.BindInt(0, history_id);
458 RunStatement(&url_statement);
459
460 std::string title_sql(StringPrintf("DELETE FROM %s WHERE history_id = ?",
461 kTitleWordStartsTableName));
462 sql::Statement title_statement(db_.GetCachedStatement(SQL_FROM_HERE,
463 title_sql.c_str()));
464 title_statement.BindInt(0, history_id);
465 RunStatement(&title_statement);
466 }
467
468 // Database Refreshing ---------------------------------------------------------
469
470 bool InMemoryURLCacheDatabase::RefreshWords(const URLIndexPrivateData& data) {
471 // Populate the words table from the contents of the word_map_. This will
472 // allow the restoration of the word_map_ as well as the word_list_ and
473 // available_words_.
474 std::string sql(StringPrintf("INSERT INTO %s (word_id, word) VALUES (?,?)",
475 kWordsTableName));
476 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
477 for (WordMap::const_iterator i = data.word_map_.begin();
478 i != data.word_map_.end(); ++i) {
479 statement.Reset(true);
480 statement.BindInt(0, i->second);
481 statement.BindString16(1, i->first);
482 if (!RunStatement(&statement))
483 return false;
484 }
485 return true;
486 }
487
488 bool InMemoryURLCacheDatabase::RefreshCharWords(
489 const URLIndexPrivateData& data) {
490 std::string sql(StringPrintf("INSERT INTO %s (char, word_id) VALUES (?,?)",
491 kCharWordsTableName));
492 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
493 for (CharWordIDMap::const_iterator i = data.char_word_map_.begin();
494 i != data.char_word_map_.end(); ++i) {
495 for (WordIDSet::const_iterator j = i->second.begin(); j != i->second.end();
496 ++j) {
497 statement.Reset(true);
498 statement.BindInt(0, i->first);
499 statement.BindInt(1, *j);
500 if (!RunStatement(&statement))
501 return false;
502 }
503 }
504 return true;
505 }
506
507 bool InMemoryURLCacheDatabase::RefreshWordHistory(
508 const URLIndexPrivateData& data) {
509 // Populate the word_history table from the contents of the
510 // word_id_history_map_. This will allow the restoration of the
511 // word_id_history_map_ as well as the history_id_word_map_.
512 std::string sql(StringPrintf(
513 "INSERT INTO %s (word_id, history_id) VALUES (?,?)",
514 kWordHistoryTableName));
515 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
516 for (WordIDHistoryMap::const_iterator i = data.word_id_history_map_.begin();
517 i != data.word_id_history_map_.end(); ++i) {
518 for (HistoryIDSet::const_iterator j = i->second.begin();
519 j != i->second.end(); ++j) {
520 statement.Reset(true);
521 statement.BindInt(0, i->first);
522 statement.BindInt64(1, *j);
523 if (!RunStatement(&statement))
524 return false;
525 }
526 }
527 return true;
528 }
529
530 bool InMemoryURLCacheDatabase::RefreshURLs(const URLIndexPrivateData& data) {
531 std::string sql(StringPrintf(
532 "INSERT INTO %s (history_id, url, title, visit_count, typed_count, "
533 "last_visit_time, hidden) VALUES (?,?,?,?,?,?,?)",
534 kURLsTableName));
535 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
536 for (HistoryInfoMap::const_iterator i = data.history_info_map_.begin();
537 i != data.history_info_map_.end(); ++i) {
538 statement.Reset(true);
539 statement.BindInt(0, i->first);
540 statement.BindString(1, URLDatabase::GURLToDatabaseURL(i->second.url()));
541 statement.BindString16(2, i->second.title());
542 statement.BindInt(3, i->second.visit_count());
543 statement.BindInt(4, i->second.typed_count());
544 statement.BindInt64(5, i->second.last_visit().ToInternalValue());
545 statement.BindBool(6, i->second.hidden());
546 if (!RunStatement(&statement))
547 return false;
548 }
549 return true;
550 }
551
552 bool InMemoryURLCacheDatabase::RefreshWordStarts(
553 const URLIndexPrivateData& data) {
554 std::string url_sql(StringPrintf(
555 "INSERT INTO %s (history_id, word_start) VALUES (?,?)",
556 kURLWordStartsTableName));
557 sql::Statement url_statement(db_.GetCachedStatement(SQL_FROM_HERE,
558 url_sql.c_str()));
559 std::string title_sql(StringPrintf(
560 "INSERT INTO %s (history_id, word_start) VALUES (?,?)",
561 kTitleWordStartsTableName));
562 sql::Statement title_statement(db_.GetCachedStatement(SQL_FROM_HERE,
563 title_sql.c_str()));
564 for (WordStartsMap::const_iterator i = data.word_starts_map_.begin();
565 i != data.word_starts_map_.end(); ++i) {
566 for (WordStarts::const_iterator w = i->second.url_word_starts_.begin();
567 w != i->second.url_word_starts_.end(); ++w) {
568 url_statement.Reset(true);
569 url_statement.BindInt(0, i->first);
570 url_statement.BindInt(1, *w);
571 if (!RunStatement(&url_statement))
572 return false;
573 }
574 for (WordStarts::const_iterator w = i->second.title_word_starts_.begin();
575 w != i->second.title_word_starts_.end(); ++w) {
576 title_statement.Reset(true);
577 title_statement.BindInt(0, i->first);
578 title_statement.BindInt(1, *w);
579 if (!RunStatement(&title_statement))
580 return false;
581 }
582 }
583 return true;
584 }
585
586 // Database Restoration --------------------------------------------------------
587
588 bool InMemoryURLCacheDatabase::RestoreWords(URLIndexPrivateData* data) {
589 // Rebuild word_list_, word_map_ and available_words_.
590 std::string sql(StringPrintf("SELECT word_id, word FROM %s ORDER BY word_id",
591 kWordsTableName));
592 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
593 while (statement.Step()) {
594 WordID word_id = statement.ColumnInt(0);
595 // A gap in contiguous word IDs indicates word slots in the vector that are
596 // currently unused and available for future use as new words are indexed.
597 while (data->word_list_.size() < word_id) {
598 data->available_words_.insert(data->word_list_.size());
599 data->word_list_.push_back(string16());
600 }
601 string16 word = statement.ColumnString16(1);
602 DCHECK_EQ(static_cast<size_t>(word_id), data->word_list_.size());
603 data->word_list_.push_back(word);
604 data->word_map_[word] = word_id;
605 }
606 return statement.Succeeded() && !data->word_list_.empty();
607 }
608
609 bool InMemoryURLCacheDatabase::RestoreCharWords(URLIndexPrivateData* data) {
610 // Rebuild char_word_map_.
611 std::string sql(StringPrintf("SELECT char, word_id FROM %s ORDER BY char",
612 kCharWordsTableName));
613 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
614 CharWordIDMap& char_map(data->char_word_map_);
615 CharWordIDMap::iterator it = char_map.begin();
616 while (statement.Step()) {
617 char16 next_char = statement.ColumnInt(0);
618 if (it == char_map.begin() || it->first != next_char)
619 it = char_map.insert(it, std::make_pair(next_char, WordIDSet()));
620 it->second.insert(statement.ColumnInt(1));
621 }
622 return statement.Succeeded() && !char_map.empty();
623 }
624
625 bool InMemoryURLCacheDatabase::RestoreWordHistory(URLIndexPrivateData* data) {
626 // Rebuild word_id_history_map_ and history_id_word_map_.
627 std::string sql(StringPrintf(
628 "SELECT word_id, history_id FROM %s ORDER BY word_id",
629 kWordHistoryTableName));
630 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
631 WordIDHistoryMap& word_map(data->word_id_history_map_);
632 WordIDHistoryMap::iterator it = word_map.begin();
633 while (statement.Step()) {
634 WordID word_id = statement.ColumnInt(0);
635 HistoryID history_id = statement.ColumnInt(1);
636 data->AddToHistoryIDWordMap(history_id, word_id);
637 if (it == word_map.begin() || it->first != word_id)
638 it = word_map.insert(it, std::make_pair(word_id, HistoryIDSet()));
639 it->second.insert(history_id);
640 }
641 return statement.Succeeded() && !word_map.empty();
642 }
643
644 bool InMemoryURLCacheDatabase::RestoreURLs(URLIndexPrivateData* data) {
645 // Rebuild history_info_map_.
646 std::string sql(StringPrintf(
647 "SELECT history_id, url, title, visit_count, typed_count, "
648 "last_visit_time, hidden FROM %s",
649 kURLsTableName));
650 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
651 while (statement.Step()) {
652 HistoryID history_id = statement.ColumnInt64(0);
653 URLRow row(GURL(statement.ColumnString(1)), history_id);
654 row.set_title(statement.ColumnString16(2));
655 row.set_visit_count(statement.ColumnInt(3));
656 row.set_typed_count(statement.ColumnInt(4));
657 row.set_last_visit(base::Time::FromInternalValue(statement.ColumnInt64(5)));
658 row.set_hidden(statement.ColumnInt(6) != 0);
659 data->history_info_map_[history_id] = row;
660 }
661 return statement.Succeeded() && !data->history_info_map_.empty();
662 }
663
664 bool InMemoryURLCacheDatabase::RestoreWordStarts(URLIndexPrivateData* data) {
665 std::string url_sql(StringPrintf(
666 "SELECT history_id, word_start FROM %s ORDER BY word_start",
667 kURLWordStartsTableName));
668 sql::Statement url_statement(db_.GetCachedStatement(SQL_FROM_HERE,
669 url_sql.c_str()));
670 while (url_statement.Step()) {
671 HistoryID history_id = url_statement.ColumnInt64(0);
672 size_t word_start = url_statement.ColumnInt64(1);
673 data->word_starts_map_[history_id].url_word_starts_.push_back(word_start);
674 }
675 if (!url_statement.Succeeded())
676 return false;
677
678 std::string title_sql(StringPrintf(
679 "SELECT history_id, word_start FROM %s ORDER BY word_start",
680 kTitleWordStartsTableName));
681 sql::Statement title_statement(db_.GetCachedStatement(SQL_FROM_HERE,
682 title_sql.c_str()));
683 while (title_statement.Step()) {
684 HistoryID history_id = title_statement.ColumnInt64(0);
685 size_t word_start = title_statement.ColumnInt64(1);
686 data->word_starts_map_[history_id].title_word_starts_.push_back(word_start);
687 }
688
689 return title_statement.Succeeded() && !data->word_starts_map_.empty();
690 }
691
692 } // namespace history
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698