From 62650c2720fddbe58c54b5b4ae9253696a691e82 Mon Sep 17 00:00:00 2001 From: Radoslaw Zarzynski Date: Mon, 10 Jan 2022 23:41:35 +0000 Subject: [PATCH] test/objectstore: verify the huge page-backed reading of BlueStore. Signed-off-by: Radoslaw Zarzynski --- src/blk/BlockDevice.h | 2 + src/blk/kernel/KernelDevice.cc | 7 +- src/test/objectstore/store_test.cc | 106 +++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/blk/BlockDevice.h b/src/blk/BlockDevice.h index a82c4761c8bf..67b4b330b6c4 100644 --- a/src/blk/BlockDevice.h +++ b/src/blk/BlockDevice.h @@ -295,6 +295,8 @@ public: virtual int open(const std::string& path) = 0; virtual void close() = 0; + struct hugepaged_raw_marker_t {}; + protected: bool is_valid_io(uint64_t off, uint64_t len) const; }; diff --git a/src/blk/kernel/KernelDevice.cc b/src/blk/kernel/KernelDevice.cc index 7a0d90b449c8..1b03ce31cd7b 100644 --- a/src/blk/kernel/KernelDevice.cc +++ b/src/blk/kernel/KernelDevice.cc @@ -31,6 +31,7 @@ #include "include/stringify.h" #include "include/str_map.h" #include "common/blkdev.h" +#include "common/buffer_instrumentation.h" #include "common/errno.h" #if defined(__FreeBSD__) #include "bsm/audit_errno.h" @@ -1048,12 +1049,14 @@ int KernelDevice::discard(uint64_t offset, uint64_t len) struct ExplicitHugePagePool { using region_queue_t = boost::lockfree::queue; + using instrumented_raw = ceph::buffer_instrumentation::instrumented_raw< + BlockDevice::hugepaged_raw_marker_t>; - struct mmaped_buffer_raw : public buffer::raw { + struct mmaped_buffer_raw : public instrumented_raw { region_queue_t& region_q; // for recycling mmaped_buffer_raw(void* mmaped_region, ExplicitHugePagePool& parent) - : raw(static_cast(mmaped_region), parent.buffer_size), + : instrumented_raw(static_cast(mmaped_region), parent.buffer_size), region_q(parent.region_q) { // the `mmaped_region` has been passed to `raw` as the buffer's `data` } diff --git a/src/test/objectstore/store_test.cc b/src/test/objectstore/store_test.cc index 02eae6b4a699..8965a25c5f88 100644 --- a/src/test/objectstore/store_test.cc +++ b/src/test/objectstore/store_test.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "os/ObjectStore.h" @@ -31,12 +32,14 @@ #include "os/bluestore/BlueFS.h" #endif #include "include/Context.h" +#include "common/buffer_instrumentation.h" #include "common/ceph_argparse.h" #include "common/admin_socket.h" #include "global/global_init.h" #include "common/ceph_mutex.h" #include "common/Cond.h" #include "common/errno.h" +#include "common/options.h" // for the size literals #include "common/pretty_binary.h" #include "include/stringify.h" #include "include/coredumpctl.h" @@ -44,6 +47,7 @@ #include "include/unordered_map.h" #include "store_test_fixture.h" + using namespace std; using namespace std::placeholders; @@ -156,6 +160,7 @@ protected: public: }; + class StoreTestSpecificAUSize : public StoreTestDeferredSetup { public: @@ -6864,6 +6869,14 @@ INSTANTIATE_TEST_SUITE_P( #endif "kstore")); +#if defined(WITH_BLUESTORE) +INSTANTIATE_TEST_SUITE_P( + ObjectStore, + StoreTestDeferredSetup, + ::testing::Values( + "bluestore")); +#endif + void doMany4KWritesTest(ObjectStore* store, unsigned max_objects, unsigned max_ops, @@ -9593,6 +9606,99 @@ TEST_P(StoreTest, BluestorePerPoolOmapFixOnMount) bstore->mount(); } +class hugepaged_raw; + +static bool is_hugepaged(const bufferptr& bp) +{ + const auto& ibp = + static_cast(bp); + return ibp.is_raw_marked(); +} + +// disabled by default b/c of the dependency on huge page ssome test +// environments might not offer without extra configuration. +TEST_P(StoreTestDeferredSetup, DISABLED_BluestoreHugeReads) +{ + if (string(GetParam()) != "bluestore") { + return; + } + + constexpr static size_t HUGE_BUFFER_SIZE{2_M}; + cout << "Configuring huge page pools" << std::endl; + { + SetVal(g_conf(), "bdev_read_preallocated_huge_buffers", + fmt::format("{}=2", HUGE_BUFFER_SIZE).c_str()); + SetVal(g_conf(), "bluestore_max_blob_size", + std::to_string(HUGE_BUFFER_SIZE).c_str()); + // let's verify the per-IOContext no-cache override + SetVal(g_conf(), "bluestore_default_buffered_read", "true"); + g_ceph_context->_conf.apply_changes(nullptr); + } + DeferredSetup(); + + coll_t cid; + ghobject_t hoid(hobject_t("test_huge_buffers", "", CEPH_NOSNAP, 0, 0, "")); + auto ch = store->create_new_collection(cid); + + bufferlist bl; + { + bufferptr bp{HUGE_BUFFER_SIZE}; + // non-zeros! Otherwise the deduplication will take place. + ::memset(bp.c_str(), 0x42, HUGE_BUFFER_SIZE); + bl.push_back(std::move(bp)); + ASSERT_EQ(bl.get_num_buffers(), 1); + ASSERT_EQ(bl.length(), HUGE_BUFFER_SIZE); + } + + cout << "Write object" << std::endl; + { + ObjectStore::Transaction t; + t.create_collection(cid, 0); + t.touch(cid, hoid); + t.write(cid, hoid, 0, bl.length(), bl); + const auto r = queue_transaction(store, ch, std::move(t)); + ASSERT_EQ(r, 0); + } + + // force cache clear + { + EXPECT_EQ(store->umount(), 0); + EXPECT_EQ(store->mount(), 0); + ch = store->open_collection(cid); + } + + // we want to extend the life-time of all huge paged-backed + // bufferlists to validate the behaviour on pool exhaustion. + bufferlist bl_1_huge, bl_2_huge, bl_3_plain; + + cout << "Read object 1st time" << std::endl; + { + const auto r = store->read(ch, hoid, 0, HUGE_BUFFER_SIZE, bl_1_huge); + ASSERT_EQ(static_cast(HUGE_BUFFER_SIZE), r); + ASSERT_TRUE(bl_eq(bl, bl_1_huge)); + ASSERT_EQ(bl_1_huge.get_num_buffers(), 1); + ASSERT_TRUE(is_hugepaged(bl_1_huge.front())); + } + + cout << "Read object 2nd time" << std::endl; + { + const auto r = store->read(ch, hoid, 0, HUGE_BUFFER_SIZE, bl_2_huge); + ASSERT_EQ(static_cast(HUGE_BUFFER_SIZE), r); + ASSERT_TRUE(bl_eq(bl, bl_2_huge)); + ASSERT_EQ(bl_2_huge.get_num_buffers(), 1); + ASSERT_TRUE(is_hugepaged(bl_2_huge.front())); + } + + cout << "Read object 3rd time" << std::endl; + { + const auto r = store->read(ch, hoid, 0, HUGE_BUFFER_SIZE, bl_3_plain); + ASSERT_EQ(static_cast(HUGE_BUFFER_SIZE), r); + ASSERT_TRUE(bl_eq(bl, bl_3_plain)); + ASSERT_EQ(bl_3_plain.get_num_buffers(), 1); + ASSERT_FALSE(is_hugepaged(bl_3_plain.front())); + } +} + TEST_P(StoreTest, SpuriousReadErrorTest) { if (string(GetParam()) != "bluestore") return; -- 2.47.3