| Index: components/history/core/browser/history_database.cc
|
| diff --git a/components/history/core/browser/history_database.cc b/components/history/core/browser/history_database.cc
|
| index a61e2901850d931402cae480de62880fb4c91e3f..becb18852192ae2c64f5ad063d55f8f4bca82da3 100644
|
| --- a/components/history/core/browser/history_database.cc
|
| +++ b/components/history/core/browser/history_database.cc
|
| @@ -42,6 +42,37 @@ const int kCompatibleVersionNumber = 16;
|
| const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
|
| const int kMaxHostsInMemory = 10000;
|
|
|
| +// Logs a migration failure to UMA and logging. The return value will be
|
| +// what to return from ::Init (to simplify the call sites). Migration failures
|
| +// are almost always fatal since the database can be in an inconsistent state.
|
| +sql::InitStatus LogMigrationFailure(int from_version) {
|
| + UMA_HISTOGRAM_SPARSE_SLOWLY("History.MigrateFailureFromVersion",
|
| + from_version);
|
| + LOG(ERROR) << "History failed to migrate from version " << from_version
|
| + << ". History will be disabled.";
|
| + return sql::INIT_FAILURE;
|
| +}
|
| +
|
| +// Reasons for initialization to fail. These are logged to UMA. It corresponds
|
| +// to the HistoryInitStep enum in enums.xml.
|
| +//
|
| +// DO NOT CHANGE THE VALUES. Leave holes if anything is removed and add only
|
| +// to the end.
|
| +enum class InitStep {
|
| + OPEN = 0,
|
| + TRANSACTION_BEGIN,
|
| + META_TABLE_INIT,
|
| + CREATE_TABLES,
|
| + VERSION,
|
| + COMMIT,
|
| +};
|
| +
|
| +sql::InitStatus LogInitFailure(InitStep what) {
|
| + UMA_HISTOGRAM_SPARSE_SLOWLY("History.InitializationFailureStep",
|
| + static_cast<int>(what));
|
| + return sql::INIT_FAILURE;
|
| +}
|
| +
|
| } // namespace
|
|
|
| HistoryDatabase::HistoryDatabase(
|
| @@ -74,13 +105,13 @@ sql::InitStatus HistoryDatabase::Init(const base::FilePath& history_name) {
|
| // mode to start out for the in-memory backend to read the data).
|
|
|
| if (!db_.Open(history_name))
|
| - return sql::INIT_FAILURE;
|
| + return LogInitFailure(InitStep::OPEN);
|
|
|
| // Wrap the rest of init in a tranaction. This will prevent the database from
|
| // getting corrupted if we crash in the middle of initialization or migration.
|
| sql::Transaction committer(&db_);
|
| if (!committer.Begin())
|
| - return sql::INIT_FAILURE;
|
| + return LogInitFailure(InitStep::TRANSACTION_BEGIN);
|
|
|
| #if defined(OS_MACOSX) && !defined(OS_IOS)
|
| // Exclude the history file from backups.
|
| @@ -94,11 +125,11 @@ sql::InitStatus HistoryDatabase::Init(const base::FilePath& history_name) {
|
| // NOTE: If you add something here, also add it to
|
| // RecreateAllButStarAndURLTables.
|
| if (!meta_table_.Init(&db_, GetCurrentVersion(), kCompatibleVersionNumber))
|
| - return sql::INIT_FAILURE;
|
| + return LogInitFailure(InitStep::META_TABLE_INIT);
|
| if (!CreateURLTable(false) || !InitVisitTable() ||
|
| !InitKeywordSearchTermsTable() || !InitDownloadTable() ||
|
| !InitSegmentTables() || !InitSyncTable())
|
| - return sql::INIT_FAILURE;
|
| + return LogInitFailure(InitStep::CREATE_TABLES);
|
| CreateMainURLIndex();
|
| CreateKeywordSearchTermsIndices();
|
|
|
| @@ -107,10 +138,14 @@ sql::InitStatus HistoryDatabase::Init(const base::FilePath& history_name) {
|
|
|
| // Version check.
|
| sql::InitStatus version_status = EnsureCurrentVersion();
|
| - if (version_status != sql::INIT_OK)
|
| + if (version_status != sql::INIT_OK) {
|
| + LogInitFailure(InitStep::VERSION);
|
| return version_status;
|
| + }
|
|
|
| - return committer.Commit() ? sql::INIT_OK : sql::INIT_FAILURE;
|
| + if (!committer.Commit())
|
| + return LogInitFailure(InitStep::COMMIT);
|
| + return sql::INIT_OK;
|
| }
|
|
|
| void HistoryDatabase::ComputeDatabaseMetrics(
|
| @@ -383,10 +418,8 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
|
| // Put migration code here
|
|
|
| if (cur_version == 15) {
|
| - if (!db_.Execute("DROP TABLE starred") || !DropStarredIDFromURLs()) {
|
| - LOG(WARNING) << "Unable to update history database to version 16.";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!db_.Execute("DROP TABLE starred") || !DropStarredIDFromURLs())
|
| + return LogMigrationFailure(15);
|
| ++cur_version;
|
| meta_table_.SetVersionNumber(cur_version);
|
| meta_table_.SetCompatibleVersionNumber(
|
| @@ -430,10 +463,8 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
|
| if (cur_version == 20) {
|
| // This is the version prior to adding the visit_duration field in visits
|
| // database. We need to migrate the database.
|
| - if (!MigrateVisitsWithoutDuration()) {
|
| - LOG(WARNING) << "Unable to update history database to version 21.";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateVisitsWithoutDuration())
|
| + return LogMigrationFailure(20);
|
| ++cur_version;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
| @@ -441,102 +472,79 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
|
| if (cur_version == 21) {
|
| // The android_urls table's data schemal was changed in version 21.
|
| #if defined(OS_ANDROID)
|
| - if (!MigrateToVersion22()) {
|
| - LOG(WARNING) << "Unable to migrate the android_urls table to version 22";
|
| - }
|
| + if (!MigrateToVersion22())
|
| + return LogMigrationFailure(21);
|
| #endif
|
| ++cur_version;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 22) {
|
| - if (!MigrateDownloadsState()) {
|
| - LOG(WARNING) << "Unable to fix invalid downloads state values";
|
| - // Invalid state values may cause crashes.
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateDownloadsState())
|
| + return LogMigrationFailure(22);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 23) {
|
| - if (!MigrateDownloadsReasonPathsAndDangerType()) {
|
| - LOG(WARNING) << "Unable to upgrade download interrupt reason and paths";
|
| - // Invalid state values may cause crashes.
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateDownloadsReasonPathsAndDangerType())
|
| + return LogMigrationFailure(23);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 24) {
|
| - if (!MigratePresentationIndex()) {
|
| - LOG(WARNING) << "Unable to migrate history to version 25";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigratePresentationIndex())
|
| + return LogMigrationFailure(24);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 25) {
|
| - if (!MigrateReferrer()) {
|
| - LOG(WARNING) << "Unable to migrate history to version 26";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateReferrer())
|
| + return LogMigrationFailure(25);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 26) {
|
| - if (!MigrateDownloadedByExtension()) {
|
| - LOG(WARNING) << "Unable to migrate history to version 27";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateDownloadedByExtension())
|
| + return LogMigrationFailure(26);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 27) {
|
| - if (!MigrateDownloadValidators()) {
|
| - LOG(WARNING) << "Unable to migrate history to version 28";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateDownloadValidators())
|
| + return LogMigrationFailure(27);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 28) {
|
| - if (!MigrateMimeType()) {
|
| - LOG(WARNING) << "Unable to migrate history to version 29";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateMimeType())
|
| + return LogMigrationFailure(28);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 29) {
|
| - if (!MigrateHashHttpMethodAndGenerateGuids()) {
|
| - LOG(WARNING) << "Unable to migrate history to version 30";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateHashHttpMethodAndGenerateGuids())
|
| + return LogMigrationFailure(29);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 30) {
|
| - if (!MigrateDownloadTabUrl()) {
|
| - LOG(WARNING) << "Unable to migrate history to version 31";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateDownloadTabUrl())
|
| + return LogMigrationFailure(30);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 31) {
|
| - if (!MigrateDownloadSiteInstanceUrl()) {
|
| - LOG(WARNING) << "Unable to migrate history to version 32";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateDownloadSiteInstanceUrl())
|
| + return LogMigrationFailure(31);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
| @@ -548,37 +556,57 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
|
| }
|
|
|
| if (cur_version == 33) {
|
| - if (!MigrateDownloadLastAccessTime()) {
|
| - LOG(WARNING) << "Unable to migrate to version 34";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateDownloadLastAccessTime())
|
| + return LogMigrationFailure(33);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 34) {
|
| + /*
|
| + This code is commented out because we suspect the additional disk storage
|
| + requirements of duplicating the URL table to update the schema cause
|
| + some devices to run out of storage. Errors during initialization are
|
| + very disruptive to the user experience.
|
| +
|
| + TODO(https://crbug.com/736136) figure out how to update users to use
|
| + AUTOINCREMENT.
|
| +
|
| // AUTOINCREMENT is added to urls table PRIMARY KEY(id), need to recreate a
|
| // new table and copy all contents over. favicon_id is removed from urls
|
| // table since we never use it. Also typed_url_sync_metadata and
|
| // autofill_model_type_state tables are introduced, no migration needed for
|
| // those two tables.
|
| - if (!RecreateURLTableWithAllContents()) {
|
| - LOG(WARNING) << "Unable to update history database to version 35.";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!RecreateURLTableWithAllContents())
|
| + return LogMigrationFailure(34);
|
| + */
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| if (cur_version == 35) {
|
| - if (!MigrateDownloadTransient()) {
|
| - LOG(WARNING) << "Unable to migrate to version 36";
|
| - return sql::INIT_FAILURE;
|
| - }
|
| + if (!MigrateDownloadTransient())
|
| + return LogMigrationFailure(35);
|
| cur_version++;
|
| meta_table_.SetVersionNumber(cur_version);
|
| }
|
|
|
| + // ========================= ^^ new migration code goes here ^^
|
| + // ADDING NEW MIGRATION CODE
|
| + // =========================
|
| + //
|
| + // Add new migration code above here. It's important to use as little space
|
| + // as possible during migration. Many phones are very near their storage
|
| + // limit, so anything that recreates or duplicates large history tables can
|
| + // easily push them over that limit.
|
| + //
|
| + // When failures happen during initialization, history is not loaded. This
|
| + // causes all components related to the history database file to fail
|
| + // completely, including autocomplete and downloads. Devices near their
|
| + // storage limit are likely to fail doing some update later, but those
|
| + // operations will then just be skipped which is not nearly as disruptive.
|
| + // See https://crbug.com/734194.
|
| +
|
| // When the version is too old, we just try to continue anyway, there should
|
| // not be a released product that makes a database too old for us to handle.
|
| LOG_IF(WARNING, cur_version < GetCurrentVersion()) <<
|
|
|