| Index: chrome/browser/net/sqlite_persistent_cookie_store.cc
|
| diff --git a/chrome/browser/net/sqlite_persistent_cookie_store.cc b/chrome/browser/net/sqlite_persistent_cookie_store.cc
|
| index f9795745bbf3c2627c2784b7d1a58f23abfbb242..e970eb198c1fb4556798140567fabdcd827bbee4 100644
|
| --- a/chrome/browser/net/sqlite_persistent_cookie_store.cc
|
| +++ b/chrome/browser/net/sqlite_persistent_cookie_store.cc
|
| @@ -29,6 +29,7 @@
|
| #include "googleurl/src/gurl.h"
|
| #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
|
| #include "net/cookies/canonical_cookie.h"
|
| +#include "sql/error_delegate_util.h"
|
| #include "sql/meta_table.h"
|
| #include "sql/statement.h"
|
| #include "sql/transaction.h"
|
| @@ -107,8 +108,7 @@ class SQLitePersistentCookieStore::Backend
|
|
|
| class KillDatabaseErrorDelegate : public sql::ErrorDelegate {
|
| public:
|
| - KillDatabaseErrorDelegate(Backend* backend,
|
| - sql::ErrorDelegate* wrapped_delegate);
|
| + KillDatabaseErrorDelegate(Backend* backend);
|
|
|
| virtual ~KillDatabaseErrorDelegate() {}
|
|
|
| @@ -119,10 +119,17 @@ class SQLitePersistentCookieStore::Backend
|
|
|
| private:
|
|
|
| + class HistogramUniquifier {
|
| + public:
|
| + static const char* name() { return "Sqlite.Cookie.Error"; }
|
| + };
|
| +
|
| // Do not increment the count on Backend, as that would create a circular
|
| // reference (Backend -> Connection -> ErrorDelegate -> Backend).
|
| Backend* backend_;
|
| - scoped_ptr<sql::ErrorDelegate> wrapped_delegate_;
|
| +
|
| + // True if the delegate has previously attempted to kill the database.
|
| + bool attempted_to_kill_database_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(KillDatabaseErrorDelegate);
|
| };
|
| @@ -273,95 +280,24 @@ class SQLitePersistentCookieStore::Backend
|
| };
|
|
|
| SQLitePersistentCookieStore::Backend::KillDatabaseErrorDelegate::
|
| -KillDatabaseErrorDelegate(Backend* backend,
|
| - sql::ErrorDelegate* wrapped_delegate)
|
| +KillDatabaseErrorDelegate(Backend* backend)
|
| : backend_(backend),
|
| - wrapped_delegate_(wrapped_delegate) {
|
| + attempted_to_kill_database_(false) {
|
| }
|
|
|
| int SQLitePersistentCookieStore::Backend::KillDatabaseErrorDelegate::OnError(
|
| int error, sql::Connection* connection, sql::Statement* stmt) {
|
| - if (wrapped_delegate_.get())
|
| - error = wrapped_delegate_->OnError(error, connection, stmt);
|
| -
|
| - bool delete_db = false;
|
| -
|
| - switch (error) {
|
| - case SQLITE_DONE:
|
| - case SQLITE_OK:
|
| - // Theoretically, the wrapped delegate might have resolved the error, and
|
| - // we would end up here.
|
| - break;
|
| -
|
| - case SQLITE_CORRUPT:
|
| - case SQLITE_NOTADB:
|
| - // Highly unlikely we would ever recover from these.
|
| - delete_db = true;
|
| - break;
|
| -
|
| - case SQLITE_CANTOPEN:
|
| - // TODO(erikwright): Figure out what this means.
|
| - break;
|
| -
|
| - case SQLITE_IOERR:
|
| - // This could be broken blocks, in which case deleting the DB would be a
|
| - // good idea. But it might also be transient.
|
| - // TODO(erikwright): Figure out if we can distinguish between the two,
|
| - // or determine through metrics analysis to what extent these failures are
|
| - // transient.
|
| - break;
|
| -
|
| - case SQLITE_BUSY:
|
| - // Presumably transient.
|
| - break;
|
| -
|
| - case SQLITE_TOOBIG:
|
| - case SQLITE_FULL:
|
| - case SQLITE_NOMEM:
|
| - // Not a problem with the database.
|
| - break;
|
| -
|
| - case SQLITE_READONLY:
|
| - // Presumably either transient or we don't have the privileges to
|
| - // move/delete the file anyway.
|
| - break;
|
| -
|
| - case SQLITE_CONSTRAINT:
|
| - case SQLITE_ERROR:
|
| - // These probably indicate a programming error or a migration failure that
|
| - // we prefer not to mask.
|
| - break;
|
| -
|
| - case SQLITE_LOCKED:
|
| - case SQLITE_INTERNAL:
|
| - case SQLITE_PERM:
|
| - case SQLITE_ABORT:
|
| - case SQLITE_INTERRUPT:
|
| - case SQLITE_NOTFOUND:
|
| - case SQLITE_PROTOCOL:
|
| - case SQLITE_EMPTY:
|
| - case SQLITE_SCHEMA:
|
| - case SQLITE_MISMATCH:
|
| - case SQLITE_MISUSE:
|
| - case SQLITE_NOLFS:
|
| - case SQLITE_AUTH:
|
| - case SQLITE_FORMAT:
|
| - case SQLITE_RANGE:
|
| - case SQLITE_ROW:
|
| - // None of these appear in error reports, so for now let's not try to
|
| - // guess at how to handle them.
|
| - break;
|
| - }
|
| + sql::LogAndRecordErrorInHistogram<HistogramUniquifier>(error, connection);
|
| +
|
| + // Do not attempt to kill database more than once. If the first time failed,
|
| + // it is unlikely that a second time will be successful.
|
| + if (!attempted_to_kill_database_ && sql::IsErrorCatastrophic(error)) {
|
| + attempted_to_kill_database_ = true;
|
|
|
| - if (delete_db && backend_) {
|
| // Don't just do the close/delete here, as we are being called by |db| and
|
| // that seems dangerous.
|
| MessageLoop::current()->PostTask(
|
| FROM_HERE, base::Bind(&Backend::KillDatabase, backend_));
|
| -
|
| - // Avoid being called more than once. This will destroy the
|
| - // KillDatabaseErrorDelegate. Do not refer to any members from here forward.
|
| - connection->set_error_delegate(wrapped_delegate_.release());
|
| }
|
|
|
| return error;
|
| @@ -614,8 +550,7 @@ bool SQLitePersistentCookieStore::Backend::InitializeDatabase() {
|
| }
|
|
|
| db_.reset(new sql::Connection);
|
| - db_->set_error_delegate(
|
| - new KillDatabaseErrorDelegate(this, GetErrorHandlerForCookieDb()));
|
| + db_->set_error_delegate(new KillDatabaseErrorDelegate(this));
|
|
|
| if (!db_->Open(path_)) {
|
| NOTREACHED() << "Unable to open cookie DB.";
|
|
|