]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/os/seastore: implement OP_MERGE_COLLECTION 68750/head
authorKefu Chai <k.chai@proxmox.com>
Tue, 5 May 2026 06:53:54 +0000 (14:53 +0800)
committerKefu Chai <k.chai@proxmox.com>
Tue, 5 May 2026 11:45:58 +0000 (19:45 +0800)
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 <k.chai@proxmox.com>
src/crimson/os/seastore/seastore.cc
src/crimson/os/seastore/seastore.h
src/test/crimson/seastore/test_seastore.cc

index 0189d840b8f7d285d2dfbad473c75e3dd2e0e037..ced864f63981a1b2d149a3bf349fb388ae5b5846 100644 (file)
@@ -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,
index f49e52709da539ccad7e9b9ae3025caadde6e323..029f2216554e6363302a48fb5251fc5d3c86b297 100644 (file)
@@ -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);
index 166ad7b3de3e8abddbe62cbe29eab69f99d9ea2f..d78b69bbbf633e893be132d580630fa5c121a3f2 100644 (file)
@@ -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<coll_t> 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");