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/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 |
OLD | NEW |