diff --git a/PRESUBMIT.py b/PRESUBMIT.py index a34c03e63b4bb9..11a05962dc42b5 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py @@ -402,7 +402,8 @@ 'leveldb::NewMemEnv', ( 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from', - 'third_party/leveldatabase/leveldb_chrome.h.', + 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments', + "to Chrome's tracing, making their memory usage visible.", ), True, ( diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc index f89417fcc3c75b..3b4dc7ffe94198 100644 --- a/base/trace_event/memory_infra_background_whitelist.cc +++ b/base/trace_event/memory_infra_background_whitelist.cc @@ -106,6 +106,7 @@ const char* const kAllocatorDumpNameWhitelist[] = { "leveldatabase/block_cache/web", "leveldatabase/db_0x?", "leveldatabase/db_0x?/block_cache", + "leveldatabase/memenv_0x?", "malloc", "malloc/allocated_objects", "malloc/metadata_fragmentation_caches", @@ -259,7 +260,8 @@ const char* const kAllocatorDumpNameWhitelist[] = { "v8/isolate_0x?/malloc", "v8/isolate_0x?/zapped_for_debug", "site_storage/blob_storage/0x?", - "site_storage/index_db/0x?", + "site_storage/index_db/db_0x?", + "site_storage/index_db/memenv_0x?", "site_storage/localstorage/0x?/cache_size", "site_storage/localstorage/0x?/leveldb", "site_storage/session_storage/0x?", diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc b/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc index 2ff9bc7e96fc7d..1c8beebfe7743d 100644 --- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc +++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc @@ -69,7 +69,7 @@ class SyncFileSystemTest : public extensions::PlatformAppBrowserTest, } void SetUpOnMainThread() override { - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("SyncFileSystemTest"); extensions::PlatformAppBrowserTest::SetUpOnMainThread(); ASSERT_TRUE(base_dir_.CreateUniqueTempDir()); diff --git a/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc b/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc index ce086beb9160e6..ab0338ec423df3 100644 --- a/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc @@ -58,7 +58,7 @@ class ConflictResolverTest : public testing::Test { void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("ConflictResolverTest"); std::unique_ptr fake_drive_service( new FakeDriveServiceWrapper); diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc b/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc index 9a9d7c3d57692f..bf32b93403ab8b 100644 --- a/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc @@ -87,7 +87,7 @@ class DriveBackendSyncTest : public testing::Test, void SetUp() override { ASSERT_TRUE(base_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("DriveBackendSyncTest"); io_task_runner_ = content::BrowserThread::GetTaskRunnerForThread( content::BrowserThread::IO); diff --git a/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc b/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc index e86363848e9b51..154cc8189b04f0 100644 --- a/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc @@ -31,7 +31,7 @@ class LevelDBWrapperTest : public testing::Test { void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("LevelDBWrapperTest"); InitializeLevelDB(); } diff --git a/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc b/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc index e85cb3ae87d729..e298d2f694a3dd 100644 --- a/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc @@ -44,7 +44,7 @@ class ListChangesTaskTest : public testing::Test { void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("ListChangesTaskTest"); std::unique_ptr fake_drive_service( new drive::FakeDriveService); diff --git a/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc index 7aeb68fd496f69..b78d82c396fb41 100644 --- a/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc @@ -59,7 +59,7 @@ class LocalToRemoteSyncerTest : public testing::Test { void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("LocalToRemoteSyncerTest"); std::unique_ptr fake_drive_service( new FakeDriveServiceWrapper); diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc index 5bbc96c5dcbd26..e1dac42e587cfe 100644 --- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc @@ -40,7 +40,8 @@ class MetadataDatabaseIndexOnDiskTest : public testing::Test { void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = + leveldb_chrome::NewMemEnv("MetadataDatabaseIndexOnDiskTest"); db_ = InitializeLevelDB(); index_ = MetadataDatabaseIndexOnDisk::Create(db_.get()); } diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc index 787ba24710482a..d5b09d882abb06 100644 --- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc @@ -68,7 +68,7 @@ std::unique_ptr CreateTestDatabaseContents() { class MetadataDatabaseIndexTest : public testing::Test { public: void SetUp() override { - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("MetadataDatabaseIndexTest"); InitializeLevelDB(); contents_ = CreateTestDatabaseContents(); diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc index 057e6bc569596d..13555224a9c2d4 100644 --- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc @@ -198,7 +198,7 @@ class MetadataDatabaseTest : public testing::TestWithParam { void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("MetadataDatabaseTest"); } void TearDown() override { DropDatabase(); } diff --git a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc index 87355d7228b1a1..b8eb17a07eb57f 100644 --- a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc @@ -50,7 +50,7 @@ class RegisterAppTaskTest : public testing::Test { void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("RegisterAppTaskTest"); std::unique_ptr fake_drive_service( new drive::FakeDriveService); diff --git a/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer_unittest.cc index 6b50c7c06120aa..732c15007c06eb 100644 --- a/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer_unittest.cc @@ -55,7 +55,7 @@ class RemoteToLocalSyncerTest : public testing::Test { void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("RemoteToLocalSyncerTest"); std::unique_ptr fake_drive_service( new drive::FakeDriveService); diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc index b10e44af1b70a5..92ff1a071c6366 100644 --- a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc @@ -51,7 +51,7 @@ class SyncEngineInitializerTest : public testing::Test { void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("SyncEngineInitializerTest"); std::unique_ptr fake_drive_service( new drive::FakeDriveService); diff --git a/chrome/browser/sync_file_system/drive_backend/sync_worker_unittest.cc b/chrome/browser/sync_file_system/drive_backend/sync_worker_unittest.cc index e21879418e21a7..01dd5e09144426 100644 --- a/chrome/browser/sync_file_system/drive_backend/sync_worker_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/sync_worker_unittest.cc @@ -105,7 +105,7 @@ class SyncWorkerTest : public testing::Test, void SetUp() override { ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("SyncWorkerTest"); extension_service_.reset(new MockExtensionService); std::unique_ptr fake_drive_service( diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc index a3c91e944dec2f..411cdf75e21691 100644 --- a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc +++ b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc @@ -40,7 +40,7 @@ class LocalFileChangeTrackerTest : public testing::Test { public: LocalFileChangeTrackerTest() : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), - in_memory_env_(leveldb_chrome::NewMemEnv(leveldb::Env::Default())), + in_memory_env_(leveldb_chrome::NewMemEnv("LocalFileChangeTrackerTest")), file_system_(GURL("http://example.com"), in_memory_env_.get(), base::ThreadTaskRunnerHandle::Get().get(), diff --git a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc index 4e96abd70079bc..8d27a42d343128 100644 --- a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc +++ b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc @@ -67,7 +67,7 @@ class LocalFileSyncContextTest : public testing::Test { void SetUp() override { RegisterSyncableFileSystem(); ASSERT_TRUE(dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("LocalFileSyncContextTest"); ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); io_task_runner_ = BrowserThread::GetTaskRunnerForThread(BrowserThread::IO); diff --git a/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc index 9a86c4a2e29532..3a2d5fb4a5f4c7 100644 --- a/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc +++ b/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc @@ -113,7 +113,7 @@ class LocalFileSyncServiceTest void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("LocalFileSyncServiceTest"); file_system_.reset(new CannedSyncableFileSystem( GURL(kOrigin), in_memory_env_.get(), diff --git a/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc b/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc index ea8e005e6199c4..9f884974e269b6 100644 --- a/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc +++ b/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc @@ -55,7 +55,8 @@ class SyncableFileOperationRunnerTest : public testing::Test { // operations in the tests. SyncableFileOperationRunnerTest() : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), - in_memory_env_(leveldb_chrome::NewMemEnv(leveldb::Env::Default())), + in_memory_env_( + leveldb_chrome::NewMemEnv("SyncableFileOperationRunnerTest")), file_system_(GURL("http://example.com"), in_memory_env_.get(), base::ThreadTaskRunnerHandle::Get().get(), diff --git a/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc b/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc index 157e15d55d1e46..8e8cc41ba16e59 100644 --- a/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc +++ b/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc @@ -35,7 +35,7 @@ namespace sync_file_system { class SyncableFileSystemTest : public testing::Test { public: SyncableFileSystemTest() - : in_memory_env_(leveldb_chrome::NewMemEnv(leveldb::Env::Default())), + : in_memory_env_(leveldb_chrome::NewMemEnv("SyncableFileSystemTest")), file_system_(GURL("http://example.com/"), in_memory_env_.get(), base::ThreadTaskRunnerHandle::Get().get(), diff --git a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc index 756f147c476c44..d0ac13d2a966a0 100644 --- a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc +++ b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc @@ -131,7 +131,7 @@ class SyncFileSystemServiceTest : public testing::Test { : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) {} void SetUp() override { - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("SyncFileSystemServiceTest"); file_system_.reset(new CannedSyncableFileSystem( GURL(kOrigin), in_memory_env_.get(), BrowserThread::GetTaskRunnerForThread(BrowserThread::IO), diff --git a/components/leveldb_proto/leveldb_database.cc b/components/leveldb_proto/leveldb_database.cc index b87eb064f06c7d..d492947df60729 100644 --- a/components/leveldb_proto/leveldb_database.cc +++ b/components/leveldb_proto/leveldb_database.cc @@ -49,7 +49,7 @@ bool LevelDB::Init(const base::FilePath& database_dir, open_options_ = options; if (database_dir.empty()) { - env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + env_ = leveldb_chrome::NewMemEnv("LevelDB"); open_options_.env = env_.get(); } diff --git a/components/leveldb_proto/proto_database_impl_unittest.cc b/components/leveldb_proto/proto_database_impl_unittest.cc index f09895e899f503..83734e9965bd18 100644 --- a/components/leveldb_proto/proto_database_impl_unittest.cc +++ b/components/leveldb_proto/proto_database_impl_unittest.cc @@ -346,9 +346,20 @@ TEST_F(ProtoDatabaseImplTest, TestDBGetSuccess) { base::RunLoop().RunUntilIdle(); } -TEST(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoadKeys) { - base::MessageLoop main_loop; +class ProtoDatabaseImplLevelDBTest : public testing::Test { + public: + void SetUp() override { main_loop_.reset(new MessageLoop()); } + + void TearDown() override { + base::RunLoop().RunUntilIdle(); + main_loop_.reset(); + } + + private: + std::unique_ptr main_loop_; +}; +TEST_F(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoadKeys) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); base::Thread db_thread("dbthread"); @@ -677,15 +688,15 @@ void TestLevelDBSaveAndLoad(bool close_after_save) { ExpectEntryPointersEquals(model, loaded_protos); } -TEST(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoad) { +TEST_F(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoad) { TestLevelDBSaveAndLoad(false); } -TEST(ProtoDatabaseImplLevelDBTest, TestDBCloseAndReopen) { +TEST_F(ProtoDatabaseImplLevelDBTest, TestDBCloseAndReopen) { TestLevelDBSaveAndLoad(true); } -TEST(ProtoDatabaseImplLevelDBTest, TestDBInitFail) { +TEST_F(ProtoDatabaseImplLevelDBTest, TestDBInitFail) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); @@ -702,7 +713,7 @@ TEST(ProtoDatabaseImplLevelDBTest, TestDBInitFail) { EXPECT_FALSE(db->Save(save_entries, remove_keys)); } -TEST(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) { +TEST_F(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) { std::unique_ptr db(new LevelDB(kTestLevelDBClientName)); std::vector load_entries; @@ -723,7 +734,7 @@ TEST(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) { EXPECT_EQ(1u, second_load_entries.size()); } -TEST(ProtoDatabaseImplLevelDBTest, TestCorruptDBReset) { +TEST_F(ProtoDatabaseImplLevelDBTest, TestCorruptDBReset) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); diff --git a/components/services/leveldb/leveldb_service_impl.cc b/components/services/leveldb/leveldb_service_impl.cc index 7e4c61283f8482..a5edbb1d561e50 100644 --- a/components/services/leveldb/leveldb_service_impl.cc +++ b/components/services/leveldb/leveldb_service_impl.cc @@ -74,14 +74,14 @@ void LevelDBServiceImpl::OpenWithOptions( void LevelDBServiceImpl::OpenInMemory( const base::Optional& memory_dump_id, + const std::string& tracking_name, leveldb::mojom::LevelDBDatabaseAssociatedRequest database, OpenCallback callback) { leveldb_env::Options options; options.create_if_missing = true; options.max_open_files = 0; // Use minimum. - std::unique_ptr env( - leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + auto env = leveldb_chrome::NewMemEnv(tracking_name); options.env = env.get(); std::unique_ptr db; diff --git a/components/services/leveldb/leveldb_service_impl.h b/components/services/leveldb/leveldb_service_impl.h index 8eb0ebf7ba6c60..9deb661648d84d 100644 --- a/components/services/leveldb/leveldb_service_impl.h +++ b/components/services/leveldb/leveldb_service_impl.h @@ -43,6 +43,7 @@ class LevelDBServiceImpl : public mojom::LevelDBService { void OpenInMemory( const base::Optional& memory_dump_id, + const std::string& tracking_name, leveldb::mojom::LevelDBDatabaseAssociatedRequest database, OpenInMemoryCallback callback) override; void Destroy(filesystem::mojom::DirectoryPtr directory, diff --git a/components/services/leveldb/leveldb_service_unittest.cc b/components/services/leveldb/leveldb_service_unittest.cc index 514144ee839f4e..8f6f8b1b0e7ba9 100644 --- a/components/services/leveldb/leveldb_service_unittest.cc +++ b/components/services/leveldb/leveldb_service_unittest.cc @@ -108,7 +108,7 @@ void LevelDBSyncOpenInMemory(mojom::LevelDBService* leveldb, mojom::LevelDBDatabaseAssociatedRequest database, mojom::DatabaseError* out_error) { base::RunLoop run_loop; - leveldb->OpenInMemory(base::nullopt, std::move(database), + leveldb->OpenInMemory(base::nullopt, "LevelDBSync", std::move(database), Capture(out_error, run_loop.QuitClosure())); run_loop.Run(); } diff --git a/components/services/leveldb/public/interfaces/leveldb.mojom b/components/services/leveldb/public/interfaces/leveldb.mojom index cb359133061b71..ab3312a6f46b93 100644 --- a/components/services/leveldb/public/interfaces/leveldb.mojom +++ b/components/services/leveldb/public/interfaces/leveldb.mojom @@ -91,8 +91,10 @@ interface LevelDBService { associated LevelDBDatabase& database) => (DatabaseError status); // Opens a database stored purely in memory. + // "tracking_name" will be used for memory-infra reporting to associate memory + // use with its origin. OpenInMemory(mojo_base.mojom.MemoryAllocatorDumpCrossProcessUid? - memory_dump_id, + memory_dump_id, string tracking_name, associated LevelDBDatabase& database) => (DatabaseError status); // Destroys the contents of the specified database. Returns OK if the database diff --git a/components/services/leveldb/remote_iterator_unittest.cc b/components/services/leveldb/remote_iterator_unittest.cc index e7637364e47d4a..34e75b71485454 100644 --- a/components/services/leveldb/remote_iterator_unittest.cc +++ b/components/services/leveldb/remote_iterator_unittest.cc @@ -52,7 +52,8 @@ class RemoteIteratorTest : public service_manager::test::ServiceTest { mojom::DatabaseError error; base::RunLoop run_loop; - leveldb()->OpenInMemory(base::nullopt, MakeRequest(&database_), + leveldb()->OpenInMemory(base::nullopt, "RemoteIteratorTest", + MakeRequest(&database_), Capture(&error, run_loop.QuitClosure())); run_loop.Run(); EXPECT_EQ(mojom::DatabaseError::OK, error); diff --git a/components/sync/model_impl/model_type_store_backend.cc b/components/sync/model_impl/model_type_store_backend.cc index 083f7356712746..8a564dbb35bfd7 100644 --- a/components/sync/model_impl/model_type_store_backend.cc +++ b/components/sync/model_impl/model_type_store_backend.cc @@ -106,7 +106,7 @@ ModelTypeStoreBackend::~ModelTypeStoreBackend() { } std::unique_ptr ModelTypeStoreBackend::CreateInMemoryEnv() { - return base::WrapUnique(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + return leveldb_chrome::NewMemEnv("ModelTypeStore"); } // static diff --git a/content/browser/dom_storage/local_storage_context_mojo.cc b/content/browser/dom_storage/local_storage_context_mojo.cc index c6975829bbe660..369046443da4d4 100644 --- a/content/browser/dom_storage/local_storage_context_mojo.cc +++ b/content/browser/dom_storage/local_storage_context_mojo.cc @@ -679,7 +679,7 @@ void LocalStorageContextMojo::InitiateConnection(bool in_memory_only) { // We were not given a subdirectory. Use a memory backed database. connector_->BindInterface(file::mojom::kServiceName, &leveldb_service_); leveldb_service_->OpenInMemory( - memory_dump_id_, MakeRequest(&database_), + memory_dump_id_, "local-storage", MakeRequest(&database_), base::BindOnce(&LocalStorageContextMojo::OnDatabaseOpened, weak_ptr_factory_.GetWeakPtr(), true)); } diff --git a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc index 1603bdb3282523..25395408cc71a3 100644 --- a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc +++ b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc @@ -1126,7 +1126,7 @@ class FakeLevelDBService : public leveldb::mojom::LevelDBService { leveldb::mojom::LevelDBDatabaseAssociatedRequest request, OpenCallback callback) override { open_requests_.push_back( - {false, dbname, std::move(request), std::move(callback)}); + {false, dbname, "", std::move(request), std::move(callback)}); if (on_open_callback_) on_open_callback_.Run(); } @@ -1140,7 +1140,7 @@ class FakeLevelDBService : public leveldb::mojom::LevelDBService { leveldb::mojom::LevelDBDatabaseAssociatedRequest request, OpenCallback callback) override { open_requests_.push_back( - {false, dbname, std::move(request), std::move(callback)}); + {false, dbname, "", std::move(request), std::move(callback)}); if (on_open_callback_) on_open_callback_.Run(); } @@ -1148,10 +1148,11 @@ class FakeLevelDBService : public leveldb::mojom::LevelDBService { void OpenInMemory( const base::Optional& memory_dump_id, + const std::string& tracking_name, leveldb::mojom::LevelDBDatabaseAssociatedRequest request, OpenCallback callback) override { open_requests_.push_back( - {true, "", std::move(request), std::move(callback)}); + {true, "", tracking_name, std::move(request), std::move(callback)}); if (on_open_callback_) on_open_callback_.Run(); } @@ -1166,6 +1167,7 @@ class FakeLevelDBService : public leveldb::mojom::LevelDBService { struct OpenRequest { bool in_memory; std::string dbname; + std::string memenv_tracking_name; leveldb::mojom::LevelDBDatabaseAssociatedRequest request; OpenCallback callback; }; diff --git a/content/browser/fileapi/browser_file_system_helper.cc b/content/browser/fileapi/browser_file_system_helper.cc index 4d8ecc2bab9936..9e56a72ff2f28f 100644 --- a/content/browser/fileapi/browser_file_system_helper.cc +++ b/content/browser/fileapi/browser_file_system_helper.cc @@ -62,11 +62,12 @@ FileSystemOptions CreateBrowserFileSystemOptions(bool is_incognito) { switches::kAllowFileAccessFromFiles)) { additional_allowed_schemes.push_back(url::kFileScheme); } - leveldb::Env* env_override = nullptr; + std::unique_ptr env_override; if (is_incognito) - env_override = leveldb_chrome::NewMemEnv(leveldb::Env::Default()); + env_override = leveldb_chrome::NewMemEnv("filesystem"); + // TODO(crbug.com/823854) Fix leaking override MemEnv. return FileSystemOptions(profile_mode, additional_allowed_schemes, - env_override); + env_override.release()); } } // namespace diff --git a/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc b/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc index e0d69eac84fc60..d53addc85b24a4 100644 --- a/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc +++ b/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc @@ -15,6 +15,7 @@ #include "content/browser/indexed_db/leveldb/leveldb_database.h" #include "content/browser/indexed_db/leveldb/mock_level_db.h" #include "content/common/indexed_db/indexed_db_metadata.h" +#include "content/public/test/test_browser_thread_bundle.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/leveldatabase/env_chromium.h" @@ -242,6 +243,9 @@ class IndexedDBTombstoneSweeperTest : public testing::TestWithParam { // Used to verify recorded data. base::HistogramTester histogram_tester_; + + private: + TestBrowserThreadBundle thread_bundle_; }; TEST_P(IndexedDBTombstoneSweeperTest, EmptyDB) { diff --git a/content/browser/indexed_db/leveldb/leveldb_database.cc b/content/browser/indexed_db/leveldb/leveldb_database.cc index 20a4218d2b23ea..c531fbec9436af 100644 --- a/content/browser/indexed_db/leveldb/leveldb_database.cc +++ b/content/browser/indexed_db/leveldb/leveldb_database.cc @@ -39,6 +39,7 @@ #include "third_party/leveldatabase/src/include/leveldb/slice.h" using base::StringPiece; +using leveldb_env::DBTracker; namespace content { @@ -334,7 +335,7 @@ std::unique_ptr LevelDBDatabase::OpenInMemory( std::unique_ptr comparator_adapter( std::make_unique(comparator)); std::unique_ptr in_memory_env( - leveldb_chrome::NewMemEnv(LevelDBEnv::Get())); + leveldb_chrome::NewMemEnv("indexed-db", LevelDBEnv::Get())); std::unique_ptr db; std::unique_ptr filter_policy; @@ -479,27 +480,42 @@ bool LevelDBDatabase::OnMemoryDump( return false; // All leveldb databases are already dumped by leveldb_env::DBTracker. Add // an edge to the existing database. - auto* tracker_dump = + auto* db_tracker_dump = leveldb_env::DBTracker::GetOrCreateAllocatorDump(pmd, db_.get()); - if (!tracker_dump) + if (!db_tracker_dump) return true; - auto* dump = pmd->CreateAllocatorDump( - base::StringPrintf("site_storage/index_db/0x%" PRIXPTR, + auto* db_dump = pmd->CreateAllocatorDump( + base::StringPrintf("site_storage/index_db/db_0x%" PRIXPTR, reinterpret_cast(db_.get()))); - dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, - base::trace_event::MemoryAllocatorDump::kUnitsBytes, - tracker_dump->GetSizeInternal()); - pmd->AddOwnershipEdge(dump->guid(), tracker_dump->guid()); + db_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + db_tracker_dump->GetSizeInternal()); + pmd->AddOwnershipEdge(db_dump->guid(), db_tracker_dump->guid()); + + if (env_ && leveldb_chrome::IsMemEnv(env_.get())) { + // All leveldb env's are already dumped by leveldb_env::DBTracker. Add + // an edge to the existing env. + auto* env_tracker_dump = + DBTracker::GetOrCreateAllocatorDump(pmd, env_.get()); + auto* env_dump = pmd->CreateAllocatorDump( + base::StringPrintf("site_storage/index_db/memenv_0x%" PRIXPTR, + reinterpret_cast(env_.get()))); + env_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + env_tracker_dump->GetSizeInternal()); + pmd->AddOwnershipEdge(env_dump->guid(), env_tracker_dump->guid()); + } - // Dumps in BACKGROUND mode cannot have strings or edges in order to minimize - // trace size and instrumentation overhead. + // Dumps in BACKGROUND mode can only have whitelisted strings (and there are + // currently none) so return early. if (args.level_of_detail == base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) { return true; } - dump->AddString("file_name", "", file_name_for_tracing); + db_dump->AddString("file_name", "", file_name_for_tracing); + return true; } diff --git a/content/browser/notifications/notification_database.cc b/content/browser/notifications/notification_database.cc index c148fdc656df99..87dca497209f94 100644 --- a/content/browser/notifications/notification_database.cc +++ b/content/browser/notifications/notification_database.cc @@ -128,7 +128,7 @@ NotificationDatabase::Status NotificationDatabase::Open( options.filter_policy = filter_policy_.get(); options.block_cache = leveldb_chrome::GetSharedWebBlockCache(); if (IsInMemoryDatabase()) { - env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + env_ = leveldb_chrome::NewMemEnv("notification"); options.env = env_.get(); } diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc index 746351acfb8238..5ff951c65c313a 100644 --- a/content/browser/service_worker/service_worker_database.cc +++ b/content/browser/service_worker/service_worker_database.cc @@ -1257,7 +1257,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::LazyOpen( leveldb_env::Options options; options.create_if_missing = create_if_missing; if (IsDatabaseInMemory()) { - env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + env_ = leveldb_chrome::NewMemEnv("service-worker"); options.env = env_.get(); } else { options.env = g_service_worker_env.Pointer(); diff --git a/storage/browser/fileapi/quota/quota_backend_impl_unittest.cc b/storage/browser/fileapi/quota/quota_backend_impl_unittest.cc index 4d21b5f7d08c91..f57d1f8ad54ff6 100644 --- a/storage/browser/fileapi/quota/quota_backend_impl_unittest.cc +++ b/storage/browser/fileapi/quota/quota_backend_impl_unittest.cc @@ -99,7 +99,7 @@ class QuotaBackendImplTest : public testing::Test { void SetUp() override { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); - in_memory_env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default())); + in_memory_env_ = leveldb_chrome::NewMemEnv("quota"); file_util_.reset(ObfuscatedFileUtil::CreateForTesting( NULL, data_dir_.GetPath(), in_memory_env_.get())); backend_.reset(new QuotaBackendImpl(file_task_runner(), file_util_.get(), diff --git a/third_party/leveldatabase/README.chromium b/third_party/leveldatabase/README.chromium index 202bd565d97acc..d1a8926df8e109 100644 --- a/third_party/leveldatabase/README.chromium +++ b/third_party/leveldatabase/README.chromium @@ -27,4 +27,5 @@ Local Additions: * Unit tests for the Chromium environment. * db_bench is built as leveldb_db_bench in Chromium. * leveldb_chrome::NewMemEnv() to create memory Env instances that are tracked to - know if a database open request is in-memory. + know if a database open request is in-memory. These memory Env instances report + memory usage to memory-infra. \ No newline at end of file diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc index caf74617ed1a44..f0f57906450f67 100644 --- a/third_party/leveldatabase/env_chromium.cc +++ b/third_party/leveldatabase/env_chromium.cc @@ -1381,8 +1381,8 @@ class DBTracker::TrackedDBImpl : public base::LinkNode, DISALLOW_COPY_AND_ASSIGN(TrackedDBImpl); }; -// Reports live databases to memory-infra. For each live database the following -// information is reported: +// Reports live databases and in-memory env's to memory-infra. For each live +// database the following information is reported: // 1. Instance pointer (to disambiguate databases). // 2. Memory taken by the database, with the shared cache being attributed // equally to each database sharing 3. The name of the database (when not in @@ -1404,6 +1404,8 @@ class DBTracker::TrackedDBImpl : public base::LinkNode, // block_cache 0 KiB 100 KiB // browser 0 KiB 40 KiB // web 0 KiB 60 KiB +// memenv_0x7FE80F2040A0 4 KiB 4 KiB +// memenv_0x7FE80F3040A0 4 KiB 4 KiB // class DBTracker::MemoryDumpProvider : public base::trace_event::MemoryDumpProvider { @@ -1453,6 +1455,7 @@ void DBTracker::MemoryDumpProvider::DumpAllDatabases(ProcessMemoryDump* pmd) { DBTracker::GetInstance()->VisitDatabases( base::BindRepeating(&DBTracker::MemoryDumpProvider::DumpVisitor, base::Unretained(this), base::Unretained(pmd))); + leveldb_chrome::DumpAllTrackedEnvs(pmd); } void DBTracker::MemoryDumpProvider::DumpVisitor(ProcessMemoryDump* pmd, @@ -1517,6 +1520,14 @@ MemoryAllocatorDump* DBTracker::GetOrCreateAllocatorDump( return pmd->GetAllocatorDump(GetDumpNameForDB(tracked_db)); } +// static +MemoryAllocatorDump* DBTracker::GetOrCreateAllocatorDump( + ProcessMemoryDump* pmd, + leveldb::Env* tracked_memenv) { + GetInstance()->mdp_->DumpAllDatabases(pmd); + return leveldb_chrome::GetEnvAllocatorDump(pmd, tracked_memenv); +} + void DBTracker::UpdateHistograms() { base::AutoLock lock(databases_lock_); if (leveldb_chrome::GetSharedWebBlockCache() == diff --git a/third_party/leveldatabase/env_chromium.h b/third_party/leveldatabase/env_chromium.h index 82116de079ff1a..fe115fc83838ce 100644 --- a/third_party/leveldatabase/env_chromium.h +++ b/third_party/leveldatabase/env_chromium.h @@ -269,6 +269,15 @@ class LEVELDB_EXPORT DBTracker { base::trace_event::ProcessMemoryDump* pmd, leveldb::DB* tracked_db); + // Returns the memory-infra dump for |tracked_memenv|. Can be used to attach + // additional info to the database dump, or to properly attribute memory + // usage in memory dump providers that also dump |tracked_memenv|. + // Note that |tracked_memenv| should be a live Env instance produced by + // leveldb_chrome::NewMemEnv(). + static base::trace_event::MemoryAllocatorDump* GetOrCreateAllocatorDump( + base::trace_event::ProcessMemoryDump* pmd, + leveldb::Env* tracked_memenv); + // Report counts to UMA. void UpdateHistograms(); @@ -300,6 +309,7 @@ class LEVELDB_EXPORT DBTracker { friend class ChromiumEnvDBTrackerTest; FRIEND_TEST_ALL_PREFIXES(ChromiumEnvDBTrackerTest, IsTrackedDB); FRIEND_TEST_ALL_PREFIXES(ChromiumEnvDBTrackerTest, MemoryDumpCreation); + FRIEND_TEST_ALL_PREFIXES(ChromiumEnvDBTrackerTest, MemEnvMemoryDumpCreation); DBTracker(); ~DBTracker(); diff --git a/third_party/leveldatabase/env_chromium_unittest.cc b/third_party/leveldatabase/env_chromium_unittest.cc index 069b3b70e8f1e9..c5030fa57b2e5f 100644 --- a/third_party/leveldatabase/env_chromium_unittest.cc +++ b/third_party/leveldatabase/env_chromium_unittest.cc @@ -14,6 +14,7 @@ #include "base/lazy_instance.h" #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/test/scoped_task_environment.h" #include "base/test/test_suite.h" #include "base/trace_event/process_memory_dump.h" #include "testing/gtest/include/gtest/gtest.h" @@ -261,6 +262,9 @@ TEST(ChromiumEnvTest, TestOpenOnRead) { class ChromiumEnvDBTrackerTest : public ::testing::Test { protected: + ChromiumEnvDBTrackerTest() + : scoped_task_environment_( + base::test::ScopedTaskEnvironment::MainThreadType::UI) {} void SetUp() override { testing::Test::SetUp(); ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); @@ -295,6 +299,7 @@ class ChromiumEnvDBTrackerTest : public ::testing::Test { private: base::ScopedTempDir scoped_temp_dir_; + base::test::ScopedTaskEnvironment scoped_task_environment_; }; TEST_F(ChromiumEnvDBTrackerTest, OpenDatabase) { @@ -417,7 +422,8 @@ TEST_F(ChromiumEnvDBTrackerTest, CheckMemEnv) { ASSERT_TRUE(env != nullptr); EXPECT_FALSE(leveldb_chrome::IsMemEnv(env)); - std::unique_ptr memenv(leveldb_chrome::NewMemEnv(env)); + std::unique_ptr memenv = + leveldb_chrome::NewMemEnv("CheckMemEnv", env); EXPECT_TRUE(leveldb_chrome::IsMemEnv(memenv.get())); } @@ -480,6 +486,41 @@ TEST_F(ChromiumEnvDBTrackerTest, MemoryDumpCreation) { EXPECT_EQ(db_size, mad3->GetSizeInternal()); } +TEST_F(ChromiumEnvDBTrackerTest, MemEnvMemoryDumpCreation) { + std::unique_ptr memenv = leveldb_chrome::NewMemEnv("test"); + + Status s; + WritableFile* writable_file; + s = memenv->NewWritableFile("first_file.txt", &writable_file); + ASSERT_TRUE(s.ok()) << s.ToString(); + + const std::string kValue(2048, 'x'); + writable_file->Append(Slice(kValue)); + delete writable_file; + + const MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::BACKGROUND}; + base::trace_event::ProcessMemoryDump dump1(nullptr, dump_args); + auto* mad = DBTracker::GetOrCreateAllocatorDump(&dump1, memenv.get()); + + uint64_t size_with_file = mad->GetSizeInternal(); + EXPECT_GE(size_with_file, kValue.size()); + + // Now rename and size should be unchanged. + s = memenv->RenameFile("first_file.txt", "xxxxx_file.txt"); // same length. + EXPECT_TRUE(s.ok()) << s.ToString(); + base::trace_event::ProcessMemoryDump dump2(nullptr, dump_args); + mad = DBTracker::GetOrCreateAllocatorDump(&dump2, memenv.get()); + EXPECT_EQ(size_with_file, mad->GetSizeInternal()); + + // Now delete and size should go down. + s = memenv->DeleteFile("xxxxx_file.txt"); + EXPECT_TRUE(s.ok()) << s.ToString(); + + base::trace_event::ProcessMemoryDump dump3(nullptr, dump_args); + mad = DBTracker::GetOrCreateAllocatorDump(&dump3, memenv.get()); + EXPECT_EQ(mad->GetSizeInternal(), 0ul); +} + } // namespace leveldb_env int main(int argc, char** argv) { return base::TestSuite(argc, argv).Run(); } diff --git a/third_party/leveldatabase/leveldb_chrome.cc b/third_party/leveldatabase/leveldb_chrome.cc index c6ea9b5d147532..f7be15849631b9 100644 --- a/third_party/leveldatabase/leveldb_chrome.cc +++ b/third_party/leveldatabase/leveldb_chrome.cc @@ -9,14 +9,24 @@ #include "base/bind.h" #include "base/containers/flat_set.h" #include "base/files/file.h" +#include "base/format_macros.h" #include "base/memory/memory_pressure_listener.h" #include "base/metrics/histogram_macros.h" +#include "base/strings/stringprintf.h" #include "base/sys_info.h" +#include "base/threading/sequenced_task_runner_handle.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 "third_party/leveldatabase/env_chromium.h" #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" #include "util/mutexlock.h" using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel; +using base::trace_event::MemoryAllocatorDump; +using base::trace_event::MemoryDumpArgs; +using base::trace_event::MemoryDumpProvider; +using base::trace_event::ProcessMemoryDump; using leveldb::Cache; using leveldb::NewLRUCache; @@ -31,6 +41,11 @@ size_t DefaultBlockCacheSize() { return 8 << 20; // 8MB } +std::string GetDumpNameForMemEnv(const leveldb::Env* memenv) { + return base::StringPrintf("leveldatabase/memenv_0x%" PRIXPTR, + reinterpret_cast(memenv)); +} + // Singleton owning resources shared by Chrome's leveldb databases. class Globals { public: @@ -83,6 +98,9 @@ class Globals { return in_memory_envs_.find(env) != in_memory_envs_.end(); } + void DumpAllTrackedEnvs(const MemoryDumpArgs& dump_args, + base::trace_event::ProcessMemoryDump* pmd); + void UpdateHistograms() { leveldb_env::DBTracker::GetInstance()->UpdateHistograms(); @@ -117,8 +135,10 @@ class Globals { class ChromeMemEnv : public leveldb::EnvWrapper { public: - ChromeMemEnv(leveldb::Env* base_env) - : EnvWrapper(leveldb::NewMemEnv(base_env)), base_env_(target()) { + ChromeMemEnv(leveldb::Env* base_env, const std::string& name) + : EnvWrapper(leveldb::NewMemEnv(base_env)), + base_env_(target()), + name_(name) { Globals::GetInstance()->DidCreateChromeMemEnv(this); } @@ -126,11 +146,115 @@ class ChromeMemEnv : public leveldb::EnvWrapper { Globals::GetInstance()->WillDestroyChromeMemEnv(this); } + leveldb::Status NewWritableFile(const std::string& f, + leveldb::WritableFile** r) override { + leveldb::Status s = leveldb::EnvWrapper::NewWritableFile(f, r); + if (s.ok()) { + base::AutoLock lock(files_lock_); + file_names_.insert(f); + } + return s; + } + + leveldb::Status NewAppendableFile(const std::string& f, + leveldb::WritableFile** r) override { + leveldb::Status s = leveldb::EnvWrapper::NewAppendableFile(f, r); + if (s.ok()) { + base::AutoLock lock(files_lock_); + file_names_.insert(f); + } + return s; + } + + leveldb::Status DeleteFile(const std::string& fname) override { + leveldb::Status s = leveldb::EnvWrapper::DeleteFile(fname); + if (s.ok()) { + base::AutoLock lock(files_lock_); + DCHECK(base::ContainsKey(file_names_, fname)); + file_names_.erase(fname); + } + return s; + } + + leveldb::Status RenameFile(const std::string& src, + const std::string& target) override { + leveldb::Status s = leveldb::EnvWrapper::RenameFile(src, target); + if (s.ok()) { + base::AutoLock lock(files_lock_); + file_names_.erase(src); + file_names_.insert(target); + } + return s; + } + + // Calculate the memory used by this in-memory database. leveldb's in-memory + // databases store their data in a MemEnv which can be shared between + // databases. Chrome rarely (if ever) shares MemEnv's. This calculation is + // also an estimate as leveldb does not expose a way to retrieve or properly + // calculate the amount of RAM used by a MemEnv. + uint64_t size() { + // This is copied from + // //third_party/leveldatabase/src/helpers/memenv/memenv.cc which cannot be + // included here. Duplicated for size calculations only. + struct FileState { + leveldb::port::Mutex refs_mutex_; + int refs_; + std::vector blocks_; + uint64_t size_; + enum { kBlockSize = 8 * 1024 }; + }; + + uint64_t total_size = 0; + base::AutoLock lock(files_lock_); + for (const std::string& fname : file_names_) { + uint64_t file_size; + leveldb::Status s = GetFileSize(fname, &file_size); + DCHECK(s.ok()); + if (s.ok()) + total_size += file_size + fname.size() + 1 + sizeof(FileState); + } + return total_size; + } + + const std::string& name() const { return name_; } + + bool OnMemoryDump(const MemoryDumpArgs& dump_args, ProcessMemoryDump* pmd) { + auto* env_dump = pmd->CreateAllocatorDump(GetDumpNameForMemEnv(this)); + + env_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + size()); + + if (dump_args.level_of_detail != + base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) { + env_dump->AddString("name", "", name()); + } + + const char* system_allocator_name = + base::trace_event::MemoryDumpManager::GetInstance() + ->system_allocator_pool_name(); + if (system_allocator_name) { + pmd->AddSuballocation(env_dump->guid(), system_allocator_name); + } + + return true; + } + private: std::unique_ptr base_env_; + const std::string name_; + base::Lock files_lock_; + std::set file_names_; DISALLOW_COPY_AND_ASSIGN(ChromeMemEnv); }; +void Globals::DumpAllTrackedEnvs(const MemoryDumpArgs& dump_args, + ProcessMemoryDump* pmd) { + leveldb::MutexLock l(&env_mutex_); + for (auto env : in_memory_envs_) + static_cast(env)->OnMemoryDump(dump_args, pmd); +} + } // namespace // Returns a separate (from the default) block cache for use by web APIs. @@ -157,8 +281,11 @@ bool IsMemEnv(const leveldb::Env* env) { return Globals::GetInstance()->IsInMemoryEnv(env); } -leveldb::Env* NewMemEnv(leveldb::Env* base_env) { - return new ChromeMemEnv(base_env); +std::unique_ptr NewMemEnv(const std::string& name, + leveldb::Env* base_env) { + if (!base_env) + base_env = leveldb::Env::Default(); + return std::make_unique(base_env, name); } void UpdateHistograms() { @@ -184,4 +311,15 @@ bool CorruptClosedDBForTesting(const base::FilePath& db_path) { return true; } +MemoryAllocatorDump* GetEnvAllocatorDump(ProcessMemoryDump* pmd, + leveldb::Env* tracked_memenv) { + DCHECK(Globals::GetInstance()->IsInMemoryEnv(tracked_memenv)) + << std::hex << tracked_memenv << " is not tracked"; + return pmd->GetAllocatorDump(GetDumpNameForMemEnv(tracked_memenv)); +} + +void DumpAllTrackedEnvs(ProcessMemoryDump* pmd) { + Globals::GetInstance()->DumpAllTrackedEnvs(pmd->dump_args(), pmd); +} + } // namespace leveldb_chrome diff --git a/third_party/leveldatabase/leveldb_chrome.h b/third_party/leveldatabase/leveldb_chrome.h index 7b8ebe1dd1b3a3..73084887eec544 100644 --- a/third_party/leveldatabase/leveldb_chrome.h +++ b/third_party/leveldatabase/leveldb_chrome.h @@ -5,12 +5,22 @@ #ifndef THIRD_PARTY_LEVELDATABASE_LEVELDB_CHROME_H_ #define THIRD_PARTY_LEVELDATABASE_LEVELDB_CHROME_H_ +#include +#include + #include "base/files/file_path.h" #include "leveldb/cache.h" #include "leveldb/env.h" #include "leveldb/export.h" #include "third_party/leveldatabase/src/db/filename.h" +namespace base { +namespace trace_event { +class MemoryAllocatorDump; +class ProcessMemoryDump; +} // namespace trace_event +} // namespace base + namespace leveldb_chrome { // Return the shared leveldb block cache for web APIs. The caller *does not* @@ -29,10 +39,14 @@ LEVELDB_EXPORT leveldb::Cache* GetSharedInMemoryBlockCache(); LEVELDB_EXPORT bool IsMemEnv(const leveldb::Env* env); // Creates an in-memory Env for which all files are stored in the heap. -LEVELDB_EXPORT leveldb::Env* NewMemEnv(leveldb::Env* base_env); +// This wraps leveldb::NewMemEnv to add memory-infra logging. +// if |base_env| is null then leveldb::Env::Default() will be used. +LEVELDB_EXPORT std::unique_ptr NewMemEnv( + const std::string& name, + leveldb::Env* base_env = nullptr); // If filename is a leveldb file, store the type of the file in *type. -// The number encoded in the filename is stored in *number. If the +// The number encoded in the filename is stored in *number. // Returns true if the filename was successfully parsed. LEVELDB_EXPORT bool ParseFileName(const std::string& filename, uint64_t* number, @@ -47,6 +61,19 @@ LEVELDB_EXPORT void UpdateHistograms(); // Note: This function will fail if |db_path| does not exist. LEVELDB_EXPORT bool CorruptClosedDBForTesting(const base::FilePath& db_path); +// Returns the memory-infra dump for |tracked_memenv|. +// Do not call this function, instead call +// leveldb_env::DBTracker::GetOrCreateAllocatorDump(). +// TODO(crbug.com/762598) Can be made private as part of leveldb cleanup. +base::trace_event::MemoryAllocatorDump* GetEnvAllocatorDump( + base::trace_event::ProcessMemoryDump* pmd, + leveldb::Env* tracked_memenv); + +// Dump all tracked in-memory env's to the |pmd|. Do not call - this is a +// private function for leveldb_env::DBTracker. +// TODO(crbug.com/762598) Can be made private as part of leveldb cleanup. +void DumpAllTrackedEnvs(base::trace_event::ProcessMemoryDump* pmd); + } // namespace leveldb_chrome #endif // THIRD_PARTY_LEVELDATABASE_LEVELDB_CHROME_H_