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