普通文本  |  168行  |  5.4 KB

// 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);
}