sqlite_diagnostics.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 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/diagnostics/sqlite_diagnostics.h" 6 7#include "app/sql/connection.h" 8#include "app/sql/diagnostic_error_delegate.h" 9#include "app/sql/statement.h" 10#include "base/file_util.h" 11#include "base/logging.h" 12#include "base/metrics/histogram.h" 13#include "base/path_service.h" 14#include "base/singleton.h" 15#include "base/string_number_conversions.h" 16#include "base/utf_string_conversions.h" 17#include "chrome/common/chrome_constants.h" 18#include "chrome/common/chrome_paths.h" 19#include "third_party/sqlite/sqlite3.h" 20#include "webkit/appcache/appcache_interfaces.h" 21#include "webkit/database/database_tracker.h" 22 23namespace { 24 25// Generic diagnostic test class for checking sqlite db integrity. 26class SqliteIntegrityTest : public DiagnosticTest { 27 public: 28 SqliteIntegrityTest(bool critical, const string16& title, 29 const FilePath& profile_relative_db_path) 30 : DiagnosticTest(title), 31 critical_(critical), 32 db_path_(profile_relative_db_path) { 33 } 34 35 virtual int GetId() { return 0; } 36 37 virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) { 38 FilePath path = GetUserDefaultProfileDir(); 39 path = path.Append(db_path_); 40 if (!file_util::PathExists(path)) { 41 RecordOutcome(ASCIIToUTF16("File not found"), 42 critical_ ? DiagnosticsModel::TEST_FAIL_CONTINUE : 43 DiagnosticsModel::TEST_OK); 44 return true; 45 } 46 47 int errors = 0; 48 { // This block scopes the lifetime of the db objects. 49 sql::Connection db; 50 db.set_exclusive_locking(); 51 if (!db.Open(path)) { 52 RecordFailure(ASCIIToUTF16("Cannot open DB. Possibly corrupted")); 53 return true; 54 } 55 sql::Statement s(db.GetUniqueStatement("PRAGMA integrity_check;")); 56 if (!s) { 57 int error = db.GetErrorCode(); 58 if (SQLITE_BUSY == error) { 59 RecordFailure(ASCIIToUTF16("DB locked by another process")); 60 } else { 61 string16 str(ASCIIToUTF16("Pragma failed. Error: ")); 62 str += base::IntToString16(error); 63 RecordFailure(str); 64 } 65 return false; 66 } 67 while (s.Step()) { 68 std::string result(s.ColumnString(0)); 69 if ("ok" != result) 70 ++errors; 71 } 72 } 73 // All done. Report to the user. 74 if (errors != 0) { 75 string16 str(ASCIIToUTF16("Database corruption detected :")); 76 str += base::IntToString16(errors) + ASCIIToUTF16(" errors"); 77 RecordFailure(str); 78 return true; 79 } 80 RecordSuccess(ASCIIToUTF16("no corruption detected")); 81 return true; 82 } 83 84 private: 85 bool critical_; 86 FilePath db_path_; 87 DISALLOW_COPY_AND_ASSIGN(SqliteIntegrityTest); 88}; 89 90// Uniquifier to use the sql::DiagnosticErrorDelegate template which 91// requires a static name() method. 92template <size_t unique> 93class HistogramUniquifier { 94 public: 95 static const char* name() { 96 const char* kHistogramNames[] = { 97 "Sqlite.Cookie.Error", 98 "Sqlite.History.Error", 99 "Sqlite.Thumbnail.Error", 100 "Sqlite.Text.Error", 101 "Sqlite.Web.Error" 102 }; 103 return kHistogramNames[unique]; 104 } 105}; 106 107} // namespace 108 109sql::ErrorDelegate* GetErrorHandlerForCookieDb() { 110 return new sql::DiagnosticErrorDelegate<HistogramUniquifier<0> >(); 111} 112 113sql::ErrorDelegate* GetErrorHandlerForHistoryDb() { 114 return new sql::DiagnosticErrorDelegate<HistogramUniquifier<1> >(); 115} 116 117sql::ErrorDelegate* GetErrorHandlerForThumbnailDb() { 118 return new sql::DiagnosticErrorDelegate<HistogramUniquifier<2> >(); 119} 120 121sql::ErrorDelegate* GetErrorHandlerForTextDb() { 122 return new sql::DiagnosticErrorDelegate<HistogramUniquifier<3> >(); 123} 124 125sql::ErrorDelegate* GetErrorHandlerForWebDb() { 126 return new sql::DiagnosticErrorDelegate<HistogramUniquifier<4> >(); 127} 128 129DiagnosticTest* MakeSqliteWebDbTest() { 130 return new SqliteIntegrityTest(true, ASCIIToUTF16("Web DB"), 131 FilePath(chrome::kWebDataFilename)); 132} 133 134DiagnosticTest* MakeSqliteCookiesDbTest() { 135 return new SqliteIntegrityTest(true, ASCIIToUTF16("Cookies DB"), 136 FilePath(chrome::kCookieFilename)); 137} 138 139DiagnosticTest* MakeSqliteHistoryDbTest() { 140 return new SqliteIntegrityTest(true, ASCIIToUTF16("History DB"), 141 FilePath(chrome::kHistoryFilename)); 142} 143 144DiagnosticTest* MakeSqliteArchivedHistoryDbTest() { 145 return new SqliteIntegrityTest(false, ASCIIToUTF16("Archived History DB"), 146 FilePath(chrome::kArchivedHistoryFilename)); 147} 148 149DiagnosticTest* MakeSqliteThumbnailsDbTest() { 150 return new SqliteIntegrityTest(false, ASCIIToUTF16("Thumbnails DB"), 151 FilePath(chrome::kThumbnailsFilename)); 152} 153 154DiagnosticTest* MakeSqliteAppCacheDbTest() { 155 FilePath appcache_dir(chrome::kAppCacheDirname); 156 FilePath appcache_db = appcache_dir.Append(appcache::kAppCacheDatabaseName); 157 return new SqliteIntegrityTest(false, ASCIIToUTF16("AppCache DB"), 158 appcache_db); 159} 160 161DiagnosticTest* MakeSqliteWebDatabaseTrackerDbTest() { 162 FilePath databases_dir(webkit_database::kDatabaseDirectoryName); 163 FilePath tracker_db = 164 databases_dir.Append(webkit_database::kTrackerDatabaseFileName); 165 return new SqliteIntegrityTest(false, ASCIIToUTF16("DatabaseTracker DB"), 166 tracker_db); 167} 168