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() {
     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
    591