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..29ac01c9e3ba980cfc892c9f8806a5afe530873b |
--- /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/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_dbs"; |
Aaron Boodman
2012/06/08 21:40:05
In Chrome, these files are normally named very hum
eaugusti
2012/06/08 22:52:08
Done.
|
+const char kRecentDb[] = "_performance_monitor_meta_recent"; |
Aaron Boodman
2012/06/08 21:40:05
Since these are inside the directory, the 'perform
eaugusti
2012/06/08 22:52:08
Done.
|
+const char kEventDb[] = "_performance_monitor_meta_events"; |
+const char kStateDb[] = "_performance_monitor_meta_state"; |
+const char kUptimeDb[] = "_performance_monitor_meta_uptime"; |
Aaron Boodman
2012/06/08 21:40:05
'uptime' has a well understood meaning that is dif
eaugusti
2012/06/08 22:52:08
How about Active Interval?
|
+const char kDelimiter = '!'; |
+ |
+// If the db is quiet for this number of microseconds, then it is considered |
+// down. |
+const int kUptimeTimeout = 5 * base::Time::kMicrosecondsPerMinute; |
Aaron Boodman
2012/06/08 19:33:56
Typically we either use base::TimeDelate, or encod
eaugusti
2012/06/08 22:52:08
Done.
|
+ |
+// Create the key used for internal uptime monitoring. |
+std::string CreateUptimeKey(const base::Time& time) { |
+ return StringPrintf("%016ld", time.ToInternalValue()); |
+} |
+} // namespace |
+ |
+namespace performance_monitor { |
+ |
+base::Time SystemClock::GetTime() { |
+ return base::Time::Now(); |
+} |
+bool Database::AddStateValueOnBackgroundThread(const std::string& key, |
+ const std::string& value) { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ UpdateUptimeOnBackgroundThread(); |
+ leveldb::DB* state_db = FetchDBOnBackgroundThread(std::string(kStateDb)); |
Aaron Boodman
2012/06/08 19:33:56
There is implicit conversion from const char[] to
eaugusti
2012/06/08 22:52:08
Done.
|
+ leveldb::Status insert_status = |
+ state_db->Put(write_options_, key, value); |
+ return insert_status.ok(); |
+} |
+ |
+std::string Database::GetStateValueOnBackgroundThread(const std::string& key) { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ UpdateUptimeOnBackgroundThread(); |
+ std::string result; |
+ leveldb::DB* db = FetchDBOnBackgroundThread(std::string(kStateDb)); |
+ db->Get(read_options_, key, &result); |
+ return result; |
+} |
+ |
+void Database::ClearOnBackgroundThread() { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ LevelDbMap::iterator db_iter; |
+ for (db_iter = databases_.begin(); db_iter != databases_.end(); ++db_iter) |
+ delete db_iter->second; |
Aaron Boodman
2012/06/08 19:33:56
Use linked_ptr so that you don't need to do the de
eaugusti
2012/06/08 22:52:08
Done.
|
+ databases_.clear(); |
+ CHECK(file_util::Delete(path_, true)); |
Aaron Boodman
2012/06/08 19:33:56
Document the magic boolean or use a named constant
Aaron Boodman
2012/06/08 19:33:56
CHECK means: if this condition is false, the code
eaugusti
2012/06/08 22:52:08
Done.
|
+ CHECK(file_util::CreateDirectory(path_)); |
+} |
+ |
+Database::TimePairs Database::GetUptimeOnBackgroundThread( |
+ const base::Time& start, const base::Time& end) { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ UpdateUptimeOnBackgroundThread(); |
Aaron Boodman
2012/06/08 21:40:05
I think you probably don't want to update here.
eaugusti
2012/06/08 22:52:08
Done.
|
+ TimePairs results; |
+ std::string start_key = CreateUptimeKey(start); |
+ std::string end_key = CreateUptimeKey(end); |
+ leveldb::DB* db = FetchDBOnBackgroundThread(kUptimeDb); |
+ leveldb::Iterator* it = 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 uptime. |
+ it->Prev(); |
+ if (it->Valid() && it->value().ToString() > start_key) { |
Aaron Boodman
2012/06/08 21:40:05
Scary to compare lexographically. In this case it
eaugusti
2012/06/08 22:52:08
In key generation we pad with enough 0's to make l
|
+ base::StringToInt64(it->key().ToString(), &start_time); |
+ base::StringToInt64(it->value().ToString(), &end_time); |
+ results.push_back(std::pair<base::Time, base::Time>( |
+ 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(std::pair<base::Time, base::Time>( |
+ base::Time::FromInternalValue(start_time), |
+ base::Time::FromInternalValue(end_time))); |
+ } |
+ delete it; |
Aaron Boodman
2012/06/08 21:40:05
scoped_ptr to avoid manual delete?
eaugusti
2012/06/08 22:52:08
Done.
|
+ return results; |
+} |
+ |
+Database::Database(const FilePath& path, scoped_refptr<DBClock> clock) |
+ : path_(path), |
+ clock_(clock), |
+ read_options_(leveldb::ReadOptions()), |
+ write_options_(leveldb::WriteOptions()) { |
+ start_time_key_ = CreateUptimeKey(clock_->GetTime()); |
+ last_update_time_ = clock->GetTime(); |
+ uptime_threshold_ = base::TimeDelta::FromMicroseconds(kUptimeTimeout); |
+} |
+ |
+Database::~Database() { |
+ CloseOnBackgroundThread(); |
+} |
+ |
+// Static |
+scoped_refptr<Database> Database::InitOnBackgroundThread( |
+ FilePath path, scoped_refptr<DBClock> clock) { |
+ 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>(); |
+ scoped_refptr<Database> db = new Database(path, clock); |
+ return db; |
+} |
+ |
+bool Database::CloseOnBackgroundThread() { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ UpdateUptimeOnBackgroundThread(); |
+ LevelDbMap::iterator db_iter; |
+ for (db_iter = databases_.begin(); db_iter != databases_.end(); ++db_iter) |
+ delete db_iter->second; |
+ databases_.clear(); |
+ return true; |
+} |
+ |
+leveldb::DB* Database::FetchDBOnBackgroundThread(const std::string& id) { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ LevelDbMap::iterator db_iter = databases_.find(id); |
+ if (db_iter != databases_.end()) |
+ return db_iter->second; |
+ leveldb::DB* new_db; |
Aaron Boodman
2012/06/08 21:40:05
= NULL;
eaugusti
2012/06/08 22:52:08
Done.
|
+ leveldb::Options open_options; |
+ open_options.create_if_missing = true; |
+ FilePath db_path = path_.AppendASCII(id); |
+ leveldb::Status status = leveldb::DB::Open(open_options, db_path.value(), |
+ &new_db); |
+ databases_[id] = new_db; |
+ return new_db; |
+} |
+ |
+// TODO(eriq): Only update uptime under certian circumstances eg. every 10 |
+// times or when forced. |
+void Database::UpdateUptimeOnBackgroundThread() { |
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ leveldb::DB* uptime_db = FetchDBOnBackgroundThread(kUptimeDb); |
+ base::Time current_time = clock_->GetTime(); |
+ std::string end_time; |
+ // If the last update was too long ago. |
+ if (current_time - last_update_time_ > uptime_threshold_) { |
+ start_time_key_ = CreateUptimeKey(current_time); |
+ end_time = start_time_key_; |
+ } else { |
+ end_time = CreateUptimeKey(clock_->GetTime()); |
+ } |
+ uptime_db->Put(write_options_, start_time_key_, end_time); |
+} |
+} // namespace performance_monitor |