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: '" << |
Yoyo Zhou
2012/09/13 00:09:20
nit: put the << on the next line and align with <<
Devlin
2012/09/13 17:00:24
Done.
| |
176 it->value().ToString() << "'. Erasing event from the database."; | |
162 continue; | 177 continue; |
163 } | 178 } |
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())); | 179 events.push_back(linked_ptr<Event>(event.release())); |
169 } | 180 } |
181 event_db_->Write(write_options_, &invalid_entries); | |
170 return events; | 182 return events; |
171 } | 183 } |
172 | 184 |
173 Database::EventTypeSet Database::GetEventTypes(const base::Time& start, | 185 Database::EventTypeSet Database::GetEventTypes(const base::Time& start, |
174 const base::Time& end) { | 186 const base::Time& end) { |
175 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 187 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
176 EventTypeSet results; | 188 EventTypeSet results; |
177 std::string start_key = | 189 std::string start_key = |
178 key_builder_->CreateEventKey(start, EVENT_UNDEFINED); | 190 key_builder_->CreateEventKey(start, EVENT_UNDEFINED); |
179 std::string end_key = | 191 std::string end_key = |
180 key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); | 192 key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); |
181 scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); | 193 scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); |
182 for (it->Seek(start_key); | 194 for (it->Seek(start_key); |
183 it->Valid() && it->key().ToString() <= end_key; | 195 it->Valid() && it->key().ToString() <= end_key; |
184 it->Next()) { | 196 it->Next()) { |
185 EventType key_type = | 197 EventType key_type = |
186 key_builder_->EventKeyToEventType(it->key().ToString()); | 198 key_builder_->EventKeyToEventType(it->key().ToString()); |
187 results.insert(key_type); | 199 results.insert(key_type); |
188 } | 200 } |
189 return results; | 201 return results; |
190 } | 202 } |
191 | 203 |
192 bool Database::AddMetric(const std::string& activity, | 204 bool Database::AddMetric(const std::string& activity, |
193 MetricType metric, | 205 const Metric& metric) { |
194 const std::string& value) { | |
195 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 206 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
207 if (!metric.IsValid()) { | |
208 LOG(ERROR) << "Metric to be added is invalid. Type: " << metric.type << | |
209 ", Time: " << metric.time.ToInternalValue() << | |
210 ", Value: " << metric.value << ". Ignoring."; | |
211 return false; | |
212 } | |
213 | |
196 UpdateActiveInterval(); | 214 UpdateActiveInterval(); |
197 base::Time timestamp = clock_->GetTime(); | |
198 std::string recent_key = | 215 std::string recent_key = |
199 key_builder_->CreateRecentKey(timestamp, metric, activity); | 216 key_builder_->CreateRecentKey(metric.time, metric.type, activity); |
200 std::string metric_key = | 217 std::string metric_key = |
201 key_builder_->CreateMetricKey(timestamp, metric, activity); | 218 key_builder_->CreateMetricKey(metric.time, metric.type, activity); |
202 std::string recent_map_key = | 219 std::string recent_map_key = |
203 key_builder_->CreateRecentMapKey(metric, activity); | 220 key_builder_->CreateRecentMapKey(metric.type, activity); |
204 // Use recent_map_ to quickly find the key that must be removed. | 221 // Use recent_map_ to quickly find the key that must be removed. |
205 RecentMap::iterator old_it = recent_map_.find(recent_map_key); | 222 RecentMap::iterator old_it = recent_map_.find(recent_map_key); |
206 if (old_it != recent_map_.end()) | 223 if (old_it != recent_map_.end()) |
207 recent_db_->Delete(write_options_, old_it->second); | 224 recent_db_->Delete(write_options_, old_it->second); |
208 recent_map_[recent_map_key] = recent_key; | 225 recent_map_[recent_map_key] = recent_key; |
209 leveldb::Status recent_status = | 226 leveldb::Status recent_status = |
210 recent_db_->Put(write_options_, recent_key, value); | 227 recent_db_->Put(write_options_, recent_key, metric.ValueAsString()); |
211 leveldb::Status metric_status = | 228 leveldb::Status metric_status = |
212 metric_db_->Put(write_options_, metric_key, value); | 229 metric_db_->Put(write_options_, metric_key, metric.ValueAsString()); |
213 | 230 |
214 bool max_value_success = UpdateMaxValue(activity, metric, value); | 231 bool max_value_success = |
232 UpdateMaxValue(activity, metric.type, metric.ValueAsString()); | |
215 return recent_status.ok() && metric_status.ok() && max_value_success; | 233 return recent_status.ok() && metric_status.ok() && max_value_success; |
216 } | 234 } |
217 | 235 |
218 bool Database::UpdateMaxValue(const std::string& activity, | 236 bool Database::UpdateMaxValue(const std::string& activity, |
219 MetricType metric, | 237 MetricType metric, |
220 const std::string& value) { | 238 const std::string& value) { |
221 std::string max_value_key( | 239 std::string max_value_key( |
222 key_builder_->CreateMaxValueKey(metric, activity)); | 240 key_builder_->CreateMaxValueKey(metric, activity)); |
223 bool has_key = ContainsKey(max_value_map_, max_value_key); | 241 bool has_key = ContainsKey(max_value_map_, max_value_key); |
224 if ((has_key && StringToDouble(value) > max_value_map_[max_value_key]) || | 242 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)); | 332 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
315 std::string recent_map_key = | 333 std::string recent_map_key = |
316 key_builder_->CreateRecentMapKey(metric_type, activity); | 334 key_builder_->CreateRecentMapKey(metric_type, activity); |
317 if (!ContainsKey(recent_map_, recent_map_key)) | 335 if (!ContainsKey(recent_map_, recent_map_key)) |
318 return false; | 336 return false; |
319 std::string recent_key = recent_map_[recent_map_key]; | 337 std::string recent_key = recent_map_[recent_map_key]; |
320 | 338 |
321 std::string result; | 339 std::string result; |
322 leveldb::Status status = recent_db_->Get(read_options_, recent_key, &result); | 340 leveldb::Status status = recent_db_->Get(read_options_, recent_key, &result); |
323 if (status.ok()) | 341 if (status.ok()) |
324 *metric = Metric(key_builder_->SplitRecentKey(recent_key).time, result); | 342 *metric = Metric(metric_type, |
343 key_builder_->SplitRecentKey(recent_key).time, | |
344 result); | |
325 return status.ok(); | 345 return status.ok(); |
326 } | 346 } |
327 | 347 |
328 Database::MetricVector Database::GetStatsForActivityAndMetric( | 348 Database::MetricVector Database::GetStatsForActivityAndMetric( |
329 const std::string& activity, | 349 const std::string& activity, |
330 MetricType metric_type, | 350 MetricType metric_type, |
331 const base::Time& start, | 351 const base::Time& start, |
332 const base::Time& end) { | 352 const base::Time& end) { |
333 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 353 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
334 MetricVector results; | 354 MetricVector results; |
335 std::string start_key = | 355 std::string start_key = |
336 key_builder_->CreateMetricKey(start, metric_type, activity); | 356 key_builder_->CreateMetricKey(start, metric_type, activity); |
337 std::string end_key = | 357 std::string end_key = |
338 key_builder_->CreateMetricKey(end, metric_type, activity); | 358 key_builder_->CreateMetricKey(end, metric_type, activity); |
359 leveldb::WriteBatch invalid_entries; | |
339 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); | 360 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); |
340 for (it->Seek(start_key); | 361 for (it->Seek(start_key); |
341 it->Valid() && it->key().ToString() <= end_key; | 362 it->Valid() && it->key().ToString() <= end_key; |
342 it->Next()) { | 363 it->Next()) { |
343 MetricKey split_key = | 364 MetricKey split_key = |
344 key_builder_->SplitMetricKey(it->key().ToString()); | 365 key_builder_->SplitMetricKey(it->key().ToString()); |
345 if (split_key.activity == activity) | 366 if (split_key.activity == activity) { |
346 results.push_back(Metric(split_key.time, it->value().ToString())); | 367 Metric metric(metric_type, split_key.time, it->value().ToString()); |
368 if (!metric.IsValid()) { | |
369 invalid_entries.Delete(it->key()); | |
370 LOG(ERROR) << "Found bad metric in the database. Type: " << | |
371 metric.type << ", Time: " << metric.time.ToInternalValue() << | |
372 ", Value: " << metric.value << ". Erasing metric from database."; | |
373 continue; | |
374 } | |
375 results.push_back(metric); | |
376 } | |
347 } | 377 } |
378 metric_db_->Write(write_options_, &invalid_entries); | |
348 return results; | 379 return results; |
349 } | 380 } |
350 | 381 |
351 Database::MetricVectorMap Database::GetStatsForMetricByActivity( | 382 Database::MetricVectorMap Database::GetStatsForMetricByActivity( |
352 MetricType metric_type, | 383 MetricType metric_type, |
353 const base::Time& start, | 384 const base::Time& start, |
354 const base::Time& end) { | 385 const base::Time& end) { |
355 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 386 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
356 MetricVectorMap results; | 387 MetricVectorMap results; |
357 std::string start_key = | 388 std::string start_key = |
358 key_builder_->CreateMetricKey(start, metric_type, std::string()); | 389 key_builder_->CreateMetricKey(start, metric_type, std::string()); |
359 std::string end_key = | 390 std::string end_key = |
360 key_builder_->CreateMetricKey(end, metric_type, std::string()); | 391 key_builder_->CreateMetricKey(end, metric_type, std::string()); |
392 leveldb::WriteBatch invalid_entries; | |
361 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); | 393 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); |
362 for (it->Seek(start_key); | 394 for (it->Seek(start_key); |
363 it->Valid() && it->key().ToString() <= end_key; | 395 it->Valid() && it->key().ToString() <= end_key; |
364 it->Next()) { | 396 it->Next()) { |
365 MetricKey split_key = key_builder_->SplitMetricKey(it->key().ToString()); | 397 MetricKey split_key = key_builder_->SplitMetricKey(it->key().ToString()); |
366 if (!results[split_key.activity].get()) { | 398 if (!results[split_key.activity].get()) { |
367 results[split_key.activity] = | 399 results[split_key.activity] = |
368 linked_ptr<MetricVector >(new MetricVector()); | 400 linked_ptr<MetricVector >(new MetricVector()); |
369 } | 401 } |
370 results[split_key.activity]->push_back( | 402 Metric metric(metric_type, split_key.time, it->value().ToString()); |
371 Metric(split_key.time, it->value().ToString())); | 403 if (!metric.IsValid()) { |
404 invalid_entries.Delete(it->key()); | |
405 LOG(ERROR) << "Found bad metric in the database. Type: " << | |
406 metric.type << ", Time: " << metric.time.ToInternalValue() << | |
407 ", Value: " << metric.value << ". Erasing metric from database."; | |
408 continue; | |
409 } | |
410 results[split_key.activity]->push_back(metric); | |
372 } | 411 } |
412 metric_db_->Write(write_options_, &invalid_entries); | |
373 return results; | 413 return results; |
374 } | 414 } |
375 | 415 |
376 Database::Database(const FilePath& path) | 416 Database::Database(const FilePath& path) |
377 : key_builder_(new KeyBuilder()), | 417 : key_builder_(new KeyBuilder()), |
378 path_(path), | 418 path_(path), |
379 read_options_(leveldb::ReadOptions()), | 419 read_options_(leveldb::ReadOptions()), |
380 write_options_(leveldb::WriteOptions()) { | 420 write_options_(leveldb::WriteOptions()) { |
381 InitDBs(); | 421 InitDBs(); |
382 LoadRecents(); | 422 LoadRecents(); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
482 start_time_key_ = key_builder_->CreateActiveIntervalKey(current_time); | 522 start_time_key_ = key_builder_->CreateActiveIntervalKey(current_time); |
483 end_time = start_time_key_; | 523 end_time = start_time_key_; |
484 } else { | 524 } else { |
485 end_time = key_builder_->CreateActiveIntervalKey(clock_->GetTime()); | 525 end_time = key_builder_->CreateActiveIntervalKey(clock_->GetTime()); |
486 } | 526 } |
487 last_update_time_ = current_time; | 527 last_update_time_ = current_time; |
488 active_interval_db_->Put(write_options_, start_time_key_, end_time); | 528 active_interval_db_->Put(write_options_, start_time_key_, end_time); |
489 } | 529 } |
490 | 530 |
491 } // namespace performance_monitor | 531 } // namespace performance_monitor |
OLD | NEW |