From 4fdd451edd71713b9aaa1d571bc6bbd977fc79c2 Mon Sep 17 00:00:00 2001 From: chunmei-liu Date: Fri, 5 Feb 2021 18:13:37 -0800 Subject: [PATCH] crimson/seastore: add collection manager implementation Signed-off-by: chunmei-liu Signed-off-by: Samuel Just --- src/crimson/CMakeLists.txt | 1 + src/crimson/os/seastore/CMakeLists.txt | 3 + src/crimson/os/seastore/cache.cc | 8 + src/crimson/os/seastore/collection_manager.cc | 14 ++ src/crimson/os/seastore/collection_manager.h | 123 ++++++++++++ .../collection_flat_node.cc | 126 ++++++++++++ .../collection_manager/collection_flat_node.h | 183 ++++++++++++++++++ .../flat_collection_manager.cc | 136 +++++++++++++ .../flat_collection_manager.h | 41 ++++ src/crimson/os/seastore/seastore_types.cc | 2 + src/crimson/os/seastore/seastore_types.h | 1 + src/osd/osd_types.h | 37 +++- src/test/crimson/seastore/CMakeLists.txt | 17 +- .../seastore/test_collection_manager.cc | 172 ++++++++++++++++ 14 files changed, 861 insertions(+), 3 deletions(-) create mode 100644 src/crimson/os/seastore/collection_manager.cc create mode 100644 src/crimson/os/seastore/collection_manager.h create mode 100644 src/crimson/os/seastore/collection_manager/collection_flat_node.cc create mode 100644 src/crimson/os/seastore/collection_manager/collection_flat_node.h create mode 100644 src/crimson/os/seastore/collection_manager/flat_collection_manager.cc create mode 100644 src/crimson/os/seastore/collection_manager/flat_collection_manager.h create mode 100644 src/test/crimson/seastore/test_collection_manager.cc diff --git a/src/crimson/CMakeLists.txt b/src/crimson/CMakeLists.txt index 530d132c693..07bec8a990d 100644 --- a/src/crimson/CMakeLists.txt +++ b/src/crimson/CMakeLists.txt @@ -26,6 +26,7 @@ set(crimson_common_srcs # - the logging is sent to Seastar backend # - and the template parameter of lock_policy is SINGLE add_library(crimson-common STATIC + ${PROJECT_SOURCE_DIR}/src/auth/Crypto.cc ${PROJECT_SOURCE_DIR}/src/common/admin_socket_client.cc ${PROJECT_SOURCE_DIR}/src/common/bit_str.cc ${PROJECT_SOURCE_DIR}/src/common/bloom_filter.cc diff --git a/src/crimson/os/seastore/CMakeLists.txt b/src/crimson/os/seastore/CMakeLists.txt index 988b0fdeb98..a8b046b6ba3 100644 --- a/src/crimson/os/seastore/CMakeLists.txt +++ b/src/crimson/os/seastore/CMakeLists.txt @@ -32,6 +32,9 @@ add_library(crimson-seastore STATIC extentmap_manager.cc extentmap_manager/btree/extentmap_btree_node_impl.cc extentmap_manager/btree/btree_extentmap_manager.cc + collection_manager.cc + collection_manager/flat_collection_manager.cc + collection_manager/collection_flat_node.cc seastore.cc ../../../test/crimson/seastore/test_block.cc ) diff --git a/src/crimson/os/seastore/cache.cc b/src/crimson/os/seastore/cache.cc index 73655c6d04e..b88e6480c6e 100644 --- a/src/crimson/os/seastore/cache.cc +++ b/src/crimson/os/seastore/cache.cc @@ -5,6 +5,7 @@ #include "crimson/common/log.h" // included for get_extent_by_type +#include "crimson/os/seastore/collection_manager/collection_flat_node.h" #include "crimson/os/seastore/extentmap_manager/btree/extentmap_btree_node_impl.h" #include "crimson/os/seastore/lba_manager/btree/lba_btree_node_impl.h" #include "crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.h" @@ -150,6 +151,8 @@ CachedExtentRef Cache::alloc_new_extent_by_type( return alloc_new_extent(t, length); case extent_types_t::OMAP_LEAF: return alloc_new_extent(t, length); + case extent_types_t::COLL_BLOCK: + return alloc_new_extent(t, length); case extent_types_t::TEST_BLOCK: return alloc_new_extent(t, length); case extent_types_t::TEST_BLOCK_PHYSICAL: @@ -539,6 +542,11 @@ Cache::get_extent_ertr::future Cache::get_extent_by_type( ).safe_then([](auto extent) { return CachedExtentRef(extent.detach(), false /* add_ref */); }); + case extent_types_t::COLL_BLOCK: + return get_extent(offset, length + ).safe_then([](auto extent) { + return CachedExtentRef(extent.detach(), false /* add_ref */); + }); case extent_types_t::ONODE_BLOCK: return get_extent(offset, length ).safe_then([](auto extent) { diff --git a/src/crimson/os/seastore/collection_manager.cc b/src/crimson/os/seastore/collection_manager.cc new file mode 100644 index 00000000000..4f5b58d01a2 --- /dev/null +++ b/src/crimson/os/seastore/collection_manager.cc @@ -0,0 +1,14 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +// +#include "crimson/os/seastore/collection_manager.h" +#include "crimson/os/seastore/transaction_manager.h" +#include "crimson/os/seastore/collection_manager/flat_collection_manager.h" + +namespace crimson::os::seastore::collection_manager { + +CollectionManagerRef create_coll_manager(TransactionManager &trans_manager) { + return CollectionManagerRef(new FlatCollectionManager(trans_manager)); +} + +} diff --git a/src/crimson/os/seastore/collection_manager.h b/src/crimson/os/seastore/collection_manager.h new file mode 100644 index 00000000000..cacf2ee9a18 --- /dev/null +++ b/src/crimson/os/seastore/collection_manager.h @@ -0,0 +1,123 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include + +#include "osd/osd_types.h" + +#include "crimson/os/seastore/seastore_types.h" +#include "crimson/os/seastore/transaction_manager.h" + +namespace crimson::os::seastore { + +/** + * coll_root_t + * + * Information for locating CollectionManager information, addr should be + * embedded into the TransactionManager root. + */ + class coll_root_t { + laddr_t coll_root_laddr; + segment_off_t size = 0; + + enum state_t : uint8_t { + CLEAN = 0, /// No pending mutations + MUTATED = 1, /// coll_root_laddr state must be written back to persistence + NONE = 0xFF /// Not yet mounted, should not be exposed to user + } state = NONE; + + public: + coll_root_t() : state(state_t::NONE) {} + + coll_root_t(laddr_t laddr, size_t size) + : coll_root_laddr(laddr), size(size), state(state_t::CLEAN) {} + + bool must_update() const { + return state == MUTATED; + } + + void update(laddr_t addr, segment_off_t s) { + state = state_t::MUTATED; + coll_root_laddr = addr; + size = s; + } + + laddr_t get_location() const { + return coll_root_laddr; + } + auto get_size() const { + return size; + } + }; + + struct coll_info_t { + unsigned split_bits; + + coll_info_t(unsigned bits) + : split_bits(bits) {} + + bool operator==(const coll_info_t &rhs) const { + return split_bits == rhs.split_bits; + } + }; + +/// Interface for maintaining set of collections +class CollectionManager { +public: + using base_ertr = TransactionManager::read_extent_ertr; + /// Initialize collection manager instance for an empty store + using mkfs_ertr = TransactionManager::alloc_extent_ertr; + using mkfs_ret = mkfs_ertr::future; + virtual mkfs_ret mkfs( + Transaction &t) = 0; + + /// Create collection + using create_ertr = base_ertr; + using create_ret = create_ertr::future<>; + virtual create_ret create( + coll_root_t &root, + Transaction &t, + coll_t cid, + coll_info_t info + ) = 0; + + /// List collections with info + using list_ertr = base_ertr; + using list_ret_bare = std::vector>; + using list_ret = list_ertr::future; + virtual list_ret list( + const coll_root_t &root, + Transaction &t) = 0; + + /// Remove cid + using remove_ertr = base_ertr; + using remove_ret = remove_ertr::future<>; + virtual remove_ret remove( + const coll_root_t &coll_root, + Transaction &t, + coll_t cid) = 0; + + /// Update info for cid + using update_ertr = base_ertr; + using update_ret = base_ertr::future<>; + virtual update_ret update( + const coll_root_t &coll_root, + Transaction &t, + coll_t cid, + coll_info_t info + ) = 0; + + virtual ~CollectionManager() {} +}; +using CollectionManagerRef = std::unique_ptr; + +namespace collection_manager { +/* creat CollectionMapManager for Collection */ +CollectionManagerRef create_coll_manager( + TransactionManager &trans_manager); + +} + +} diff --git a/src/crimson/os/seastore/collection_manager/collection_flat_node.cc b/src/crimson/os/seastore/collection_manager/collection_flat_node.cc new file mode 100644 index 00000000000..52a0e081ca4 --- /dev/null +++ b/src/crimson/os/seastore/collection_manager/collection_flat_node.cc @@ -0,0 +1,126 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "include/buffer.h" +#include "osd/osd_types.h" +#include "crimson/os/seastore/transaction_manager.h" +#include "crimson/os/seastore/collection_manager/collection_flat_node.h" + +namespace { + seastar::logger& logger() { + return crimson::get_logger(ceph_subsys_filestore); + } +} + +namespace crimson::os::seastore::collection_manager { + +void delta_t::replay(coll_map_t &l) const +{ + switch (op) { + case op_t::INSERT: { + l.insert(coll, bits); + break; + } + case op_t::UPDATE: { + l.update(coll, bits); + break; + } + case op_t::REMOVE: { + l.erase(coll); + break; + } + case op_t::INVALID: { + assert(0 == "impossible"); + break; + } + __builtin_unreachable(); + } +} + + +std::ostream &CollectionNode::print_detail_l(std::ostream &out) const +{ + return out; +} + +CollectionNode::list_ret +CollectionNode::list() +{ + read_to_local(); + logger().debug("CollectionNode:{}, {}", __func__, *this); + std::vector> list_result; + for (auto &&it : decoded) { + list_result.emplace_back( + std::make_pair( + static_cast(it.first), + coll_info_t{ it.second } + )); + } + return list_ret( + list_ertr::ready_future_marker{}, + std::move(list_result)); +} + +CollectionNode::create_ret +CollectionNode::create(coll_context_t cc, coll_t coll, unsigned bits) +{ + read_to_local(); + logger().debug("CollectionNode:{}", __func__); + if (!is_pending()) { + auto mut = cc.tm.get_mutable_extent(cc.t, this)->cast(); + return mut->create(cc, coll, bits); + } + logger().debug("CollectionNode::create {} {} {}", coll, bits, *this); + auto [iter, inserted] = decoded.insert(coll, bits); + assert(inserted); + if (encoded_sizeof((base_coll_map_t&)decoded) > get_bptr().length()) { + decoded.erase(iter); + return create_ret( + create_ertr::ready_future_marker{}, + create_result_t::OVERFLOW); + } else { + if (auto buffer = maybe_get_delta_buffer(); buffer) { + buffer->insert(coll, bits); + } + copy_to_node(); + return create_ret( + create_ertr::ready_future_marker{}, + create_result_t::SUCCESS); + } +} + +CollectionNode::update_ret +CollectionNode::update(coll_context_t cc, coll_t coll, unsigned bits) +{ + read_to_local(); + logger().debug("CollectionNode:{}", __func__); + if (!is_pending()) { + auto mut = cc.tm.get_mutable_extent(cc.t, this)->cast(); + return mut->update(cc, coll, bits); + } + if (auto buffer = maybe_get_delta_buffer(); buffer) { + buffer->update(coll, bits); + } + decoded.update(coll, bits); + copy_to_node(); + return seastar::now(); +} + +CollectionNode::remove_ret +CollectionNode::remove(coll_context_t cc, coll_t coll) +{ + read_to_local(); + logger().debug("CollectionNode:{}", __func__); + if (!is_pending()) { + auto mut = cc.tm.get_mutable_extent(cc.t, this)->cast(); + return mut->remove(cc, coll); + } + if (auto buffer = maybe_get_delta_buffer(); buffer) { + buffer->remove(coll); + } + decoded.remove(coll); + copy_to_node(); + return seastar::now(); +} + +} diff --git a/src/crimson/os/seastore/collection_manager/collection_flat_node.h b/src/crimson/os/seastore/collection_manager/collection_flat_node.h new file mode 100644 index 00000000000..fbb9f28faa4 --- /dev/null +++ b/src/crimson/os/seastore/collection_manager/collection_flat_node.h @@ -0,0 +1,183 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include "crimson/os/seastore/seastore_types.h" +#include "crimson/os/seastore/transaction_manager.h" +#include "crimson/os/seastore/collection_manager.h" + +namespace crimson::os::seastore::collection_manager { +struct coll_context_t { + TransactionManager &tm; + Transaction &t; +}; + +using base_coll_map_t = std::map; +struct coll_map_t : base_coll_map_t { + auto insert(coll_t coll, unsigned bits) { + return emplace( + std::make_pair(denc_coll_t{coll}, bits) + ); + } + + void update(coll_t coll, unsigned bits) { + (*this)[denc_coll_t{coll}] = bits; + } + + void remove(coll_t coll) { + erase(denc_coll_t{coll}); + } +}; + +struct delta_t { + enum class op_t : uint_fast8_t { + INSERT, + UPDATE, + REMOVE, + INVALID + } op = op_t::INVALID; + + denc_coll_t coll; + uint32_t bits = 0; + + delta_t() = default; + + DENC(delta_t, v, p) { + DENC_START(1, 1, p); + denc(v.op, p); + denc(v.coll, p); + denc(v.bits, p); + DENC_FINISH(p); + } + + void replay(coll_map_t &l) const; +}; +} +WRITE_CLASS_DENC(crimson::os::seastore::collection_manager::delta_t) + +namespace crimson::os::seastore::collection_manager { +class delta_buffer_t { + std::vector buffer; +public: + bool empty() const { + return buffer.empty(); + } + + void insert(coll_t coll, uint32_t bits) { + buffer.push_back(delta_t{delta_t::op_t::INSERT, denc_coll_t(coll), bits}); + } + void update(coll_t coll, uint32_t bits) { + buffer.push_back(delta_t{delta_t::op_t::UPDATE, denc_coll_t(coll), bits}); + } + void remove(coll_t coll) { + buffer.push_back(delta_t{delta_t::op_t::REMOVE, denc_coll_t(coll), 0}); + } + void replay(coll_map_t &l) { + for (auto &i: buffer) { + i.replay(l); + } + } + + void clear() { buffer.clear(); } + + DENC(delta_buffer_t, v, p) { + DENC_START(1, 1, p); + denc(v.buffer, p); + DENC_FINISH(p); + } +}; +} +WRITE_CLASS_DENC(crimson::os::seastore::collection_manager::delta_buffer_t) + +namespace crimson::os::seastore::collection_manager { + +struct CollectionNode + : LogicalCachedExtent { + using CollectionNodeRef = TCachedExtentRef; + + bool loaded = false; + + template + CollectionNode(T&&... t) + : LogicalCachedExtent(std::forward(t)...) {} + + static constexpr extent_types_t type = extent_types_t::COLL_BLOCK; + + coll_map_t decoded; + delta_buffer_t delta_buffer; + + CachedExtentRef duplicate_for_write() final { + assert(delta_buffer.empty()); + return CachedExtentRef(new CollectionNode(*this)); + } + delta_buffer_t *maybe_get_delta_buffer() { + return is_mutation_pending() ? &delta_buffer : nullptr; + } + + using list_ertr = CollectionManager::list_ertr; + using list_ret = CollectionManager::list_ret; + list_ret list(); + + + enum class create_result_t : uint8_t { + SUCCESS, + OVERFLOW + }; + using create_ertr = CollectionManager::create_ertr; + using create_ret = create_ertr::future; + create_ret create(coll_context_t cc, coll_t coll, unsigned bits); + + using remove_ertr = CollectionManager::remove_ertr; + using remove_ret = CollectionManager::remove_ret; + remove_ret remove(coll_context_t cc, coll_t coll); + + using update_ertr = CollectionManager::update_ertr; + using update_ret = CollectionManager::update_ret; + update_ret update(coll_context_t cc, coll_t coll, unsigned bits); + + void read_to_local() { + if (loaded) return; + bufferlist bl; + bl.append(get_bptr()); + auto iter = bl.cbegin(); + decode((base_coll_map_t&)decoded, iter); + loaded = true; + } + + void copy_to_node() { + bufferlist bl; + encode((base_coll_map_t&)decoded, bl); + auto iter = bl.begin(); + auto size = encoded_sizeof((base_coll_map_t&)decoded); + assert(size <= get_bptr().length()); + get_bptr().zero(); + iter.copy(size, get_bptr().c_str()); + + } + + ceph::bufferlist get_delta() final { + assert(!delta_buffer.empty()); + ceph::bufferlist bl; + encode(delta_buffer, bl); + delta_buffer.clear(); + return bl; + } + + void apply_delta(const ceph::bufferlist &bl) final { + assert(bl.length()); + delta_buffer_t buffer; + auto bptr = bl.begin(); + decode(buffer, bptr); + buffer.replay(decoded); + copy_to_node(); + } + + extent_types_t get_type() const final { + return type; + } + + std::ostream &print_detail_l(std::ostream &out) const final; +}; +using CollectionNodeRef = CollectionNode::CollectionNodeRef; +} diff --git a/src/crimson/os/seastore/collection_manager/flat_collection_manager.cc b/src/crimson/os/seastore/collection_manager/flat_collection_manager.cc new file mode 100644 index 00000000000..35ee8b3375a --- /dev/null +++ b/src/crimson/os/seastore/collection_manager/flat_collection_manager.cc @@ -0,0 +1,136 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include + +#include "crimson/common/log.h" + +#include "include/buffer.h" +#include "include/stringify.h" +#include "crimson/os/seastore/collection_manager/flat_collection_manager.h" +#include "crimson/os/seastore/collection_manager/collection_flat_node.h" + +namespace { + seastar::logger& logger() { + return crimson::get_logger(ceph_subsys_filestore); + } +} + +namespace crimson::os::seastore::collection_manager { + +constexpr static segment_off_t MIN_FLAT_BLOCK_SIZE = 4<<10; +constexpr static segment_off_t MAX_FLAT_BLOCK_SIZE = 4<<20; + +FlatCollectionManager::FlatCollectionManager( + TransactionManager &tm) + : tm(tm) {} + +FlatCollectionManager::mkfs_ret +FlatCollectionManager::mkfs(Transaction &t) +{ + + logger().debug("FlatCollectionManager: {}", __func__); + return tm.alloc_extent( + t, L_ADDR_MIN, MIN_FLAT_BLOCK_SIZE + ).safe_then([this](auto&& root_extent) { + coll_root_t coll_root = coll_root_t( + root_extent->get_laddr(), + MIN_FLAT_BLOCK_SIZE + ); + return mkfs_ertr::make_ready_future(coll_root); + }); +} + +FlatCollectionManager::get_root_ret +FlatCollectionManager::get_coll_root(const coll_root_t &coll_root, Transaction &t) +{ + logger().debug("FlatCollectionManager: {}", __func__); + assert(coll_root.get_location() != L_ADDR_NULL); + auto cc = get_coll_context(t); + return cc.tm.read_extents( + cc.t, + coll_root.get_location(), + coll_root.get_size() + ).safe_then([](auto&& extents) { + assert(extents.size() == 1); + [[maybe_unused]] auto [laddr, e] = extents.front(); + return get_root_ertr::make_ready_future(std::move(e)); + }); +} + +FlatCollectionManager::create_ret +FlatCollectionManager::create(coll_root_t &coll_root, Transaction &t, + coll_t cid, coll_info_t info) +{ + logger().debug("FlatCollectionManager: {}", __func__); + return get_coll_root(coll_root, t + ).safe_then([=, &coll_root, &t] (auto &&extent) { + return extent->create( + get_coll_context(t), cid, info.split_bits + ).safe_then([=, &coll_root, &t] (auto ret) { + switch (ret) { + case CollectionNode::create_result_t::OVERFLOW: { + logger().debug("FlatCollectionManager: {} overflow!", __func__); + auto new_size = coll_root.get_size() * 2; // double each time + + // TODO return error probably, but such a nonsensically large number of + // collections would create a ton of other problems as well + assert(new_size < MAX_FLAT_BLOCK_SIZE); + return tm.alloc_extent( + t, L_ADDR_MIN, new_size + ).safe_then([=, &coll_root, &t] (auto &&root_extent) { + coll_root.update(root_extent->get_laddr(), root_extent->get_length()); + + root_extent->decoded = extent->decoded; + root_extent->loaded = true; + return root_extent->create( + get_coll_context(t), cid, info.split_bits + ).safe_then([=, &t](auto result) { + assert(result == CollectionNode::create_result_t::SUCCESS); + return tm.dec_ref(t, extent->get_laddr()); + }).safe_then([] (auto) { + return create_ertr::make_ready_future<>(); + }); + }); + } + case CollectionNode::create_result_t::SUCCESS: { + return create_ertr::make_ready_future<>(); + } + } + __builtin_unreachable(); + }); + }); + +} +FlatCollectionManager::list_ret +FlatCollectionManager::list(const coll_root_t &coll_root, Transaction &t) +{ + logger().debug("FlatCollectionManager: {}", __func__); + return get_coll_root(coll_root, t) + .safe_then([this, &t] (auto extent) { + return extent->list(); + }); +} + +FlatCollectionManager::update_ret +FlatCollectionManager::update(const coll_root_t &coll_root, Transaction &t, + coll_t cid, coll_info_t info) +{ + logger().debug("FlatCollectionManager: {}", __func__); + return get_coll_root(coll_root, t) + .safe_then([this, &t, cid, info] (auto extent) { + return extent->update(get_coll_context(t), cid, info.split_bits); + }); +} + +FlatCollectionManager::remove_ret +FlatCollectionManager::remove(const coll_root_t &coll_root, Transaction &t, + coll_t cid ) +{ + logger().debug("FlatCollectionManager: {}", __func__); + return get_coll_root(coll_root, t).safe_then([this, &t, cid] (auto extent) { + return extent->remove(get_coll_context(t), cid); + }); +} + +} diff --git a/src/crimson/os/seastore/collection_manager/flat_collection_manager.h b/src/crimson/os/seastore/collection_manager/flat_collection_manager.h new file mode 100644 index 00000000000..3ef071605b3 --- /dev/null +++ b/src/crimson/os/seastore/collection_manager/flat_collection_manager.h @@ -0,0 +1,41 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include "include/ceph_assert.h" + +#include "crimson/os/seastore/collection_manager.h" +#include "crimson/os/seastore/collection_manager/collection_flat_node.h" +#include "crimson/os/seastore/seastore_types.h" +#include "crimson/os/seastore/transaction_manager.h" + +namespace crimson::os::seastore::collection_manager { + +class FlatCollectionManager : public CollectionManager { + TransactionManager &tm; + + coll_context_t get_coll_context(Transaction &t) { + return coll_context_t{tm, t}; + } + + using get_root_ertr = TransactionManager::read_extent_ertr; + using get_root_ret = get_root_ertr::future; + get_root_ret get_coll_root(const coll_root_t &coll_root, Transaction &t); + +public: + explicit FlatCollectionManager(TransactionManager &tm); + + mkfs_ret mkfs(Transaction &t) final; + + create_ret create(coll_root_t &coll_root, Transaction &t, coll_t cid, + coll_info_t info) final; + + list_ret list(const coll_root_t &coll_root, Transaction &t) final; + + remove_ret remove(const coll_root_t &coll_root, Transaction &t, coll_t cid) final; + + update_ret update(const coll_root_t &coll_root, Transaction &t, coll_t cid, coll_info_t info) final; +}; +using FlatCollectionManagerRef = std::unique_ptr; +} diff --git a/src/crimson/os/seastore/seastore_types.cc b/src/crimson/os/seastore/seastore_types.cc index e4e52dfd0d2..0ece4f4a370 100644 --- a/src/crimson/os/seastore/seastore_types.cc +++ b/src/crimson/os/seastore/seastore_types.cc @@ -63,6 +63,8 @@ std::ostream &operator<<(std::ostream &out, extent_types_t t) return out << "OMAP_INNER"; case extent_types_t::OMAP_LEAF: return out << "OMAP_LEAF"; + case extent_types_t::COLL_BLOCK: + return out << "COLL_BLOCK"; case extent_types_t::TEST_BLOCK: return out << "TEST_BLOCK"; case extent_types_t::TEST_BLOCK_PHYSICAL: diff --git a/src/crimson/os/seastore/seastore_types.h b/src/crimson/os/seastore/seastore_types.h index 28ffdad18fa..0c1bea23d69 100644 --- a/src/crimson/os/seastore/seastore_types.h +++ b/src/crimson/os/seastore/seastore_types.h @@ -284,6 +284,7 @@ enum class extent_types_t : uint8_t { OMAP_INNER = 6, OMAP_LEAF = 7, ONODE_BLOCK_STAGED = 8, + COLL_BLOCK = 9, // Test Block Types TEST_BLOCK = 0xF0, diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index 2250f6f3b0e..b23bc52790d 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -656,7 +656,7 @@ std::ostream& operator<<(std::ostream& out, const spg_t &pg); // ---------------------- class coll_t { - enum type_t { + enum type_t : uint8_t { TYPE_META = 0, TYPE_LEGACY_TEMP = 1, /* no longer used */ TYPE_PG = 2, @@ -676,6 +676,7 @@ class coll_t { calc_str(); } + friend class denc_coll_t; public: coll_t() : type(TYPE_META), removal_seq(0) { @@ -842,6 +843,40 @@ inline std::ostream& operator<<(std::ostream& out, const ceph_object_layout &ol) return out; } +struct denc_coll_t { + coll_t coll; + + auto &get_type() const { return coll.type; } + auto &get_type() { return coll.type; } + auto &get_pgid() const { return coll.pgid; } + auto &get_pgid() { return coll.pgid; } + + denc_coll_t() = default; + denc_coll_t(const denc_coll_t &) = default; + denc_coll_t(denc_coll_t &&) = default; + + denc_coll_t &operator=(const denc_coll_t &) = default; + denc_coll_t &operator=(denc_coll_t &&) = default; + + explicit denc_coll_t(const coll_t &coll) : coll(coll) {} + operator coll_t() const { + return coll; + } + + bool operator<(const denc_coll_t &rhs) const { + return coll < rhs.coll; + } + + DENC(denc_coll_t, v, p) { + DENC_START(1, 1, p); + denc(v.get_type(), p); + denc(v.get_pgid().pgid.m_pool, p); + denc(v.get_pgid().pgid.m_seed, p); + denc(v.get_pgid().shard.id, p); + DENC_FINISH(p); + } +}; +WRITE_CLASS_DENC(denc_coll_t) // compound rados version type diff --git a/src/test/crimson/seastore/CMakeLists.txt b/src/test/crimson/seastore/CMakeLists.txt index 840a59070c7..c4876555560 100644 --- a/src/test/crimson/seastore/CMakeLists.txt +++ b/src/test/crimson/seastore/CMakeLists.txt @@ -42,8 +42,21 @@ add_executable(unittest-extmap-manager add_ceph_unittest(unittest-extmap-manager) target_link_libraries( unittest-extmap-manager - ${CMAKE_DL_LIBS} - crimson-seastore) + crimson::gtest + crimson-seastore + crimson-os + crimson-common) + +add_executable(unittest-collection-manager + test_collection_manager.cc + ../gtest_seastar.cc) +add_ceph_unittest(unittest-collection-manager) +target_link_libraries( + unittest-collection-manager + crimson::gtest + crimson-seastore + crimson-os + crimson-common) add_executable(unittest_omap_manager test_omap_manager.cc diff --git a/src/test/crimson/seastore/test_collection_manager.cc b/src/test/crimson/seastore/test_collection_manager.cc new file mode 100644 index 00000000000..07cd36461c9 --- /dev/null +++ b/src/test/crimson/seastore/test_collection_manager.cc @@ -0,0 +1,172 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "os/ObjectStore.h" +#include "test/crimson/gtest_seastar.h" +#include "test/crimson/seastore/transaction_manager_test_state.h" + +#include "crimson/os/seastore/cache.h" +#include "crimson/os/seastore/transaction_manager.h" +#include "crimson/os/seastore/segment_manager.h" +#include "crimson/os/seastore/collection_manager.h" + +#include "test/crimson/seastore/test_block.h" + +using namespace crimson; +using namespace crimson::os; +using namespace crimson::os::seastore; + +namespace { + [[maybe_unused]] seastar::logger& logger() { + return crimson::get_logger(ceph_subsys_test); + } +} + + +struct collection_manager_test_t : + public seastar_test_suite_t, + TMTestState { + + CollectionManagerRef collection_manager; + + collection_manager_test_t() {} + + seastar::future<> set_up_fut() final { + return tm_setup().then([this] { + collection_manager = collection_manager::create_coll_manager(*tm); + return seastar::now(); + }); + } + + seastar::future<> tear_down_fut() final { + return tm_teardown().then([this] { + collection_manager.reset(); + return seastar::now(); + }); + } + + using test_collection_t = std::map; + test_collection_t test_coll_mappings; + + void replay() { + logger().debug("{}: begin", __func__); + restart(); + collection_manager = collection_manager::create_coll_manager(*tm); + logger().debug("{}: end", __func__); + } + + void checking_mappings(coll_root_t &coll_root, Transaction &t) { + auto coll_list = collection_manager->list(coll_root, t).unsafe_get0(); + EXPECT_EQ(test_coll_mappings.size(), coll_list.size()); + for (std::pair p : test_coll_mappings) { + EXPECT_NE( + std::find(coll_list.begin(), coll_list.end(), p), + coll_list.end()); + } + } + + void checking_mappings(coll_root_t &coll_root) { + auto t = tm->create_transaction(); + checking_mappings(coll_root, *t); + } + +}; + +TEST_F(collection_manager_test_t, basic) +{ + run_async([this] { + coll_root_t coll_root; + { + auto t = tm->create_transaction(); + coll_root = collection_manager->mkfs(*t).unsafe_get0(); + tm->submit_transaction(std::move(t)).unsafe_get(); + } + { + auto t = tm->create_transaction(); + for (int i = 0; i < 20; i++) { + coll_t cid(spg_t(pg_t(i+1,i+2), shard_id_t::NO_SHARD)); + collection_manager->create(coll_root, *t, cid, coll_info_t(i)).unsafe_get0(); + test_coll_mappings.emplace(cid, coll_info_t(i)); + } + checking_mappings(coll_root, *t); + tm->submit_transaction(std::move(t)).unsafe_get(); + EXPECT_EQ(test_coll_mappings.size(), 20); + } + + replay(); + checking_mappings(coll_root); + { + auto t = tm->create_transaction(); + for (auto& ite : test_coll_mappings) { + collection_manager->remove(coll_root, *t, ite.first).unsafe_get0(); + test_coll_mappings.erase(ite.first); + } + tm->submit_transaction(std::move(t)).unsafe_get(); + } + replay(); + { + auto t = tm->create_transaction(); + auto list_ret = collection_manager->list(coll_root, *t).unsafe_get0(); + tm->submit_transaction(std::move(t)).unsafe_get(); + EXPECT_EQ(list_ret.size(), test_coll_mappings.size()); + } + }); +} + +TEST_F(collection_manager_test_t, overflow) +{ + run_async([this] { + coll_root_t coll_root; + { + auto t = tm->create_transaction(); + coll_root = collection_manager->mkfs(*t).unsafe_get0(); + tm->submit_transaction(std::move(t)).unsafe_get(); + } + auto old_location = coll_root.get_location(); + + auto t = tm->create_transaction(); + for (int i = 0; i < 412; i++) { + coll_t cid(spg_t(pg_t(i+1,i+2), shard_id_t::NO_SHARD)); + collection_manager->create(coll_root, *t, cid, coll_info_t(i)).unsafe_get0(); + test_coll_mappings.emplace(cid, coll_info_t(i)); + } + tm->submit_transaction(std::move(t)).unsafe_get(); + EXPECT_NE(old_location, coll_root.get_location()); + checking_mappings(coll_root); + + replay(); + checking_mappings(coll_root); + }); +} + +TEST_F(collection_manager_test_t, update) +{ + run_async([this] { + coll_root_t coll_root; + { + auto t = tm->create_transaction(); + coll_root = collection_manager->mkfs(*t).unsafe_get0(); + tm->submit_transaction(std::move(t)).unsafe_get(); + } + { + auto t = tm->create_transaction(); + for (int i = 0; i < 2; i++) { + coll_t cid(spg_t(pg_t(1,i+1), shard_id_t::NO_SHARD)); + collection_manager->create(coll_root, *t, cid, coll_info_t(i)).unsafe_get0(); + test_coll_mappings.emplace(cid, coll_info_t(i)); + } + tm->submit_transaction(std::move(t)).unsafe_get(); + } + { + auto iter1= test_coll_mappings.begin(); + auto iter2 = std::next(test_coll_mappings.begin(), 1); + EXPECT_NE(iter1->second.split_bits, iter2->second.split_bits); + auto t = tm->create_transaction(); + collection_manager->update(coll_root, *t, iter1->first, iter2->second).unsafe_get0(); + tm->submit_transaction(std::move(t)).unsafe_get(); + iter1->second.split_bits = iter2->second.split_bits; + } + replay(); + checking_mappings(coll_root); + }); +} -- 2.47.3