OLD | NEW |
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 "chrome/browser/performance_monitor/database.h" | 5 #include "chrome/browser/performance_monitor/database.h" |
6 | 6 |
7 #include "base/file_path.h" | 7 #include "base/file_path.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/path_service.h" | 12 #include "base/path_service.h" |
13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
14 #include "base/string_number_conversions.h" | 14 #include "base/string_number_conversions.h" |
15 #include "base/time.h" | 15 #include "base/time.h" |
16 #include "base/utf_string_conversions.h" | 16 #include "base/utf_string_conversions.h" |
17 #include "chrome/browser/performance_monitor/key_builder.h" | 17 #include "chrome/browser/performance_monitor/key_builder.h" |
18 #include "chrome/common/chrome_paths.h" | 18 #include "chrome/common/chrome_paths.h" |
19 #include "content/public/browser/browser_thread.h" | 19 #include "content/public/browser/browser_thread.h" |
20 #include "third_party/leveldatabase/src/include/leveldb/db.h" | 20 #include "third_party/leveldatabase/src/include/leveldb/db.h" |
| 21 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" |
| 22 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
21 | 23 |
22 namespace performance_monitor { | 24 namespace performance_monitor { |
23 namespace { | 25 namespace { |
24 const char kDbDir[] = "Performance Monitor Databases"; | 26 const char kDbDir[] = "Performance Monitor Databases"; |
25 const char kRecentDb[] = "Recent Metrics"; | 27 const char kRecentDb[] = "Recent Metrics"; |
26 const char kMaxValueDb[] = "Max Value Metrics"; | 28 const char kMaxValueDb[] = "Max Value Metrics"; |
27 const char kEventDb[] = "Events"; | 29 const char kEventDb[] = "Events"; |
28 const char kStateDb[] = "Configuration"; | 30 const char kStateDb[] = "Configuration"; |
29 const char kActiveIntervalDb[] = "Active Interval"; | 31 const char kActiveIntervalDb[] = "Active Interval"; |
30 const char kMetricDb[] = "Metrics"; | 32 const char kMetricDb[] = "Metrics"; |
(...skipping 12 matching lines...) Expand all Loading... |
43 base::Time::FromInternalValue(end_time_int)); | 45 base::Time::FromInternalValue(end_time_int)); |
44 } | 46 } |
45 | 47 |
46 double StringToDouble(const std::string& s) { | 48 double StringToDouble(const std::string& s) { |
47 double value = 0.0; | 49 double value = 0.0; |
48 if (!base::StringToDouble(s, &value)) | 50 if (!base::StringToDouble(s, &value)) |
49 LOG(ERROR) << "Failed to convert " << s << " to double."; | 51 LOG(ERROR) << "Failed to convert " << s << " to double."; |
50 return value; | 52 return value; |
51 } | 53 } |
52 | 54 |
| 55 // Returns an event from the given JSON string; the scoped_ptr will be NULL if |
| 56 // we are unable to properly parse the JSON. |
| 57 scoped_ptr<Event> EventFromJSON(const std::string& data) { |
| 58 Value* value = base::JSONReader::Read(data); |
| 59 DictionaryValue* dict = NULL; |
| 60 if (!value || !value->GetAsDictionary(&dict)) |
| 61 return scoped_ptr<Event>(); |
| 62 |
| 63 return Event::FromValue(scoped_ptr<DictionaryValue>(dict)); |
| 64 } |
| 65 |
53 } // namespace | 66 } // namespace |
54 | 67 |
55 const char Database::kDatabaseSequenceToken[] = | 68 const char Database::kDatabaseSequenceToken[] = |
56 "_performance_monitor_db_sequence_token_"; | 69 "_performance_monitor_db_sequence_token_"; |
57 | 70 |
58 TimeRange::TimeRange() { | 71 TimeRange::TimeRange() { |
59 } | 72 } |
60 | 73 |
61 TimeRange::TimeRange(base::Time start_time, base::Time end_time) | 74 TimeRange::TimeRange(base::Time start_time, base::Time end_time) |
62 : start(start_time), | 75 : start(start_time), |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 | 151 |
139 Database::EventVector Database::GetEvents(EventType type, | 152 Database::EventVector Database::GetEvents(EventType type, |
140 const base::Time& start, | 153 const base::Time& start, |
141 const base::Time& end) { | 154 const base::Time& end) { |
142 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 155 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
143 EventVector events; | 156 EventVector events; |
144 std::string start_key = | 157 std::string start_key = |
145 key_builder_->CreateEventKey(start, EVENT_UNDEFINED); | 158 key_builder_->CreateEventKey(start, EVENT_UNDEFINED); |
146 std::string end_key = | 159 std::string end_key = |
147 key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); | 160 key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); |
| 161 leveldb::WriteBatch invalid_entries; |
148 scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); | 162 scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); |
149 for (it->Seek(start_key); | 163 for (it->Seek(start_key); |
150 it->Valid() && it->key().ToString() <= end_key; | 164 it->Valid() && it->key().ToString() <= end_key; |
151 it->Next()) { | 165 it->Next()) { |
152 if (type != EVENT_UNDEFINED) { | 166 if (type != EVENT_UNDEFINED) { |
153 EventType key_type = | 167 EventType key_type = |
154 key_builder_->EventKeyToEventType(it->key().ToString()); | 168 key_builder_->EventKeyToEventType(it->key().ToString()); |
155 if (key_type != type) | 169 if (key_type != type) |
156 continue; | 170 continue; |
157 } | 171 } |
158 base::DictionaryValue* dict = NULL; | 172 scoped_ptr<Event> event = EventFromJSON(it->value().ToString()); |
159 if (!base::JSONReader::Read( | 173 if (!event.get()) { |
160 it->value().ToString())->GetAsDictionary(&dict)) { | 174 invalid_entries.Delete(it->key()); |
161 LOG(ERROR) << "Unable to convert database event to JSON."; | 175 LOG(ERROR) << "Found invalid event in the database. JSON: '" |
| 176 << it->value().ToString() |
| 177 << "'. Erasing event from the database."; |
162 continue; | 178 continue; |
163 } | 179 } |
164 scoped_ptr<Event> event = | |
165 Event::FromValue(scoped_ptr<base::DictionaryValue>(dict)); | |
166 if (!event.get()) | |
167 continue; | |
168 events.push_back(linked_ptr<Event>(event.release())); | 180 events.push_back(linked_ptr<Event>(event.release())); |
169 } | 181 } |
| 182 event_db_->Write(write_options_, &invalid_entries); |
170 return events; | 183 return events; |
171 } | 184 } |
172 | 185 |
173 Database::EventTypeSet Database::GetEventTypes(const base::Time& start, | 186 Database::EventTypeSet Database::GetEventTypes(const base::Time& start, |
174 const base::Time& end) { | 187 const base::Time& end) { |
175 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 188 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
176 EventTypeSet results; | 189 EventTypeSet results; |
177 std::string start_key = | 190 std::string start_key = |
178 key_builder_->CreateEventKey(start, EVENT_UNDEFINED); | 191 key_builder_->CreateEventKey(start, EVENT_UNDEFINED); |
179 std::string end_key = | 192 std::string end_key = |
180 key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); | 193 key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); |
181 scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); | 194 scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); |
182 for (it->Seek(start_key); | 195 for (it->Seek(start_key); |
183 it->Valid() && it->key().ToString() <= end_key; | 196 it->Valid() && it->key().ToString() <= end_key; |
184 it->Next()) { | 197 it->Next()) { |
185 EventType key_type = | 198 EventType key_type = |
186 key_builder_->EventKeyToEventType(it->key().ToString()); | 199 key_builder_->EventKeyToEventType(it->key().ToString()); |
187 results.insert(key_type); | 200 results.insert(key_type); |
188 } | 201 } |
189 return results; | 202 return results; |
190 } | 203 } |
191 | 204 |
192 bool Database::AddMetric(const std::string& activity, | 205 bool Database::AddMetric(const std::string& activity, |
193 MetricType metric, | 206 const Metric& metric) { |
194 const std::string& value) { | |
195 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 207 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 208 if (!metric.IsValid()) { |
| 209 LOG(ERROR) << "Metric to be added is invalid. Type: " << metric.type |
| 210 << ", Time: " << metric.time.ToInternalValue() |
| 211 << ", Value: " << metric.value << ". Ignoring."; |
| 212 return false; |
| 213 } |
| 214 |
196 UpdateActiveInterval(); | 215 UpdateActiveInterval(); |
197 base::Time timestamp = clock_->GetTime(); | |
198 std::string recent_key = | 216 std::string recent_key = |
199 key_builder_->CreateRecentKey(timestamp, metric, activity); | 217 key_builder_->CreateRecentKey(metric.time, metric.type, activity); |
200 std::string metric_key = | 218 std::string metric_key = |
201 key_builder_->CreateMetricKey(timestamp, metric, activity); | 219 key_builder_->CreateMetricKey(metric.time, metric.type, activity); |
202 std::string recent_map_key = | 220 std::string recent_map_key = |
203 key_builder_->CreateRecentMapKey(metric, activity); | 221 key_builder_->CreateRecentMapKey(metric.type, activity); |
204 // Use recent_map_ to quickly find the key that must be removed. | 222 // Use recent_map_ to quickly find the key that must be removed. |
205 RecentMap::iterator old_it = recent_map_.find(recent_map_key); | 223 RecentMap::iterator old_it = recent_map_.find(recent_map_key); |
206 if (old_it != recent_map_.end()) | 224 if (old_it != recent_map_.end()) |
207 recent_db_->Delete(write_options_, old_it->second); | 225 recent_db_->Delete(write_options_, old_it->second); |
208 recent_map_[recent_map_key] = recent_key; | 226 recent_map_[recent_map_key] = recent_key; |
209 leveldb::Status recent_status = | 227 leveldb::Status recent_status = |
210 recent_db_->Put(write_options_, recent_key, value); | 228 recent_db_->Put(write_options_, recent_key, metric.ValueAsString()); |
211 leveldb::Status metric_status = | 229 leveldb::Status metric_status = |
212 metric_db_->Put(write_options_, metric_key, value); | 230 metric_db_->Put(write_options_, metric_key, metric.ValueAsString()); |
213 | 231 |
214 bool max_value_success = UpdateMaxValue(activity, metric, value); | 232 bool max_value_success = |
| 233 UpdateMaxValue(activity, metric.type, metric.ValueAsString()); |
215 return recent_status.ok() && metric_status.ok() && max_value_success; | 234 return recent_status.ok() && metric_status.ok() && max_value_success; |
216 } | 235 } |
217 | 236 |
218 bool Database::UpdateMaxValue(const std::string& activity, | 237 bool Database::UpdateMaxValue(const std::string& activity, |
219 MetricType metric, | 238 MetricType metric, |
220 const std::string& value) { | 239 const std::string& value) { |
221 std::string max_value_key( | 240 std::string max_value_key( |
222 key_builder_->CreateMaxValueKey(metric, activity)); | 241 key_builder_->CreateMaxValueKey(metric, activity)); |
223 bool has_key = ContainsKey(max_value_map_, max_value_key); | 242 bool has_key = ContainsKey(max_value_map_, max_value_key); |
224 if ((has_key && StringToDouble(value) > max_value_map_[max_value_key]) || | 243 if ((has_key && StringToDouble(value) > max_value_map_[max_value_key]) || |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 333 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
315 std::string recent_map_key = | 334 std::string recent_map_key = |
316 key_builder_->CreateRecentMapKey(metric_type, activity); | 335 key_builder_->CreateRecentMapKey(metric_type, activity); |
317 if (!ContainsKey(recent_map_, recent_map_key)) | 336 if (!ContainsKey(recent_map_, recent_map_key)) |
318 return false; | 337 return false; |
319 std::string recent_key = recent_map_[recent_map_key]; | 338 std::string recent_key = recent_map_[recent_map_key]; |
320 | 339 |
321 std::string result; | 340 std::string result; |
322 leveldb::Status status = recent_db_->Get(read_options_, recent_key, &result); | 341 leveldb::Status status = recent_db_->Get(read_options_, recent_key, &result); |
323 if (status.ok()) | 342 if (status.ok()) |
324 *metric = Metric(key_builder_->SplitRecentKey(recent_key).time, result); | 343 *metric = Metric(metric_type, |
| 344 key_builder_->SplitRecentKey(recent_key).time, |
| 345 result); |
325 return status.ok(); | 346 return status.ok(); |
326 } | 347 } |
327 | 348 |
328 Database::MetricVector Database::GetStatsForActivityAndMetric( | 349 Database::MetricVector Database::GetStatsForActivityAndMetric( |
329 const std::string& activity, | 350 const std::string& activity, |
330 MetricType metric_type, | 351 MetricType metric_type, |
331 const base::Time& start, | 352 const base::Time& start, |
332 const base::Time& end) { | 353 const base::Time& end) { |
333 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 354 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
334 MetricVector results; | 355 MetricVector results; |
335 std::string start_key = | 356 std::string start_key = |
336 key_builder_->CreateMetricKey(start, metric_type, activity); | 357 key_builder_->CreateMetricKey(start, metric_type, activity); |
337 std::string end_key = | 358 std::string end_key = |
338 key_builder_->CreateMetricKey(end, metric_type, activity); | 359 key_builder_->CreateMetricKey(end, metric_type, activity); |
| 360 leveldb::WriteBatch invalid_entries; |
339 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); | 361 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); |
340 for (it->Seek(start_key); | 362 for (it->Seek(start_key); |
341 it->Valid() && it->key().ToString() <= end_key; | 363 it->Valid() && it->key().ToString() <= end_key; |
342 it->Next()) { | 364 it->Next()) { |
343 MetricKey split_key = | 365 MetricKey split_key = |
344 key_builder_->SplitMetricKey(it->key().ToString()); | 366 key_builder_->SplitMetricKey(it->key().ToString()); |
345 if (split_key.activity == activity) | 367 if (split_key.activity == activity) { |
346 results.push_back(Metric(split_key.time, it->value().ToString())); | 368 Metric metric(metric_type, split_key.time, it->value().ToString()); |
| 369 if (!metric.IsValid()) { |
| 370 invalid_entries.Delete(it->key()); |
| 371 LOG(ERROR) << "Found bad metric in the database. Type: " |
| 372 << metric.type << ", Time: " << metric.time.ToInternalValue() |
| 373 << ", Value: " << metric.value |
| 374 << ". Erasing metric from database."; |
| 375 continue; |
| 376 } |
| 377 results.push_back(metric); |
| 378 } |
347 } | 379 } |
| 380 metric_db_->Write(write_options_, &invalid_entries); |
348 return results; | 381 return results; |
349 } | 382 } |
350 | 383 |
351 Database::MetricVectorMap Database::GetStatsForMetricByActivity( | 384 Database::MetricVectorMap Database::GetStatsForMetricByActivity( |
352 MetricType metric_type, | 385 MetricType metric_type, |
353 const base::Time& start, | 386 const base::Time& start, |
354 const base::Time& end) { | 387 const base::Time& end) { |
355 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 388 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
356 MetricVectorMap results; | 389 MetricVectorMap results; |
357 std::string start_key = | 390 std::string start_key = |
358 key_builder_->CreateMetricKey(start, metric_type, std::string()); | 391 key_builder_->CreateMetricKey(start, metric_type, std::string()); |
359 std::string end_key = | 392 std::string end_key = |
360 key_builder_->CreateMetricKey(end, metric_type, std::string()); | 393 key_builder_->CreateMetricKey(end, metric_type, std::string()); |
| 394 leveldb::WriteBatch invalid_entries; |
361 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); | 395 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); |
362 for (it->Seek(start_key); | 396 for (it->Seek(start_key); |
363 it->Valid() && it->key().ToString() <= end_key; | 397 it->Valid() && it->key().ToString() <= end_key; |
364 it->Next()) { | 398 it->Next()) { |
365 MetricKey split_key = key_builder_->SplitMetricKey(it->key().ToString()); | 399 MetricKey split_key = key_builder_->SplitMetricKey(it->key().ToString()); |
366 if (!results[split_key.activity].get()) { | 400 if (!results[split_key.activity].get()) { |
367 results[split_key.activity] = | 401 results[split_key.activity] = |
368 linked_ptr<MetricVector >(new MetricVector()); | 402 linked_ptr<MetricVector >(new MetricVector()); |
369 } | 403 } |
370 results[split_key.activity]->push_back( | 404 Metric metric(metric_type, split_key.time, it->value().ToString()); |
371 Metric(split_key.time, it->value().ToString())); | 405 if (!metric.IsValid()) { |
| 406 invalid_entries.Delete(it->key()); |
| 407 LOG(ERROR) << "Found bad metric in the database. Type: " |
| 408 << metric.type << ", Time: " << metric.time.ToInternalValue() |
| 409 << ", Value: " << metric.value |
| 410 << ". Erasing metric from database."; |
| 411 continue; |
| 412 } |
| 413 results[split_key.activity]->push_back(metric); |
372 } | 414 } |
| 415 metric_db_->Write(write_options_, &invalid_entries); |
373 return results; | 416 return results; |
374 } | 417 } |
375 | 418 |
376 Database::Database(const FilePath& path) | 419 Database::Database(const FilePath& path) |
377 : key_builder_(new KeyBuilder()), | 420 : key_builder_(new KeyBuilder()), |
378 path_(path), | 421 path_(path), |
379 read_options_(leveldb::ReadOptions()), | 422 read_options_(leveldb::ReadOptions()), |
380 write_options_(leveldb::WriteOptions()) { | 423 write_options_(leveldb::WriteOptions()) { |
381 InitDBs(); | 424 InitDBs(); |
382 LoadRecents(); | 425 LoadRecents(); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 start_time_key_ = key_builder_->CreateActiveIntervalKey(current_time); | 525 start_time_key_ = key_builder_->CreateActiveIntervalKey(current_time); |
483 end_time = start_time_key_; | 526 end_time = start_time_key_; |
484 } else { | 527 } else { |
485 end_time = key_builder_->CreateActiveIntervalKey(clock_->GetTime()); | 528 end_time = key_builder_->CreateActiveIntervalKey(clock_->GetTime()); |
486 } | 529 } |
487 last_update_time_ = current_time; | 530 last_update_time_ = current_time; |
488 active_interval_db_->Put(write_options_, start_time_key_, end_time); | 531 active_interval_db_->Put(write_options_, start_time_key_, end_time); |
489 } | 532 } |
490 | 533 |
491 } // namespace performance_monitor | 534 } // namespace performance_monitor |
OLD | NEW |