Index: chrome/browser/performance_monitor/database.cc |
diff --git a/chrome/browser/performance_monitor/database.cc b/chrome/browser/performance_monitor/database.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..fab4d8f80150fb6d795f095cd466813a8dcefc64 |
--- /dev/null |
+++ b/chrome/browser/performance_monitor/database.cc |
@@ -0,0 +1,172 @@ |
+// 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/file_path.h" |
+#include "base/file_util.h" |
+#include "base/logging.h" |
+#include "base/path_service.h" |
+#include "base/string_number_conversions.h" |
+#include "base/stringprintf.h" |
+#include "base/time.h" |
+#include "chrome/common/chrome_paths.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "third_party/leveldatabase/src/include/leveldb/db.h" |
+ |
+namespace { |
+const char kDbDir[] = "Performance Monitor Databases"; |
+const char kRecentDb[] = "Recent Metrics"; |
+const char kEventDb[] = "Events"; |
+const char kStateDb[] = "Configuration"; |
+const char kActiveIntervalDb[] = "Active Interval"; |
+const char kMetricDb[] = "Metrics"; |
+const char kDelimiter = '!'; |
+ |
+// If the db is quiet for this number of microseconds, then it is considered |
+// down. |
+const base::TimeDelta kActiveIntervalTimeout = base::TimeDelta::FromSeconds(5); |
+ |
+// Create the key used for internal active interval monitoring. |
+std::string CreateActiveIntervalKey(const base::Time& time) { |
+ return StringPrintf("%016ld", time.ToInternalValue()); |
+} |
+} // namespace |
+ |
+namespace performance_monitor { |
+ |
+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(); |
+} |
+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; |
+} |
+ |
+void Database::Clear() { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ metric_db_.reset(); |
+ recent_db_.reset(); |
+ state_db_.reset(); |
+ active_interval_db_.reset(); |
+ // Recursively delete all the databases. |
+ if (!file_util::Delete(path_, true /* recursive */) || |
+ !file_util::CreateDirectory(path_)) |
+ LOG(ERROR) << "Failed to clear the performance monitor databases."; |
+} |
+ |
+std::vector<TimeRange> Database::GetActiveInterval(const base::Time& start, |
+ const base::Time& end) { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ std::vector<TimeRange> results; |
+ std::string start_key = CreateActiveIntervalKey(start); |
+ std::string end_key = CreateActiveIntervalKey(end); |
+ scoped_ptr<leveldb::Iterator> it(active_interval_db_->NewIterator( |
+ read_options_)); |
+ it->Seek(start_key); |
+ int64 start_time; |
+ int64 end_time; |
+ // Check the previous value in case we jumped in in the middle of an active |
+ // interval. |
+ it->Prev(); |
+ if (it->Valid() && it->value().ToString() > start_key) { |
+ base::StringToInt64(it->key().ToString(), &start_time); |
+ base::StringToInt64(it->value().ToString(), &end_time); |
+ results.push_back(TimeRange(base::Time::FromInternalValue(start_time), |
+ base::Time::FromInternalValue(end_time))); |
+ } |
+ for (it->Seek(start_key); |
+ it->Valid() && it->key().ToString() < end_key; |
+ it->Next()) { |
+ base::StringToInt64(it->key().ToString(), &start_time); |
+ base::StringToInt64(it->value().ToString(), &end_time); |
+ results.push_back(TimeRange(base::Time::FromInternalValue(start_time), |
+ base::Time::FromInternalValue(end_time))); |
+ } |
+ return results; |
+} |
+ |
+Database::Database(const FilePath& path) |
+ : path_(path), |
+ read_options_(leveldb::ReadOptions()), |
+ write_options_(leveldb::WriteOptions()) { |
+ leveldb::DB* new_db = NULL; |
+ leveldb::Options open_options; |
+ open_options.create_if_missing = true; |
+ leveldb::DB::Open(open_options, path_.AppendASCII(kRecentDb).value(), |
+ &new_db); |
+ recent_db_ = scoped_ptr<leveldb::DB>(new_db); |
+ leveldb::DB::Open(open_options, path_.AppendASCII(kStateDb).value(), |
+ &new_db); |
+ state_db_ = scoped_ptr<leveldb::DB>(new_db); |
+ leveldb::DB::Open(open_options, path_.AppendASCII(kActiveIntervalDb).value(), |
+ &new_db); |
+ active_interval_db_ = scoped_ptr<leveldb::DB>(new_db); |
+ leveldb::DB::Open(open_options, path_.AppendASCII(kMetricDb).value(), |
+ &new_db); |
+ metric_db_ = scoped_ptr<leveldb::DB>(new_db); |
+ clock_ = scoped_ptr<Clock>(new SystemClock()); |
+} |
+ |
+Database::~Database() { |
+ Close(); |
+} |
+ |
+// Static |
+scoped_refptr<Database> Database::Create(FilePath path) { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ if (path.empty()) { |
+ CHECK(PathService::Get(chrome::DIR_USER_DATA, &path)); |
+ path = path.AppendASCII(kDbDir); |
+ } |
+ if (!file_util::DirectoryExists(path) && !file_util::CreateDirectory(path)) |
+ return scoped_refptr<Database>(); |
+ return scoped_refptr<Database>(new Database(path)); |
+} |
+ |
+bool Database::Close() { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ UpdateActiveInterval(); |
+ start_time_key_.clear(); |
+ return true; |
+} |
+ |
+// TODO(eriq): 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_ = CreateActiveIntervalKey(current_time); |
+ end_time = start_time_key_; |
+ } else { |
+ end_time = CreateActiveIntervalKey(clock_->GetTime()); |
+ } |
+ active_interval_db_->Put(write_options_, start_time_key_, end_time); |
+} |
+} // namespace performance_monitor |