Chromium Code Reviews| Index: third_party/leveldatabase/env_chromium.cc |
| diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc |
| index 124689256368a042c35b39cf336cb69e8bbf387e..a65a70d513edda8ae425ff0b9620e6ec3ab36104 100644 |
| --- a/third_party/leveldatabase/env_chromium.cc |
| +++ b/third_party/leveldatabase/env_chromium.cc |
| @@ -4,6 +4,8 @@ |
| #include "third_party/leveldatabase/env_chromium.h" |
| +#include <inttypes.h> |
| + |
| #include <utility> |
| #if defined(OS_POSIX) |
| @@ -18,10 +20,14 @@ |
| #include "base/metrics/histogram_functions.h" |
| #include "base/process/process_metrics.h" |
| #include "base/stl_util.h" |
| +#include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/thread_restrictions.h" |
| +#include "base/trace_event/memory_dump_manager.h" |
| +#include "base/trace_event/memory_dump_provider.h" |
| +#include "base/trace_event/process_memory_dump.h" |
| #include "base/trace_event/trace_event.h" |
| #include "third_party/leveldatabase/chromium_logger.h" |
| #include "third_party/leveldatabase/src/include/leveldb/options.h" |
| @@ -1095,6 +1101,159 @@ LevelDBStatusValue GetLevelDBStatusUMAValue(const leveldb::Status& s) { |
| return LEVELDB_STATUS_INVALID_ARGUMENT; |
| } |
| +// DBRegistry's leveldb::DB wrapper. Forwards all calls to the underlying |
| +// leveldb::DB instance. Registers / unregisters itself in the registry. |
| +class DBRegistry::DBWrapperImpl : public base::LinkNode<DBWrapperImpl>, |
| + public DBWrapper { |
| + public: |
| + DBWrapperImpl(const std::string name, leveldb::DB* db) |
| + : name_(name), db_(db) { |
| + DBRegistry::GetInstance()->RegisterDatabase(this); |
| + } |
| + |
| + ~DBWrapperImpl() override { |
| + DBRegistry::GetInstance()->UnregisterDatabase(this); |
| + } |
| + |
| + const std::string& name() const override { return name_; } |
| + |
| + leveldb::Status Put(const leveldb::WriteOptions& options, |
| + const leveldb::Slice& key, |
| + const leveldb::Slice& value) override { |
| + return db_->Put(options, key, value); |
| + } |
| + |
| + leveldb::Status Delete(const leveldb::WriteOptions& options, |
| + const leveldb::Slice& key) override { |
| + return db_->Delete(options, key); |
| + } |
| + |
| + leveldb::Status Write(const leveldb::WriteOptions& options, |
| + leveldb::WriteBatch* updates) override { |
| + return db_->Write(options, updates); |
| + } |
| + |
| + leveldb::Status Get(const leveldb::ReadOptions& options, |
| + const leveldb::Slice& key, |
| + std::string* value) override { |
| + return db_->Get(options, key, value); |
| + } |
| + |
| + const leveldb::Snapshot* GetSnapshot() override { return db_->GetSnapshot(); } |
| + |
| + void ReleaseSnapshot(const leveldb::Snapshot* snapshot) override { |
| + return db_->ReleaseSnapshot(snapshot); |
| + } |
| + |
| + bool GetProperty(const leveldb::Slice& property, |
| + std::string* value) override { |
| + return db_->GetProperty(property, value); |
| + } |
| + |
| + void GetApproximateSizes(const leveldb::Range* range, |
| + int n, |
| + uint64_t* sizes) override { |
| + return db_->GetApproximateSizes(range, n, sizes); |
| + } |
| + |
| + void CompactRange(const leveldb::Slice* begin, |
| + const leveldb::Slice* end) override { |
| + return db_->CompactRange(begin, end); |
| + } |
| + |
| + leveldb::Iterator* NewIterator(const leveldb::ReadOptions& options) override { |
| + return db_->NewIterator(options); |
| + } |
| + |
| + private: |
| + std::string name_; |
| + std::unique_ptr<leveldb::DB> db_; |
| +}; |
| + |
| +// DBRegistry MemoryDumpProvider implementation. Declared here to minimize |
| +// dependencies in the header file. |
| +class DBRegistry::MDP : public base::trace_event::MemoryDumpProvider { |
| + public: |
| + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, |
| + base::trace_event::ProcessMemoryDump* pmd) override { |
| + auto db_visitor = [&](DBWrapper* db) { |
| + std::string db_dump_name = base::StringPrintf( |
| + "leveldatabase/0x%" PRIXPTR, reinterpret_cast<uintptr_t>(db)); |
|
Marijn Kruisselbrink
2017/06/20 23:38:52
nit: should this be leveldb/ something to be consi
ssid
2017/06/20 23:52:13
I think it is intentional.
How about leveldb_regis
DmitrySkiba
2017/06/20 23:59:21
Yes, the name is intentionally different. Some of
|
| + auto* db_dump = pmd->CreateAllocatorDump(db_dump_name.c_str()); |
| + |
| + uint64_t db_memory_usage = 0; |
| + { |
| + std::string usage_string; |
| + bool success = db->GetProperty("leveldb.approximate-memory-usage", |
| + &usage_string) && |
| + base::StringToUint64(usage_string, &db_memory_usage); |
| + DCHECK(success); |
| + } |
| + db_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
| + base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| + db_memory_usage); |
| + |
| + if (args.level_of_detail != |
| + base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) { |
| + db_dump->AddString("name", "", db->name()); |
| + } |
| + |
| + const char* system_allocator_name = |
| + base::trace_event::MemoryDumpManager::GetInstance() |
| + ->system_allocator_pool_name(); |
| + if (system_allocator_name) { |
| + pmd->AddSuballocation(db_dump->guid(), system_allocator_name); |
| + } |
| + }; |
| + |
| + DBRegistry::GetInstance()->VisitDatabases(db_visitor); |
| + return true; |
| + } |
| +}; |
| + |
| +DBRegistry::DBRegistry() : mdp_(new MDP()) { |
| + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
| + mdp_.get(), "LevelDB", nullptr); |
| +} |
| + |
| +DBRegistry::~DBRegistry() { |
| + base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( |
|
ssid
2017/06/20 23:52:13
You cannot unregister dump providers without task
DmitrySkiba
2017/06/21 01:08:06
Ouch, I didn't know about that. I wonder if Unregi
|
| + mdp_.get()); |
| +} |
| + |
| +DBRegistry* DBRegistry::GetInstance() { |
| + static DBRegistry* instance = new DBRegistry(); |
| + return instance; |
| +} |
| + |
| +leveldb::Status DBRegistry::Open(const leveldb::Options& options, |
| + const std::string& name, |
| + leveldb::DB** dbptr) { |
| + auto status = leveldb::DB::Open(options, name, dbptr); |
| + if (status.ok()) { |
| + // DBWrapperImpl ctor registers the instance in DBRegistry |
| + *dbptr = new DBWrapperImpl(name, *dbptr); |
| + } |
| + return status; |
| +} |
| + |
| +void DBRegistry::VisitDatabases(const DatabaseVisitor& visitor) { |
| + base::AutoLock lock(databases_lock_); |
| + for (auto* i = databases_.head(); i != databases_.end(); i = i->next()) { |
| + visitor(i->value()); |
| + } |
| +} |
| + |
| +void DBRegistry::RegisterDatabase(DBWrapperImpl* database) { |
| + base::AutoLock lock(databases_lock_); |
| + databases_.Append(database); |
| +} |
| + |
| +void DBRegistry::UnregisterDatabase(DBWrapperImpl* database) { |
| + base::AutoLock lock(databases_lock_); |
| + database->RemoveFromList(); |
| +} |
| + |
| } // namespace leveldb_env |
| namespace leveldb { |