| Index: chrome/browser/extensions/activity_log/activity_database.cc
|
| diff --git a/chrome/browser/extensions/activity_log/activity_database.cc b/chrome/browser/extensions/activity_log/activity_database.cc
|
| index 0a6feee5efbd4f44b33138f5e1e8a124595c60e6..72d9a1d65d4f1ea56017934e371450d9bc47d40d 100644
|
| --- a/chrome/browser/extensions/activity_log/activity_database.cc
|
| +++ b/chrome/browser/extensions/activity_log/activity_database.cc
|
| @@ -13,7 +13,9 @@
|
| #include "base/time/clock.h"
|
| #include "chrome/browser/extensions/activity_log/activity_database.h"
|
| #include "chrome/common/chrome_switches.h"
|
| +#include "sql/error_delegate_util.h"
|
| #include "sql/transaction.h"
|
| +#include "third_party/sqlite/sqlite3.h"
|
|
|
| #if defined(OS_MACOSX)
|
| #include "base/mac/mac_util.h"
|
| @@ -34,7 +36,9 @@ namespace extensions {
|
|
|
| ActivityDatabase::ActivityDatabase()
|
| : testing_clock_(NULL),
|
| - initialized_(false) {
|
| + valid_db_(false),
|
| + already_closed_(false),
|
| + did_init_(false) {
|
| // We don't batch commits when in testing mode.
|
| batch_mode_ = !(CommandLine::ForCurrentProcess()->
|
| HasSwitch(switches::kEnableExtensionActivityLogTesting));
|
| @@ -42,14 +46,14 @@ ActivityDatabase::ActivityDatabase()
|
|
|
| ActivityDatabase::~ActivityDatabase() {}
|
|
|
| -void ActivityDatabase::SetErrorCallback(
|
| - const sql::Connection::ErrorCallback& error_callback) {
|
| - db_.set_error_callback(error_callback);
|
| -}
|
| -
|
| void ActivityDatabase::Init(const base::FilePath& db_name) {
|
| + if (did_init_) return;
|
| + did_init_ = true;
|
| if (BrowserThread::IsMessageLoopValid(BrowserThread::DB))
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| + db_.set_error_callback(
|
| + base::Bind(&ActivityDatabase::DatabaseErrorCallback,
|
| + base::Unretained(this)));
|
| db_.set_page_size(4096);
|
| db_.set_cache_size(32);
|
|
|
| @@ -87,7 +91,7 @@ void ActivityDatabase::Init(const base::FilePath& db_name) {
|
| if (stat != sql::INIT_OK)
|
| return LogInitFailure();
|
|
|
| - initialized_ = true;
|
| + valid_db_ = true;
|
| timer_.Start(FROM_HERE,
|
| base::TimeDelta::FromMinutes(2),
|
| this,
|
| @@ -96,23 +100,30 @@ void ActivityDatabase::Init(const base::FilePath& db_name) {
|
|
|
| void ActivityDatabase::LogInitFailure() {
|
| LOG(ERROR) << "Couldn't initialize the activity log database.";
|
| + SoftFailureClose();
|
| }
|
|
|
| void ActivityDatabase::RecordAction(scoped_refptr<Action> action) {
|
| - if (initialized_) {
|
| - if (batch_mode_)
|
| - batched_actions_.push_back(action);
|
| - else
|
| - action->Record(&db_);
|
| + if (!valid_db_) return;
|
| + if (batch_mode_) {
|
| + batched_actions_.push_back(action);
|
| + } else {
|
| + if (!action->Record(&db_)) SoftFailureClose();
|
| }
|
| }
|
|
|
| void ActivityDatabase::RecordBatchedActions() {
|
| + if (!valid_db_) return;
|
| + bool failure = false;
|
| std::vector<scoped_refptr<Action> >::size_type i;
|
| for (i = 0; i != batched_actions_.size(); ++i) {
|
| - batched_actions_.at(i)->Record(&db_);
|
| + if (!batched_actions_.at(i)->Record(&db_)) {
|
| + failure = true;
|
| + break;
|
| + }
|
| }
|
| batched_actions_.clear();
|
| + if (failure) SoftFailureClose();
|
| }
|
|
|
| void ActivityDatabase::SetBatchModeForTesting(bool batch_mode) {
|
| @@ -135,7 +146,7 @@ scoped_ptr<std::vector<scoped_refptr<Action> > > ActivityDatabase::GetActions(
|
| DCHECK_GE(days_ago, 0);
|
| scoped_ptr<std::vector<scoped_refptr<Action> > >
|
| actions(new std::vector<scoped_refptr<Action> >());
|
| - if (!initialized_)
|
| + if (!valid_db_)
|
| return actions.Pass();
|
| // Compute the time bounds for that day.
|
| base::Time morning_midnight = testing_clock_ ?
|
| @@ -164,7 +175,7 @@ scoped_ptr<std::vector<scoped_refptr<Action> > > ActivityDatabase::GetActions(
|
| dom_statement.BindString(0, extension_id);
|
| dom_statement.BindInt64(1, early_bound);
|
| dom_statement.BindInt64(2, late_bound);
|
| - while (dom_statement.Step()) {
|
| + while (dom_statement.is_valid() && dom_statement.Step()) {
|
| scoped_refptr<DOMAction> action = new DOMAction(dom_statement);
|
| actions->push_back(action);
|
| }
|
| @@ -178,7 +189,7 @@ scoped_ptr<std::vector<scoped_refptr<Action> > > ActivityDatabase::GetActions(
|
| api_statement.BindString(0, extension_id);
|
| api_statement.BindInt64(1, early_bound);
|
| api_statement.BindInt64(2, late_bound);
|
| - while (api_statement.Step()) {
|
| + while (api_statement.is_valid() && api_statement.Step()) {
|
| scoped_refptr<APIAction> action = new APIAction(api_statement);
|
| actions->push_back(action);
|
| }
|
| @@ -192,7 +203,7 @@ scoped_ptr<std::vector<scoped_refptr<Action> > > ActivityDatabase::GetActions(
|
| blocked_statement.BindString(0, extension_id);
|
| blocked_statement.BindInt64(1, early_bound);
|
| blocked_statement.BindInt64(2, late_bound);
|
| - while (blocked_statement.Step()) {
|
| + while (blocked_statement.is_valid() && blocked_statement.Step()) {
|
| scoped_refptr<BlockedAction> action = new BlockedAction(blocked_statement);
|
| actions->push_back(action);
|
| }
|
| @@ -201,32 +212,40 @@ scoped_ptr<std::vector<scoped_refptr<Action> > > ActivityDatabase::GetActions(
|
| return actions.Pass();
|
| }
|
|
|
| -void ActivityDatabase::BeginTransaction() {
|
| - db_.BeginTransaction();
|
| -}
|
| -
|
| -void ActivityDatabase::CommitTransaction() {
|
| - db_.CommitTransaction();
|
| -}
|
| -
|
| -void ActivityDatabase::RollbackTransaction() {
|
| - db_.RollbackTransaction();
|
| -}
|
| -
|
| -bool ActivityDatabase::Raze() {
|
| - return db_.Raze();
|
| -}
|
| -
|
| void ActivityDatabase::Close() {
|
| timer_.Stop();
|
| - RecordBatchedActions();
|
| - db_.Close();
|
| + if (!already_closed_) {
|
| + RecordBatchedActions();
|
| + db_.reset_error_callback();
|
| + }
|
| + valid_db_ = false;
|
| + already_closed_ = true;
|
| delete this;
|
| }
|
|
|
| -void ActivityDatabase::KillDatabase() {
|
| +void ActivityDatabase::HardFailureClose() {
|
| + if (already_closed_) return;
|
| + valid_db_ = false;
|
| timer_.Stop();
|
| + db_.reset_error_callback();
|
| db_.RazeAndClose();
|
| + already_closed_ = true;
|
| +}
|
| +
|
| +void ActivityDatabase::SoftFailureClose() {
|
| + valid_db_ = false;
|
| + timer_.Stop();
|
| +}
|
| +
|
| +void ActivityDatabase::DatabaseErrorCallback(int error, sql::Statement* stmt) {
|
| + if (sql::IsErrorCatastrophic(error)) {
|
| + LOG(ERROR) << "Killing the ActivityDatabase due to catastrophic error.";
|
| + HardFailureClose();
|
| + } else if (error != SQLITE_BUSY) {
|
| + // We ignore SQLITE_BUSY errors because they are presumably transient.
|
| + LOG(ERROR) << "Closing the ActivityDatabase due to error.";
|
| + SoftFailureClose();
|
| + }
|
| }
|
|
|
| void ActivityDatabase::SetClockForTesting(base::Clock* clock) {
|
|
|