Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(743)

Side by Side Diff: chrome/browser/extensions/activity_log/activity_database.cc

Issue 16510002: Better ActivityLog error handling (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Reinstating the command line Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <string> 5 #include <string>
6 #include "base/command_line.h" 6 #include "base/command_line.h"
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/string_util.h" 8 #include "base/string_util.h"
9 #include "base/stringprintf.h" 9 #include "base/stringprintf.h"
10 #include "base/threading/thread.h" 10 #include "base/threading/thread.h"
11 #include "base/threading/thread_checker.h" 11 #include "base/threading/thread_checker.h"
12 #include "base/time.h" 12 #include "base/time.h"
13 #include "base/time/clock.h" 13 #include "base/time/clock.h"
14 #include "chrome/browser/extensions/activity_log/activity_database.h" 14 #include "chrome/browser/extensions/activity_log/activity_database.h"
15 #include "chrome/common/chrome_switches.h" 15 #include "chrome/common/chrome_switches.h"
16 #include "sql/error_delegate_util.h"
16 #include "sql/transaction.h" 17 #include "sql/transaction.h"
18 #include "third_party/sqlite/sqlite3.h"
17 19
18 #if defined(OS_MACOSX) 20 #if defined(OS_MACOSX)
19 #include "base/mac/mac_util.h" 21 #include "base/mac/mac_util.h"
20 #endif 22 #endif
21 23
22 using content::BrowserThread; 24 using content::BrowserThread;
23 25
24 namespace { 26 namespace {
25 27
26 bool SortActionsByTime(const scoped_refptr<extensions::Action> a, 28 bool SortActionsByTime(const scoped_refptr<extensions::Action> a,
27 const scoped_refptr<extensions::Action> b) { 29 const scoped_refptr<extensions::Action> b) {
28 return a->time() > b->time(); 30 return a->time() > b->time();
29 } 31 }
30 32
31 } // namespace 33 } // namespace
32 34
33 namespace extensions { 35 namespace extensions {
34 36
35 ActivityDatabase::ActivityDatabase() 37 ActivityDatabase::ActivityDatabase()
36 : testing_clock_(NULL), 38 : testing_clock_(NULL),
37 initialized_(false) { 39 valid_db_(false),
40 already_closed_(false),
41 did_init_(false) {
38 // We don't batch commits when in testing mode. 42 // We don't batch commits when in testing mode.
39 batch_mode_ = !(CommandLine::ForCurrentProcess()-> 43 batch_mode_ = !(CommandLine::ForCurrentProcess()->
40 HasSwitch(switches::kEnableExtensionActivityLogTesting)); 44 HasSwitch(switches::kEnableExtensionActivityLogTesting));
41 } 45 }
42 46
43 ActivityDatabase::~ActivityDatabase() {} 47 ActivityDatabase::~ActivityDatabase() {}
44 48
45 void ActivityDatabase::SetErrorCallback(
46 const sql::Connection::ErrorCallback& error_callback) {
47 db_.set_error_callback(error_callback);
48 }
49
50 void ActivityDatabase::Init(const base::FilePath& db_name) { 49 void ActivityDatabase::Init(const base::FilePath& db_name) {
50 if (did_init_) return;
51 did_init_ = true;
51 if (BrowserThread::IsMessageLoopValid(BrowserThread::DB)) 52 if (BrowserThread::IsMessageLoopValid(BrowserThread::DB))
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
54 db_.set_error_callback(
55 base::Bind(&ActivityDatabase::DatabaseErrorCallback,
56 base::Unretained(this)));
53 db_.set_page_size(4096); 57 db_.set_page_size(4096);
54 db_.set_cache_size(32); 58 db_.set_cache_size(32);
55 59
56 if (!db_.Open(db_name)) { 60 if (!db_.Open(db_name)) {
57 LOG(ERROR) << db_.GetErrorMessage(); 61 LOG(ERROR) << db_.GetErrorMessage();
58 return LogInitFailure(); 62 return LogInitFailure();
59 } 63 }
60 64
61 // Wrap the initialization in a transaction so that the db doesn't 65 // Wrap the initialization in a transaction so that the db doesn't
62 // get corrupted if init fails/crashes. 66 // get corrupted if init fails/crashes.
(...skipping 17 matching lines...) Expand all
80 return LogInitFailure(); 84 return LogInitFailure();
81 85
82 // Create the BlockedAction database. 86 // Create the BlockedAction database.
83 if (!BlockedAction::InitializeTable(&db_)) 87 if (!BlockedAction::InitializeTable(&db_))
84 return LogInitFailure(); 88 return LogInitFailure();
85 89
86 sql::InitStatus stat = committer.Commit() ? sql::INIT_OK : sql::INIT_FAILURE; 90 sql::InitStatus stat = committer.Commit() ? sql::INIT_OK : sql::INIT_FAILURE;
87 if (stat != sql::INIT_OK) 91 if (stat != sql::INIT_OK)
88 return LogInitFailure(); 92 return LogInitFailure();
89 93
90 initialized_ = true; 94 valid_db_ = true;
91 timer_.Start(FROM_HERE, 95 timer_.Start(FROM_HERE,
92 base::TimeDelta::FromMinutes(2), 96 base::TimeDelta::FromMinutes(2),
93 this, 97 this,
94 &ActivityDatabase::RecordBatchedActions); 98 &ActivityDatabase::RecordBatchedActions);
95 } 99 }
96 100
97 void ActivityDatabase::LogInitFailure() { 101 void ActivityDatabase::LogInitFailure() {
98 LOG(ERROR) << "Couldn't initialize the activity log database."; 102 LOG(ERROR) << "Couldn't initialize the activity log database.";
103 SoftFailureClose();
99 } 104 }
100 105
101 void ActivityDatabase::RecordAction(scoped_refptr<Action> action) { 106 void ActivityDatabase::RecordAction(scoped_refptr<Action> action) {
102 if (initialized_) { 107 if (!valid_db_) return;
103 if (batch_mode_) 108 if (batch_mode_) {
104 batched_actions_.push_back(action); 109 batched_actions_.push_back(action);
105 else 110 } else {
106 action->Record(&db_); 111 if (!action->Record(&db_)) SoftFailureClose();
107 } 112 }
108 } 113 }
109 114
110 void ActivityDatabase::RecordBatchedActions() { 115 void ActivityDatabase::RecordBatchedActions() {
116 if (!valid_db_) return;
117 bool failure = false;
111 std::vector<scoped_refptr<Action> >::size_type i; 118 std::vector<scoped_refptr<Action> >::size_type i;
112 for (i = 0; i != batched_actions_.size(); ++i) { 119 for (i = 0; i != batched_actions_.size(); ++i) {
113 batched_actions_.at(i)->Record(&db_); 120 if (!batched_actions_.at(i)->Record(&db_)) {
121 failure = true;
122 break;
123 }
114 } 124 }
115 batched_actions_.clear(); 125 batched_actions_.clear();
126 if (failure) SoftFailureClose();
116 } 127 }
117 128
118 void ActivityDatabase::SetBatchModeForTesting(bool batch_mode) { 129 void ActivityDatabase::SetBatchModeForTesting(bool batch_mode) {
119 if (batch_mode && !batch_mode_) { 130 if (batch_mode && !batch_mode_) {
120 timer_.Start(FROM_HERE, 131 timer_.Start(FROM_HERE,
121 base::TimeDelta::FromMinutes(2), 132 base::TimeDelta::FromMinutes(2),
122 this, 133 this,
123 &ActivityDatabase::RecordBatchedActions); 134 &ActivityDatabase::RecordBatchedActions);
124 } else if (!batch_mode && batch_mode_) { 135 } else if (!batch_mode && batch_mode_) {
125 timer_.Stop(); 136 timer_.Stop();
126 RecordBatchedActions(); 137 RecordBatchedActions();
127 } 138 }
128 batch_mode_ = batch_mode; 139 batch_mode_ = batch_mode;
129 } 140 }
130 141
131 scoped_ptr<std::vector<scoped_refptr<Action> > > ActivityDatabase::GetActions( 142 scoped_ptr<std::vector<scoped_refptr<Action> > > ActivityDatabase::GetActions(
132 const std::string& extension_id, const int days_ago) { 143 const std::string& extension_id, const int days_ago) {
133 if (BrowserThread::IsMessageLoopValid(BrowserThread::DB)) 144 if (BrowserThread::IsMessageLoopValid(BrowserThread::DB))
134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
135 DCHECK_GE(days_ago, 0); 146 DCHECK_GE(days_ago, 0);
136 scoped_ptr<std::vector<scoped_refptr<Action> > > 147 scoped_ptr<std::vector<scoped_refptr<Action> > >
137 actions(new std::vector<scoped_refptr<Action> >()); 148 actions(new std::vector<scoped_refptr<Action> >());
138 if (!initialized_) 149 if (!valid_db_)
139 return actions.Pass(); 150 return actions.Pass();
140 // Compute the time bounds for that day. 151 // Compute the time bounds for that day.
141 base::Time morning_midnight = testing_clock_ ? 152 base::Time morning_midnight = testing_clock_ ?
142 testing_clock_->Now().LocalMidnight() : 153 testing_clock_->Now().LocalMidnight() :
143 base::Time::Now().LocalMidnight(); 154 base::Time::Now().LocalMidnight();
144 int64 early_bound = 0; 155 int64 early_bound = 0;
145 int64 late_bound = 0; 156 int64 late_bound = 0;
146 if (days_ago == 0) { 157 if (days_ago == 0) {
147 early_bound = morning_midnight.ToInternalValue(); 158 early_bound = morning_midnight.ToInternalValue();
148 late_bound = base::Time::Max().ToInternalValue(); 159 late_bound = base::Time::Max().ToInternalValue();
149 } else { 160 } else {
150 base::Time early_time = morning_midnight - 161 base::Time early_time = morning_midnight -
151 base::TimeDelta::FromDays(days_ago); 162 base::TimeDelta::FromDays(days_ago);
152 base::Time late_time = morning_midnight - 163 base::Time late_time = morning_midnight -
153 base::TimeDelta::FromDays(days_ago-1); 164 base::TimeDelta::FromDays(days_ago-1);
154 early_bound = early_time.ToInternalValue(); 165 early_bound = early_time.ToInternalValue();
155 late_bound = late_time.ToInternalValue(); 166 late_bound = late_time.ToInternalValue();
156 } 167 }
157 // Get the DOMActions. 168 // Get the DOMActions.
158 std::string dom_str = base::StringPrintf("SELECT * FROM %s " 169 std::string dom_str = base::StringPrintf("SELECT * FROM %s "
159 "WHERE extension_id=? AND " 170 "WHERE extension_id=? AND "
160 "time>? AND time<=?", 171 "time>? AND time<=?",
161 DOMAction::kTableName); 172 DOMAction::kTableName);
162 sql::Statement dom_statement(db_.GetCachedStatement(SQL_FROM_HERE, 173 sql::Statement dom_statement(db_.GetCachedStatement(SQL_FROM_HERE,
163 dom_str.c_str())); 174 dom_str.c_str()));
164 dom_statement.BindString(0, extension_id); 175 dom_statement.BindString(0, extension_id);
165 dom_statement.BindInt64(1, early_bound); 176 dom_statement.BindInt64(1, early_bound);
166 dom_statement.BindInt64(2, late_bound); 177 dom_statement.BindInt64(2, late_bound);
167 while (dom_statement.Step()) { 178 while (dom_statement.is_valid() && dom_statement.Step()) {
168 scoped_refptr<DOMAction> action = new DOMAction(dom_statement); 179 scoped_refptr<DOMAction> action = new DOMAction(dom_statement);
169 actions->push_back(action); 180 actions->push_back(action);
170 } 181 }
171 // Get the APIActions. 182 // Get the APIActions.
172 std::string api_str = base::StringPrintf("SELECT * FROM %s " 183 std::string api_str = base::StringPrintf("SELECT * FROM %s "
173 "WHERE extension_id=? AND " 184 "WHERE extension_id=? AND "
174 "time>? AND time<=?", 185 "time>? AND time<=?",
175 APIAction::kTableName); 186 APIAction::kTableName);
176 sql::Statement api_statement(db_.GetCachedStatement(SQL_FROM_HERE, 187 sql::Statement api_statement(db_.GetCachedStatement(SQL_FROM_HERE,
177 api_str.c_str())); 188 api_str.c_str()));
178 api_statement.BindString(0, extension_id); 189 api_statement.BindString(0, extension_id);
179 api_statement.BindInt64(1, early_bound); 190 api_statement.BindInt64(1, early_bound);
180 api_statement.BindInt64(2, late_bound); 191 api_statement.BindInt64(2, late_bound);
181 while (api_statement.Step()) { 192 while (api_statement.is_valid() && api_statement.Step()) {
182 scoped_refptr<APIAction> action = new APIAction(api_statement); 193 scoped_refptr<APIAction> action = new APIAction(api_statement);
183 actions->push_back(action); 194 actions->push_back(action);
184 } 195 }
185 // Get the BlockedActions. 196 // Get the BlockedActions.
186 std::string blocked_str = base::StringPrintf("SELECT * FROM %s " 197 std::string blocked_str = base::StringPrintf("SELECT * FROM %s "
187 "WHERE extension_id=? AND " 198 "WHERE extension_id=? AND "
188 "time>? AND time<=?", 199 "time>? AND time<=?",
189 BlockedAction::kTableName); 200 BlockedAction::kTableName);
190 sql::Statement blocked_statement(db_.GetCachedStatement(SQL_FROM_HERE, 201 sql::Statement blocked_statement(db_.GetCachedStatement(SQL_FROM_HERE,
191 blocked_str.c_str())); 202 blocked_str.c_str()));
192 blocked_statement.BindString(0, extension_id); 203 blocked_statement.BindString(0, extension_id);
193 blocked_statement.BindInt64(1, early_bound); 204 blocked_statement.BindInt64(1, early_bound);
194 blocked_statement.BindInt64(2, late_bound); 205 blocked_statement.BindInt64(2, late_bound);
195 while (blocked_statement.Step()) { 206 while (blocked_statement.is_valid() && blocked_statement.Step()) {
196 scoped_refptr<BlockedAction> action = new BlockedAction(blocked_statement); 207 scoped_refptr<BlockedAction> action = new BlockedAction(blocked_statement);
197 actions->push_back(action); 208 actions->push_back(action);
198 } 209 }
199 // Sort by time (from newest to oldest). 210 // Sort by time (from newest to oldest).
200 std::sort(actions->begin(), actions->end(), SortActionsByTime); 211 std::sort(actions->begin(), actions->end(), SortActionsByTime);
201 return actions.Pass(); 212 return actions.Pass();
202 } 213 }
203 214
204 void ActivityDatabase::BeginTransaction() {
205 db_.BeginTransaction();
206 }
207
208 void ActivityDatabase::CommitTransaction() {
209 db_.CommitTransaction();
210 }
211
212 void ActivityDatabase::RollbackTransaction() {
213 db_.RollbackTransaction();
214 }
215
216 bool ActivityDatabase::Raze() {
217 return db_.Raze();
218 }
219
220 void ActivityDatabase::Close() { 215 void ActivityDatabase::Close() {
221 timer_.Stop(); 216 timer_.Stop();
222 RecordBatchedActions(); 217 if (!already_closed_) {
223 db_.Close(); 218 RecordBatchedActions();
219 db_.reset_error_callback();
220 }
221 valid_db_ = false;
222 already_closed_ = true;
224 delete this; 223 delete this;
225 } 224 }
226 225
227 void ActivityDatabase::KillDatabase() { 226 void ActivityDatabase::HardFailureClose() {
227 if (already_closed_) return;
228 valid_db_ = false;
228 timer_.Stop(); 229 timer_.Stop();
230 db_.reset_error_callback();
229 db_.RazeAndClose(); 231 db_.RazeAndClose();
232 already_closed_ = true;
233 }
234
235 void ActivityDatabase::SoftFailureClose() {
236 valid_db_ = false;
237 timer_.Stop();
238 }
239
240 void ActivityDatabase::DatabaseErrorCallback(int error, sql::Statement* stmt) {
241 if (sql::IsErrorCatastrophic(error)) {
242 LOG(ERROR) << "Killing the ActivityDatabase due to catastrophic error.";
243 HardFailureClose();
244 } else if (error != SQLITE_BUSY) {
245 // We ignore SQLITE_BUSY errors because they are presumably transient.
246 LOG(ERROR) << "Closing the ActivityDatabase due to error.";
247 SoftFailureClose();
248 }
230 } 249 }
231 250
232 void ActivityDatabase::SetClockForTesting(base::Clock* clock) { 251 void ActivityDatabase::SetClockForTesting(base::Clock* clock) {
233 testing_clock_ = clock; 252 testing_clock_ = clock;
234 } 253 }
235 254
236 void ActivityDatabase::RecordBatchedActionsWhileTesting() { 255 void ActivityDatabase::RecordBatchedActionsWhileTesting() {
237 RecordBatchedActions(); 256 RecordBatchedActions();
238 timer_.Stop(); 257 timer_.Stop();
239 } 258 }
240 259
241 void ActivityDatabase::SetTimerForTesting(int ms) { 260 void ActivityDatabase::SetTimerForTesting(int ms) {
242 timer_.Stop(); 261 timer_.Stop();
243 timer_.Start(FROM_HERE, 262 timer_.Start(FROM_HERE,
244 base::TimeDelta::FromMilliseconds(ms), 263 base::TimeDelta::FromMilliseconds(ms),
245 this, 264 this,
246 &ActivityDatabase::RecordBatchedActionsWhileTesting); 265 &ActivityDatabase::RecordBatchedActionsWhileTesting);
247 } 266 }
248 267
249 } // namespace extensions 268 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698