diff --git a/core/storage/rocksdb/rocksdb.cpp b/core/storage/rocksdb/rocksdb.cpp index 842ed665d5..e3b0bcc21a 100644 --- a/core/storage/rocksdb/rocksdb.cpp +++ b/core/storage/rocksdb/rocksdb.cpp @@ -197,7 +197,7 @@ namespace kagome::storage { column_family_descriptors, &column_family_handles, &db_raw); - std::unique_ptr db(db_raw); + std::shared_ptr db(db_raw); if (not status.ok()) { SL_ERROR(log, "Can't open old database in {}: {}", @@ -205,30 +205,9 @@ namespace kagome::storage { status.ToString()); return status_as_error(status); } + auto defer_db = + std::make_unique(db, column_family_handles, log); - auto cleanup = [&db, &column_family_handles, &log](int *i) { - auto status = db->Flush(rocksdb::FlushOptions()); - if (not status.ok()) { - SL_ERROR(log, "Can't flush database: {}", status.ToString()); - } - status = db->WaitForCompact(rocksdb::WaitForCompactOptions()); - if (not status.ok()) { - SL_ERROR( - log, "Can't wait for background compaction: {}", status.ToString()); - } - for (auto *handle : column_family_handles) { - db->DestroyColumnFamilyHandle(handle); - } - status = db->Close(); - if (not status.ok()) { - SL_ERROR(log, "Can't close database: {}", status.ToString()); - } - db.reset(); - delete i; - }; - - std::unique_ptr defer_db(new int, cleanup); - rocksdb::DBWithTTL *db_with_ttl_raw = nullptr; std::vector column_family_handles_with_ttl; const auto ttl_path = path.parent_path() / "db_ttl"; std::error_code ec; @@ -240,6 +219,7 @@ namespace kagome::storage { ec); return DatabaseError::IO_ERROR; } + rocksdb::DBWithTTL *db_with_ttl_raw = nullptr; status = rocksdb::DBWithTTL::Open(options, ttl_path.native(), column_family_descriptors, @@ -253,30 +233,10 @@ namespace kagome::storage { status.ToString()); return status_as_error(status); } - std::unique_ptr db_with_ttl(db_with_ttl_raw); - const auto ttl_cleanup = [&db_with_ttl, - &column_family_handles_with_ttl, - &log](int *i) { - auto status = db_with_ttl->Flush(rocksdb::FlushOptions()); - if (not status.ok()) { - SL_ERROR(log, "Can't flush ttl database: {}", status.ToString()); - } - status = db_with_ttl->WaitForCompact(rocksdb::WaitForCompactOptions()); - if (not status.ok()) { - SL_ERROR( - log, "Can't wait for background compaction: {}", status.ToString()); - } - for (auto *handle : column_family_handles_with_ttl) { - db_with_ttl->DestroyColumnFamilyHandle(handle); - } - status = db_with_ttl->Close(); - if (not status.ok()) { - SL_ERROR(log, "Can't close ttl database: {}", status.ToString()); - } - db_with_ttl.reset(); - delete i; - }; - std::unique_ptr defer_ttl(new int, ttl_cleanup); + std::shared_ptr db_with_ttl(db_with_ttl_raw); + auto defer_db_ttl = std::make_unique( + db_with_ttl, column_family_handles_with_ttl, log); + for (std::size_t i = 0; i < column_family_handles.size(); ++i) { const auto from_handle = column_family_handles[i]; auto to_handle = column_family_handles_with_ttl[i]; @@ -296,7 +256,7 @@ namespace kagome::storage { return status_as_error(it->status()); } } - defer_ttl.reset(); + defer_db_ttl.reset(); defer_db.reset(); fs::remove_all(path, ec); if (ec) { @@ -405,6 +365,53 @@ namespace kagome::storage { return options; } + RocksDb::DatabaseGuard::DatabaseGuard( + std::shared_ptr db, + std::vector column_family_handles, + const log::Logger &log) + : db_(std::move(db)), + column_family_handles_(std::move(column_family_handles)), + log_(log) {} + + RocksDb::DatabaseGuard::DatabaseGuard( + std::shared_ptr db_ttl, + std::vector column_family_handles, + const log::Logger &log) + : db_ttl_(std::move(db_ttl)), + column_family_handles_(std::move(column_family_handles)), + log_(log) {} + + RocksDb::DatabaseGuard::~DatabaseGuard() { + const auto clean = [this](auto db) { + auto status = db->Flush(rocksdb::FlushOptions()); + if (not status.ok()) { + SL_ERROR(log_, "Can't flush database: {}", status.ToString()); + } + + status = db->WaitForCompact(rocksdb::WaitForCompactOptions()); + if (not status.ok()) { + SL_ERROR(log_, + "Can't wait for background compaction: {}", + status.ToString()); + } + + for (auto *handle : column_family_handles_) { + db->DestroyColumnFamilyHandle(handle); + } + + status = db->Close(); + if (not status.ok()) { + SL_ERROR(log_, "Can't close database: {}", status.ToString()); + } + db.reset(); + }; + if (db_) { + clean(db_); + } else if (db_ttl_) { + clean(db_ttl_); + } + } + RocksDbSpace::RocksDbSpace(std::weak_ptr storage, const RocksDb::ColumnFamilyHandlePtr &column, log::Logger logger) diff --git a/core/storage/rocksdb/rocksdb.hpp b/core/storage/rocksdb/rocksdb.hpp index 1c9fb31673..2981041bd5 100644 --- a/core/storage/rocksdb/rocksdb.hpp +++ b/core/storage/rocksdb/rocksdb.hpp @@ -76,8 +76,27 @@ namespace kagome::storage { friend class RocksDbBatch; private: - RocksDb(); + struct DatabaseGuard { + DatabaseGuard( + std::shared_ptr db, + std::vector column_family_handles, + const log::Logger &log); + + DatabaseGuard( + std::shared_ptr db_ttl, + std::vector column_family_handles, + const log::Logger &log); + + ~DatabaseGuard(); + + private: + std::shared_ptr db_; + std::shared_ptr db_ttl_; + std::vector column_family_handles_; + log::Logger log_; + }; + RocksDb(); static rocksdb::ColumnFamilyOptions configureColumn(uint32_t memory_budget); static outcome::result createDirectory( const std::filesystem::path &absolute_path, log::Logger &log); diff --git a/test/core/injector/application_injector_test.cpp b/test/core/injector/application_injector_test.cpp index 28d2f9f7af..49b6eb61c9 100644 --- a/test/core/injector/application_injector_test.cpp +++ b/test/core/injector/application_injector_test.cpp @@ -96,6 +96,8 @@ namespace { .WillRepeatedly(testing::Return(db_path)); EXPECT_CALL(config_mock, keystorePath(_)) .WillRepeatedly(testing::Return(db_path / "keys")); + EXPECT_CALL(config_mock, enableDbMigration()) + .WillRepeatedly(testing::Return(true)); kagome::network::Roles roles; roles.flags.full = 1; roles.flags.authority = 1;