Home | History | Annotate | Download | only in diagnostics
      1 // Copyright (c) 2011 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/memory/singleton.h"
     13 #include "base/metrics/histogram.h"
     14 #include "base/path_service.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 
     23 namespace {
     24 
     25 // Generic diagnostic test class for checking sqlite db integrity.
     26 class 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.
     92 template <size_t unique>
     93 class 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 
    109 sql::ErrorDelegate* GetErrorHandlerForCookieDb() {
    110   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<0> >();
    111 }
    112 
    113 sql::ErrorDelegate* GetErrorHandlerForHistoryDb() {
    114   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<1> >();
    115 }
    116 
    117 sql::ErrorDelegate* GetErrorHandlerForThumbnailDb() {
    118   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<2> >();
    119 }
    120 
    121 sql::ErrorDelegate* GetErrorHandlerForTextDb() {
    122   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<3> >();
    123 }
    124 
    125 sql::ErrorDelegate* GetErrorHandlerForWebDb() {
    126   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<4> >();
    127 }
    128 
    129 DiagnosticTest* MakeSqliteWebDbTest() {
    130   return new SqliteIntegrityTest(true, ASCIIToUTF16("Web DB"),
    131                                  FilePath(chrome::kWebDataFilename));
    132 }
    133 
    134 DiagnosticTest* MakeSqliteCookiesDbTest() {
    135   return new SqliteIntegrityTest(true, ASCIIToUTF16("Cookies DB"),
    136                                  FilePath(chrome::kCookieFilename));
    137 }
    138 
    139 DiagnosticTest* MakeSqliteHistoryDbTest() {
    140   return new SqliteIntegrityTest(true, ASCIIToUTF16("History DB"),
    141                                  FilePath(chrome::kHistoryFilename));
    142 }
    143 
    144 DiagnosticTest* MakeSqliteArchivedHistoryDbTest() {
    145   return new SqliteIntegrityTest(false, ASCIIToUTF16("Archived History DB"),
    146                                  FilePath(chrome::kArchivedHistoryFilename));
    147 }
    148 
    149 DiagnosticTest* MakeSqliteThumbnailsDbTest() {
    150   return new SqliteIntegrityTest(false, ASCIIToUTF16("Thumbnails DB"),
    151                                  FilePath(chrome::kThumbnailsFilename));
    152 }
    153 
    154 DiagnosticTest* 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 
    161 DiagnosticTest* 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