Chromium Code Reviews| Index: components/history/core/browser/history_backend.cc |
| diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc |
| index 42732d85f1fe31ec625d0eedd10747b901a47a50..0444f3dc38969a27e77d831a5f8f811e7bc2efd7 100644 |
| --- a/components/history/core/browser/history_backend.cc |
| +++ b/components/history/core/browser/history_backend.cc |
| @@ -68,12 +68,18 @@ using base::TimeTicks; |
| namespace history { |
| namespace { |
| + |
| void RunUnlessCanceled( |
| const base::Closure& closure, |
| const base::CancelableTaskTracker::IsCanceledCallback& is_canceled) { |
| if (!is_canceled.Run()) |
| closure.Run(); |
| } |
| + |
| +void NullErrorHandler(int error, sql::Statement* stmt) { |
| + // Does nothing. Prevents DCHECKING on SQLITE errors on Debug builds. |
| +} |
| + |
| } // namespace |
| // How long we'll wait to do a commit, so that things are batched together. |
| @@ -206,6 +212,8 @@ HistoryBackend::HistoryBackend( |
| scoped_refptr<base::SequencedTaskRunner> task_runner) |
| : delegate_(delegate), |
| scheduled_kill_db_(false), |
| + error_callback_(base::Bind(&HistoryBackend::DatabaseErrorCallback, |
| + base::Unretained(this))), |
| expirer_(this, backend_client.get(), task_runner), |
| recent_redirects_(kMaxRedirectCount), |
| backend_destroy_message_loop_(nullptr), |
| @@ -648,18 +656,12 @@ void HistoryBackend::InitImpl( |
| history_database_params.download_interrupt_reason_none, |
| history_database_params.download_interrupt_reason_crash)); |
| - // Unretained to avoid a ref loop with db_. |
| - db_->set_error_callback(base::Bind(&HistoryBackend::DatabaseErrorCallback, |
| - base::Unretained(this))); |
| + db_->set_error_callback(error_callback_); |
| sql::InitStatus status = db_->Init(history_name); |
| switch (status) { |
| case sql::INIT_OK: |
| break; |
| - case sql::INIT_TOO_NEW: |
| - delegate_->NotifyProfileError(status); |
| - db_.reset(); |
| - return; |
| case sql::INIT_FAILURE: { |
| // A null db_ will cause all calls on this object to notice this error |
| // and to not continue. If the error callback scheduled killing the |
| @@ -669,7 +671,24 @@ void HistoryBackend::InitImpl( |
| if (kill_db) |
| KillHistoryDatabase(); |
| UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db); |
| - delegate_->NotifyProfileError(status); |
| + } // Falls through. |
| + case sql::INIT_TOO_NEW: { |
| + std::vector<base::FilePath::StringType> path_components; |
| + history_name.GetComponents(&path_components); |
| +#if defined(OS_WIN) |
| + const base::FilePath::StringType default_dir(L"Default"); |
| +#else |
| + const base::FilePath::StringType default_dir("Default"); |
| +#endif // defined(OS_WIN) |
| + |
| + auto itr = std::find(path_components.begin(), path_components.end(), |
|
michaeln
2016/07/12 20:05:32
This test for default vs not a is probably not 100
afakhry
2016/07/13 19:57:59
I think you meant:
history_name.DirName().BaseNam
|
| + default_dir); |
| + const std::string corrupted_file_name = |
| + history_name.BaseName().AsUTF8Unsafe() + (itr != path_components.end() |
| + ? " [Default profile]" |
| + : " [User profile]"); |
| + db_diagnostics_["Corrupted file"] = corrupted_file_name; |
| + delegate_->NotifyProfileError(status, db_diagnostics_); |
| db_.reset(); |
| return; |
| } |
| @@ -2410,6 +2429,12 @@ void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) { |
| void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) { |
| if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) { |
| scheduled_kill_db_ = true; |
| + |
| + // Gather diagnostic info, but prevent reentrant error callbacks. |
| + db_->set_error_callback(base::Bind(&NullErrorHandler)); |
| + db_diagnostics_ = db_->GetDiagnosticMap(); |
| + db_->set_error_callback(error_callback_); |
| + |
| // Don't just do the close/delete here, as we are being called by |db| and |
| // that seems dangerous. |
| // TODO(shess): Consider changing KillHistoryDatabase() to use |