| Index: chrome/browser/history/in_memory_url_cache_database.cc
|
| ===================================================================
|
| --- chrome/browser/history/in_memory_url_cache_database.cc (revision 0)
|
| +++ chrome/browser/history/in_memory_url_cache_database.cc (revision 0)
|
| @@ -0,0 +1,692 @@
|
| +// Copyright (c) 2012 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/history/in_memory_url_cache_database.h"
|
| +
|
| +#include <algorithm>
|
| +#include <functional>
|
| +#include <iterator>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/file_path.h"
|
| +#include "base/string_util.h"
|
| +#include "base/stringprintf.h"
|
| +#include "base/time.h"
|
| +#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
|
| +#include "chrome/browser/history/url_database.h"
|
| +#include "chrome/browser/history/url_index_private_data.h"
|
| +#include "chrome/common/chrome_notification_types.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/browser/notification_service.h"
|
| +#include "sql/diagnostic_error_delegate.h"
|
| +#include "sql/statement.h"
|
| +#include "sql/transaction.h"
|
| +#include "third_party/sqlite/sqlite3.h"
|
| +
|
| +using content::BrowserThread;
|
| +
|
| +namespace history {
|
| +
|
| +namespace {
|
| +
|
| +static const int kCurrentVersionNumber = 1;
|
| +static const int kCompatibleVersionNumber = 1;
|
| +
|
| +const char* kWordsTableName = "words";
|
| +const char* kCharWordsTableName = "char_words";
|
| +const char* kWordHistoryTableName = "word_history";
|
| +const char* kURLsTableName = "urls";
|
| +const char* kURLWordStartsTableName = "url_word_starts";
|
| +const char* kTitleWordStartsTableName = "title_word_starts";
|
| +
|
| +} // namespace
|
| +
|
| +// Public Methods --------------------------------------------------------------
|
| +
|
| +InMemoryURLCacheDatabase::InMemoryURLCacheDatabase()
|
| + : update_error_(SQLITE_OK),
|
| + shutdown_(false) {
|
| +}
|
| +
|
| +InMemoryURLCacheDatabase::~InMemoryURLCacheDatabase() {}
|
| +
|
| +bool InMemoryURLCacheDatabase::Init(
|
| + const FilePath& file_path,
|
| + const base::SequencedWorkerPool::SequenceToken& sequence_token) {
|
| + DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
|
| + !BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + if (shutdown_)
|
| + return false;
|
| + sequence_token_ = sequence_token;
|
| + db_.set_error_delegate(GetErrorHandlerForHQPCacheDb());
|
| + // Don't use very much memory caching this database. We primarily use it
|
| + // as a backing store for existing in-memory data.
|
| + db_.set_cache_size(64);
|
| + db_.set_exclusive_locking();
|
| + if (!db_.Open(file_path)) {
|
| + UMA_HISTOGRAM_ENUMERATION("Sqlite.HQPCacheOpen.Error", db_.GetErrorCode(),
|
| + sql::kMaxSqliteError);
|
| + return false;
|
| + }
|
| + if (!InitDatabase()) {
|
| + db_.Close();
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::Shutdown() {
|
| + shutdown_ = true;
|
| + // Allow all outstanding sequenced database operations to complete.
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::ShutdownTask, this));
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RestorePrivateData(URLIndexPrivateData* data) {
|
| + DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
|
| + !BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + return RestoreWords(data) && RestoreCharWords(data) &&
|
| + RestoreWordHistory(data) && RestoreURLs(data) && RestoreWordStarts(data);
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::Reset() {
|
| + DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
|
| + !BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + if (db_.Raze() && CreateTables())
|
| + return true;
|
| + UMA_HISTOGRAM_ENUMERATION("Sqlite.HQPCacheCreate.Error", db_.GetErrorCode(),
|
| + sql::kMaxSqliteError);
|
| + return false;
|
| +}
|
| +
|
| +// Database Updating -----------------------------------------------------------
|
| +
|
| +void InMemoryURLCacheDatabase::AddHistoryToURLs(history::HistoryID history_id,
|
| + const history::URLRow& row) {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::AddHistoryToURLsTask, this,
|
| + history_id, row));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::AddHistoryToWordHistory(WordID word_id,
|
| + HistoryID history_id) {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::AddHistoryToWordHistoryTask, this,
|
| + word_id, history_id));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::AddWordToWords(WordID word_id,
|
| + const string16& uni_word) {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::AddWordToWordsTask, this, word_id,
|
| + uni_word));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::AddWordToCharWords(char16 uni_char,
|
| + WordID word_id) {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::AddWordToCharWordsTask, this,
|
| + uni_char, word_id));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::AddRowWordStarts(
|
| + HistoryID history_id,
|
| + const RowWordStarts& row_word_starts) {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::AddRowWordStartsTask, this,
|
| + history_id, row_word_starts));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::RemoveHistoryIDFromURLs(HistoryID history_id) {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::RemoveHistoryIDFromURLsTask, this,
|
| + history_id));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::RemoveHistoryIDFromWordHistory(
|
| + HistoryID history_id) {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::RemoveHistoryIDFromWordHistoryTask,
|
| + this, history_id));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::RemoveWordFromWords(WordID word_id) {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::RemoveWordFromWordsTask, this,
|
| + word_id));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::RemoveWordStarts(HistoryID history_id) {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::RemoveWordStartsTask, this,
|
| + history_id));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::BeginTransaction() {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::BeginTransactionTask, this));
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::CommitTransaction() {
|
| + PostSequencedDBTask(FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::CommitTransactionTask, this));
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::Refresh(const URLIndexPrivateData& data) {
|
| + DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
|
| + !BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + return RefreshWords(data) && RefreshCharWords(data) &&
|
| + RefreshWordHistory(data) && RefreshURLs(data) && RefreshWordStarts(data);
|
| +}
|
| +
|
| +// Private Methods -------------------------------------------------------------
|
| +
|
| +bool InMemoryURLCacheDatabase::InitDatabase() {
|
| + db_.Preload(); // Prime the cache.
|
| + if (EnsureCurrentVersion() != sql::INIT_OK)
|
| + return false;
|
| +
|
| + // Create the tables if any do not already exist.
|
| + return VerifyTables() || Reset();
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::PostSequencedDBTask(
|
| + const tracked_objects::Location& from_here,
|
| + const base::Closure& task) {
|
| + BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
|
| + sequence_token_, from_here, task);
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::ShutdownTask() {
|
| + DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
|
| + !BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + db_.Close();
|
| +}
|
| +
|
| +sql::InitStatus InMemoryURLCacheDatabase::EnsureCurrentVersion() {
|
| + // We can't read databases newer than we were designed for.
|
| + if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
|
| + return sql::INIT_FAILURE;
|
| + if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
|
| + LOG(WARNING) << "In-memory URL Cache database is too new.";
|
| + return sql::INIT_TOO_NEW;
|
| + }
|
| +
|
| + // NOTE: Add migration code here as required.
|
| +
|
| + return sql::INIT_OK;
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::BeginTransactionTask() {
|
| + DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
|
| + !BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + db_.BeginTransaction();
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::CommitTransactionTask() {
|
| + DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
|
| + !BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + if (update_error_ != SQLITE_OK) {
|
| + db_.RollbackTransaction();
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&InMemoryURLCacheDatabase::NotifyDatabaseFailure,
|
| + base::Unretained(this)));
|
| + return;
|
| + }
|
| + db_.CommitTransaction();
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::VerifyTables() {
|
| + if (db_.DoesTableExist(kWordsTableName) &&
|
| + db_.DoesTableExist(kCharWordsTableName) &&
|
| + db_.DoesTableExist(kWordHistoryTableName) &&
|
| + db_.DoesTableExist(kURLsTableName) &&
|
| + db_.DoesTableExist(kURLWordStartsTableName) &&
|
| + db_.DoesTableExist(kTitleWordStartsTableName))
|
| + return true;
|
| + UMA_HISTOGRAM_ENUMERATION("Sqlite.HQPCacheVerify.Error", db_.GetErrorCode(),
|
| + sql::kMaxSqliteError);
|
| + return false;
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::CreateTables() {
|
| + std::string sql(StringPrintf(
|
| + "CREATE TABLE %s (word_id INTEGER PRIMARY KEY, word TEXT)",
|
| + kWordsTableName));
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| + sql = StringPrintf("CREATE INDEX %s_index ON %s (word_id)",
|
| + kWordsTableName, kWordsTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| +
|
| + sql = StringPrintf("CREATE TABLE %s (char LONGCHAR, word_id INTEGER)",
|
| + kCharWordsTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| + sql = StringPrintf("CREATE INDEX %s_index ON %s (char)",
|
| + kCharWordsTableName, kCharWordsTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| +
|
| + sql = StringPrintf("CREATE TABLE %s (word_id INTEGER, history_id INTEGER)",
|
| + kWordHistoryTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| + sql = StringPrintf("CREATE INDEX %s_history_index ON %s (history_id)",
|
| + kWordHistoryTableName, kWordHistoryTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| +
|
| + sql = StringPrintf(
|
| + "CREATE TABLE %s (history_id INTEGER PRIMARY KEY, url TEXT, "
|
| + "title TEXT, visit_count INTEGER, typed_count INTEGER, "
|
| + "last_visit_time INTEGER, hidden INTEGER)", kURLsTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| + sql = StringPrintf("CREATE INDEX %s_index ON %s (history_id)",
|
| + kURLsTableName, kURLsTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| +
|
| + sql = StringPrintf("CREATE TABLE %s (history_id INTEGER, word_start INTEGER)",
|
| + kURLWordStartsTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| + sql = StringPrintf("CREATE INDEX %s_index ON %s (history_id)",
|
| + kURLWordStartsTableName, kURLWordStartsTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| +
|
| + sql = StringPrintf("CREATE TABLE %s (history_id INTEGER, word_start INTEGER)",
|
| + kTitleWordStartsTableName);
|
| + if (!db_.Execute(sql.c_str()))
|
| + return false;
|
| + sql = StringPrintf("CREATE INDEX %s_index ON %s (history_id)",
|
| + kTitleWordStartsTableName, kTitleWordStartsTableName);
|
| + return db_.Execute(sql.c_str());
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::NotifyDatabaseFailure() {
|
| + content::NotificationService::current()->Notify(
|
| + chrome::NOTIFICATION_IN_MEMORY_URL_CACHE_DATABASE_FAILURE,
|
| + content::Source<InMemoryURLCacheDatabase>(this),
|
| + content::NotificationService::NoDetails());
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RunStatement(sql::Statement* statement) {
|
| + if (statement->Run())
|
| + return true;
|
| + // If a failure has already occurred don't spew more histograms and don't
|
| + // forget the very first failure code.
|
| + if (update_error_ != SQLITE_OK)
|
| + return false;
|
| + update_error_ = db_.GetErrorCode();
|
| + UMA_HISTOGRAM_ENUMERATION("Sqlite.HQPCacheUpdate.Error", update_error_,
|
| + sql::kMaxSqliteError);
|
| + return false;
|
| +}
|
| +
|
| +// Database Additions ----------------------------------------------------------
|
| +
|
| +void InMemoryURLCacheDatabase::AddHistoryToURLsTask(
|
| + history::HistoryID history_id,
|
| + const history::URLRow& row) {
|
| + std::string sql(StringPrintf(
|
| + "INSERT INTO %s (history_id, url, title, visit_count, typed_count, "
|
| + "last_visit_time, hidden) VALUES (?,?,?,?,?,?,?)",
|
| + kURLsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + statement.BindInt(0, history_id);
|
| + statement.BindString(1, URLDatabase::GURLToDatabaseURL(row.url()));
|
| + statement.BindString16(2, row.title());
|
| + statement.BindInt(3, row.visit_count());
|
| + statement.BindInt(4, row.typed_count());
|
| + statement.BindInt64(5, row.last_visit().ToInternalValue());
|
| + statement.BindBool(6, row.hidden());
|
| + RunStatement(&statement);
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::AddHistoryToWordHistoryTask(
|
| + WordID word_id,
|
| + HistoryID history_id) {
|
| + std::string sql(StringPrintf(
|
| + "INSERT INTO %s (word_id, history_id) VALUES (?,?)",
|
| + kWordHistoryTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + statement.BindInt(0, word_id);
|
| + statement.BindInt(1, history_id);
|
| + RunStatement(&statement);
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::AddWordToWordsTask(WordID word_id,
|
| + const string16& uni_word) {
|
| + std::string sql(StringPrintf(
|
| + "INSERT INTO %s (word_id, word) VALUES (?,?)",
|
| + kWordsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + statement.BindInt(0, word_id);
|
| + statement.BindString16(1, uni_word);
|
| + RunStatement(&statement);
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::AddWordToCharWordsTask(char16 uni_char,
|
| + WordID word_id) {
|
| + std::string sql(StringPrintf("INSERT INTO %s (char, word_id) VALUES (?,?)",
|
| + kCharWordsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + statement.BindInt(0, uni_char);
|
| + statement.BindInt(1, word_id);
|
| + RunStatement(&statement);
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::AddRowWordStartsTask(
|
| + HistoryID history_id,
|
| + const RowWordStarts& row_word_starts) {
|
| + std::string sql_1(StringPrintf(
|
| + "INSERT INTO %s (history_id, word_start) VALUES (?,?)",
|
| + kURLWordStartsTableName));
|
| + sql::Statement url_statement(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + sql_1.c_str()));
|
| + for (WordStarts::const_iterator i = row_word_starts.url_word_starts_.begin();
|
| + i != row_word_starts.url_word_starts_.end(); ++i) {
|
| + url_statement.Reset(true);
|
| + url_statement.BindInt(0, history_id);
|
| + url_statement.BindInt(1, *i);
|
| + RunStatement(&url_statement);
|
| + }
|
| + std::string sql_2(StringPrintf(
|
| + "INSERT INTO %s (history_id, word_start) VALUES (?,?)",
|
| + kTitleWordStartsTableName));
|
| + sql::Statement title_statement(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + sql_2.c_str()));
|
| + for (WordStarts::const_iterator i =
|
| + row_word_starts.title_word_starts_.begin();
|
| + i != row_word_starts.title_word_starts_.end(); ++i) {
|
| + title_statement.Reset(true);
|
| + title_statement.BindInt(0, history_id);
|
| + title_statement.BindInt(1, *i);
|
| + RunStatement(&title_statement);
|
| + }
|
| +}
|
| +
|
| +// Database Removals -----------------------------------------------------------
|
| +
|
| +void InMemoryURLCacheDatabase::RemoveHistoryIDFromURLsTask(
|
| + HistoryID history_id) {
|
| + std::string sql(StringPrintf("DELETE FROM %s WHERE history_id = ?",
|
| + kURLsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + statement.BindInt(0, history_id);
|
| + RunStatement(&statement);
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::RemoveHistoryIDFromWordHistoryTask(
|
| + HistoryID history_id) {
|
| + std::string sql(StringPrintf("DELETE FROM %s WHERE history_id = ?",
|
| + kWordHistoryTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + statement.BindInt(0, history_id);
|
| + RunStatement(&statement);
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::RemoveWordFromWordsTask(WordID word_id) {
|
| + std::string sql_1(StringPrintf("DELETE FROM %s WHERE word_id = ?",
|
| + kWordsTableName));
|
| + sql::Statement statement_1(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + sql_1.c_str()));
|
| + statement_1.BindInt(0, word_id);
|
| + RunStatement(&statement_1);
|
| +
|
| + std::string sql_2(StringPrintf("DELETE FROM %s WHERE word_id = ?",
|
| + kCharWordsTableName));
|
| + sql::Statement statement_2(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + sql_2.c_str()));
|
| + statement_2.BindInt(0, word_id);
|
| + RunStatement(&statement_2);
|
| +}
|
| +
|
| +void InMemoryURLCacheDatabase::RemoveWordStartsTask(HistoryID history_id) {
|
| + std::string url_sql(StringPrintf("DELETE FROM %s WHERE history_id = ?",
|
| + kURLWordStartsTableName));
|
| + sql::Statement url_statement(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + url_sql.c_str()));
|
| + url_statement.BindInt(0, history_id);
|
| + RunStatement(&url_statement);
|
| +
|
| + std::string title_sql(StringPrintf("DELETE FROM %s WHERE history_id = ?",
|
| + kTitleWordStartsTableName));
|
| + sql::Statement title_statement(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + title_sql.c_str()));
|
| + title_statement.BindInt(0, history_id);
|
| + RunStatement(&title_statement);
|
| +}
|
| +
|
| +// Database Refreshing ---------------------------------------------------------
|
| +
|
| +bool InMemoryURLCacheDatabase::RefreshWords(const URLIndexPrivateData& data) {
|
| + // Populate the words table from the contents of the word_map_. This will
|
| + // allow the restoration of the word_map_ as well as the word_list_ and
|
| + // available_words_.
|
| + std::string sql(StringPrintf("INSERT INTO %s (word_id, word) VALUES (?,?)",
|
| + kWordsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + for (WordMap::const_iterator i = data.word_map_.begin();
|
| + i != data.word_map_.end(); ++i) {
|
| + statement.Reset(true);
|
| + statement.BindInt(0, i->second);
|
| + statement.BindString16(1, i->first);
|
| + if (!RunStatement(&statement))
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RefreshCharWords(
|
| + const URLIndexPrivateData& data) {
|
| + std::string sql(StringPrintf("INSERT INTO %s (char, word_id) VALUES (?,?)",
|
| + kCharWordsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + for (CharWordIDMap::const_iterator i = data.char_word_map_.begin();
|
| + i != data.char_word_map_.end(); ++i) {
|
| + for (WordIDSet::const_iterator j = i->second.begin(); j != i->second.end();
|
| + ++j) {
|
| + statement.Reset(true);
|
| + statement.BindInt(0, i->first);
|
| + statement.BindInt(1, *j);
|
| + if (!RunStatement(&statement))
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RefreshWordHistory(
|
| + const URLIndexPrivateData& data) {
|
| + // Populate the word_history table from the contents of the
|
| + // word_id_history_map_. This will allow the restoration of the
|
| + // word_id_history_map_ as well as the history_id_word_map_.
|
| + std::string sql(StringPrintf(
|
| + "INSERT INTO %s (word_id, history_id) VALUES (?,?)",
|
| + kWordHistoryTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + for (WordIDHistoryMap::const_iterator i = data.word_id_history_map_.begin();
|
| + i != data.word_id_history_map_.end(); ++i) {
|
| + for (HistoryIDSet::const_iterator j = i->second.begin();
|
| + j != i->second.end(); ++j) {
|
| + statement.Reset(true);
|
| + statement.BindInt(0, i->first);
|
| + statement.BindInt64(1, *j);
|
| + if (!RunStatement(&statement))
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RefreshURLs(const URLIndexPrivateData& data) {
|
| + std::string sql(StringPrintf(
|
| + "INSERT INTO %s (history_id, url, title, visit_count, typed_count, "
|
| + "last_visit_time, hidden) VALUES (?,?,?,?,?,?,?)",
|
| + kURLsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + for (HistoryInfoMap::const_iterator i = data.history_info_map_.begin();
|
| + i != data.history_info_map_.end(); ++i) {
|
| + statement.Reset(true);
|
| + statement.BindInt(0, i->first);
|
| + statement.BindString(1, URLDatabase::GURLToDatabaseURL(i->second.url()));
|
| + statement.BindString16(2, i->second.title());
|
| + statement.BindInt(3, i->second.visit_count());
|
| + statement.BindInt(4, i->second.typed_count());
|
| + statement.BindInt64(5, i->second.last_visit().ToInternalValue());
|
| + statement.BindBool(6, i->second.hidden());
|
| + if (!RunStatement(&statement))
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RefreshWordStarts(
|
| + const URLIndexPrivateData& data) {
|
| + std::string url_sql(StringPrintf(
|
| + "INSERT INTO %s (history_id, word_start) VALUES (?,?)",
|
| + kURLWordStartsTableName));
|
| + sql::Statement url_statement(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + url_sql.c_str()));
|
| + std::string title_sql(StringPrintf(
|
| + "INSERT INTO %s (history_id, word_start) VALUES (?,?)",
|
| + kTitleWordStartsTableName));
|
| + sql::Statement title_statement(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + title_sql.c_str()));
|
| + for (WordStartsMap::const_iterator i = data.word_starts_map_.begin();
|
| + i != data.word_starts_map_.end(); ++i) {
|
| + for (WordStarts::const_iterator w = i->second.url_word_starts_.begin();
|
| + w != i->second.url_word_starts_.end(); ++w) {
|
| + url_statement.Reset(true);
|
| + url_statement.BindInt(0, i->first);
|
| + url_statement.BindInt(1, *w);
|
| + if (!RunStatement(&url_statement))
|
| + return false;
|
| + }
|
| + for (WordStarts::const_iterator w = i->second.title_word_starts_.begin();
|
| + w != i->second.title_word_starts_.end(); ++w) {
|
| + title_statement.Reset(true);
|
| + title_statement.BindInt(0, i->first);
|
| + title_statement.BindInt(1, *w);
|
| + if (!RunStatement(&title_statement))
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// Database Restoration --------------------------------------------------------
|
| +
|
| +bool InMemoryURLCacheDatabase::RestoreWords(URLIndexPrivateData* data) {
|
| + // Rebuild word_list_, word_map_ and available_words_.
|
| + std::string sql(StringPrintf("SELECT word_id, word FROM %s ORDER BY word_id",
|
| + kWordsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + while (statement.Step()) {
|
| + WordID word_id = statement.ColumnInt(0);
|
| + // A gap in contiguous word IDs indicates word slots in the vector that are
|
| + // currently unused and available for future use as new words are indexed.
|
| + while (data->word_list_.size() < word_id) {
|
| + data->available_words_.insert(data->word_list_.size());
|
| + data->word_list_.push_back(string16());
|
| + }
|
| + string16 word = statement.ColumnString16(1);
|
| + DCHECK_EQ(static_cast<size_t>(word_id), data->word_list_.size());
|
| + data->word_list_.push_back(word);
|
| + data->word_map_[word] = word_id;
|
| + }
|
| + return statement.Succeeded() && !data->word_list_.empty();
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RestoreCharWords(URLIndexPrivateData* data) {
|
| + // Rebuild char_word_map_.
|
| + std::string sql(StringPrintf("SELECT char, word_id FROM %s ORDER BY char",
|
| + kCharWordsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + CharWordIDMap& char_map(data->char_word_map_);
|
| + CharWordIDMap::iterator it = char_map.begin();
|
| + while (statement.Step()) {
|
| + char16 next_char = statement.ColumnInt(0);
|
| + if (it == char_map.begin() || it->first != next_char)
|
| + it = char_map.insert(it, std::make_pair(next_char, WordIDSet()));
|
| + it->second.insert(statement.ColumnInt(1));
|
| + }
|
| + return statement.Succeeded() && !char_map.empty();
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RestoreWordHistory(URLIndexPrivateData* data) {
|
| + // Rebuild word_id_history_map_ and history_id_word_map_.
|
| + std::string sql(StringPrintf(
|
| + "SELECT word_id, history_id FROM %s ORDER BY word_id",
|
| + kWordHistoryTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + WordIDHistoryMap& word_map(data->word_id_history_map_);
|
| + WordIDHistoryMap::iterator it = word_map.begin();
|
| + while (statement.Step()) {
|
| + WordID word_id = statement.ColumnInt(0);
|
| + HistoryID history_id = statement.ColumnInt(1);
|
| + data->AddToHistoryIDWordMap(history_id, word_id);
|
| + if (it == word_map.begin() || it->first != word_id)
|
| + it = word_map.insert(it, std::make_pair(word_id, HistoryIDSet()));
|
| + it->second.insert(history_id);
|
| + }
|
| + return statement.Succeeded() && !word_map.empty();
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RestoreURLs(URLIndexPrivateData* data) {
|
| + // Rebuild history_info_map_.
|
| + std::string sql(StringPrintf(
|
| + "SELECT history_id, url, title, visit_count, typed_count, "
|
| + "last_visit_time, hidden FROM %s",
|
| + kURLsTableName));
|
| + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
|
| + while (statement.Step()) {
|
| + HistoryID history_id = statement.ColumnInt64(0);
|
| + URLRow row(GURL(statement.ColumnString(1)), history_id);
|
| + row.set_title(statement.ColumnString16(2));
|
| + row.set_visit_count(statement.ColumnInt(3));
|
| + row.set_typed_count(statement.ColumnInt(4));
|
| + row.set_last_visit(base::Time::FromInternalValue(statement.ColumnInt64(5)));
|
| + row.set_hidden(statement.ColumnInt(6) != 0);
|
| + data->history_info_map_[history_id] = row;
|
| + }
|
| + return statement.Succeeded() && !data->history_info_map_.empty();
|
| +}
|
| +
|
| +bool InMemoryURLCacheDatabase::RestoreWordStarts(URLIndexPrivateData* data) {
|
| + std::string url_sql(StringPrintf(
|
| + "SELECT history_id, word_start FROM %s ORDER BY word_start",
|
| + kURLWordStartsTableName));
|
| + sql::Statement url_statement(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + url_sql.c_str()));
|
| + while (url_statement.Step()) {
|
| + HistoryID history_id = url_statement.ColumnInt64(0);
|
| + size_t word_start = url_statement.ColumnInt64(1);
|
| + data->word_starts_map_[history_id].url_word_starts_.push_back(word_start);
|
| + }
|
| + if (!url_statement.Succeeded())
|
| + return false;
|
| +
|
| + std::string title_sql(StringPrintf(
|
| + "SELECT history_id, word_start FROM %s ORDER BY word_start",
|
| + kTitleWordStartsTableName));
|
| + sql::Statement title_statement(db_.GetCachedStatement(SQL_FROM_HERE,
|
| + title_sql.c_str()));
|
| + while (title_statement.Step()) {
|
| + HistoryID history_id = title_statement.ColumnInt64(0);
|
| + size_t word_start = title_statement.ColumnInt64(1);
|
| + data->word_starts_map_[history_id].title_word_starts_.push_back(word_start);
|
| + }
|
| +
|
| + return title_statement.Succeeded() && !data->word_starts_map_.empty();
|
| +}
|
| +
|
| +} // namespace history
|
|
|
| Property changes on: chrome/browser/history/in_memory_url_cache_database.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|