sqlite_diagnostics.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
1// Copyright (c) 2012 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 "base/file_util.h"
8#include "base/logging.h"
9#include "base/memory/singleton.h"
10#include "base/metrics/histogram.h"
11#include "base/path_service.h"
12#include "base/strings/string_number_conversions.h"
13#include "base/utf_string_conversions.h"
14#include "chrome/common/chrome_constants.h"
15#include "chrome/common/chrome_paths.h"
16#include "components/webdata/common/webdata_constants.h"
17#include "content/public/common/content_constants.h"
18#include "sql/connection.h"
19#include "sql/statement.h"
20#include "third_party/sqlite/sqlite3.h"
21#include "webkit/appcache/appcache_interfaces.h"
22#include "webkit/browser/database/database_tracker.h"
23
24namespace {
25
26// Generic diagnostic test class for checking sqlite db integrity.
27class SqliteIntegrityTest : public DiagnosticTest {
28 public:
29  SqliteIntegrityTest(bool critical, const string16& title,
30                      const base::FilePath& profile_relative_db_path)
31      : DiagnosticTest(title),
32        critical_(critical),
33        db_path_(profile_relative_db_path) {
34  }
35
36  virtual int GetId() OVERRIDE { return 0; }
37
38  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE {
39    base::FilePath path = GetUserDefaultProfileDir();
40    path = path.Append(db_path_);
41    if (!file_util::PathExists(path)) {
42      RecordOutcome(ASCIIToUTF16("File not found"),
43                    critical_ ? DiagnosticsModel::TEST_FAIL_CONTINUE :
44                                DiagnosticsModel::TEST_OK);
45      return true;
46    }
47
48    int errors = 0;
49    { // This block scopes the lifetime of the db objects.
50      sql::Connection db;
51      db.set_exclusive_locking();
52      if (!db.Open(path)) {
53        RecordFailure(ASCIIToUTF16("Cannot open DB. Possibly corrupted"));
54        return true;
55      }
56      sql::Statement s(db.GetUniqueStatement("PRAGMA integrity_check;"));
57      if (!s.is_valid()) {
58        int error = db.GetErrorCode();
59        if (SQLITE_BUSY == error) {
60          RecordFailure(ASCIIToUTF16("DB locked by another process"));
61        } else {
62          string16 str(ASCIIToUTF16("Pragma failed. Error: "));
63          str += base::IntToString16(error);
64          RecordFailure(str);
65        }
66        return false;
67      }
68      while (s.Step()) {
69        std::string result(s.ColumnString(0));
70        if ("ok" != result)
71          ++errors;
72      }
73    }
74    // All done. Report to the user.
75    if (errors != 0) {
76      string16 str(ASCIIToUTF16("Database corruption detected :"));
77      str += base::IntToString16(errors) + ASCIIToUTF16(" errors");
78      RecordFailure(str);
79      return true;
80    }
81    RecordSuccess(ASCIIToUTF16("no corruption detected"));
82    return true;
83  }
84
85 private:
86  bool critical_;
87  base::FilePath db_path_;
88  DISALLOW_COPY_AND_ASSIGN(SqliteIntegrityTest);
89};
90
91}  // namespace
92
93DiagnosticTest* MakeSqliteWebDbTest() {
94  return new SqliteIntegrityTest(true, ASCIIToUTF16("Web DB"),
95                                 base::FilePath(kWebDataFilename));
96}
97
98DiagnosticTest* MakeSqliteCookiesDbTest() {
99  return new SqliteIntegrityTest(true, ASCIIToUTF16("Cookies DB"),
100                                 base::FilePath(chrome::kCookieFilename));
101}
102
103DiagnosticTest* MakeSqliteHistoryDbTest() {
104  return new SqliteIntegrityTest(true, ASCIIToUTF16("History DB"),
105                                 base::FilePath(chrome::kHistoryFilename));
106}
107
108DiagnosticTest* MakeSqliteArchivedHistoryDbTest() {
109  return new SqliteIntegrityTest(
110      false, ASCIIToUTF16("Archived History DB"),
111      base::FilePath(chrome::kArchivedHistoryFilename));
112}
113
114DiagnosticTest* MakeSqliteThumbnailsDbTest() {
115  return new SqliteIntegrityTest(false, ASCIIToUTF16("Thumbnails DB"),
116                                 base::FilePath(chrome::kThumbnailsFilename));
117}
118
119DiagnosticTest* MakeSqliteAppCacheDbTest() {
120  base::FilePath appcache_dir(content::kAppCacheDirname);
121  base::FilePath appcache_db =
122      appcache_dir.Append(appcache::kAppCacheDatabaseName);
123  return new SqliteIntegrityTest(false, ASCIIToUTF16("AppCache DB"),
124                                 appcache_db);
125}
126
127DiagnosticTest* MakeSqliteWebDatabaseTrackerDbTest() {
128  base::FilePath databases_dir(webkit_database::kDatabaseDirectoryName);
129  base::FilePath tracker_db =
130      databases_dir.Append(webkit_database::kTrackerDatabaseFileName);
131  return new SqliteIntegrityTest(false, ASCIIToUTF16("DatabaseTracker DB"),
132                                 tracker_db);
133}
134