From 6f70571c2cb8903e6620c33e79011003188c2e78 Mon Sep 17 00:00:00 2001 From: Yingxin Cheng Date: Thu, 15 Oct 2020 10:02:19 +0800 Subject: [PATCH] crimson/onode-staged-tree: implement benchmark tool Signed-off-by: Yingxin Cheng --- .../onode_manager/staged-fltree/tree_utils.h | 331 ++++++++++++++++++ .../seastore/onode_tree/test_staged_fltree.cc | 290 ++------------- src/tools/crimson/CMakeLists.txt | 3 + src/tools/crimson/perf_staged_fltree.cc | 163 +++++++++ 4 files changed, 527 insertions(+), 260 deletions(-) create mode 100644 src/crimson/os/seastore/onode_manager/staged-fltree/tree_utils.h create mode 100644 src/tools/crimson/perf_staged_fltree.cc diff --git a/src/crimson/os/seastore/onode_manager/staged-fltree/tree_utils.h b/src/crimson/os/seastore/onode_manager/staged-fltree/tree_utils.h new file mode 100644 index 00000000000..23c1723589d --- /dev/null +++ b/src/crimson/os/seastore/onode_manager/staged-fltree/tree_utils.h @@ -0,0 +1,331 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "crimson/common/log.h" +#include "stages/key_layout.h" +#include "tree.h" + +namespace crimson::os::seastore::onode { + +ghobject_t make_ghobj( + int shard, unsigned pool, unsigned crush, + std::string ns, std::string oid, unsigned snap, unsigned gen) { + assert(shard <= std::numeric_limits::max()); + assert(shard >= std::numeric_limits::min()); + assert(pool <= std::numeric_limits::max()); + assert(crush <= std::numeric_limits::max()); + assert(snap <= std::numeric_limits::max()); + assert(gen <= std::numeric_limits::max()); + ghobject_t ghobj; + ghobj.shard_id.id = shard; + ghobj.hobj.pool = pool; + ghobj.hobj.set_hash(crush); + ghobj.hobj.nspace = ns; + ghobj.hobj.oid.name = oid; + ghobj.hobj.snap = snap; + ghobj.generation = gen; + return ghobj; +} + +class Onodes { + public: + Onodes(size_t n) { + for (size_t i = 1; i <= n; ++i) { + auto p_onode = &create(i * 8); + onodes.push_back(p_onode); + } + } + + Onodes(std::vector sizes) { + for (auto& size : sizes) { + auto p_onode = &create(size); + onodes.push_back(p_onode); + } + } + + ~Onodes() { + std::for_each(tracked_onodes.begin(), tracked_onodes.end(), + [] (onode_t* onode) { + std::free(onode); + }); + } + + const onode_t& create(size_t size) { + ceph_assert(size >= sizeof(onode_t) + sizeof(uint32_t)); + uint32_t target = size * 137; + auto p_mem = (char*)std::malloc(size); + auto p_onode = (onode_t*)p_mem; + tracked_onodes.push_back(p_onode); + p_onode->size = size; + p_onode->id = id++; + p_mem += (size - sizeof(uint32_t)); + std::memcpy(p_mem, &target, sizeof(uint32_t)); + validate(*p_onode); + return *p_onode; + } + + const onode_t& pick() const { + auto index = rd() % onodes.size(); + return *onodes[index]; + } + + const onode_t& pick_largest() const { + return *onodes[onodes.size() - 1]; + } + + static void validate_cursor( + const Btree::Cursor& cursor, const ghobject_t& key, const onode_t& onode) { + ceph_assert(!cursor.is_end()); + ceph_assert(cursor.get_ghobj() == key); + ceph_assert(cursor.value()); + ceph_assert(cursor.value() != &onode); + ceph_assert(*cursor.value() == onode); + validate(*cursor.value()); + } + + private: + static void validate(const onode_t& node) { + auto p_target = (const char*)&node + node.size - sizeof(uint32_t); + uint32_t target; + std::memcpy(&target, p_target, sizeof(uint32_t)); + ceph_assert(target == node.size * 137); + } + + uint16_t id = 0; + mutable std::random_device rd; + std::vector onodes; + std::vector tracked_onodes; +}; + +class KVPool { + struct kv_conf_t { + unsigned index2; + unsigned index1; + unsigned index0; + size_t ns_size; + size_t oid_size; + const onode_t* p_value; + + ghobject_t get_ghobj() const { + assert(index1 < 10); + std::ostringstream os_ns; + os_ns << "ns" << index1; + unsigned current_size = (unsigned)os_ns.tellp(); + assert(ns_size >= current_size); + os_ns << std::string(ns_size - current_size, '_'); + + std::ostringstream os_oid; + os_oid << "oid" << index1; + current_size = (unsigned)os_oid.tellp(); + assert(oid_size >= current_size); + os_oid << std::string(oid_size - current_size, '_'); + + return make_ghobj(index2, index2, index2, + os_ns.str(), os_oid.str(), index0, index0); + } + }; + using kv_vector_t = std::vector; + + public: + using kv_t = std::pair; + + KVPool(const std::vector& str_sizes, + const std::vector& onode_sizes, + const std::pair& range2, + const std::pair& range1, + const std::pair& range0) + : str_sizes{str_sizes}, onodes{onode_sizes} { + ceph_assert(range2.first < range2.second); + ceph_assert(range2.second - 1 <= (unsigned)std::numeric_limits::max()); + ceph_assert(range2.second - 1 <= std::numeric_limits::max()); + ceph_assert(range2.second - 1 <= std::numeric_limits::max()); + ceph_assert(range1.first < range1.second); + ceph_assert(range1.second - 1 <= 9); + ceph_assert(range0.first < range0.second); + ceph_assert(range0.second - 1 <= std::numeric_limits::max()); + ceph_assert(range0.second - 1 <= std::numeric_limits::max()); + std::random_device rd; + for (unsigned i = range2.first; i < range2.second; ++i) { + for (unsigned j = range1.first; j < range1.second; ++j) { + auto ns_size = (unsigned)str_sizes[rd() % str_sizes.size()]; + auto oid_size = (unsigned)str_sizes[rd() % str_sizes.size()]; + for (unsigned k = range0.first; k < range0.second; ++k) { + kvs.emplace_back(kv_conf_t{i, j, k, ns_size, oid_size, &onodes.pick()}); + } + } + } + random_kvs = kvs; + std::random_shuffle(random_kvs.begin(), random_kvs.end()); + } + + class iterator_t { + public: + iterator_t() = default; + iterator_t(const iterator_t&) = default; + iterator_t(iterator_t&&) = default; + iterator_t& operator=(const iterator_t&) = default; + iterator_t& operator=(iterator_t&&) = default; + + kv_t get_kv() const { + assert(!is_end()); + auto& conf = (*p_kvs)[i]; + return std::make_pair(conf.get_ghobj(), conf.p_value); + } + bool is_end() const { return !p_kvs || i >= p_kvs->size(); } + size_t index() const { return i; } + + iterator_t& operator++() { + assert(!is_end()); + ++i; + return *this; + } + + iterator_t operator++(int) { + iterator_t tmp = *this; + ++*this; + return tmp; + } + + private: + iterator_t(const kv_vector_t& kvs) : p_kvs{&kvs} {} + + const kv_vector_t* p_kvs = nullptr; + size_t i = 0; + friend class KVPool; + }; + + iterator_t begin() const { + return iterator_t(kvs); + } + + iterator_t random_begin() const { + return iterator_t(random_kvs); + } + + size_t size() const { + return kvs.size(); + } + + private: + std::vector str_sizes; + Onodes onodes; + kv_vector_t kvs; + kv_vector_t random_kvs; +}; + +template +class TreeBuilder { + public: + using ertr = Btree::btree_ertr; + template + using future = ertr::future; + + TreeBuilder(KVPool& kvs, NodeExtentManagerURef&& nm) + : kvs{kvs}, ref_t{make_transaction()}, t{*ref_t}, tree{std::move(nm)} {} + + future<> bootstrap() { + return tree.mkfs(t); + } + + future<> run() { + std::ostringstream oss; +#ifndef NDEBUG + oss << "debug on, "; +#else + oss << "debug off, "; +#endif + if constexpr (TRACK) { + oss << "track on"; + } else { + oss << "track off"; + } + kv_iter = kvs.random_begin(); + logger().warn("start inserting {} kvs ({}) ...", kvs.size(), oss.str()); + auto start_time = mono_clock::now(); + return crimson::do_until([this]() -> future { + if (kv_iter.is_end()) { + return ertr::make_ready_future(true); + } + auto [key, p_value] = kv_iter.get_kv(); + logger().debug("[{}] {} -> {}", kv_iter.index(), key_hobj_t{key}, *p_value); + return tree.insert(t, key, *p_value).safe_then([this](auto ret) { + auto& [cursor, success] = ret; + assert(success == true); + if constexpr (TRACK) { + cursors.emplace_back(cursor); + } +#ifndef NDEBUG + auto [key, p_value] = kv_iter.get_kv(); + Onodes::validate_cursor(cursor, key, *p_value); + return tree.lower_bound(t, key).safe_then([this, cursor](auto cursor_) { + auto [key, p_value] = kv_iter.get_kv(); + ceph_assert(cursor_.get_ghobj() == key); + ceph_assert(cursor_.value() == cursor.value()); + ++kv_iter; + return ertr::make_ready_future(false); + }); +#else + ++kv_iter; + return ertr::make_ready_future(false); +#endif + }); + }).safe_then([this, start_time] { + std::chrono::duration duration = mono_clock::now() - start_time; + logger().warn("Insert done! {}s", duration.count()); + return tree.get_stats_slow(t); + }).safe_then([this](auto stats) { + logger().warn("{}", stats); + if (!cursors.empty()) { + logger().info("Verifing tracked cursors ..."); + kv_iter = kvs.random_begin(); + return seastar::do_with( + cursors.begin(), [this](auto& c_iter) { + return crimson::do_until([this, &c_iter]() -> future { + if (kv_iter.is_end()) { + logger().info("Verify done!"); + return ertr::make_ready_future(true); + } + assert(c_iter != cursors.end()); + auto [k, v] = kv_iter.get_kv(); + // validate values in tree keep intact + return tree.lower_bound(t, k).safe_then([this, &c_iter](auto cursor) { + auto [k, v] = kv_iter.get_kv(); + Onodes::validate_cursor(cursor, k, *v); + // validate values in cursors keep intact + Onodes::validate_cursor(*c_iter, k, *v); + ++kv_iter; + ++c_iter; + return ertr::make_ready_future(false); + }); + }); + }); + } else { + return ertr::now(); + } + }); + } + + private: + static seastar::logger& logger() { + return crimson::get_logger(ceph_subsys_filestore); + } + + KVPool& kvs; + TransactionRef ref_t; + Transaction& t; + Btree tree; + KVPool::iterator_t kv_iter; + std::vector cursors; +}; + +} diff --git a/src/test/crimson/seastore/onode_tree/test_staged_fltree.cc b/src/test/crimson/seastore/onode_tree/test_staged_fltree.cc index 13ddab7f86a..29341720689 100644 --- a/src/test/crimson/seastore/onode_tree/test_staged_fltree.cc +++ b/src/test/crimson/seastore/onode_tree/test_staged_fltree.cc @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -15,40 +14,24 @@ #include "crimson/os/seastore/onode_manager/staged-fltree/node_extent_manager.h" #include "crimson/os/seastore/onode_manager/staged-fltree/node_layout.h" #include "crimson/os/seastore/onode_manager/staged-fltree/tree.h" +#include "crimson/os/seastore/onode_manager/staged-fltree/tree_utils.h" #include "crimson/os/seastore/segment_manager.h" #include "crimson/os/seastore/transaction_manager.h" #include "test/crimson/gtest_seastar.h" using namespace crimson::os::seastore::onode; -using crimson::os::seastore::Cache; -using crimson::os::seastore::Journal; -using crimson::os::seastore::LBAManagerRef; -using crimson::os::seastore::lba_manager::create_lba_manager; -using crimson::os::seastore::SegmentCleaner; -using crimson::os::seastore::SegmentManager; -using crimson::os::seastore::segment_manager::create_ephemeral; -using crimson::os::seastore::segment_manager::DEFAULT_TEST_EPHEMERAL; +namespace seastore = crimson::os::seastore; +using seastore::lba_manager::create_lba_manager; +using seastore::segment_manager::create_ephemeral; +using seastore::segment_manager::DEFAULT_TEST_EPHEMERAL; +using sc_config_t = seastore::SegmentCleaner::config_t; namespace { [[maybe_unused]] seastar::logger& logger() { return crimson::get_logger(ceph_subsys_test); } - ghobject_t make_ghobj( - shard_t shard, pool_t pool, crush_hash_t crush, - std::string ns, std::string oid, snap_t snap, gen_t gen) { - ghobject_t ghobj; - ghobj.shard_id.id = shard; - ghobj.hobj.pool = pool; - ghobj.hobj.set_hash(crush); - ghobj.hobj.nspace = ns; - ghobj.hobj.oid.name = oid; - ghobj.hobj.snap = snap; - ghobj.generation = gen; - return ghobj; - } - // return a key_view_t and its underlying memory buffer. // the buffer needs to be freed manually. std::pair build_key_view(const ghobject_t& hobj) { @@ -78,76 +61,6 @@ namespace { return {key_view, p_mem}; } - - class Onodes { - public: - Onodes(size_t n) { - for (size_t i = 1; i <= n; ++i) { - auto p_onode = &create(i * 8); - onodes.push_back(p_onode); - } - } - - Onodes(std::vector sizes) { - for (auto& size : sizes) { - auto p_onode = &create(size); - onodes.push_back(p_onode); - } - } - - ~Onodes() { - std::for_each(tracked_onodes.begin(), tracked_onodes.end(), - [] (onode_t* onode) { - std::free(onode); - }); - } - - const onode_t& create(size_t size) { - assert(size >= sizeof(onode_t) + sizeof(uint32_t)); - uint32_t target = size * 137; - auto p_mem = (char*)std::malloc(size); - auto p_onode = (onode_t*)p_mem; - tracked_onodes.push_back(p_onode); - p_onode->size = size; - p_onode->id = id++; - p_mem += (size - sizeof(uint32_t)); - std::memcpy(p_mem, &target, sizeof(uint32_t)); - validate(*p_onode); - return *p_onode; - } - - const onode_t& pick() const { - auto index = rd() % onodes.size(); - return *onodes[index]; - } - - const onode_t& pick_largest() const { - return *onodes[onodes.size() - 1]; - } - - static void validate_cursor( - const Btree::Cursor& cursor, const ghobject_t& key, const onode_t& onode) { - assert(!cursor.is_end()); - assert(cursor.get_ghobj() == key); - assert(cursor.value()); - assert(cursor.value() != &onode); - assert(*cursor.value() == onode); - validate(*cursor.value()); - } - - private: - static void validate(const onode_t& node) { - auto p_target = (const char*)&node + node.size - sizeof(uint32_t); - uint32_t target; - std::memcpy(&target, p_target, sizeof(uint32_t)); - assert(target == node.size * 137); - } - - uint16_t id = 0; - mutable std::random_device rd; - std::vector onodes; - std::vector tracked_onodes; - }; } struct a_basic_test_t : public seastar_test_suite_t {}; @@ -433,6 +346,7 @@ static std::set build_key_set( std::pair range_0, std::string padding = "", bool is_internal = false) { + assert(range_1.second <= 10); std::set ret; ghobject_t key; for (unsigned i = range_2.first; i < range_2.second; ++i) { @@ -1237,143 +1151,33 @@ TEST_F(c_dummy_test_t, 5_split_internal_node) }); } -class KVPool { - struct kv_conf_t { - unsigned index_2; - unsigned index_1; - unsigned index_0; - size_t ns_size; - size_t oid_size; - const onode_t* p_value; - - ghobject_t get_ghobj() const { - assert(index_1 < 10); - std::ostringstream os_ns; - os_ns << "ns" << index_1; - unsigned current_size = (unsigned)os_ns.tellp(); - assert(ns_size >= current_size); - os_ns << std::string(ns_size - current_size, '_'); - - std::ostringstream os_oid; - os_oid << "oid" << index_1; - current_size = (unsigned)os_oid.tellp(); - assert(oid_size >= current_size); - os_oid << std::string(oid_size - current_size, '_'); - - return make_ghobj(index_2, index_2, index_2, - os_ns.str(), os_oid.str(), index_0, index_0); - } - }; - using kv_vector_t = std::vector; - - public: - using kv_t = std::pair; - - KVPool(std::vector str_sizes, - std::vector onode_sizes, - std::pair range_2, - std::pair range_1, - std::pair range_0) - : str_sizes{str_sizes}, onodes{onode_sizes} { - std::random_device rd; - for (unsigned i = range_2.first; i < range_2.second; ++i) { - for (unsigned j = range_1.first; j < range_1.second; ++j) { - auto ns_size = (unsigned)str_sizes[rd() % str_sizes.size()]; - auto oid_size = (unsigned)str_sizes[rd() % str_sizes.size()]; - for (unsigned k = range_0.first; k < range_0.second; ++k) { - kvs.emplace_back(kv_conf_t{i, j, k, ns_size, oid_size, &onodes.pick()}); - } - } - } - random_kvs = kvs; - std::random_shuffle(random_kvs.begin(), random_kvs.end()); - } - - class iterator_t { - public: - kv_t get_kv() const { - assert(!is_end()); - auto& conf = (*p_kvs)[i]; - return std::make_pair(conf.get_ghobj(), conf.p_value); - } - bool is_end() const { return i >= p_kvs->size(); } - size_t index() const { return i; } - - iterator_t& operator++() { - assert(!is_end()); - ++i; - return *this; - } - - iterator_t operator++(int) { - iterator_t tmp = *this; - ++*this; - return tmp; - } - - private: - iterator_t(const kv_vector_t& kvs) : p_kvs{&kvs} {} - - const kv_vector_t* p_kvs; - size_t i = 0; - friend class KVPool; - }; - - iterator_t begin() const { - return iterator_t(kvs); - } - - iterator_t random_begin() const { - return iterator_t(random_kvs); - } - - size_t size() const { - return kvs.size(); - } - - kv_t make_kv(unsigned index_2, unsigned index_1, unsigned index_0, - size_t ns_size, size_t oid_size, size_t onode_size) { - auto& onode = onodes.create(onode_size); - kv_conf_t conf{index_2, index_1, index_0, ns_size, oid_size, &onode}; - return std::make_pair(conf.get_ghobj(), &onode); - } - - private: - std::vector str_sizes; - Onodes onodes; - kv_vector_t kvs; - kv_vector_t random_kvs; -}; - struct d_seastore_tree_test_t : public seastar_test_suite_t { - std::unique_ptr segment_manager; - SegmentCleaner segment_cleaner; - Journal journal; - Cache cache; - LBAManagerRef lba_manager; - TransactionManager tm; - NodeExtentManagerURef moved_nm; - TransactionRef ref_t; - Transaction& t; - Btree tree; + std::unique_ptr segment_manager; + seastore::SegmentCleaner segment_cleaner; + seastore::Journal journal; + seastore::Cache cache; + seastore::LBAManagerRef lba_manager; + seastore::TransactionManager tm; + KVPool kvs; + TreeBuilder tree; d_seastore_tree_test_t() : segment_manager(create_ephemeral(DEFAULT_TEST_EPHEMERAL)), - segment_cleaner(SegmentCleaner::config_t::default_from_segment_manager( - *segment_manager)), + segment_cleaner(sc_config_t::default_from_segment_manager(*segment_manager)), journal(*segment_manager), cache(*segment_manager), lba_manager(create_lba_manager(*segment_manager, cache)), tm(*segment_manager, segment_cleaner, journal, cache, *lba_manager), - moved_nm{ + kvs({8, 11, 64, 256, 301, 320}, + {8, 16, 128, 512, 576, 640}, + {0, 32}, {0, 10}, {0, 4}), + tree{kvs, #if 0 - NodeExtentManager::create_dummy(false)}, + NodeExtentManager::create_dummy(false) #else - NodeExtentManager::create_seastore(tm)}, + NodeExtentManager::create_seastore(tm) #endif - ref_t{make_transaction()}, - t{*ref_t}, - tree{std::move(moved_nm)} { + } { journal.set_segment_provider(&segment_cleaner); segment_cleaner.set_extent_callback(&tm); } @@ -1384,7 +1188,7 @@ struct d_seastore_tree_test_t : public seastar_test_suite_t { }).safe_then([this] { return tm.mount(); }).safe_then([this] { - return tree.mkfs(t); + return tree.bootstrap(); }).handle_error( crimson::ct_error::all_same_way([] { ASSERT_FALSE("Unable to mkfs"); @@ -1403,45 +1207,11 @@ struct d_seastore_tree_test_t : public seastar_test_suite_t { TEST_F(d_seastore_tree_test_t, 6_random_insert_leaf_node) { - run_async([this] { - KVPool kvs({8, 11, 64, 256, 301, 320}, - {8, 16, 128, 512, 576, 640}, - {0, 32}, {0, 10}, {0, 4}); - auto iter = kvs.random_begin(); - std::vector cursors; - while (!iter.is_end()) { - auto [key, p_value] = iter.get_kv(); - logger().info("[{}] {} -> {}", iter.index(), key_hobj_t{key}, *p_value); - auto [cursor, success] = tree.insert(t, key, *p_value).unsafe_get0(); - assert(success == true); -#if 1 // validate cursor tracking - cursors.emplace_back(cursor); -#endif - Onodes::validate_cursor(cursor, key, *p_value); - auto cursor_ = tree.lower_bound(t, key).unsafe_get0(); - assert(cursor_.get_ghobj() == key); - assert(cursor_.value() == cursor.value()); - ++iter; - } - - logger().info("Insert done!"); - logger().info("{}", tree.get_stats_slow(t).unsafe_get0()); - - if (!cursors.empty()) { - auto kv_iter = kvs.random_begin(); - auto c_iter = cursors.begin(); - while (!kv_iter.is_end()) { - assert(c_iter != cursors.end()); - auto [k, v] = kv_iter.get_kv(); - // validate values in tree keep intact - auto cursor = tree.lower_bound(t, k).unsafe_get0(); - Onodes::validate_cursor(cursor, k, *v); - // validate values in cursors keep intact - Onodes::validate_cursor(*c_iter, k, *v); - - ++kv_iter; - ++c_iter; - } - } + run([this] { + return tree.run().handle_error( + crimson::ct_error::all_same_way([] { + ASSERT_FALSE("Test failed"); + }) + ); }); } diff --git a/src/tools/crimson/CMakeLists.txt b/src/tools/crimson/CMakeLists.txt index fb4baf7a94a..94fc4a636f5 100644 --- a/src/tools/crimson/CMakeLists.txt +++ b/src/tools/crimson/CMakeLists.txt @@ -3,3 +3,6 @@ target_link_libraries(perf_crimson_msgr crimson) add_executable(perf_async_msgr perf_async_msgr.cc) target_link_libraries(perf_async_msgr ceph-common global ${ALLOC_LIBS}) + +add_executable(perf_staged_fltree perf_staged_fltree.cc) +target_link_libraries(perf_staged_fltree crimson-seastore) diff --git a/src/tools/crimson/perf_staged_fltree.cc b/src/tools/crimson/perf_staged_fltree.cc new file mode 100644 index 00000000000..9b3de748550 --- /dev/null +++ b/src/tools/crimson/perf_staged_fltree.cc @@ -0,0 +1,163 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include + +#include +#include + +#include "crimson/os/seastore/onode_manager/staged-fltree/tree_utils.h" +#include "crimson/os/seastore/onode_manager/staged-fltree/node_extent_manager.h" +#include "crimson/os/seastore/segment_manager.h" +#include "crimson/os/seastore/transaction_manager.h" + +using namespace crimson::os::seastore::onode; +namespace bpo = boost::program_options; +namespace seastore = crimson::os::seastore; +using seastore::lba_manager::create_lba_manager; +using seastore::segment_manager::create_ephemeral; +using seastore::segment_manager::DEFAULT_TEST_EPHEMERAL; +using sc_config_t = seastore::SegmentCleaner::config_t; + +template +class PerfTree { + public: + PerfTree(bool is_dummy, + const std::vector& str_sizes, + const std::vector& onode_sizes, + const std::pair& range2, + const std::pair& range1, + const std::pair& range0) + : is_dummy{is_dummy}, + segment_manager(create_ephemeral(DEFAULT_TEST_EPHEMERAL)), + segment_cleaner(sc_config_t::default_from_segment_manager(*segment_manager)), + journal(*segment_manager), + cache(*segment_manager), + lba_manager(create_lba_manager(*segment_manager, cache)), + tm(*segment_manager, segment_cleaner, journal, cache, *lba_manager), + kvs(str_sizes, onode_sizes, range2, range1, range0), + tree{kvs, is_dummy ? NodeExtentManager::create_dummy(true) + : NodeExtentManager::create_seastore(tm)} { + journal.set_segment_provider(&segment_cleaner); + segment_cleaner.set_extent_callback(&tm); + } + + seastar::future<> run() { + return start().then([this] { + return tree.run().handle_error( + crimson::ct_error::all_same_way([] { + ceph_abort("runtime error"); + }) + ); + }).then([this] { + return stop(); + }); + } + + private: + seastar::future<> start() { + if (is_dummy) { + return tree.bootstrap().handle_error( + crimson::ct_error::all_same_way([] { + ceph_abort("Unable to mkfs"); + }) + ); + } else { + return segment_manager->init().safe_then([this] { + return tm.mkfs(); + }).safe_then([this] { + return tm.mount(); + }).safe_then([this] { + return tree.bootstrap(); + }).handle_error( + crimson::ct_error::all_same_way([] { + ceph_abort("Unable to mkfs"); + }) + ); + } + } + + seastar::future<> stop() { + if (is_dummy) { + return seastar::now(); + } else { + return tm.close().handle_error( + crimson::ct_error::all_same_way([] { + ceph_abort("Unable to close"); + }) + ); + } + } + + bool is_dummy; + std::unique_ptr segment_manager; + seastore::SegmentCleaner segment_cleaner; + seastore::Journal journal; + seastore::Cache cache; + seastore::LBAManagerRef lba_manager; + seastore::TransactionManager tm; + KVPool kvs; + TreeBuilder tree; +}; + +template +seastar::future<> run(const bpo::variables_map& config) { + return seastar::async([&config]{ + auto backend = config["backend"].as(); + bool is_dummy; + if (backend == "dummy") { + is_dummy = true; + } else if (backend == "seastore") { + is_dummy = false; + } else { + ceph_abort(false && "invalid backend"); + } + auto str_sizes = config["str-sizes"].as>(); + auto onode_sizes = config["onode-sizes"].as>(); + auto range2 = config["range2"].as>(); + ceph_assert(range2.size() == 2); + auto range1 = config["range1"].as>(); + ceph_assert(range1.size() == 2); + auto range0 = config["range0"].as>(); + ceph_assert(range0.size() == 2); + + PerfTree perf{is_dummy, str_sizes, onode_sizes, + {range2[0], range2[1]}, {range1[0], range1[1]}, {range0[0], range0[1]}}; + perf.run().get0(); + }); +} + + +int main(int argc, char** argv) +{ + seastar::app_template app; + app.add_options() + ("backend", bpo::value()->default_value("dummy"), + "tree backend: dummy, seastore") + ("tracked", bpo::value()->default_value(false), + "track inserted cursors") + ("str-sizes", bpo::value>()->default_value( + {8, 11, 64, 256, 301, 320}), + "sizes of ns/oid strings") + ("onode-sizes", bpo::value>()->default_value( + {8, 16, 128, 512, 576, 640}), + "sizes of onode") + ("range2", bpo::value>()->default_value( + {0, 128}), + "range of shard-pool-crush [a, b)") + ("range1", bpo::value>()->default_value( + {0, 10}), + "range of ns-oid strings [a, b)") + ("range0", bpo::value>()->default_value( + {0, 4}), + "range of snap-gen [a, b)"); + return app.run(argc, argv, [&app] { + auto&& config = app.configuration(); + auto tracked = config["tracked"].as(); + if (tracked) { + return run(config); + } else { + return run(config); + } + }); +} -- 2.39.5