| // Copyright (c) 2011 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/diagnostics/sqlite_diagnostics.h" |
| |
| #include "app/sql/connection.h" |
| #include "app/sql/diagnostic_error_delegate.h" |
| #include "app/sql/statement.h" |
| #include "base/file_util.h" |
| #include "base/logging.h" |
| #include "base/memory/singleton.h" |
| #include "base/metrics/histogram.h" |
| #include "base/path_service.h" |
| #include "base/string_number_conversions.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "third_party/sqlite/sqlite3.h" |
| #include "webkit/appcache/appcache_interfaces.h" |
| #include "webkit/database/database_tracker.h" |
| |
| namespace { |
| |
| // Generic diagnostic test class for checking sqlite db integrity. |
| class SqliteIntegrityTest : public DiagnosticTest { |
| public: |
| SqliteIntegrityTest(bool critical, const string16& title, |
| const FilePath& profile_relative_db_path) |
| : DiagnosticTest(title), |
| critical_(critical), |
| db_path_(profile_relative_db_path) { |
| } |
| |
| virtual int GetId() { return 0; } |
| |
| virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) { |
| FilePath path = GetUserDefaultProfileDir(); |
| path = path.Append(db_path_); |
| if (!file_util::PathExists(path)) { |
| RecordOutcome(ASCIIToUTF16("File not found"), |
| critical_ ? DiagnosticsModel::TEST_FAIL_CONTINUE : |
| DiagnosticsModel::TEST_OK); |
| return true; |
| } |
| |
| int errors = 0; |
| { // This block scopes the lifetime of the db objects. |
| sql::Connection db; |
| db.set_exclusive_locking(); |
| if (!db.Open(path)) { |
| RecordFailure(ASCIIToUTF16("Cannot open DB. Possibly corrupted")); |
| return true; |
| } |
| sql::Statement s(db.GetUniqueStatement("PRAGMA integrity_check;")); |
| if (!s) { |
| int error = db.GetErrorCode(); |
| if (SQLITE_BUSY == error) { |
| RecordFailure(ASCIIToUTF16("DB locked by another process")); |
| } else { |
| string16 str(ASCIIToUTF16("Pragma failed. Error: ")); |
| str += base::IntToString16(error); |
| RecordFailure(str); |
| } |
| return false; |
| } |
| while (s.Step()) { |
| std::string result(s.ColumnString(0)); |
| if ("ok" != result) |
| ++errors; |
| } |
| } |
| // All done. Report to the user. |
| if (errors != 0) { |
| string16 str(ASCIIToUTF16("Database corruption detected :")); |
| str += base::IntToString16(errors) + ASCIIToUTF16(" errors"); |
| RecordFailure(str); |
| return true; |
| } |
| RecordSuccess(ASCIIToUTF16("no corruption detected")); |
| return true; |
| } |
| |
| private: |
| bool critical_; |
| FilePath db_path_; |
| DISALLOW_COPY_AND_ASSIGN(SqliteIntegrityTest); |
| }; |
| |
| // Uniquifier to use the sql::DiagnosticErrorDelegate template which |
| // requires a static name() method. |
| template <size_t unique> |
| class HistogramUniquifier { |
| public: |
| static const char* name() { |
| const char* kHistogramNames[] = { |
| "Sqlite.Cookie.Error", |
| "Sqlite.History.Error", |
| "Sqlite.Thumbnail.Error", |
| "Sqlite.Text.Error", |
| "Sqlite.Web.Error" |
| }; |
| return kHistogramNames[unique]; |
| } |
| }; |
| |
| } // namespace |
| |
| sql::ErrorDelegate* GetErrorHandlerForCookieDb() { |
| return new sql::DiagnosticErrorDelegate<HistogramUniquifier<0> >(); |
| } |
| |
| sql::ErrorDelegate* GetErrorHandlerForHistoryDb() { |
| return new sql::DiagnosticErrorDelegate<HistogramUniquifier<1> >(); |
| } |
| |
| sql::ErrorDelegate* GetErrorHandlerForThumbnailDb() { |
| return new sql::DiagnosticErrorDelegate<HistogramUniquifier<2> >(); |
| } |
| |
| sql::ErrorDelegate* GetErrorHandlerForTextDb() { |
| return new sql::DiagnosticErrorDelegate<HistogramUniquifier<3> >(); |
| } |
| |
| sql::ErrorDelegate* GetErrorHandlerForWebDb() { |
| return new sql::DiagnosticErrorDelegate<HistogramUniquifier<4> >(); |
| } |
| |
| DiagnosticTest* MakeSqliteWebDbTest() { |
| return new SqliteIntegrityTest(true, ASCIIToUTF16("Web DB"), |
| FilePath(chrome::kWebDataFilename)); |
| } |
| |
| DiagnosticTest* MakeSqliteCookiesDbTest() { |
| return new SqliteIntegrityTest(true, ASCIIToUTF16("Cookies DB"), |
| FilePath(chrome::kCookieFilename)); |
| } |
| |
| DiagnosticTest* MakeSqliteHistoryDbTest() { |
| return new SqliteIntegrityTest(true, ASCIIToUTF16("History DB"), |
| FilePath(chrome::kHistoryFilename)); |
| } |
| |
| DiagnosticTest* MakeSqliteArchivedHistoryDbTest() { |
| return new SqliteIntegrityTest(false, ASCIIToUTF16("Archived History DB"), |
| FilePath(chrome::kArchivedHistoryFilename)); |
| } |
| |
| DiagnosticTest* MakeSqliteThumbnailsDbTest() { |
| return new SqliteIntegrityTest(false, ASCIIToUTF16("Thumbnails DB"), |
| FilePath(chrome::kThumbnailsFilename)); |
| } |
| |
| DiagnosticTest* MakeSqliteAppCacheDbTest() { |
| FilePath appcache_dir(chrome::kAppCacheDirname); |
| FilePath appcache_db = appcache_dir.Append(appcache::kAppCacheDatabaseName); |
| return new SqliteIntegrityTest(false, ASCIIToUTF16("AppCache DB"), |
| appcache_db); |
| } |
| |
| DiagnosticTest* MakeSqliteWebDatabaseTrackerDbTest() { |
| FilePath databases_dir(webkit_database::kDatabaseDirectoryName); |
| FilePath tracker_db = |
| databases_dir.Append(webkit_database::kTrackerDatabaseFileName); |
| return new SqliteIntegrityTest(false, ASCIIToUTF16("DatabaseTracker DB"), |
| tracker_db); |
| } |