]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
os/bluestore: check unshare blobs during snapshot deletion and fix unshare logic. 68607/head
authordheart <dheart_joe@163.com>
Sun, 10 May 2026 01:53:35 +0000 (09:53 +0800)
committerdheart <dheart_joe@163.com>
Sun, 10 May 2026 01:53:35 +0000 (09:53 +0800)
Signed-off-by: dheart <dheart_joe@163.com>
src/os/bluestore/BlueStore.cc
src/test/objectstore/store_test.cc

index 6e0b94f3abea244b30e558e25178acd53d4160ad..aa9c06ac202df2870fe7d696a59376ad1dd2935f 100644 (file)
@@ -18221,7 +18221,8 @@ int BlueStore::_do_remove(
 {
   set<SharedBlob*> maybe_unshared_blobs;
   bool is_gen = !o->oid.is_no_gen();
-  _do_truncate(txc, c, o, 0, is_gen ? &maybe_unshared_blobs : nullptr);
+  bool is_snap = o->oid.hobj.is_snap();
+  _do_truncate(txc, c, o, 0, (is_gen || is_snap) ? &maybe_unshared_blobs : nullptr);
   if (o->onode.has_omap()) {
     o->flush();
     _do_omap_clear(txc, o);
@@ -18243,7 +18244,7 @@ int BlueStore::_do_remove(
   o->onode = bluestore_onode_t();
   _debug_obj_on_delete(o->oid);
 
-  if (!is_gen || maybe_unshared_blobs.empty()) {
+  if (maybe_unshared_blobs.empty()) {
     return 0;
   }
 
@@ -18251,12 +18252,18 @@ int BlueStore::_do_remove(
   dout(10) << __func__ << " gen and maybe_unshared_blobs "
           << maybe_unshared_blobs << dendl;
   ghobject_t nogen = o->oid;
-  nogen.generation = ghobject_t::NO_GEN;
+  if (is_gen)
+    nogen.generation = ghobject_t::NO_GEN;
+  else if (is_snap)
+    nogen.hobj.snap = CEPH_NOSNAP;
   OnodeRef h = c->get_onode(nogen, false);
 
   if (!h || !h->exists) {
     return 0;
   }
+
+  //Populate the extent map structure from DB; required for shared blob processing below.
+  h->extent_map.fault_range(db, 0, h->onode.size);
   // Set maybe_unshared_blobs contains those shared blobs that have all nref=1.
   // Is .head object is using all those segments?
   // If it is using all, then no one else can use the shared blob,
index 1ab4191dda153422c96898b94010fc30f1c1266c..fe399166e3ad80d589c61fe713d045204625bca5 100644 (file)
@@ -4139,6 +4139,102 @@ TEST_P(StoreTest, BlueStoreUnshareBlobTest) {
       ASSERT_EQ(cnt, 0);
     }
   }
+  {
+    ghobject_t hoid(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
+    ghobject_t coid1 = hoid;
+    coid1.hobj.snap = 1;
+    ghobject_t coid2 = hoid;
+    coid2.hobj.snap = 2;
+
+    bufferlist data, newdata;
+    data.append(string(1<<20, 'a')); //Conditions for resharding are met.
+
+    ObjectStore::Transaction t;
+    t.write(cid, hoid, 0, data.length(), data);
+    cerr << "Creating object and write 1M " << hoid << std::endl;
+    r = queue_transaction(store, ch, std::move(t));
+    ASSERT_EQ(r, 0);
+
+    ObjectStore::Transaction clone_t1;
+    clone_t1.clone(cid, hoid, coid1);
+    cerr << "Clone object" << std::endl;
+    r = queue_transaction(store, ch, std::move(clone_t1));
+    ASSERT_EQ(r, 0);
+
+    ObjectStore::Transaction clone_t2;
+    clone_t2.clone(cid, hoid, coid2);
+    cerr << "Clone object" << std::endl;
+    r = queue_transaction(store, ch, std::move(clone_t2));
+    ASSERT_EQ(r, 0);
+
+    data.clear();
+    data.append(string(4096, 'b'));
+
+    ObjectStore::Transaction t3;
+    t3.write(cid, hoid, 0, data.length(), data);
+    cerr << "Writing 4k to source object " << hoid << std::endl;
+    r = queue_transaction(store, ch, std::move(t3));
+    ASSERT_EQ(r, 0);
+    ObjectStore::Transaction t4;
+    t4.write(cid, hoid, 8192, data.length(), data);
+    cerr << "Writing 4k to source object " << hoid << std::endl;
+    t4.write(cid, hoid, 16384, data.length(), data);
+    cerr << "Writing 4k to source object " << hoid << std::endl;
+    r = queue_transaction(store, ch, std::move(t4));
+    ASSERT_EQ(r, 0);
+
+    {
+      BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
+      ch.reset();
+      // this trims hoid one out of onode cache
+      EXPECT_EQ(bstore->umount(), 0);
+      bluestore_stats_t store_stats1;
+      EXPECT_EQ(bstore->fsck_with_stats(true, store_stats1), 0);
+      EXPECT_EQ(bstore->mount(), 0);
+      ch = bstore->open_collection(cid);
+
+      ObjectStore::Transaction c1_remove_t;
+      c1_remove_t.remove(cid, coid1);
+      cerr << "Deleting dest object" << coid1 << std::endl;
+      r = queue_transaction(bstore, ch, std::move(c1_remove_t));
+      ASSERT_EQ(r, 0);
+
+      ch.reset();
+      // this ensures remove operation submitted to kv store
+      EXPECT_EQ(bstore->umount(), 0);
+      bluestore_stats_t store_stats2;
+      EXPECT_EQ(bstore->fsck_with_stats(true, store_stats2), 0);
+      EXPECT_EQ(bstore->mount(), 0);
+      ch = bstore->open_collection(cid);
+
+      ASSERT_EQ(store_stats1.num_objects-store_stats2.num_objects, 1);
+      ASSERT_EQ(store_stats1.num_shared_blobs, store_stats2.num_shared_blobs);
+
+      ObjectStore::Transaction c2_remove_t;
+      c2_remove_t.remove(cid, coid2);
+      cerr << "Deleting dest object" << coid2 << std::endl;
+      r = queue_transaction(store, ch, std::move(c2_remove_t));
+      ASSERT_EQ(r, 0);
+
+      ch.reset();
+      // this ensures remove operation submitted to kv store
+      EXPECT_EQ(bstore->umount(), 0);
+      bluestore_stats_t store_stats3;
+      EXPECT_EQ(bstore->fsck_with_stats(true, store_stats3), 0);
+      EXPECT_EQ(bstore->mount(), 0);
+      ch = bstore->open_collection(cid);
+
+      ASSERT_EQ(store_stats2.num_objects-store_stats3.num_objects, 1);
+      ASSERT_EQ(store_stats3.num_shared_blobs, 0);
+    }
+    {
+      ObjectStore::Transaction t;
+      t.remove(cid, hoid);
+      cerr << "Cleaning" << std::endl;
+      r = queue_transaction(store, ch, std::move(t));
+      ASSERT_EQ(r, 0);
+    }
+  }
   {
     ObjectStore::Transaction t;
     t.remove(cid, hoid);