]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/seastore: add collection manager implementation 39037/head
authorchunmei-liu <chunmei.liu@intel.com>
Sat, 6 Feb 2021 02:13:37 +0000 (18:13 -0800)
committerchunmei-liu <chunmei.liu@intel.com>
Wed, 10 Feb 2021 06:48:37 +0000 (22:48 -0800)
Signed-off-by: chunmei-liu <chunmei.liu@intel.com>
Signed-off-by: Samuel Just <sjust@redhat.com>
14 files changed:
src/crimson/CMakeLists.txt
src/crimson/os/seastore/CMakeLists.txt
src/crimson/os/seastore/cache.cc
src/crimson/os/seastore/collection_manager.cc [new file with mode: 0644]
src/crimson/os/seastore/collection_manager.h [new file with mode: 0644]
src/crimson/os/seastore/collection_manager/collection_flat_node.cc [new file with mode: 0644]
src/crimson/os/seastore/collection_manager/collection_flat_node.h [new file with mode: 0644]
src/crimson/os/seastore/collection_manager/flat_collection_manager.cc [new file with mode: 0644]
src/crimson/os/seastore/collection_manager/flat_collection_manager.h [new file with mode: 0644]
src/crimson/os/seastore/seastore_types.cc
src/crimson/os/seastore/seastore_types.h
src/osd/osd_types.h
src/test/crimson/seastore/CMakeLists.txt
src/test/crimson/seastore/test_collection_manager.cc [new file with mode: 0644]

index 530d132c693d89befb1f1cf787fc0f1bce0d6a18..07bec8a990da6544fb42e890dae7a3aa604f28ba 100644 (file)
@@ -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
index 988b0fdeb9802cd81e677c1d29be63d571d8ec58..a8b046b6ba32aeaed1f0f1008a105f43b5cf90bb 100644 (file)
@@ -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
        )
index 73655c6d04e2f58f201646a44ce2bee61e72eb23..b88e6480c6e54eabdfc8522f10c1b3b0bbe09de3 100644 (file)
@@ -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<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:
@@ -539,6 +542,11 @@ Cache::get_extent_ertr::future<CachedExtentRef> 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<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) {
diff --git a/src/crimson/os/seastore/collection_manager.cc b/src/crimson/os/seastore/collection_manager.cc
new file mode 100644 (file)
index 0000000..4f5b58d
--- /dev/null
@@ -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 (file)
index 0000000..cacf2ee
--- /dev/null
@@ -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 <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);
+
+}
+
+}
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 (file)
index 0000000..52a0e08
--- /dev/null
@@ -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<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();
+}
+
+}
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 (file)
index 0000000..fbb9f28
--- /dev/null
@@ -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<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;
+}
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 (file)
index 0000000..35ee8b3
--- /dev/null
@@ -0,0 +1,136 @@
+// -*- 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);
+  });
+}
+
+}
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 (file)
index 0000000..3ef0716
--- /dev/null
@@ -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<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>;
+}
index e4e52dfd0d2680d6e100d2fd8ad5216884b3936f..0ece4f4a37098e38d5ef672220453172978207f0 100644 (file)
@@ -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:
index 28ffdad18fa627e3f07ca54694e04249ad365933..0c1bea23d69350ee053f733302d0128618bae9f8 100644 (file)
@@ -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,
index 2250f6f3b0ed764da8b1d81c702ea7288b6c8363..b23bc52790d511a0909808938d3cdfc8c4eb4679 100644 (file)
@@ -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
index 840a59070c7d4aa640d5c5244bf4dfb4f79c0a4e..c48765555608264c42aa10bc65f6b535701a4307 100644 (file)
@@ -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 (file)
index 0000000..07cd364
--- /dev/null
@@ -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<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);
+  });
+}