• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SqliteIntegrityTest(bool critical,const string16 & title,const FilePath & profile_relative_db_path)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 
GetId()35   virtual int GetId() { return 0; }
36 
ExecuteImpl(DiagnosticsModel::Observer * observer)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:
name()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 
GetErrorHandlerForCookieDb()109 sql::ErrorDelegate* GetErrorHandlerForCookieDb() {
110   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<0> >();
111 }
112 
GetErrorHandlerForHistoryDb()113 sql::ErrorDelegate* GetErrorHandlerForHistoryDb() {
114   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<1> >();
115 }
116 
GetErrorHandlerForThumbnailDb()117 sql::ErrorDelegate* GetErrorHandlerForThumbnailDb() {
118   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<2> >();
119 }
120 
GetErrorHandlerForTextDb()121 sql::ErrorDelegate* GetErrorHandlerForTextDb() {
122   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<3> >();
123 }
124 
GetErrorHandlerForWebDb()125 sql::ErrorDelegate* GetErrorHandlerForWebDb() {
126   return new sql::DiagnosticErrorDelegate<HistogramUniquifier<4> >();
127 }
128 
MakeSqliteWebDbTest()129 DiagnosticTest* MakeSqliteWebDbTest() {
130   return new SqliteIntegrityTest(true, ASCIIToUTF16("Web DB"),
131                                  FilePath(chrome::kWebDataFilename));
132 }
133 
MakeSqliteCookiesDbTest()134 DiagnosticTest* MakeSqliteCookiesDbTest() {
135   return new SqliteIntegrityTest(true, ASCIIToUTF16("Cookies DB"),
136                                  FilePath(chrome::kCookieFilename));
137 }
138 
MakeSqliteHistoryDbTest()139 DiagnosticTest* MakeSqliteHistoryDbTest() {
140   return new SqliteIntegrityTest(true, ASCIIToUTF16("History DB"),
141                                  FilePath(chrome::kHistoryFilename));
142 }
143 
MakeSqliteArchivedHistoryDbTest()144 DiagnosticTest* MakeSqliteArchivedHistoryDbTest() {
145   return new SqliteIntegrityTest(false, ASCIIToUTF16("Archived History DB"),
146                                  FilePath(chrome::kArchivedHistoryFilename));
147 }
148 
MakeSqliteThumbnailsDbTest()149 DiagnosticTest* MakeSqliteThumbnailsDbTest() {
150   return new SqliteIntegrityTest(false, ASCIIToUTF16("Thumbnails DB"),
151                                  FilePath(chrome::kThumbnailsFilename));
152 }
153 
MakeSqliteAppCacheDbTest()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 
MakeSqliteWebDatabaseTrackerDbTest()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