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