]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
test/objectstore: fix memory leak test_bluestore_types.cc 63600/head
authorKefu Chai <tchaikov@gmail.com>
Fri, 30 May 2025 01:40:41 +0000 (09:40 +0800)
committerKefu Chai <tchaikov@gmail.com>
Fri, 30 May 2025 04:19:23 +0000 (12:19 +0800)
Previously, we had memory leak in the test_bluestore_types.cc tests where
`BufferCacheShard` and `OnodeCacheShard` objects were allocated with
raw pointers but never freed, causing leaks detected by AddressSanitizer.

ASan rightly pointed this out:

```
Direct leak of 224 byte(s) in 1 object(s) allocated from:
    #0 0x55a7432a079d in operator new(unsigned long) (/home/jenkins-build/build/workspace/ceph-pull-requests/build/bin/unittest_bluestore_types+0xf2e79d) (BuildId: c3bec647afa97df6bb147bc82eac937531fc6272)
    #1 0x55a743523340 in BlueStore::BufferCacheShard::create(BlueStore*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, ceph::common::PerfCounters*) /home/jenkins-build/build/workspace/ceph-pull-requests/src/os/bluestore/Bl
ueStore.cc:1678:9
    #2 0x55a74330b617 in ExtentMap_seek_lextent_Test::TestBody() /home/jenkins-build/build/workspace/ceph-pull-requests/src/test/objectstore/test_bluestore_types.cc:1077:7
    #3 0x55a7434f2b2d in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/jenkins-build/build/workspace/ceph-pull-requests/src/googletest/googletest/src/gtest.
cc:2653:10
    #4 0x55a7434b5775 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/jenkins-build/build/workspace/ceph-pull-requests/src/googletest/googletest/src/gtest.cc:
2689:14
    #5 0x55a74347005d in testing::Test::Run() /home/jenkins-build/build/workspace/ceph-pull-requests/src/googletest/googletest/src/gtest.cc:2728:5
```
```
Direct leak of 9928 byte(s) in 1 object(s) allocated from:
    #0 0x7ff249d21a2d in operator new(unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:86
    #1 0x6048ed878b76 in BlueStore::OnodeCacheShard::create(ceph::common::CephContext*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, ceph::common::PerfCounters*) /home/kefu/dev/ceph/src/os/bluestore/BlueStore.cc:1219
    #2 0x6048ed66d4f9 in GarbageCollector_BasicTest_Test::TestBody() /home/kefu/dev/ceph/src/test/objectstore/test_bluestore_types.cc:2662
    #3 0x6048ed820555 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/kefu/dev/ceph/src/googletest/googletest/src/gtest.cc:2653
    #4 0x6048ed80c78a in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/kefu/dev/ceph/src/googletest/googletest/src/gtest.cc:2689
    #5 0x6048ed7b8bfa in testing::Test::Run() /home/kefu/dev/ceph/src/googletest/googletest/src/gtest.cc:2728
```

In this change, we replace raw pointer allocation with unique_ptr to
ensure automatic cleanup when the objects go out of scope.
`
Signed-off-by: Kefu Chai <tchaikov@gmail.com>
src/test/objectstore/test_bluestore_types.cc

index c8fc38c80290fbdb26fec8edfd6402fa84958499..436e8928698f10bedc5720a6a518f24ef1f94982 100644 (file)
@@ -124,12 +124,12 @@ TEST(sb_info_space_efficient_map_t, size) {
   sb_info_space_efficient_map_t sb_info;
 
   BlueStore store(g_ceph_context, "", 4096);
-  BlueStore::OnodeCacheShard *oc =
-      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-  BlueStore::BufferCacheShard *bc =
-      BlueStore::BufferCacheShard::create(&store, "lru", NULL);
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+  std::unique_ptr<BlueStore::BufferCacheShard> bc{
+      BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
 
-  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
 
   for (size_t i = 0; i < num_shared; i++) {
     auto &sbi = sb_info.add_or_adopt(i);
@@ -420,53 +420,53 @@ TEST(bluestore_blob_t, csum_bench) {
 TEST(Blob, put_ref) {
   {
     BlueStore store(g_ceph_context, "", 4096);
-    BlueStore::OnodeCacheShard *oc =
-        BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-    BlueStore::BufferCacheShard *bc =
-        BlueStore::BufferCacheShard::create(&store, "lru", NULL);
-
-    auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
-    BlueStore::Blob b(coll.get());
-    b.dirty_blob().allocated_test(bluestore_pextent_t(0x40715000, 0x2000));
-    b.dirty_blob().allocated_test(
+    std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+        BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+    std::unique_ptr<BlueStore::BufferCacheShard> bc{
+        BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
+
+    auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
+    BlueStore::BlobRef b = coll->new_blob();
+    b->dirty_blob().allocated_test(bluestore_pextent_t(0x40715000, 0x2000));
+    b->dirty_blob().allocated_test(
         bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET, 0x8000));
-    b.dirty_blob().allocated_test(bluestore_pextent_t(0x4071f000, 0x5000));
-    b.get_ref(coll.get(), 0, 0x1200);
-    b.get_ref(coll.get(), 0xae00, 0x4200);
-    ASSERT_EQ(0x5400u, b.get_referenced_bytes());
+    b->dirty_blob().allocated_test(bluestore_pextent_t(0x4071f000, 0x5000));
+    b->get_ref(coll.get(), 0, 0x1200);
+    b->get_ref(coll.get(), 0xae00, 0x4200);
+    ASSERT_EQ(0x5400u, b->get_referenced_bytes());
     cout << b << std::endl;
     PExtentVector r;
 
-    ASSERT_FALSE(b.put_ref(coll.get(), 0, 0x1200, &r));
-    ASSERT_EQ(0x4200u, b.get_referenced_bytes());
+    ASSERT_FALSE(b->put_ref(coll.get(), 0, 0x1200, &r));
+    ASSERT_EQ(0x4200u, b->get_referenced_bytes());
     cout << " r " << r << std::endl;
     cout << b << std::endl;
 
     r.clear();
-    ASSERT_TRUE(b.put_ref(coll.get(), 0xae00, 0x4200, &r));
-    ASSERT_EQ(0u, b.get_referenced_bytes());
+    ASSERT_TRUE(b->put_ref(coll.get(), 0xae00, 0x4200, &r));
+    ASSERT_EQ(0u, b->get_referenced_bytes());
     cout << " r " << r << std::endl;
     cout << b << std::endl;
   }
 
   unsigned mas = 4096;
   BlueStore store(g_ceph_context, "", 8192);
-  BlueStore::OnodeCacheShard *oc =
-      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-  BlueStore::BufferCacheShard *bc =
-      BlueStore::BufferCacheShard::create(&store, "lru", NULL);
-  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+  std::unique_ptr<BlueStore::BufferCacheShard> bc{
+      BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
+  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
 
   {
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(0, mas * 2));
-    B.get_ref(coll.get(), 0, mas * 2);
-    ASSERT_EQ(mas * 2, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 2);
+    ASSERT_EQ(mas * 2, B->get_referenced_bytes());
     ASSERT_TRUE(b.is_allocated(0, mas * 2));
-    ASSERT_TRUE(B.put_ref(coll.get(), 0, mas * 2, &r));
-    ASSERT_EQ(0u, B.get_referenced_bytes());
+    ASSERT_TRUE(B->put_ref(coll.get(), 0, mas * 2, &r));
+    ASSERT_EQ(0u, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(0u, r[0].offset);
@@ -478,20 +478,20 @@ TEST(Blob, put_ref) {
     ASSERT_EQ(mas * 2, b.get_extents()[0].length);
   }
   {
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(123, mas * 2));
-    B.get_ref(coll.get(), 0, mas * 2);
-    ASSERT_EQ(mas * 2, B.get_referenced_bytes());
-    ASSERT_FALSE(B.put_ref(coll.get(), 0, mas, &r));
-    ASSERT_EQ(mas, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 2);
+    ASSERT_EQ(mas * 2, B->get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), 0, mas, &r));
+    ASSERT_EQ(mas, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 2));
-    ASSERT_TRUE(B.put_ref(coll.get(), mas, mas, &r));
-    ASSERT_EQ(0u, B.get_referenced_bytes());
-    ASSERT_EQ(0u, B.get_referenced_bytes());
+    ASSERT_TRUE(B->put_ref(coll.get(), mas, mas, &r));
+    ASSERT_EQ(0u, B->get_referenced_bytes());
+    ASSERT_EQ(0u, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(123u, r[0].offset);
@@ -501,29 +501,29 @@ TEST(Blob, put_ref) {
     ASSERT_EQ(mas * 2, b.get_extents()[0].length);
   }
   {
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(1, mas));
     b.allocated_test(bluestore_pextent_t(2, mas));
     b.allocated_test(bluestore_pextent_t(3, mas));
     b.allocated_test(bluestore_pextent_t(4, mas));
-    B.get_ref(coll.get(), 0, mas * 4);
-    ASSERT_EQ(mas * 4, B.get_referenced_bytes());
-    ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
-    ASSERT_EQ(mas * 3, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 4);
+    ASSERT_EQ(mas * 4, B->get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas, mas, &r));
+    ASSERT_EQ(mas * 3, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 4));
     ASSERT_TRUE(b.is_allocated(mas, mas));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 2, mas, &r));
-    ASSERT_EQ(mas * 2, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 2, mas, &r));
+    ASSERT_EQ(mas * 2, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(mas * 2, mas));
     ASSERT_TRUE(b.is_allocated(0, mas * 4));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 3, mas, &r));
-    ASSERT_EQ(mas, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 3, mas, &r));
+    ASSERT_EQ(mas, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(2u, r.size());
     ASSERT_EQ(3u, r[0].offset);
@@ -538,8 +538,8 @@ TEST(Blob, put_ref) {
     ASSERT_EQ(3u, b.get_extents().size());
   }
   {
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(1, mas));
     b.allocated_test(bluestore_pextent_t(2, mas));
@@ -547,20 +547,20 @@ TEST(Blob, put_ref) {
     b.allocated_test(bluestore_pextent_t(4, mas));
     b.allocated_test(bluestore_pextent_t(5, mas));
     b.allocated_test(bluestore_pextent_t(6, mas));
-    B.get_ref(coll.get(), 0, mas * 6);
-    ASSERT_EQ(mas * 6, B.get_referenced_bytes());
-    ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
-    ASSERT_EQ(mas * 5, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 6);
+    ASSERT_EQ(mas * 6, B->get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas, mas, &r));
+    ASSERT_EQ(mas * 5, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 6));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 2, mas, &r));
-    ASSERT_EQ(mas * 4, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 2, mas, &r));
+    ASSERT_EQ(mas * 4, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 6));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 3, mas, &r));
-    ASSERT_EQ(mas * 3, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 3, mas, &r));
+    ASSERT_EQ(mas * 3, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(2u, r.size());
     ASSERT_EQ(3u, r[0].offset);
@@ -578,24 +578,24 @@ TEST(Blob, put_ref) {
     ASSERT_TRUE(b.get_extents()[4].is_valid());
   }
   {
-    BlueStore::Blob B(coll);
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(1, mas * 6));
-    B.get_ref(coll.get(), 0, mas * 6);
-    ASSERT_EQ(mas * 6, B.get_referenced_bytes());
-    ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
-    ASSERT_EQ(mas * 5, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 6);
+    ASSERT_EQ(mas * 6, B->get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas, mas, &r));
+    ASSERT_EQ(mas * 5, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 6));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 2, mas, &r));
-    ASSERT_EQ(mas * 4, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 2, mas, &r));
+    ASSERT_EQ(mas * 4, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 6));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 3, mas, &r));
-    ASSERT_EQ(mas * 3, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 3, mas, &r));
+    ASSERT_EQ(mas * 3, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(0x2001u, r[0].offset);
@@ -609,26 +609,26 @@ TEST(Blob, put_ref) {
     ASSERT_TRUE(b.get_extents()[2].is_valid());
   }
   {
-    BlueStore::Blob B(coll);
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(1, mas * 4));
     b.allocated_test(bluestore_pextent_t(2, mas * 4));
     b.allocated_test(bluestore_pextent_t(3, mas * 4));
-    B.get_ref(coll.get(), 0, mas * 12);
-    ASSERT_EQ(mas * 12, B.get_referenced_bytes());
-    ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
-    ASSERT_EQ(mas * 11, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 12);
+    ASSERT_EQ(mas * 12, B->get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas, mas, &r));
+    ASSERT_EQ(mas * 11, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 12));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 9, mas, &r));
-    ASSERT_EQ(mas * 10, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 9, mas, &r));
+    ASSERT_EQ(mas * 10, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 12));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 2, mas * 7, &r));
-    ASSERT_EQ(mas * 3, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 2, mas * 7, &r));
+    ASSERT_EQ(mas * 3, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(3u, r.size());
     ASSERT_EQ(0x2001u, r[0].offset);
@@ -646,26 +646,26 @@ TEST(Blob, put_ref) {
     ASSERT_TRUE(b.get_extents()[2].is_valid());
   }
   {
-    BlueStore::Blob B(coll);
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(1, mas * 4));
     b.allocated_test(bluestore_pextent_t(2, mas * 4));
     b.allocated_test(bluestore_pextent_t(3, mas * 4));
-    B.get_ref(coll.get(), 0, mas * 12);
-    ASSERT_EQ(mas * 12, B.get_referenced_bytes());
-    ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
-    ASSERT_EQ(mas * 11, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 12);
+    ASSERT_EQ(mas * 12, B->get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas, mas, &r));
+    ASSERT_EQ(mas * 11, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 12));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 9, mas, &r));
-    ASSERT_EQ(mas * 10, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 9, mas, &r));
+    ASSERT_EQ(mas * 10, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 12));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 2, mas * 7, &r));
-    ASSERT_EQ(mas * 3, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 2, mas * 7, &r));
+    ASSERT_EQ(mas * 3, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(3u, r.size());
     ASSERT_EQ(0x2001u, r[0].offset);
@@ -681,8 +681,8 @@ TEST(Blob, put_ref) {
     ASSERT_TRUE(b.get_extents()[0].is_valid());
     ASSERT_FALSE(b.get_extents()[1].is_valid());
     ASSERT_TRUE(b.get_extents()[2].is_valid());
-    ASSERT_FALSE(B.put_ref(coll.get(), 0, mas, &r));
-    ASSERT_EQ(mas * 2, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), 0, mas, &r));
+    ASSERT_EQ(mas * 2, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(0x1u, r[0].offset);
@@ -690,8 +690,8 @@ TEST(Blob, put_ref) {
     ASSERT_EQ(2u, b.get_extents().size());
     ASSERT_FALSE(b.get_extents()[0].is_valid());
     ASSERT_TRUE(b.get_extents()[1].is_valid());
-    ASSERT_TRUE(B.put_ref(coll.get(), mas * 10, mas * 2, &r));
-    ASSERT_EQ(mas * 0, B.get_referenced_bytes());
+    ASSERT_TRUE(B->put_ref(coll.get(), mas * 10, mas * 2, &r));
+    ASSERT_EQ(mas * 0, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(0x2003u, r[0].offset);
@@ -700,26 +700,26 @@ TEST(Blob, put_ref) {
     ASSERT_FALSE(b.get_extents()[0].is_valid());
   }
   {
-    BlueStore::Blob B(coll);
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(1, mas * 4));
     b.allocated_test(bluestore_pextent_t(2, mas * 4));
     b.allocated_test(bluestore_pextent_t(3, mas * 4));
-    B.get_ref(coll.get(), 0, mas * 12);
-    ASSERT_EQ(mas * 12, B.get_referenced_bytes());
-    ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
-    ASSERT_EQ(mas * 11, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 12);
+    ASSERT_EQ(mas * 12, B->get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas, mas, &r));
+    ASSERT_EQ(mas * 11, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 12));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 9, mas, &r));
-    ASSERT_EQ(mas * 10, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 9, mas, &r));
+    ASSERT_EQ(mas * 10, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 12));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 2, mas * 7, &r));
-    ASSERT_EQ(mas * 3, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 2, mas * 7, &r));
+    ASSERT_EQ(mas * 3, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(3u, r.size());
     ASSERT_EQ(0x2001u, r[0].offset);
@@ -735,8 +735,8 @@ TEST(Blob, put_ref) {
     ASSERT_TRUE(b.get_extents()[0].is_valid());
     ASSERT_FALSE(b.get_extents()[1].is_valid());
     ASSERT_TRUE(b.get_extents()[2].is_valid());
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 10, mas * 2, &r));
-    ASSERT_EQ(mas * 1, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 10, mas * 2, &r));
+    ASSERT_EQ(mas * 1, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(0x2003u, r[0].offset);
@@ -744,8 +744,8 @@ TEST(Blob, put_ref) {
     ASSERT_EQ(2u, b.get_extents().size());
     ASSERT_TRUE(b.get_extents()[0].is_valid());
     ASSERT_FALSE(b.get_extents()[1].is_valid());
-    ASSERT_TRUE(B.put_ref(coll.get(), 0, mas, &r));
-    ASSERT_EQ(mas * 0, B.get_referenced_bytes());
+    ASSERT_TRUE(B->put_ref(coll.get(), 0, mas, &r));
+    ASSERT_EQ(mas * 0, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(0x1u, r[0].offset);
@@ -754,29 +754,29 @@ TEST(Blob, put_ref) {
     ASSERT_FALSE(b.get_extents()[0].is_valid());
   }
   {
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(1, mas * 8));
-    B.get_ref(coll.get(), 0, mas * 8);
-    ASSERT_EQ(mas * 8, B.get_referenced_bytes());
-    ASSERT_FALSE(B.put_ref(coll.get(), 0, mas, &r));
-    ASSERT_EQ(mas * 7, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 8);
+    ASSERT_EQ(mas * 8, B->get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), 0, mas, &r));
+    ASSERT_EQ(mas * 7, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 8));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 7, mas, &r));
-    ASSERT_EQ(mas * 6, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 7, mas, &r));
+    ASSERT_EQ(mas * 6, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 8));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 2, mas, &r));
-    ASSERT_EQ(mas * 5, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 2, mas, &r));
+    ASSERT_EQ(mas * 5, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, 8));
-    ASSERT_FALSE(B.put_ref(coll.get(), mas * 3, mas * 4, &r));
-    ASSERT_EQ(mas * 1, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), mas * 3, mas * 4, &r));
+    ASSERT_EQ(mas * 1, B->get_referenced_bytes());
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(0x2001u, r[0].offset);
     ASSERT_EQ(mas * 6, r[0].length);
@@ -785,8 +785,8 @@ TEST(Blob, put_ref) {
     ASSERT_EQ(2u, b.get_extents().size());
     ASSERT_TRUE(b.get_extents()[0].is_valid());
     ASSERT_FALSE(b.get_extents()[1].is_valid());
-    ASSERT_TRUE(B.put_ref(coll.get(), mas, mas, &r));
-    ASSERT_EQ(mas * 0, B.get_referenced_bytes());
+    ASSERT_TRUE(B->put_ref(coll.get(), mas, mas, &r));
+    ASSERT_EQ(mas * 0, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(0x1u, r[0].offset);
@@ -796,16 +796,16 @@ TEST(Blob, put_ref) {
   }
   // verify csum chunk size if factored in properly
   {
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     PExtentVector r;
     b.allocated_test(bluestore_pextent_t(0, mas * 4));
     b.init_csum(Checksummer::CSUM_CRC32C, 14, mas * 4);
-    B.get_ref(coll.get(), 0, mas * 4);
-    ASSERT_EQ(mas * 4, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0, mas * 4);
+    ASSERT_EQ(mas * 4, B->get_referenced_bytes());
     ASSERT_TRUE(b.is_allocated(0, mas * 4));
-    ASSERT_FALSE(B.put_ref(coll.get(), 0, mas * 3, &r));
-    ASSERT_EQ(mas * 1, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), 0, mas * 3, &r));
+    ASSERT_EQ(mas * 1, B->get_referenced_bytes());
     cout << "r " << r << " " << b << std::endl;
     ASSERT_EQ(0u, r.size());
     ASSERT_TRUE(b.is_allocated(0, mas * 4));
@@ -813,57 +813,57 @@ TEST(Blob, put_ref) {
     ASSERT_EQ(mas * 4, b.get_extents()[0].length);
   }
   {
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     b.allocated_test(bluestore_pextent_t(0x40101000, 0x4000));
     b.allocated_test(
         bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET, 0x13000));
 
     b.allocated_test(bluestore_pextent_t(0x40118000, 0x7000));
-    B.get_ref(coll.get(), 0x0, 0x3800);
-    B.get_ref(coll.get(), 0x17c00, 0x6400);
-    ASSERT_EQ(0x3800u + 0x6400u, B.get_referenced_bytes());
+    B->get_ref(coll.get(), 0x0, 0x3800);
+    B->get_ref(coll.get(), 0x17c00, 0x6400);
+    ASSERT_EQ(0x3800u + 0x6400u, B->get_referenced_bytes());
     b.set_flag(bluestore_blob_t::FLAG_SHARED);
     b.init_csum(Checksummer::CSUM_CRC32C, 12, 0x1e000);
 
     cout << "before: " << B << std::endl;
     PExtentVector r;
-    ASSERT_FALSE(B.put_ref(coll.get(), 0x1800, 0x2000, &r));
-    ASSERT_EQ(0x3800u + 0x6400u - 0x2000u, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), 0x1800, 0x2000, &r));
+    ASSERT_EQ(0x3800u + 0x6400u - 0x2000u, B->get_referenced_bytes());
     cout << "after: " << B << std::endl;
     cout << "r " << r << std::endl;
   }
   {
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     b.allocated_test(bluestore_pextent_t(1, 0x5000));
     b.allocated_test(bluestore_pextent_t(2, 0x5000));
-    B.get_ref(coll.get(), 0x0, 0xa000);
-    ASSERT_EQ(0xa000u, B.get_referenced_bytes());
-    cout << "before: " << B << std::endl;
+    B->get_ref(coll.get(), 0x0, 0xa000);
+    ASSERT_EQ(0xa000u, B->get_referenced_bytes());
+    cout << "before: " << *B << std::endl;
     PExtentVector r;
-    ASSERT_FALSE(B.put_ref(coll.get(), 0x8000, 0x2000, &r));
+    ASSERT_FALSE(B->put_ref(coll.get(), 0x8000, 0x2000, &r));
     cout << "after: " << B << std::endl;
     cout << "r " << r << std::endl;
-    ASSERT_EQ(0x8000u, B.get_referenced_bytes());
+    ASSERT_EQ(0x8000u, B->get_referenced_bytes());
     ASSERT_EQ(1u, r.size());
     ASSERT_EQ(0x3002u, r[0].offset);
     ASSERT_EQ(0x2000u, r[0].length);
   }
   {
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     b.allocated_test(bluestore_pextent_t(1, 0x7000));
     b.allocated_test(bluestore_pextent_t(2, 0x7000));
-    B.get_ref(coll.get(), 0x0, 0xe000);
-    ASSERT_EQ(0xe000u, B.get_referenced_bytes());
-    cout << "before: " << B << std::endl;
+    B->get_ref(coll.get(), 0x0, 0xe000);
+    ASSERT_EQ(0xe000u, B->get_referenced_bytes());
+    cout << "before: " << *B << std::endl;
     PExtentVector r;
-    ASSERT_FALSE(B.put_ref(coll.get(), 0, 0xb000, &r));
-    ASSERT_EQ(0x3000u, B.get_referenced_bytes());
+    ASSERT_FALSE(B->put_ref(coll.get(), 0, 0xb000, &r));
+    ASSERT_EQ(0x3000u, B->get_referenced_bytes());
     cout << "after: " << B << std::endl;
     cout << "r " << r << std::endl;
-    ASSERT_EQ(0x3000u, B.get_referenced_bytes());
+    ASSERT_EQ(0x3000u, B->get_referenced_bytes());
     ASSERT_EQ(2u, r.size());
     ASSERT_EQ(1u, r[0].offset);
     ASSERT_EQ(0x7000u, r[0].length);
@@ -874,24 +874,26 @@ TEST(Blob, put_ref) {
   }
   {
     BlueStore store(g_ceph_context, "", 0x4000);
-    BlueStore::OnodeCacheShard *oc =
-        BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-    BlueStore::BufferCacheShard *bc =
-        BlueStore::BufferCacheShard::create(&store, "lru", NULL);
-
-    auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
-    BlueStore::Blob B(coll.get());
-    bluestore_blob_t &b = B.dirty_blob();
+    std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+        BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+    std::unique_ptr<BlueStore::BufferCacheShard> bc{
+        BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
+
+    auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
+    // Blob assumes that it is in the coll_cache, and removes itself from the
+    // coll_cache in the dtor,
+    BlueStore::BlobRef B = coll->new_blob();
+    bluestore_blob_t &b = B->dirty_blob();
     b.allocated_test(bluestore_pextent_t(1, 0x5000));
     b.allocated_test(bluestore_pextent_t(2, 0x7000));
-    B.get_ref(coll.get(), 0x0, 0xc000);
-    ASSERT_EQ(0xc000u, B.get_referenced_bytes());
-    cout << "before: " << B << std::endl;
+    B->get_ref(coll.get(), 0x0, 0xc000);
+    ASSERT_EQ(0xc000u, B->get_referenced_bytes());
+    cout << "before: " << *B << std::endl;
     PExtentVector r;
-    ASSERT_FALSE(B.put_ref(coll.get(), 0x2000, 0xa000, &r));
+    ASSERT_FALSE(B->put_ref(coll.get(), 0x2000, 0xa000, &r));
     cout << "after: " << B << std::endl;
     cout << "r " << r << std::endl;
-    ASSERT_EQ(0x2000u, B.get_referenced_bytes());
+    ASSERT_EQ(0x2000u, B->get_referenced_bytes());
     ASSERT_EQ(2u, r.size());
     ASSERT_EQ(0x4001u, r[0].offset);
     ASSERT_EQ(0x1000u, r[0].length);
@@ -958,70 +960,70 @@ TEST(bluestore_blob_t, prune_tail) {
 
 TEST(Blob, split) {
   BlueStore store(g_ceph_context, "", 4096);
-  BlueStore::OnodeCacheShard *oc =
-      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-  BlueStore::BufferCacheShard *bc =
-      BlueStore::BufferCacheShard::create(&store, "lru", NULL);
-  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+  std::unique_ptr<BlueStore::BufferCacheShard> bc{
+      BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
+  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
   {
-    BlueStore::Blob L(coll.get());
-    BlueStore::Blob R(coll.get());
-    L.dirty_blob().allocated_test(bluestore_pextent_t(0x2000, 0x2000));
-    L.dirty_blob().init_csum(Checksummer::CSUM_CRC32C, 12, 0x2000);
-    L.get_ref(coll.get(), 0, 0x2000);
-    L.split(coll.get(), 0x1000, &R);
-    ASSERT_EQ(0x1000u, L.get_blob().get_logical_length());
-    ASSERT_EQ(4u, L.get_blob().csum_data.length());
-    ASSERT_EQ(1u, L.get_blob().get_extents().size());
-    ASSERT_EQ(0x2000u, L.get_blob().get_extents().front().offset);
-    ASSERT_EQ(0x1000u, L.get_blob().get_extents().front().length);
-    ASSERT_EQ(0x1000u, L.get_referenced_bytes());
-    ASSERT_EQ(0x1000u, R.get_blob().get_logical_length());
-    ASSERT_EQ(4u, R.get_blob().csum_data.length());
-    ASSERT_EQ(1u, R.get_blob().get_extents().size());
-    ASSERT_EQ(0x3000u, R.get_blob().get_extents().front().offset);
-    ASSERT_EQ(0x1000u, R.get_blob().get_extents().front().length);
-    ASSERT_EQ(0x1000u, R.get_referenced_bytes());
+    BlueStore::BlobRef L = coll->new_blob();
+    BlueStore::BlobRef R = coll->new_blob();
+    L->dirty_blob().allocated_test(bluestore_pextent_t(0x2000, 0x2000));
+    L->dirty_blob().init_csum(Checksummer::CSUM_CRC32C, 12, 0x2000);
+    L->get_ref(coll.get(), 0, 0x2000);
+    L->split(coll.get(), 0x1000, R.get());
+    ASSERT_EQ(0x1000u, L->get_blob().get_logical_length());
+    ASSERT_EQ(4u, L->get_blob().csum_data.length());
+    ASSERT_EQ(1u, L->get_blob().get_extents().size());
+    ASSERT_EQ(0x2000u, L->get_blob().get_extents().front().offset);
+    ASSERT_EQ(0x1000u, L->get_blob().get_extents().front().length);
+    ASSERT_EQ(0x1000u, L->get_referenced_bytes());
+    ASSERT_EQ(0x1000u, R->get_blob().get_logical_length());
+    ASSERT_EQ(4u, R->get_blob().csum_data.length());
+    ASSERT_EQ(1u, R->get_blob().get_extents().size());
+    ASSERT_EQ(0x3000u, R->get_blob().get_extents().front().offset);
+    ASSERT_EQ(0x1000u, R->get_blob().get_extents().front().length);
+    ASSERT_EQ(0x1000u, R->get_referenced_bytes());
   }
   {
-    BlueStore::Blob L(coll.get());
-    BlueStore::Blob R(coll.get());
-    L.dirty_blob().allocated_test(bluestore_pextent_t(0x2000, 0x1000));
-    L.dirty_blob().allocated_test(bluestore_pextent_t(0x12000, 0x1000));
-    L.dirty_blob().init_csum(Checksummer::CSUM_CRC32C, 12, 0x2000);
-    L.get_ref(coll.get(), 0, 0x1000);
-    L.get_ref(coll.get(), 0x1000, 0x1000);
-    L.split(coll.get(), 0x1000, &R);
-    ASSERT_EQ(0x1000u, L.get_blob().get_logical_length());
-    ASSERT_EQ(4u, L.get_blob().csum_data.length());
-    ASSERT_EQ(1u, L.get_blob().get_extents().size());
-    ASSERT_EQ(0x2000u, L.get_blob().get_extents().front().offset);
-    ASSERT_EQ(0x1000u, L.get_blob().get_extents().front().length);
-    ASSERT_EQ(0x1000u, L.get_referenced_bytes());
-    ASSERT_EQ(0x1000u, R.get_blob().get_logical_length());
-    ASSERT_EQ(4u, R.get_blob().csum_data.length());
-    ASSERT_EQ(1u, R.get_blob().get_extents().size());
-    ASSERT_EQ(0x12000u, R.get_blob().get_extents().front().offset);
-    ASSERT_EQ(0x1000u, R.get_blob().get_extents().front().length);
-    ASSERT_EQ(0x1000u, R.get_referenced_bytes());
+    BlueStore::BlobRef L = coll->new_blob();
+    BlueStore::BlobRef R = coll->new_blob();
+    L->dirty_blob().allocated_test(bluestore_pextent_t(0x2000, 0x1000));
+    L->dirty_blob().allocated_test(bluestore_pextent_t(0x12000, 0x1000));
+    L->dirty_blob().init_csum(Checksummer::CSUM_CRC32C, 12, 0x2000);
+    L->get_ref(coll.get(), 0, 0x1000);
+    L->get_ref(coll.get(), 0x1000, 0x1000);
+    L->split(coll.get(), 0x1000, R.get());
+    ASSERT_EQ(0x1000u, L->get_blob().get_logical_length());
+    ASSERT_EQ(4u, L->get_blob().csum_data.length());
+    ASSERT_EQ(1u, L->get_blob().get_extents().size());
+    ASSERT_EQ(0x2000u, L->get_blob().get_extents().front().offset);
+    ASSERT_EQ(0x1000u, L->get_blob().get_extents().front().length);
+    ASSERT_EQ(0x1000u, L->get_referenced_bytes());
+    ASSERT_EQ(0x1000u, R->get_blob().get_logical_length());
+    ASSERT_EQ(4u, R->get_blob().csum_data.length());
+    ASSERT_EQ(1u, R->get_blob().get_extents().size());
+    ASSERT_EQ(0x12000u, R->get_blob().get_extents().front().offset);
+    ASSERT_EQ(0x1000u, R->get_blob().get_extents().front().length);
+    ASSERT_EQ(0x1000u, R->get_referenced_bytes());
   }
 }
 
 TEST(Blob, legacy_decode) {
   BlueStore store(g_ceph_context, "", 4096);
-  BlueStore::OnodeCacheShard *oc =
-      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-  BlueStore::BufferCacheShard *bc =
-      BlueStore::BufferCacheShard::create(&store, "lru", NULL);
-  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+  std::unique_ptr<BlueStore::BufferCacheShard> bc{
+      BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
+  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
   bufferlist bl, bl2;
   {
-    BlueStore::Blob B(coll.get());
+    BlueStore::BlobRef B = coll->new_blob();
 
-    B.dirty_blob().allocated_test(bluestore_pextent_t(0x1, 0x2000));
-    B.dirty_blob().init_csum(Checksummer::CSUM_CRC32C, 12, 0x2000);
-    B.get_ref(coll.get(), 0, 0xff0);
-    B.get_ref(coll.get(), 0x1fff, 1);
+    B->dirty_blob().allocated_test(bluestore_pextent_t(0x1, 0x2000));
+    B->dirty_blob().init_csum(Checksummer::CSUM_CRC32C, 12, 0x2000);
+    B->get_ref(coll.get(), 0, 0xff0);
+    B->get_ref(coll.get(), 0x1fff, 1);
 
     bluestore_extent_ref_map_t fake_ref_map;
     fake_ref_map.get(0, 0xff0);
@@ -1029,54 +1031,54 @@ TEST(Blob, legacy_decode) {
 
     size_t bound = 0, bound2 = 0;
 
-    B.bound_encode(bound, 1, /*struct_v*/
-                   0,        /*sbid*/
-                   false);
+    B->bound_encode(bound, 1, /*struct_v*/
+                   0,        /*sbid*/
+                   false);
     fake_ref_map.bound_encode(bound);
 
-    B.bound_encode(bound2, 2, /*struct_v*/
+    B->bound_encode(bound2, 2, /*struct_v*/
                    0,         /*sbid*/
                    true);
 
     {
       auto app = bl.get_contiguous_appender(bound);
       auto app2 = bl2.get_contiguous_appender(bound2);
-      B.encode(app, 1, /*struct_v*/
-               0,      /*sbid*/
-               false);
+      B->encode(app, 1, /*struct_v*/
+               0,      /*sbid*/
+               false);
       fake_ref_map.encode(app);
 
-      B.encode(app2, 2, /*struct_v*/
-               0,       /*sbid*/
-               true);
+      B->encode(app2, 2, /*struct_v*/
+               0,       /*sbid*/
+               true);
     }
 
     auto p = bl.front().begin_deep();
     auto p2 = bl2.front().begin_deep();
-    BlueStore::Blob Bres(coll.get());
-    BlueStore::Blob Bres2(coll.get());
+    BlueStore::BlobRef Bres = coll->new_blob();
+    BlueStore::BlobRef Bres2 = coll->new_blob();
 
     uint64_t sbid, sbid2;
-    Bres.decode(p, 1, /*struct_v*/
-                &sbid, true, coll.get());
-    Bres2.decode(p2, 2, /*struct_v*/
-                 &sbid2, true, coll.get());
+    Bres->decode(p, 1, /*struct_v*/
+                &sbid, true, coll.get());
+    Bres2->decode(p2, 2, /*struct_v*/
+                 &sbid2, true, coll.get());
 
-    ASSERT_EQ(0xff0u + 1u, Bres.get_blob_use_tracker().get_referenced_bytes());
-    ASSERT_EQ(0xff0u + 1u, Bres2.get_blob_use_tracker().get_referenced_bytes());
+    ASSERT_EQ(0xff0u + 1u, Bres->get_blob_use_tracker().get_referenced_bytes());
+    ASSERT_EQ(0xff0u + 1u, Bres2->get_blob_use_tracker().get_referenced_bytes());
     ASSERT_TRUE(
-        Bres.get_blob_use_tracker().equal(Bres2.get_blob_use_tracker()));
+        Bres->get_blob_use_tracker().equal(Bres2->get_blob_use_tracker()));
   }
 }
 
 TEST(ExtentMap, seek_lextent) {
   BlueStore store(g_ceph_context, "", 4096);
-  BlueStore::OnodeCacheShard *oc =
-      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-  BlueStore::BufferCacheShard *bc =
-      BlueStore::BufferCacheShard::create(&store, "lru", NULL);
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+  std::unique_ptr<BlueStore::BufferCacheShard> bc{
+      BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
 
-  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
   BlueStore::Onode onode(coll.get(), ghobject_t(), "");
   BlueStore::ExtentMap em(
       &onode,
@@ -1124,11 +1126,11 @@ TEST(ExtentMap, seek_lextent) {
 
 TEST(ExtentMap, has_any_lextents) {
   BlueStore store(g_ceph_context, "", 4096);
-  BlueStore::OnodeCacheShard *oc =
-      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-  BlueStore::BufferCacheShard *bc =
-      BlueStore::BufferCacheShard::create(&store, "lru", NULL);
-  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+  std::unique_ptr<BlueStore::BufferCacheShard> bc{
+      BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
+  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
   BlueStore::Onode onode(coll.get(), ghobject_t(), "");
   BlueStore::ExtentMap em(
       &onode,
@@ -1181,12 +1183,12 @@ void erase_and_delete(BlueStore::ExtentMap &em, size_t v) {
 
 TEST(ExtentMap, compress_extent_map) {
   BlueStore store(g_ceph_context, "", 4096);
-  BlueStore::OnodeCacheShard *oc =
-      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-  BlueStore::BufferCacheShard *bc =
-      BlueStore::BufferCacheShard::create(&store, "lru", NULL);
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+  std::unique_ptr<BlueStore::BufferCacheShard> bc{
+      BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
 
-  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
   BlueStore::Onode onode(coll.get(), ghobject_t(), "");
   BlueStore::ExtentMap em(
       &onode,
@@ -1577,8 +1579,8 @@ class ExtentMapFixture : virtual public ::testing::Test {
 
 public:
   BlueStore store;
-  BlueStore::OnodeCacheShard *oc;
-  BlueStore::BufferCacheShard *bc;
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc;
+  std::unique_ptr<BlueStore::BufferCacheShard> bc;
   BlueStore::CollectionRef coll;
 
   static constexpr uint32_t au_size = 4096;
@@ -1611,9 +1613,9 @@ public:
     }
   }
   explicit ExtentMapFixture() : store(g_ceph_context, "", au_size) {
-    oc = BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-    bc = BlueStore::BufferCacheShard::create(&store, "lru", NULL);
-    coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+    oc.reset(BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL));
+    bc.reset(BlueStore::BufferCacheShard::create(&store, "lru", NULL));
+    coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
   }
 
   void SetUp() override {}
@@ -2477,13 +2479,13 @@ INSTANTIATE_TEST_SUITE_P(
 TEST(ExtentMap, dup_extent_map)
 {
   BlueStore store(g_ceph_context, "", 4096);
-  BlueStore::OnodeCacheShard *oc =
-      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-  BlueStore::BufferCacheShard *bc =
-      BlueStore::BufferCacheShard::create(&store, "lru", NULL);
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+  std::unique_ptr<BlueStore::BufferCacheShard> bc{
+      BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
 
   size_t csum_order = 12; // 1^12 = 4096 bytes
-  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
   std::unique_ptr<ceph::Formatter> formatter(Formatter::create("json"));
 
   ///////////////////////////
@@ -2656,12 +2658,12 @@ void clear_and_dispose(BlueStore::old_extent_map_t &old_em) {
 
 TEST(GarbageCollector, BasicTest) {
   BlueStore store(g_ceph_context, "", 4096);
-  BlueStore::OnodeCacheShard *oc =
-      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL);
-  BlueStore::BufferCacheShard *bc =
-      BlueStore::BufferCacheShard::create(&store, "lru", NULL);
+  std::unique_ptr<BlueStore::OnodeCacheShard> oc{
+      BlueStore::OnodeCacheShard::create(g_ceph_context, "lru", NULL)};
+  std::unique_ptr<BlueStore::BufferCacheShard> bc{
+      BlueStore::BufferCacheShard::create(&store, "lru", NULL)};
 
-  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+  auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
   BlueStore::Onode onode(coll.get(), ghobject_t(), "");
   BlueStore::ExtentMap em(
       &onode,
@@ -2747,7 +2749,7 @@ TEST(GarbageCollector, BasicTest) {
    */
   {
     BlueStore store(g_ceph_context, "", 0x10000);
-    auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+    auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
     BlueStore::Onode onode(coll.get(), ghobject_t(), "");
     BlueStore::ExtentMap em(
         &onode,
@@ -2873,7 +2875,7 @@ TEST(GarbageCollector, BasicTest) {
    */
   {
     BlueStore store(g_ceph_context, "", 0x10000);
-    auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
+    auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc.get(), bc.get(), coll_t());
     BlueStore::Onode onode(coll.get(), ghobject_t(), "");
     BlueStore::ExtentMap em(
         &onode,