# - 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
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
)
#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"
return alloc_new_extent<omap_manager::OMapInnerNode>(t, length);
case extent_types_t::OMAP_LEAF:
return alloc_new_extent<omap_manager::OMapLeafNode>(t, length);
+ case extent_types_t::COLL_BLOCK:
+ return alloc_new_extent<collection_manager::CollectionNode>(t, length);
case extent_types_t::TEST_BLOCK:
return alloc_new_extent<TestBlock>(t, length);
case extent_types_t::TEST_BLOCK_PHYSICAL:
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
+ case extent_types_t::COLL_BLOCK:
+ return get_extent<collection_manager::CollectionNode>(offset, length
+ ).safe_then([](auto extent) {
+ return CachedExtentRef(extent.detach(), false /* add_ref */);
+ });
case extent_types_t::ONODE_BLOCK:
return get_extent<OnodeBlock>(offset, length
).safe_then([](auto extent) {
--- /dev/null
+// -*- 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));
+}
+
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#pragma once
+
+#include <seastar/core/future.hh>
+
+#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<coll_root_t>;
+ 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<std::pair<coll_t, coll_info_t>>;
+ using list_ret = list_ertr::future<list_ret_bare>;
+ 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<CollectionManager>;
+
+namespace collection_manager {
+/* creat CollectionMapManager for Collection */
+CollectionManagerRef create_coll_manager(
+ TransactionManager &trans_manager);
+
+}
+
+}
--- /dev/null
+// -*- 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<std::pair<coll_t, coll_info_t>> list_result;
+ for (auto &&it : decoded) {
+ list_result.emplace_back(
+ std::make_pair(
+ static_cast<coll_t>(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<CollectionNode>();
+ 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<CollectionNode>();
+ 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<CollectionNode>();
+ 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();
+}
+
+}
--- /dev/null
+// -*- 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<denc_coll_t, uint32_t>;
+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<delta_t> 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<CollectionNode>;
+
+ bool loaded = false;
+
+ template <typename... T>
+ CollectionNode(T&&... t)
+ : LogicalCachedExtent(std::forward<T>(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_result_t>;
+ 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;
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <string.h>
+
+#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<CollectionNode>(
+ 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_t>(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<CollectionNode>(
+ 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<CollectionNodeRef>(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<CollectionNode>(
+ 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);
+ });
+}
+
+}
--- /dev/null
+// -*- 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<CollectionNodeRef>;
+ 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<FlatCollectionManager>;
+}
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:
OMAP_INNER = 6,
OMAP_LEAF = 7,
ONODE_BLOCK_STAGED = 8,
+ COLL_BLOCK = 9,
// Test Block Types
TEST_BLOCK = 0xF0,
// ----------------------
class coll_t {
- enum type_t {
+ enum type_t : uint8_t {
TYPE_META = 0,
TYPE_LEGACY_TEMP = 1, /* no longer used */
TYPE_PG = 2,
calc_str();
}
+ friend class denc_coll_t;
public:
coll_t() : type(TYPE_META), removal_seq(0)
{
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
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
--- /dev/null
+// -*- 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<coll_t, coll_info_t>;
+ 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<coll_t, coll_info_t> 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);
+ });
+}