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

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

Issue 21646004: Compressed activity log database storage (Closed) Base URL: http://git.chromium.org/chromium/src.git@refactor-cleanups
Patch Set: Delete a debugging log message Created 7 years, 4 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "chrome/browser/extensions/activity_log/fullstream_ui_policy.h" 5 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
6 6
7 #include "base/callback.h" 7 #include "base/callback.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/json/json_reader.h" 10 #include "base/json/json_reader.h"
(...skipping 13 matching lines...) Expand all
24 #include "url/gurl.h" 24 #include "url/gurl.h"
25 25
26 using base::Callback; 26 using base::Callback;
27 using base::FilePath; 27 using base::FilePath;
28 using base::Time; 28 using base::Time;
29 using base::Unretained; 29 using base::Unretained;
30 using content::BrowserThread; 30 using content::BrowserThread;
31 31
32 namespace constants = activity_log_constants; 32 namespace constants = activity_log_constants;
33 33
34 namespace {
35
36 // Key strings for passing parameters to the ProcessAction member function.
37 const char kKeyReason[] = "fsuip.reason";
38 const char kKeyDomainAction[] = "fsuip.domact";
39 const char kKeyURLTitle[] = "fsuip.urltitle";
40 const char kKeyDetailsString[] = "fsuip.details";
41
42 // Obsolete database tables: these should be dropped from the database if
43 // found.
44 const char* kObsoleteTables[] = {"activitylog_apis", "activitylog_blocked",
45 "activitylog_urls"};
46
47 std::string Serialize(const base::Value* value) {
48 std::string value_as_text;
49 if (!value) {
50 value_as_text = "null";
51 } else {
52 JSONStringValueSerializer serializer(&value_as_text);
53 serializer.SerializeAndOmitBinaryValues(*value);
54 }
55 return value_as_text;
56 }
57
58 } // namespace
59
60 namespace extensions { 34 namespace extensions {
61 35
62 const char* FullStreamUIPolicy::kTableName = "activitylog_full"; 36 const char* FullStreamUIPolicy::kTableName = "activitylog_full";
63 const char* FullStreamUIPolicy::kTableContentFields[] = { 37 const char* FullStreamUIPolicy::kTableContentFields[] = {
64 "extension_id", "time", "action_type", "api_name", "args", "page_url", 38 "extension_id", "time", "action_type", "api_name", "args", "page_url",
65 "page_title", "arg_url", "other" 39 "page_title", "arg_url", "other"
66 }; 40 };
67 const char* FullStreamUIPolicy::kTableFieldTypes[] = { 41 const char* FullStreamUIPolicy::kTableFieldTypes[] = {
68 "LONGVARCHAR NOT NULL", "INTEGER", "INTEGER", "LONGVARCHAR", "LONGVARCHAR", 42 "LONGVARCHAR NOT NULL", "INTEGER", "INTEGER", "LONGVARCHAR", "LONGVARCHAR",
69 "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR" 43 "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR"
70 }; 44 };
71 const int FullStreamUIPolicy::kTableFieldCount = arraysize(kTableContentFields); 45 const int FullStreamUIPolicy::kTableFieldCount =
46 arraysize(FullStreamUIPolicy::kTableContentFields);
72 47
73 FullStreamUIPolicy::FullStreamUIPolicy(Profile* profile) 48 FullStreamUIPolicy::FullStreamUIPolicy(Profile* profile)
74 : ActivityLogDatabasePolicy( 49 : ActivityLogDatabasePolicy(
75 profile, 50 profile,
76 FilePath(chrome::kExtensionActivityLogFilename)) {} 51 FilePath(chrome::kExtensionActivityLogFilename)) {}
77 52
78 FullStreamUIPolicy::~FullStreamUIPolicy() {} 53 FullStreamUIPolicy::~FullStreamUIPolicy() {}
79 54
80 bool FullStreamUIPolicy::InitDatabase(sql::Connection* db) { 55 bool FullStreamUIPolicy::InitDatabase(sql::Connection* db) {
81 // Drop old database tables. 56 if (!Util::DropObsoleteTables(db))
82 for (size_t i = 0; i < arraysize(kObsoleteTables); i++) { 57 return false;
83 const char* table_name = kObsoleteTables[i];
84 if (db->DoesTableExist(table_name)) {
85 std::string drop_statement =
86 base::StringPrintf("DROP TABLE %s", table_name);
87 if (!db->Execute(drop_statement.c_str())) {
88 return false;
89 }
90 }
91 }
92 58
93 // Create the unified activity log entry table. 59 // Create the unified activity log entry table.
94 return ActivityDatabase::InitializeTable(db, 60 return ActivityDatabase::InitializeTable(db,
95 kTableName, 61 kTableName,
96 kTableContentFields, 62 kTableContentFields,
97 kTableFieldTypes, 63 kTableFieldTypes,
98 arraysize(kTableContentFields)); 64 arraysize(kTableContentFields));
99 } 65 }
100 66
101 bool FullStreamUIPolicy::FlushDatabase(sql::Connection* db) { 67 bool FullStreamUIPolicy::FlushDatabase(sql::Connection* db) {
102 if (queued_actions_.empty()) 68 if (queued_actions_.empty())
103 return true; 69 return true;
104 70
105 sql::Transaction transaction(db); 71 sql::Transaction transaction(db);
106 if (!transaction.Begin()) 72 if (!transaction.Begin())
107 return false; 73 return false;
108 74
109 std::string sql_str = 75 std::string sql_str =
110 "INSERT INTO " + std::string(FullStreamUIPolicy::kTableName) + 76 "INSERT INTO " + std::string(FullStreamUIPolicy::kTableName) +
111 " (extension_id, time, action_type, api_name, args, " 77 " (extension_id, time, action_type, api_name, args, "
112 "page_url, page_title, arg_url, other) VALUES (?,?,?,?,?,?,?,?,?)"; 78 "page_url, page_title, arg_url, other) VALUES (?,?,?,?,?,?,?,?,?)";
113 sql::Statement statement(db->GetCachedStatement( 79 sql::Statement statement(db->GetCachedStatement(
114 sql::StatementID(SQL_FROM_HERE), sql_str.c_str())); 80 sql::StatementID(SQL_FROM_HERE), sql_str.c_str()));
115 81
116 url_canon::Replacements<char> url_sanitizer;
117 if (!CommandLine::ForCurrentProcess()->HasSwitch(
118 switches::kEnableExtensionActivityLogTesting)) {
119 url_sanitizer.ClearQuery();
120 url_sanitizer.ClearRef();
121 }
122
123 Action::ActionVector::size_type i; 82 Action::ActionVector::size_type i;
124 for (i = 0; i != queued_actions_.size(); ++i) { 83 for (i = 0; i != queued_actions_.size(); ++i) {
125 const Action& action = *queued_actions_[i]; 84 const Action& action = *queued_actions_[i];
126 statement.Reset(true); 85 statement.Reset(true);
127 statement.BindString(0, action.extension_id()); 86 statement.BindString(0, action.extension_id());
128 statement.BindInt64(1, action.time().ToInternalValue()); 87 statement.BindInt64(1, action.time().ToInternalValue());
129 statement.BindInt(2, static_cast<int>(action.action_type())); 88 statement.BindInt(2, static_cast<int>(action.action_type()));
130 statement.BindString(3, action.api_name()); 89 statement.BindString(3, action.api_name());
131 if (action.args()) { 90 if (action.args()) {
132 statement.BindString(4, Serialize(action.args())); 91 statement.BindString(4, Util::Serialize(action.args()));
133 } 92 }
134 if (action.page_url().is_valid()) { 93 std::string page_url_string = action.SerializePageUrl();
135 if (action.page_incognito()) { 94 if (!page_url_string.empty()) {
136 statement.BindString(5, constants::kIncognitoUrl); 95 statement.BindString(5, page_url_string);
137 } else {
138 statement.BindString(
139 5, action.page_url().ReplaceComponents(url_sanitizer).spec());
140 }
141 } 96 }
142 if (!action.page_title().empty() && !action.page_incognito()) { 97 if (!action.page_title().empty()) {
143 statement.BindString(6, action.page_title()); 98 statement.BindString(6, action.page_title());
144 } 99 }
145 if (action.arg_url().is_valid()) { 100 std::string arg_url_string = action.SerializePageUrl();
146 if (action.arg_incognito()) { 101 if (!arg_url_string.empty()) {
147 statement.BindString(7, constants::kIncognitoUrl); 102 statement.BindString(5, arg_url_string);
148 } else {
149 statement.BindString(
150 7, action.arg_url().ReplaceComponents(url_sanitizer).spec());
151 }
152 } 103 }
153 if (action.other()) { 104 if (action.other()) {
154 statement.BindString(8, Serialize(action.other())); 105 statement.BindString(8, Util::Serialize(action.other()));
155 } 106 }
156 107
157 if (!statement.Run()) { 108 if (!statement.Run()) {
158 LOG(ERROR) << "Activity log database I/O failed: " << sql_str; 109 LOG(ERROR) << "Activity log database I/O failed: " << sql_str;
159 return false; 110 return false;
160 } 111 }
161 } 112 }
162 113
163 if (!transaction.Commit()) 114 if (!transaction.Commit())
164 return false; 115 return false;
165 116
166 queued_actions_.clear(); 117 queued_actions_.clear();
167 return true; 118 return true;
168 } 119 }
169 120
170 scoped_ptr<Action::ActionVector> FullStreamUIPolicy::DoReadData( 121 scoped_ptr<Action::ActionVector> FullStreamUIPolicy::DoReadData(
171 const std::string& extension_id, 122 const std::string& extension_id,
172 const int days_ago) { 123 const int days_ago) {
124 // Ensure data is flushed to the database first so that we query over all
125 // data.
126 activity_database()->AdviseFlush(ActivityDatabase::kFlushImmediately);
127
173 DCHECK_GE(days_ago, 0); 128 DCHECK_GE(days_ago, 0);
174 scoped_ptr<Action::ActionVector> actions(new Action::ActionVector()); 129 scoped_ptr<Action::ActionVector> actions(new Action::ActionVector());
175 130
176 sql::Connection* db = GetDatabaseConnection(); 131 sql::Connection* db = GetDatabaseConnection();
177 if (!db) { 132 if (!db) {
178 return actions.Pass(); 133 return actions.Pass();
179 } 134 }
180 135
181 // Compute the time bounds for that day. 136 int64 early_bound;
182 base::Time morning_midnight = Now().LocalMidnight(); 137 int64 late_bound;
183 int64 early_bound = 0; 138 Util::ComputeDatabaseTimeBounds(Now(), days_ago, &early_bound, &late_bound);
184 int64 late_bound = 0;
185 if (days_ago == 0) {
186 early_bound = morning_midnight.ToInternalValue();
187 late_bound = base::Time::Max().ToInternalValue();
188 } else {
189 base::Time early_time = morning_midnight -
190 base::TimeDelta::FromDays(days_ago);
191 base::Time late_time = morning_midnight -
192 base::TimeDelta::FromDays(days_ago-1);
193 early_bound = early_time.ToInternalValue();
194 late_bound = late_time.ToInternalValue();
195 }
196 std::string query_str = base::StringPrintf( 139 std::string query_str = base::StringPrintf(
197 "SELECT time, action_type, api_name, args, page_url, page_title, " 140 "SELECT time, action_type, api_name, args, page_url, page_title, "
198 "arg_url, other " 141 "arg_url, other "
199 "FROM %s WHERE extension_id=? AND time>? AND time<=? " 142 "FROM %s WHERE extension_id=? AND time>? AND time<=? "
200 "ORDER BY time DESC", 143 "ORDER BY time DESC",
201 kTableName); 144 kTableName);
202 sql::Statement query(db->GetCachedStatement(SQL_FROM_HERE, 145 sql::Statement query(db->GetCachedStatement(SQL_FROM_HERE,
203 query_str.c_str())); 146 query_str.c_str()));
204 query.BindString(0, extension_id); 147 query.BindString(0, extension_id);
205 query.BindInt64(1, early_bound); 148 query.BindInt64(1, early_bound);
(...skipping 10 matching lines...) Expand all
216 base::JSONReader::Read(query.ColumnString(3))); 159 base::JSONReader::Read(query.ColumnString(3)));
217 if (parsed_value && parsed_value->IsType(Value::TYPE_LIST)) { 160 if (parsed_value && parsed_value->IsType(Value::TYPE_LIST)) {
218 action->set_args( 161 action->set_args(
219 make_scoped_ptr(static_cast<ListValue*>(parsed_value.release()))); 162 make_scoped_ptr(static_cast<ListValue*>(parsed_value.release())));
220 } else { 163 } else {
221 LOG(WARNING) << "Unable to parse args: '" << query.ColumnString(3) 164 LOG(WARNING) << "Unable to parse args: '" << query.ColumnString(3)
222 << "'"; 165 << "'";
223 } 166 }
224 } 167 }
225 168
226 GURL page_url(query.ColumnString(4)); 169 action->ParsePageUrl(query.ColumnString(4));
227 action->set_page_url(page_url);
228
229 action->set_page_title(query.ColumnString(5)); 170 action->set_page_title(query.ColumnString(5));
230 171 action->ParseArgUrl(query.ColumnString(6));
231 GURL arg_url(query.ColumnString(6));
232 action->set_arg_url(arg_url);
233 172
234 if (query.ColumnType(7) != sql::COLUMN_TYPE_NULL) { 173 if (query.ColumnType(7) != sql::COLUMN_TYPE_NULL) {
235 scoped_ptr<Value> parsed_value( 174 scoped_ptr<Value> parsed_value(
236 base::JSONReader::Read(query.ColumnString(7))); 175 base::JSONReader::Read(query.ColumnString(7)));
237 if (parsed_value && parsed_value->IsType(Value::TYPE_DICTIONARY)) { 176 if (parsed_value && parsed_value->IsType(Value::TYPE_DICTIONARY)) {
238 action->set_other(make_scoped_ptr( 177 action->set_other(make_scoped_ptr(
239 static_cast<DictionaryValue*>(parsed_value.release()))); 178 static_cast<DictionaryValue*>(parsed_value.release())));
240 } else { 179 } else {
241 LOG(WARNING) << "Unable to parse other: '" << query.ColumnString(7) 180 LOG(WARNING) << "Unable to parse other: '" << query.ColumnString(7)
242 << "'"; 181 << "'";
(...skipping 27 matching lines...) Expand all
270 BrowserThread::PostTaskAndReplyWithResult( 209 BrowserThread::PostTaskAndReplyWithResult(
271 BrowserThread::DB, 210 BrowserThread::DB,
272 FROM_HERE, 211 FROM_HERE,
273 base::Bind(&FullStreamUIPolicy::DoReadData, 212 base::Bind(&FullStreamUIPolicy::DoReadData,
274 base::Unretained(this), 213 base::Unretained(this),
275 extension_id, 214 extension_id,
276 day), 215 day),
277 callback); 216 callback);
278 } 217 }
279 218
280 std::string FullStreamUIPolicy::GetKey(ActivityLogPolicy::KeyType key_ty) const
281 {
282 switch (key_ty) {
283 case PARAM_KEY_REASON:
284 return std::string(kKeyReason);
285 case PARAM_KEY_DOM_ACTION:
286 return std::string(kKeyDomainAction);
287 case PARAM_KEY_URL_TITLE:
288 return std::string(kKeyURLTitle);
289 case PARAM_KEY_DETAILS_STRING:
290 return std::string(kKeyDetailsString);
291 default:
292 return std::string();
293 }
294 }
295
296 scoped_refptr<Action> FullStreamUIPolicy::ProcessArguments( 219 scoped_refptr<Action> FullStreamUIPolicy::ProcessArguments(
297 scoped_refptr<Action> action) const { 220 scoped_refptr<Action> action) const {
298 return action; 221 return action;
299 } 222 }
300 223
301 void FullStreamUIPolicy::ProcessAction(scoped_refptr<Action> action) { 224 void FullStreamUIPolicy::ProcessAction(scoped_refptr<Action> action) {
302 // TODO(mvrable): Right now this argument stripping updates the Action object 225 // TODO(mvrable): Right now this argument stripping updates the Action object
303 // in place, which isn't good if there are other users of the object. When 226 // in place, which isn't good if there are other users of the object. When
304 // database writing is moved to policy class, the modifications should be 227 // database writing is moved to policy class, the modifications should be
305 // made locally. 228 // made locally.
306 action = ProcessArguments(action); 229 action = ProcessArguments(action);
307 ScheduleAndForget(this, &FullStreamUIPolicy::QueueAction, action); 230 ScheduleAndForget(this, &FullStreamUIPolicy::QueueAction, action);
308 } 231 }
309 232
310 void FullStreamUIPolicy::QueueAction(scoped_refptr<Action> action) { 233 void FullStreamUIPolicy::QueueAction(scoped_refptr<Action> action) {
311 if (activity_database()->is_db_valid()) { 234 if (activity_database()->is_db_valid()) {
312 queued_actions_.push_back(action); 235 queued_actions_.push_back(action);
313 activity_database()->NotifyAction(); 236 activity_database()->AdviseFlush(queued_actions_.size());
314 } 237 }
315 } 238 }
316 239
317 } // namespace extensions 240 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698