From: Kefu Chai Date: Tue, 5 May 2026 06:53:54 +0000 (+0800) Subject: crimson/os/seastore: implement OP_MERGE_COLLECTION X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=9fa5e520f1af38df9960378afdd6c751e25ee6fb;p=ceph.git crimson/os/seastore: implement OP_MERGE_COLLECTION Add a handler for Transaction::OP_MERGE_COLLECTION in SeaStore's _do_transaction_step() and the corresponding _merge_collection() implementation. Since coll_t is not part of the onode key, no onode re-keying is needed: the operation updates the destination collection's split_bits and removes the source collection from the collection B-tree, all within a single transaction. Signed-off-by: Kefu Chai --- diff --git a/src/crimson/os/seastore/seastore.cc b/src/crimson/os/seastore/seastore.cc index 0189d840b8f7..ced864f63981 100644 --- a/src/crimson/os/seastore/seastore.cc +++ b/src/crimson/os/seastore/seastore.cc @@ -1779,6 +1779,15 @@ SeaStore::Shard::_do_transaction_step( *ctx.transaction, cid, dest_cid, bits); return _split_collection(ctx, cid, bits); } + case Transaction::OP_MERGE_COLLECTION: + { + uint32_t bits = op->split_bits; + coll_t cid = i.get_cid(op->cid); + coll_t dest_cid = i.get_cid(op->dest_cid); + DEBUGT("op OP_MERGE_COLLECTION, cid={}, dest_cid={}, bits={}", + *ctx.transaction, cid, dest_cid, bits); + return _merge_collection(ctx, cid, dest_cid, bits); + } } using onode_iertr = OnodeManager::get_onode_iertr::extend< @@ -2475,6 +2484,25 @@ SeaStore::Shard::_split_collection( ); } +SeaStore::Shard::tm_ret +SeaStore::Shard::_merge_collection( + internal_context_t &ctx, + coll_t cid, + coll_t dest_cid, + int bits) +{ + auto cmroot = co_await transaction_manager->read_collection_root( + *ctx.transaction); + co_await collection_manager->update(cmroot, *ctx.transaction, dest_cid, bits) + .handle_error_interruptible( + tm_iertr::pass_further{}, + crimson::ct_error::assert_all{"unexpected error from update in _merge_collection"}); + co_await collection_manager->remove(cmroot, *ctx.transaction, cid) + .handle_error_interruptible( + tm_iertr::pass_further{}, + crimson::ct_error::assert_all{"unexpected error from remove in _merge_collection"}); +} + SeaStore::Shard::tm_ret SeaStore::Shard::_create_collection( internal_context_t &ctx, diff --git a/src/crimson/os/seastore/seastore.h b/src/crimson/os/seastore/seastore.h index f49e52709da5..029f2216554e 100644 --- a/src/crimson/os/seastore/seastore.h +++ b/src/crimson/os/seastore/seastore.h @@ -402,6 +402,11 @@ public: tm_ret _split_collection( internal_context_t &ctx, const coll_t& cid, int bits); + tm_ret _merge_collection( + internal_context_t &ctx, + coll_t cid, + coll_t dest_cid, + int bits); tm_ret _remove_collection( internal_context_t &ctx, const coll_t& cid); diff --git a/src/test/crimson/seastore/test_seastore.cc b/src/test/crimson/seastore/test_seastore.cc index 166ad7b3de3e..d78b69bbbf63 100644 --- a/src/test/crimson/seastore/test_seastore.cc +++ b/src/test/crimson/seastore/test_seastore.cc @@ -899,6 +899,43 @@ TEST_P(seastore_test_t, collection_split) }); } +TEST_P(seastore_test_t, collection_merge) +{ + run_async([this] { + coll_t src_coll{spg_t{pg_t{17, 0}}}; + coll_t dest_coll{spg_t{pg_t{1, 0}}}; + + sharded_seastore->create_new_collection(dest_coll).get(); + { + CTransaction t; + t.create_collection(dest_coll, 5); + do_transaction(std::move(t)); + } + sharded_seastore->create_new_collection(src_coll).get(); + { + CTransaction t; + t.create_collection(src_coll, 5); + do_transaction(std::move(t)); + } + + { + CTransaction t; + t.merge_collection(src_coll, dest_coll, 4); + do_transaction(std::move(t)); + } + + auto raw = seastore->list_collections().get(); + std::vector colls; + colls.reserve(raw.size()); + std::ranges::transform(raw, std::back_inserter(colls), + [](const auto& p) { return p.first; }); + EXPECT_EQ(colls.size(), 2u); + EXPECT_TRUE(contains(colls, coll_name)); + EXPECT_TRUE(contains(colls, dest_coll)); + EXPECT_FALSE(contains(colls, src_coll)); + }); +} + TEST_P(seastore_test_t, meta) { run_async([this] { set_meta("key1", "value1");