OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/performance_monitor/database.h" | |
6 | |
7 #include "base/files/file_path.h" | |
8 #include "base/files/file_util.h" | |
9 #include "base/json/json_reader.h" | |
10 #include "base/json/json_writer.h" | |
11 #include "base/logging.h" | |
12 #include "base/path_service.h" | |
13 #include "base/stl_util.h" | |
14 #include "base/strings/string_number_conversions.h" | |
15 #include "base/strings/utf_string_conversions.h" | |
16 #include "base/time/time.h" | |
17 #include "chrome/browser/performance_monitor/key_builder.h" | |
18 #include "chrome/common/chrome_paths.h" | |
19 #include "content/public/browser/browser_thread.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 | |
24 namespace performance_monitor { | |
25 namespace { | |
26 const char kDbDir[] = "Performance Monitor Databases"; | |
27 const char kRecentDb[] = "Recent Metrics"; | |
28 const char kMaxValueDb[] = "Max Value Metrics"; | |
29 const char kEventDb[] = "Events"; | |
30 const char kStateDb[] = "Configuration"; | |
31 const char kActiveIntervalDb[] = "Active Interval"; | |
32 const char kMetricDb[] = "Metrics"; | |
33 const double kDefaultMaxValue = 0.0; | |
34 | |
35 // If the db is quiet for this number of minutes, then it is considered down. | |
36 const base::TimeDelta kActiveIntervalTimeout() { | |
37 return base::TimeDelta::FromMinutes(5); | |
38 } | |
39 | |
40 TimeRange ActiveIntervalToTimeRange(const std::string& start_time, | |
41 const std::string& end_time) { | |
42 int64 start_time_int = 0; | |
43 int64 end_time_int = 0; | |
44 base::StringToInt64(start_time, &start_time_int); | |
45 base::StringToInt64(end_time, &end_time_int); | |
46 return TimeRange(base::Time::FromInternalValue(start_time_int), | |
47 base::Time::FromInternalValue(end_time_int)); | |
48 } | |
49 | |
50 double StringToDouble(const std::string& s) { | |
51 double value = 0.0; | |
52 if (!base::StringToDouble(s, &value)) | |
53 LOG(ERROR) << "Failed to convert " << s << " to double."; | |
54 return value; | |
55 } | |
56 | |
57 // Returns an event from the given JSON string; the scoped_ptr will be NULL if | |
58 // we are unable to properly parse the JSON. | |
59 scoped_ptr<Event> EventFromJSON(const std::string& data) { | |
60 base::Value* value = base::JSONReader::Read(data); | |
61 base::DictionaryValue* dict = NULL; | |
62 if (!value || !value->GetAsDictionary(&dict)) | |
63 return scoped_ptr<Event>(); | |
64 | |
65 return Event::FromValue(scoped_ptr<base::DictionaryValue>(dict)); | |
66 } | |
67 | |
68 } // namespace | |
69 | |
70 const char Database::kDatabaseSequenceToken[] = | |
71 "_performance_monitor_db_sequence_token_"; | |
72 | |
73 TimeRange::TimeRange() { | |
74 } | |
75 | |
76 TimeRange::TimeRange(base::Time start_time, base::Time end_time) | |
77 : start(start_time), | |
78 end(end_time) { | |
79 } | |
80 | |
81 TimeRange::~TimeRange() { | |
82 } | |
83 | |
84 base::Time Database::SystemClock::GetTime() { | |
85 return base::Time::Now(); | |
86 } | |
87 | |
88 // Static | |
89 scoped_ptr<Database> Database::Create(base::FilePath path) { | |
90 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
91 if (path.empty()) { | |
92 CHECK(PathService::Get(chrome::DIR_USER_DATA, &path)); | |
93 path = path.AppendASCII(kDbDir); | |
94 } | |
95 scoped_ptr<Database> database; | |
96 if (!base::DirectoryExists(path) && !base::CreateDirectory(path)) | |
97 return database.Pass(); | |
98 database.reset(new Database(path)); | |
99 | |
100 // If the database did not initialize correctly, return a NULL scoped_ptr. | |
101 if (!database->valid_) | |
102 database.reset(); | |
103 return database.Pass(); | |
104 } | |
105 | |
106 bool Database::AddStateValue(const std::string& key, const std::string& value) { | |
107 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
108 UpdateActiveInterval(); | |
109 leveldb::Status insert_status = state_db_->Put(write_options_, key, value); | |
110 return insert_status.ok(); | |
111 } | |
112 | |
113 std::string Database::GetStateValue(const std::string& key) { | |
114 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
115 std::string result; | |
116 state_db_->Get(read_options_, key, &result); | |
117 return result; | |
118 } | |
119 | |
120 bool Database::AddEvent(const Event& event) { | |
121 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
122 UpdateActiveInterval(); | |
123 std::string value; | |
124 base::JSONWriter::Write(event.data(), &value); | |
125 std::string key = key_builder_->CreateEventKey(event.time(), event.type()); | |
126 leveldb::Status status = event_db_->Put(write_options_, key, value); | |
127 return status.ok(); | |
128 } | |
129 | |
130 std::vector<TimeRange> Database::GetActiveIntervals(const base::Time& start, | |
131 const base::Time& end) { | |
132 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
133 std::vector<TimeRange> results; | |
134 std::string start_key = key_builder_->CreateActiveIntervalKey(start); | |
135 std::string end_key = key_builder_->CreateActiveIntervalKey(end); | |
136 scoped_ptr<leveldb::Iterator> it(active_interval_db_->NewIterator( | |
137 read_options_)); | |
138 it->Seek(start_key); | |
139 // If the interator is valid, we check the previous value in case we jumped | |
140 // into the middle of an active interval. If the iterator is not valid, then | |
141 // the key may be in the current active interval. | |
142 if (it->Valid()) | |
143 it->Prev(); | |
144 else | |
145 it->SeekToLast(); | |
146 if (it->Valid() && it->value().ToString() > start_key) { | |
147 results.push_back(ActiveIntervalToTimeRange(it->key().ToString(), | |
148 it->value().ToString())); | |
149 } | |
150 | |
151 for (it->Seek(start_key); | |
152 it->Valid() && it->key().ToString() < end_key; | |
153 it->Next()) { | |
154 results.push_back(ActiveIntervalToTimeRange(it->key().ToString(), | |
155 it->value().ToString())); | |
156 } | |
157 return results; | |
158 } | |
159 | |
160 Database::EventVector Database::GetEvents(EventType type, | |
161 const base::Time& start, | |
162 const base::Time& end) { | |
163 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
164 EventVector events; | |
165 std::string start_key = | |
166 key_builder_->CreateEventKey(start, EVENT_UNDEFINED); | |
167 std::string end_key = | |
168 key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); | |
169 leveldb::WriteBatch invalid_entries; | |
170 scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); | |
171 for (it->Seek(start_key); | |
172 it->Valid() && it->key().ToString() <= end_key; | |
173 it->Next()) { | |
174 if (type != EVENT_UNDEFINED) { | |
175 EventType key_type = | |
176 key_builder_->EventKeyToEventType(it->key().ToString()); | |
177 if (key_type != type) | |
178 continue; | |
179 } | |
180 scoped_ptr<Event> event = EventFromJSON(it->value().ToString()); | |
181 if (!event.get()) { | |
182 invalid_entries.Delete(it->key()); | |
183 LOG(ERROR) << "Found invalid event in the database. JSON: '" | |
184 << it->value().ToString() | |
185 << "'. Erasing event from the database."; | |
186 continue; | |
187 } | |
188 events.push_back(linked_ptr<Event>(event.release())); | |
189 } | |
190 event_db_->Write(write_options_, &invalid_entries); | |
191 return events; | |
192 } | |
193 | |
194 Database::EventTypeSet Database::GetEventTypes(const base::Time& start, | |
195 const base::Time& end) { | |
196 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
197 EventTypeSet results; | |
198 std::string start_key = | |
199 key_builder_->CreateEventKey(start, EVENT_UNDEFINED); | |
200 std::string end_key = | |
201 key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); | |
202 scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); | |
203 for (it->Seek(start_key); | |
204 it->Valid() && it->key().ToString() <= end_key; | |
205 it->Next()) { | |
206 EventType key_type = | |
207 key_builder_->EventKeyToEventType(it->key().ToString()); | |
208 results.insert(key_type); | |
209 } | |
210 return results; | |
211 } | |
212 | |
213 bool Database::AddMetric(const std::string& activity, | |
214 const Metric& metric) { | |
215 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
216 if (!metric.IsValid()) { | |
217 DLOG(ERROR) << "Metric to be added is invalid. Type: " << metric.type | |
218 << ", Time: " << metric.time.ToInternalValue() | |
219 << ", Value: " << metric.value << ". Ignoring."; | |
220 return false; | |
221 } | |
222 | |
223 UpdateActiveInterval(); | |
224 std::string recent_key = | |
225 key_builder_->CreateRecentKey(metric.time, metric.type, activity); | |
226 std::string metric_key = | |
227 key_builder_->CreateMetricKey(metric.time, metric.type, activity); | |
228 std::string recent_map_key = | |
229 key_builder_->CreateRecentMapKey(metric.type, activity); | |
230 // Use recent_map_ to quickly find the key that must be removed. | |
231 RecentMap::iterator old_it = recent_map_.find(recent_map_key); | |
232 if (old_it != recent_map_.end()) | |
233 recent_db_->Delete(write_options_, old_it->second); | |
234 recent_map_[recent_map_key] = recent_key; | |
235 leveldb::Status recent_status = | |
236 recent_db_->Put(write_options_, recent_key, metric.ValueAsString()); | |
237 leveldb::Status metric_status = | |
238 metric_db_->Put(write_options_, metric_key, metric.ValueAsString()); | |
239 | |
240 bool max_value_success = | |
241 UpdateMaxValue(activity, metric.type, metric.ValueAsString()); | |
242 return recent_status.ok() && metric_status.ok() && max_value_success; | |
243 } | |
244 | |
245 bool Database::UpdateMaxValue(const std::string& activity, | |
246 MetricType metric, | |
247 const std::string& value) { | |
248 std::string max_value_key( | |
249 key_builder_->CreateMaxValueKey(metric, activity)); | |
250 bool has_key = ContainsKey(max_value_map_, max_value_key); | |
251 if ((has_key && StringToDouble(value) > max_value_map_[max_value_key]) || | |
252 !has_key) { | |
253 max_value_map_[max_value_key] = StringToDouble(value); | |
254 return max_value_db_->Put(write_options_, max_value_key, value).ok(); | |
255 } | |
256 | |
257 return true; | |
258 } | |
259 | |
260 Database::MetricTypeSet Database::GetActiveMetrics(const base::Time& start, | |
261 const base::Time& end) { | |
262 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
263 std::string recent_start_key = key_builder_->CreateRecentKey( | |
264 start, static_cast<MetricType>(0), std::string()); | |
265 std::string recent_end_key = key_builder_->CreateRecentKey( | |
266 end, METRIC_NUMBER_OF_METRICS, std::string()); | |
267 std::string recent_end_of_time_key = key_builder_->CreateRecentKey( | |
268 clock_->GetTime(), METRIC_NUMBER_OF_METRICS, std::string()); | |
269 | |
270 MetricTypeSet active_metrics; | |
271 // Get all the guaranteed metrics. | |
272 scoped_ptr<leveldb::Iterator> recent_it( | |
273 recent_db_->NewIterator(read_options_)); | |
274 for (recent_it->Seek(recent_start_key); | |
275 recent_it->Valid() && recent_it->key().ToString() <= recent_end_key; | |
276 recent_it->Next()) { | |
277 RecentKey split_key = | |
278 key_builder_->SplitRecentKey(recent_it->key().ToString()); | |
279 active_metrics.insert(split_key.type); | |
280 } | |
281 // Get all the possible metrics (metrics that may have been updated after | |
282 // |end|). | |
283 MetricTypeSet possible_metrics; | |
284 for (recent_it->Seek(recent_end_key); | |
285 recent_it->Valid() && | |
286 recent_it->key().ToString() <= recent_end_of_time_key; | |
287 recent_it->Next()) { | |
288 RecentKey split_key = | |
289 key_builder_->SplitRecentKey(recent_it->key().ToString()); | |
290 possible_metrics.insert(split_key.type); | |
291 } | |
292 MetricTypeSet::iterator possible_it; | |
293 scoped_ptr<leveldb::Iterator> metric_it( | |
294 metric_db_->NewIterator(read_options_)); | |
295 for (possible_it = possible_metrics.begin(); | |
296 possible_it != possible_metrics.end(); | |
297 ++possible_it) { | |
298 std::string metric_start_key = | |
299 key_builder_->CreateMetricKey(start, *possible_it,std::string()); | |
300 std::string metric_end_key = | |
301 key_builder_->CreateMetricKey(end, *possible_it, std::string()); | |
302 metric_it->Seek(metric_start_key); | |
303 // Stats in the timerange from any activity makes the metric active. | |
304 if (metric_it->Valid() && metric_it->key().ToString() <= metric_end_key) { | |
305 active_metrics.insert(*possible_it); | |
306 } | |
307 } | |
308 | |
309 return active_metrics; | |
310 } | |
311 | |
312 std::set<std::string> Database::GetActiveActivities(MetricType metric_type, | |
313 const base::Time& start) { | |
314 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
315 std::set<std::string> results; | |
316 std::string start_key = key_builder_->CreateRecentKey( | |
317 start, static_cast<MetricType>(0), std::string()); | |
318 scoped_ptr<leveldb::Iterator> it(recent_db_->NewIterator(read_options_)); | |
319 for (it->Seek(start_key); it->Valid(); it->Next()) { | |
320 RecentKey split_key = | |
321 key_builder_->SplitRecentKey(it->key().ToString()); | |
322 if (split_key.type == metric_type) | |
323 results.insert(split_key.activity); | |
324 } | |
325 return results; | |
326 } | |
327 | |
328 double Database::GetMaxStatsForActivityAndMetric(const std::string& activity, | |
329 MetricType metric) { | |
330 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
331 std::string max_value_key( | |
332 key_builder_->CreateMaxValueKey(metric, activity)); | |
333 if (ContainsKey(max_value_map_, max_value_key)) | |
334 return max_value_map_[max_value_key]; | |
335 return kDefaultMaxValue; | |
336 } | |
337 | |
338 bool Database::GetRecentStatsForActivityAndMetric(const std::string& activity, | |
339 MetricType metric_type, | |
340 Metric* metric) { | |
341 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
342 std::string recent_map_key = | |
343 key_builder_->CreateRecentMapKey(metric_type, activity); | |
344 if (!ContainsKey(recent_map_, recent_map_key)) | |
345 return false; | |
346 std::string recent_key = recent_map_[recent_map_key]; | |
347 | |
348 std::string result; | |
349 leveldb::Status status = recent_db_->Get(read_options_, recent_key, &result); | |
350 if (status.ok()) | |
351 *metric = Metric(metric_type, | |
352 key_builder_->SplitRecentKey(recent_key).time, | |
353 result); | |
354 return status.ok(); | |
355 } | |
356 | |
357 scoped_ptr<Database::MetricVector> Database::GetStatsForActivityAndMetric( | |
358 const std::string& activity, | |
359 MetricType metric_type, | |
360 const base::Time& start, | |
361 const base::Time& end) { | |
362 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
363 scoped_ptr<MetricVector> results(new MetricVector()); | |
364 std::string start_key = | |
365 key_builder_->CreateMetricKey(start, metric_type, activity); | |
366 std::string end_key = | |
367 key_builder_->CreateMetricKey(end, metric_type, activity); | |
368 leveldb::WriteBatch invalid_entries; | |
369 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); | |
370 for (it->Seek(start_key); | |
371 it->Valid() && it->key().ToString() <= end_key; | |
372 it->Next()) { | |
373 MetricKey split_key = | |
374 key_builder_->SplitMetricKey(it->key().ToString()); | |
375 if (split_key.activity == activity) { | |
376 Metric metric(metric_type, split_key.time, it->value().ToString()); | |
377 if (!metric.IsValid()) { | |
378 invalid_entries.Delete(it->key()); | |
379 LOG(ERROR) << "Found bad metric in the database. Type: " | |
380 << metric.type << ", Time: " << metric.time.ToInternalValue() | |
381 << ", Value: " << metric.value | |
382 << ". Erasing metric from database."; | |
383 continue; | |
384 } | |
385 results->push_back(metric); | |
386 } | |
387 } | |
388 metric_db_->Write(write_options_, &invalid_entries); | |
389 return results.Pass(); | |
390 } | |
391 | |
392 Database::MetricVectorMap Database::GetStatsForMetricByActivity( | |
393 MetricType metric_type, | |
394 const base::Time& start, | |
395 const base::Time& end) { | |
396 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
397 MetricVectorMap results; | |
398 std::string start_key = | |
399 key_builder_->CreateMetricKey(start, metric_type, std::string()); | |
400 std::string end_key = | |
401 key_builder_->CreateMetricKey(end, metric_type, std::string()); | |
402 leveldb::WriteBatch invalid_entries; | |
403 scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); | |
404 for (it->Seek(start_key); | |
405 it->Valid() && it->key().ToString() <= end_key; | |
406 it->Next()) { | |
407 MetricKey split_key = key_builder_->SplitMetricKey(it->key().ToString()); | |
408 if (!results[split_key.activity].get()) { | |
409 results[split_key.activity] = | |
410 linked_ptr<MetricVector >(new MetricVector()); | |
411 } | |
412 Metric metric(metric_type, split_key.time, it->value().ToString()); | |
413 if (!metric.IsValid()) { | |
414 invalid_entries.Delete(it->key()); | |
415 LOG(ERROR) << "Found bad metric in the database. Type: " | |
416 << metric.type << ", Time: " << metric.time.ToInternalValue() | |
417 << ", Value: " << metric.value | |
418 << ". Erasing metric from database."; | |
419 continue; | |
420 } | |
421 results[split_key.activity]->push_back(metric); | |
422 } | |
423 metric_db_->Write(write_options_, &invalid_entries); | |
424 return results; | |
425 } | |
426 | |
427 Database::Database(const base::FilePath& path) | |
428 : key_builder_(new KeyBuilder()), | |
429 path_(path), | |
430 read_options_(leveldb::ReadOptions()), | |
431 write_options_(leveldb::WriteOptions()), | |
432 valid_(false) { | |
433 if (!InitDBs()) | |
434 return; | |
435 LoadRecents(); | |
436 LoadMaxValues(); | |
437 clock_ = scoped_ptr<Clock>(new SystemClock()); | |
438 valid_ = true; | |
439 } | |
440 | |
441 Database::~Database() { | |
442 } | |
443 | |
444 bool Database::InitDBs() { | |
445 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
446 leveldb::Options open_options; | |
447 open_options.max_open_files = 0; // Use minimum. | |
448 open_options.create_if_missing = true; | |
449 | |
450 // TODO (rdevlin.cronin): This code is ugly. Fix it. | |
451 recent_db_ = SafelyOpenDatabase(open_options, | |
452 kRecentDb, | |
453 true); // fix if damaged | |
454 max_value_db_ = SafelyOpenDatabase(open_options, | |
455 kMaxValueDb, | |
456 true); // fix if damaged | |
457 state_db_ = SafelyOpenDatabase(open_options, | |
458 kStateDb, | |
459 true); // fix if damaged | |
460 active_interval_db_ = SafelyOpenDatabase(open_options, | |
461 kActiveIntervalDb, | |
462 true); // fix if damaged | |
463 metric_db_ = SafelyOpenDatabase(open_options, | |
464 kMetricDb, | |
465 true); // fix if damaged | |
466 event_db_ = SafelyOpenDatabase(open_options, | |
467 kEventDb, | |
468 true); // fix if damaged | |
469 return recent_db_ && max_value_db_ && state_db_ && | |
470 active_interval_db_ && metric_db_ && event_db_; | |
471 } | |
472 | |
473 scoped_ptr<leveldb::DB> Database::SafelyOpenDatabase( | |
474 const leveldb::Options& options, | |
475 const std::string& path, | |
476 bool fix_if_damaged) { | |
477 #if defined(OS_POSIX) | |
478 std::string name = path_.AppendASCII(path).value(); | |
479 #elif defined(OS_WIN) | |
480 std::string name = base::WideToUTF8(path_.AppendASCII(path).value()); | |
481 #endif | |
482 | |
483 leveldb::DB* database; | |
484 leveldb::Status status = leveldb::DB::Open(options, name, &database); | |
485 // If all goes well, return the database. | |
486 if (status.ok()) | |
487 return scoped_ptr<leveldb::DB>(database); | |
488 | |
489 // Return NULL and print the error if we either didn't find the database and | |
490 // don't want to create it, or if we don't want to try to fix it. | |
491 if ((status.IsNotFound() && !options.create_if_missing) || !fix_if_damaged) { | |
492 LOG(ERROR) << status.ToString(); | |
493 return scoped_ptr<leveldb::DB>(); | |
494 } | |
495 // Otherwise, we have an error (corruption, io error, or a not found error | |
496 // even if we tried to create it). | |
497 // | |
498 // First, we try again. | |
499 LOG(ERROR) << "Database error: " << status.ToString() << ". Trying again."; | |
500 status = leveldb::DB::Open(options, name, &database); | |
501 // If we fail on corruption, we can try to repair it. | |
502 if (status.IsCorruption()) { | |
503 LOG(ERROR) << "Database corrupt (second attempt). Trying to repair."; | |
504 status = leveldb::RepairDB(name, options); | |
505 // If the repair succeeds and we can open the database, return the | |
506 // database. Otherwise, continue on. | |
507 if (status.ok()) { | |
508 status = leveldb::DB::Open(options, name, &database); | |
509 if (status.ok()) | |
510 return scoped_ptr<leveldb::DB>(database); | |
511 } | |
512 LOG(ERROR) << "Repair failed. Deleting database."; | |
513 } | |
514 // Next, try to delete and recreate the database. Return NULL if we fail | |
515 // on either of these steps. | |
516 status = leveldb::DestroyDB(name, options); | |
517 if (!status.ok()) { | |
518 LOG(ERROR) << "Failed to delete database. " << status.ToString(); | |
519 return scoped_ptr<leveldb::DB>(); | |
520 } | |
521 // If we don't have the create_if_missing option, add it (it's safe to | |
522 // assume this is okay, since we have permission to |fix_if_damaged|). | |
523 if (!options.create_if_missing) { | |
524 leveldb::Options create_options(options); | |
525 create_options.create_if_missing = true; | |
526 status = leveldb::DB::Open(create_options, name, &database); | |
527 } else { | |
528 status = leveldb::DB::Open(options, name, &database); | |
529 } | |
530 // There's nothing else we can try at this point. | |
531 if (status.ok()) | |
532 return scoped_ptr<leveldb::DB>(database); | |
533 // Return the database if we succeeded, or NULL on failure. | |
534 LOG(ERROR) << "Failed to recreate database. " << status.ToString(); | |
535 return scoped_ptr<leveldb::DB>(); | |
536 } | |
537 | |
538 bool Database::Close() { | |
539 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
540 metric_db_.reset(); | |
541 event_db_.reset(); | |
542 recent_db_.reset(); | |
543 max_value_db_.reset(); | |
544 state_db_.reset(); | |
545 active_interval_db_.reset(); | |
546 start_time_key_.clear(); | |
547 return true; | |
548 } | |
549 | |
550 void Database::LoadRecents() { | |
551 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
552 recent_map_.clear(); | |
553 scoped_ptr<leveldb::Iterator> it(recent_db_->NewIterator(read_options_)); | |
554 for (it->SeekToFirst(); it->Valid(); it->Next()) { | |
555 RecentKey split_key = key_builder_->SplitRecentKey(it->key().ToString()); | |
556 recent_map_[key_builder_-> | |
557 CreateRecentMapKey(split_key.type, split_key.activity)] = | |
558 it->key().ToString(); | |
559 } | |
560 } | |
561 | |
562 void Database::LoadMaxValues() { | |
563 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
564 max_value_map_.clear(); | |
565 scoped_ptr<leveldb::Iterator> it(max_value_db_->NewIterator(read_options_)); | |
566 for (it->SeekToFirst(); it->Valid(); it->Next()) { | |
567 max_value_map_[it->key().ToString()] = | |
568 StringToDouble(it->value().ToString()); | |
569 } | |
570 } | |
571 | |
572 // TODO(chebert): Only update the active interval under certian circumstances | |
573 // eg. every 10 times or when forced. | |
574 void Database::UpdateActiveInterval() { | |
575 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
576 base::Time current_time = clock_->GetTime(); | |
577 std::string end_time; | |
578 // If the last update was too long ago. | |
579 if (start_time_key_.empty() || | |
580 current_time - last_update_time_ > kActiveIntervalTimeout()) { | |
581 start_time_key_ = key_builder_->CreateActiveIntervalKey(current_time); | |
582 end_time = start_time_key_; | |
583 } else { | |
584 end_time = key_builder_->CreateActiveIntervalKey(clock_->GetTime()); | |
585 } | |
586 last_update_time_ = current_time; | |
587 active_interval_db_->Put(write_options_, start_time_key_, end_time); | |
588 } | |
589 | |
590 } // namespace performance_monitor | |
OLD | NEW |