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

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

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

Powered by Google App Engine
This is Rietveld 408576698