Index: chrome/browser/performance_monitor/database.cc |
diff --git a/chrome/browser/performance_monitor/database.cc b/chrome/browser/performance_monitor/database.cc |
deleted file mode 100644 |
index f3522d20e48838ed4c91636a8d7b5e6d2fff9cbc..0000000000000000000000000000000000000000 |
--- a/chrome/browser/performance_monitor/database.cc |
+++ /dev/null |
@@ -1,590 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/performance_monitor/database.h" |
- |
-#include "base/files/file_path.h" |
-#include "base/files/file_util.h" |
-#include "base/json/json_reader.h" |
-#include "base/json/json_writer.h" |
-#include "base/logging.h" |
-#include "base/path_service.h" |
-#include "base/stl_util.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "base/time/time.h" |
-#include "chrome/browser/performance_monitor/key_builder.h" |
-#include "chrome/common/chrome_paths.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "third_party/leveldatabase/src/include/leveldb/db.h" |
-#include "third_party/leveldatabase/src/include/leveldb/iterator.h" |
-#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
- |
-namespace performance_monitor { |
-namespace { |
-const char kDbDir[] = "Performance Monitor Databases"; |
-const char kRecentDb[] = "Recent Metrics"; |
-const char kMaxValueDb[] = "Max Value Metrics"; |
-const char kEventDb[] = "Events"; |
-const char kStateDb[] = "Configuration"; |
-const char kActiveIntervalDb[] = "Active Interval"; |
-const char kMetricDb[] = "Metrics"; |
-const double kDefaultMaxValue = 0.0; |
- |
-// If the db is quiet for this number of minutes, then it is considered down. |
-const base::TimeDelta kActiveIntervalTimeout() { |
- return base::TimeDelta::FromMinutes(5); |
-} |
- |
-TimeRange ActiveIntervalToTimeRange(const std::string& start_time, |
- const std::string& end_time) { |
- int64 start_time_int = 0; |
- int64 end_time_int = 0; |
- base::StringToInt64(start_time, &start_time_int); |
- base::StringToInt64(end_time, &end_time_int); |
- return TimeRange(base::Time::FromInternalValue(start_time_int), |
- base::Time::FromInternalValue(end_time_int)); |
-} |
- |
-double StringToDouble(const std::string& s) { |
- double value = 0.0; |
- if (!base::StringToDouble(s, &value)) |
- LOG(ERROR) << "Failed to convert " << s << " to double."; |
- return value; |
-} |
- |
-// Returns an event from the given JSON string; the scoped_ptr will be NULL if |
-// we are unable to properly parse the JSON. |
-scoped_ptr<Event> EventFromJSON(const std::string& data) { |
- base::Value* value = base::JSONReader::Read(data); |
- base::DictionaryValue* dict = NULL; |
- if (!value || !value->GetAsDictionary(&dict)) |
- return scoped_ptr<Event>(); |
- |
- return Event::FromValue(scoped_ptr<base::DictionaryValue>(dict)); |
-} |
- |
-} // namespace |
- |
-const char Database::kDatabaseSequenceToken[] = |
- "_performance_monitor_db_sequence_token_"; |
- |
-TimeRange::TimeRange() { |
-} |
- |
-TimeRange::TimeRange(base::Time start_time, base::Time end_time) |
- : start(start_time), |
- end(end_time) { |
-} |
- |
-TimeRange::~TimeRange() { |
-} |
- |
-base::Time Database::SystemClock::GetTime() { |
- return base::Time::Now(); |
-} |
- |
-// Static |
-scoped_ptr<Database> Database::Create(base::FilePath path) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- if (path.empty()) { |
- CHECK(PathService::Get(chrome::DIR_USER_DATA, &path)); |
- path = path.AppendASCII(kDbDir); |
- } |
- scoped_ptr<Database> database; |
- if (!base::DirectoryExists(path) && !base::CreateDirectory(path)) |
- return database.Pass(); |
- database.reset(new Database(path)); |
- |
- // If the database did not initialize correctly, return a NULL scoped_ptr. |
- if (!database->valid_) |
- database.reset(); |
- return database.Pass(); |
-} |
- |
-bool Database::AddStateValue(const std::string& key, const std::string& value) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- UpdateActiveInterval(); |
- leveldb::Status insert_status = state_db_->Put(write_options_, key, value); |
- return insert_status.ok(); |
-} |
- |
-std::string Database::GetStateValue(const std::string& key) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- std::string result; |
- state_db_->Get(read_options_, key, &result); |
- return result; |
-} |
- |
-bool Database::AddEvent(const Event& event) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- UpdateActiveInterval(); |
- std::string value; |
- base::JSONWriter::Write(event.data(), &value); |
- std::string key = key_builder_->CreateEventKey(event.time(), event.type()); |
- leveldb::Status status = event_db_->Put(write_options_, key, value); |
- return status.ok(); |
-} |
- |
-std::vector<TimeRange> Database::GetActiveIntervals(const base::Time& start, |
- const base::Time& end) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- std::vector<TimeRange> results; |
- std::string start_key = key_builder_->CreateActiveIntervalKey(start); |
- std::string end_key = key_builder_->CreateActiveIntervalKey(end); |
- scoped_ptr<leveldb::Iterator> it(active_interval_db_->NewIterator( |
- read_options_)); |
- it->Seek(start_key); |
- // If the interator is valid, we check the previous value in case we jumped |
- // into the middle of an active interval. If the iterator is not valid, then |
- // the key may be in the current active interval. |
- if (it->Valid()) |
- it->Prev(); |
- else |
- it->SeekToLast(); |
- if (it->Valid() && it->value().ToString() > start_key) { |
- results.push_back(ActiveIntervalToTimeRange(it->key().ToString(), |
- it->value().ToString())); |
- } |
- |
- for (it->Seek(start_key); |
- it->Valid() && it->key().ToString() < end_key; |
- it->Next()) { |
- results.push_back(ActiveIntervalToTimeRange(it->key().ToString(), |
- it->value().ToString())); |
- } |
- return results; |
-} |
- |
-Database::EventVector Database::GetEvents(EventType type, |
- const base::Time& start, |
- const base::Time& end) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- EventVector events; |
- std::string start_key = |
- key_builder_->CreateEventKey(start, EVENT_UNDEFINED); |
- std::string end_key = |
- key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); |
- leveldb::WriteBatch invalid_entries; |
- scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); |
- for (it->Seek(start_key); |
- it->Valid() && it->key().ToString() <= end_key; |
- it->Next()) { |
- if (type != EVENT_UNDEFINED) { |
- EventType key_type = |
- key_builder_->EventKeyToEventType(it->key().ToString()); |
- if (key_type != type) |
- continue; |
- } |
- scoped_ptr<Event> event = EventFromJSON(it->value().ToString()); |
- if (!event.get()) { |
- invalid_entries.Delete(it->key()); |
- LOG(ERROR) << "Found invalid event in the database. JSON: '" |
- << it->value().ToString() |
- << "'. Erasing event from the database."; |
- continue; |
- } |
- events.push_back(linked_ptr<Event>(event.release())); |
- } |
- event_db_->Write(write_options_, &invalid_entries); |
- return events; |
-} |
- |
-Database::EventTypeSet Database::GetEventTypes(const base::Time& start, |
- const base::Time& end) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- EventTypeSet results; |
- std::string start_key = |
- key_builder_->CreateEventKey(start, EVENT_UNDEFINED); |
- std::string end_key = |
- key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); |
- scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); |
- for (it->Seek(start_key); |
- it->Valid() && it->key().ToString() <= end_key; |
- it->Next()) { |
- EventType key_type = |
- key_builder_->EventKeyToEventType(it->key().ToString()); |
- results.insert(key_type); |
- } |
- return results; |
-} |
- |
-bool Database::AddMetric(const std::string& activity, |
- const Metric& metric) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- if (!metric.IsValid()) { |
- DLOG(ERROR) << "Metric to be added is invalid. Type: " << metric.type |
- << ", Time: " << metric.time.ToInternalValue() |
- << ", Value: " << metric.value << ". Ignoring."; |
- return false; |
- } |
- |
- UpdateActiveInterval(); |
- std::string recent_key = |
- key_builder_->CreateRecentKey(metric.time, metric.type, activity); |
- std::string metric_key = |
- key_builder_->CreateMetricKey(metric.time, metric.type, activity); |
- std::string recent_map_key = |
- key_builder_->CreateRecentMapKey(metric.type, activity); |
- // Use recent_map_ to quickly find the key that must be removed. |
- RecentMap::iterator old_it = recent_map_.find(recent_map_key); |
- if (old_it != recent_map_.end()) |
- recent_db_->Delete(write_options_, old_it->second); |
- recent_map_[recent_map_key] = recent_key; |
- leveldb::Status recent_status = |
- recent_db_->Put(write_options_, recent_key, metric.ValueAsString()); |
- leveldb::Status metric_status = |
- metric_db_->Put(write_options_, metric_key, metric.ValueAsString()); |
- |
- bool max_value_success = |
- UpdateMaxValue(activity, metric.type, metric.ValueAsString()); |
- return recent_status.ok() && metric_status.ok() && max_value_success; |
-} |
- |
-bool Database::UpdateMaxValue(const std::string& activity, |
- MetricType metric, |
- const std::string& value) { |
- std::string max_value_key( |
- key_builder_->CreateMaxValueKey(metric, activity)); |
- bool has_key = ContainsKey(max_value_map_, max_value_key); |
- if ((has_key && StringToDouble(value) > max_value_map_[max_value_key]) || |
- !has_key) { |
- max_value_map_[max_value_key] = StringToDouble(value); |
- return max_value_db_->Put(write_options_, max_value_key, value).ok(); |
- } |
- |
- return true; |
-} |
- |
-Database::MetricTypeSet Database::GetActiveMetrics(const base::Time& start, |
- const base::Time& end) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- std::string recent_start_key = key_builder_->CreateRecentKey( |
- start, static_cast<MetricType>(0), std::string()); |
- std::string recent_end_key = key_builder_->CreateRecentKey( |
- end, METRIC_NUMBER_OF_METRICS, std::string()); |
- std::string recent_end_of_time_key = key_builder_->CreateRecentKey( |
- clock_->GetTime(), METRIC_NUMBER_OF_METRICS, std::string()); |
- |
- MetricTypeSet active_metrics; |
- // Get all the guaranteed metrics. |
- scoped_ptr<leveldb::Iterator> recent_it( |
- recent_db_->NewIterator(read_options_)); |
- for (recent_it->Seek(recent_start_key); |
- recent_it->Valid() && recent_it->key().ToString() <= recent_end_key; |
- recent_it->Next()) { |
- RecentKey split_key = |
- key_builder_->SplitRecentKey(recent_it->key().ToString()); |
- active_metrics.insert(split_key.type); |
- } |
- // Get all the possible metrics (metrics that may have been updated after |
- // |end|). |
- MetricTypeSet possible_metrics; |
- for (recent_it->Seek(recent_end_key); |
- recent_it->Valid() && |
- recent_it->key().ToString() <= recent_end_of_time_key; |
- recent_it->Next()) { |
- RecentKey split_key = |
- key_builder_->SplitRecentKey(recent_it->key().ToString()); |
- possible_metrics.insert(split_key.type); |
- } |
- MetricTypeSet::iterator possible_it; |
- scoped_ptr<leveldb::Iterator> metric_it( |
- metric_db_->NewIterator(read_options_)); |
- for (possible_it = possible_metrics.begin(); |
- possible_it != possible_metrics.end(); |
- ++possible_it) { |
- std::string metric_start_key = |
- key_builder_->CreateMetricKey(start, *possible_it,std::string()); |
- std::string metric_end_key = |
- key_builder_->CreateMetricKey(end, *possible_it, std::string()); |
- metric_it->Seek(metric_start_key); |
- // Stats in the timerange from any activity makes the metric active. |
- if (metric_it->Valid() && metric_it->key().ToString() <= metric_end_key) { |
- active_metrics.insert(*possible_it); |
- } |
- } |
- |
- return active_metrics; |
-} |
- |
-std::set<std::string> Database::GetActiveActivities(MetricType metric_type, |
- const base::Time& start) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- std::set<std::string> results; |
- std::string start_key = key_builder_->CreateRecentKey( |
- start, static_cast<MetricType>(0), std::string()); |
- scoped_ptr<leveldb::Iterator> it(recent_db_->NewIterator(read_options_)); |
- for (it->Seek(start_key); it->Valid(); it->Next()) { |
- RecentKey split_key = |
- key_builder_->SplitRecentKey(it->key().ToString()); |
- if (split_key.type == metric_type) |
- results.insert(split_key.activity); |
- } |
- return results; |
-} |
- |
-double Database::GetMaxStatsForActivityAndMetric(const std::string& activity, |
- MetricType metric) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- std::string max_value_key( |
- key_builder_->CreateMaxValueKey(metric, activity)); |
- if (ContainsKey(max_value_map_, max_value_key)) |
- return max_value_map_[max_value_key]; |
- return kDefaultMaxValue; |
-} |
- |
-bool Database::GetRecentStatsForActivityAndMetric(const std::string& activity, |
- MetricType metric_type, |
- Metric* metric) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- std::string recent_map_key = |
- key_builder_->CreateRecentMapKey(metric_type, activity); |
- if (!ContainsKey(recent_map_, recent_map_key)) |
- return false; |
- std::string recent_key = recent_map_[recent_map_key]; |
- |
- std::string result; |
- leveldb::Status status = recent_db_->Get(read_options_, recent_key, &result); |
- if (status.ok()) |
- *metric = Metric(metric_type, |
- key_builder_->SplitRecentKey(recent_key).time, |
- result); |
- return status.ok(); |
-} |
- |
-scoped_ptr<Database::MetricVector> Database::GetStatsForActivityAndMetric( |
- const std::string& activity, |
- MetricType metric_type, |
- const base::Time& start, |
- const base::Time& end) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- scoped_ptr<MetricVector> results(new MetricVector()); |
- std::string start_key = |
- key_builder_->CreateMetricKey(start, metric_type, activity); |
- std::string end_key = |
- key_builder_->CreateMetricKey(end, metric_type, activity); |
- leveldb::WriteBatch invalid_entries; |
- scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); |
- for (it->Seek(start_key); |
- it->Valid() && it->key().ToString() <= end_key; |
- it->Next()) { |
- MetricKey split_key = |
- key_builder_->SplitMetricKey(it->key().ToString()); |
- if (split_key.activity == activity) { |
- Metric metric(metric_type, split_key.time, it->value().ToString()); |
- if (!metric.IsValid()) { |
- invalid_entries.Delete(it->key()); |
- LOG(ERROR) << "Found bad metric in the database. Type: " |
- << metric.type << ", Time: " << metric.time.ToInternalValue() |
- << ", Value: " << metric.value |
- << ". Erasing metric from database."; |
- continue; |
- } |
- results->push_back(metric); |
- } |
- } |
- metric_db_->Write(write_options_, &invalid_entries); |
- return results.Pass(); |
-} |
- |
-Database::MetricVectorMap Database::GetStatsForMetricByActivity( |
- MetricType metric_type, |
- const base::Time& start, |
- const base::Time& end) { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- MetricVectorMap results; |
- std::string start_key = |
- key_builder_->CreateMetricKey(start, metric_type, std::string()); |
- std::string end_key = |
- key_builder_->CreateMetricKey(end, metric_type, std::string()); |
- leveldb::WriteBatch invalid_entries; |
- scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); |
- for (it->Seek(start_key); |
- it->Valid() && it->key().ToString() <= end_key; |
- it->Next()) { |
- MetricKey split_key = key_builder_->SplitMetricKey(it->key().ToString()); |
- if (!results[split_key.activity].get()) { |
- results[split_key.activity] = |
- linked_ptr<MetricVector >(new MetricVector()); |
- } |
- Metric metric(metric_type, split_key.time, it->value().ToString()); |
- if (!metric.IsValid()) { |
- invalid_entries.Delete(it->key()); |
- LOG(ERROR) << "Found bad metric in the database. Type: " |
- << metric.type << ", Time: " << metric.time.ToInternalValue() |
- << ", Value: " << metric.value |
- << ". Erasing metric from database."; |
- continue; |
- } |
- results[split_key.activity]->push_back(metric); |
- } |
- metric_db_->Write(write_options_, &invalid_entries); |
- return results; |
-} |
- |
-Database::Database(const base::FilePath& path) |
- : key_builder_(new KeyBuilder()), |
- path_(path), |
- read_options_(leveldb::ReadOptions()), |
- write_options_(leveldb::WriteOptions()), |
- valid_(false) { |
- if (!InitDBs()) |
- return; |
- LoadRecents(); |
- LoadMaxValues(); |
- clock_ = scoped_ptr<Clock>(new SystemClock()); |
- valid_ = true; |
-} |
- |
-Database::~Database() { |
-} |
- |
-bool Database::InitDBs() { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- leveldb::Options open_options; |
- open_options.max_open_files = 0; // Use minimum. |
- open_options.create_if_missing = true; |
- |
- // TODO (rdevlin.cronin): This code is ugly. Fix it. |
- recent_db_ = SafelyOpenDatabase(open_options, |
- kRecentDb, |
- true); // fix if damaged |
- max_value_db_ = SafelyOpenDatabase(open_options, |
- kMaxValueDb, |
- true); // fix if damaged |
- state_db_ = SafelyOpenDatabase(open_options, |
- kStateDb, |
- true); // fix if damaged |
- active_interval_db_ = SafelyOpenDatabase(open_options, |
- kActiveIntervalDb, |
- true); // fix if damaged |
- metric_db_ = SafelyOpenDatabase(open_options, |
- kMetricDb, |
- true); // fix if damaged |
- event_db_ = SafelyOpenDatabase(open_options, |
- kEventDb, |
- true); // fix if damaged |
- return recent_db_ && max_value_db_ && state_db_ && |
- active_interval_db_ && metric_db_ && event_db_; |
-} |
- |
-scoped_ptr<leveldb::DB> Database::SafelyOpenDatabase( |
- const leveldb::Options& options, |
- const std::string& path, |
- bool fix_if_damaged) { |
-#if defined(OS_POSIX) |
- std::string name = path_.AppendASCII(path).value(); |
-#elif defined(OS_WIN) |
- std::string name = base::WideToUTF8(path_.AppendASCII(path).value()); |
-#endif |
- |
- leveldb::DB* database; |
- leveldb::Status status = leveldb::DB::Open(options, name, &database); |
- // If all goes well, return the database. |
- if (status.ok()) |
- return scoped_ptr<leveldb::DB>(database); |
- |
- // Return NULL and print the error if we either didn't find the database and |
- // don't want to create it, or if we don't want to try to fix it. |
- if ((status.IsNotFound() && !options.create_if_missing) || !fix_if_damaged) { |
- LOG(ERROR) << status.ToString(); |
- return scoped_ptr<leveldb::DB>(); |
- } |
- // Otherwise, we have an error (corruption, io error, or a not found error |
- // even if we tried to create it). |
- // |
- // First, we try again. |
- LOG(ERROR) << "Database error: " << status.ToString() << ". Trying again."; |
- status = leveldb::DB::Open(options, name, &database); |
- // If we fail on corruption, we can try to repair it. |
- if (status.IsCorruption()) { |
- LOG(ERROR) << "Database corrupt (second attempt). Trying to repair."; |
- status = leveldb::RepairDB(name, options); |
- // If the repair succeeds and we can open the database, return the |
- // database. Otherwise, continue on. |
- if (status.ok()) { |
- status = leveldb::DB::Open(options, name, &database); |
- if (status.ok()) |
- return scoped_ptr<leveldb::DB>(database); |
- } |
- LOG(ERROR) << "Repair failed. Deleting database."; |
- } |
- // Next, try to delete and recreate the database. Return NULL if we fail |
- // on either of these steps. |
- status = leveldb::DestroyDB(name, options); |
- if (!status.ok()) { |
- LOG(ERROR) << "Failed to delete database. " << status.ToString(); |
- return scoped_ptr<leveldb::DB>(); |
- } |
- // If we don't have the create_if_missing option, add it (it's safe to |
- // assume this is okay, since we have permission to |fix_if_damaged|). |
- if (!options.create_if_missing) { |
- leveldb::Options create_options(options); |
- create_options.create_if_missing = true; |
- status = leveldb::DB::Open(create_options, name, &database); |
- } else { |
- status = leveldb::DB::Open(options, name, &database); |
- } |
- // There's nothing else we can try at this point. |
- if (status.ok()) |
- return scoped_ptr<leveldb::DB>(database); |
- // Return the database if we succeeded, or NULL on failure. |
- LOG(ERROR) << "Failed to recreate database. " << status.ToString(); |
- return scoped_ptr<leveldb::DB>(); |
-} |
- |
-bool Database::Close() { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- metric_db_.reset(); |
- event_db_.reset(); |
- recent_db_.reset(); |
- max_value_db_.reset(); |
- state_db_.reset(); |
- active_interval_db_.reset(); |
- start_time_key_.clear(); |
- return true; |
-} |
- |
-void Database::LoadRecents() { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- recent_map_.clear(); |
- scoped_ptr<leveldb::Iterator> it(recent_db_->NewIterator(read_options_)); |
- for (it->SeekToFirst(); it->Valid(); it->Next()) { |
- RecentKey split_key = key_builder_->SplitRecentKey(it->key().ToString()); |
- recent_map_[key_builder_-> |
- CreateRecentMapKey(split_key.type, split_key.activity)] = |
- it->key().ToString(); |
- } |
-} |
- |
-void Database::LoadMaxValues() { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- max_value_map_.clear(); |
- scoped_ptr<leveldb::Iterator> it(max_value_db_->NewIterator(read_options_)); |
- for (it->SeekToFirst(); it->Valid(); it->Next()) { |
- max_value_map_[it->key().ToString()] = |
- StringToDouble(it->value().ToString()); |
- } |
-} |
- |
-// TODO(chebert): Only update the active interval under certian circumstances |
-// eg. every 10 times or when forced. |
-void Database::UpdateActiveInterval() { |
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- base::Time current_time = clock_->GetTime(); |
- std::string end_time; |
- // If the last update was too long ago. |
- if (start_time_key_.empty() || |
- current_time - last_update_time_ > kActiveIntervalTimeout()) { |
- start_time_key_ = key_builder_->CreateActiveIntervalKey(current_time); |
- end_time = start_time_key_; |
- } else { |
- end_time = key_builder_->CreateActiveIntervalKey(clock_->GetTime()); |
- } |
- last_update_time_ = current_time; |
- active_interval_db_->Put(write_options_, start_time_key_, end_time); |
-} |
- |
-} // namespace performance_monitor |