]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/seastore/onode_tree: implement FLTreeOnodeManager unittest
authorYingxin Cheng <yingxin.cheng@intel.com>
Fri, 12 Mar 2021 08:12:14 +0000 (16:12 +0800)
committerYingxin Cheng <yingxin.cheng@intel.com>
Wed, 17 Mar 2021 01:47:10 +0000 (09:47 +0800)
Signed-off-by: Yingxin Cheng <yingxin.cheng@intel.com>
src/crimson/os/seastore/onode_manager/staged-fltree/tree_utils.h
src/test/crimson/seastore/onode_tree/test_fltree_onode_manager.cc

index 172a10249b3a7e989f77ac08cd9366efc96979a4..712258a7503399379c498a98fd5aa85f40e2d475 100644 (file)
@@ -109,52 +109,27 @@ class KVPool {
   };
   using kv_vector_t = std::vector<kv_t>;
   using kvptr_vector_t = std::vector<kv_t*>;
+  using iterator_t = typename kvptr_vector_t::iterator;
 
-  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_p_kv() const {
-      assert(!is_end());
-      return (*p_kvptrs)[i];
-    }
-    bool is_end() const { return i >= p_kvptrs->size(); }
-    index_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 kvptr_vector_t& kvs) : p_kvptrs{&kvs} {}
-
-    const kvptr_vector_t* p_kvptrs;
-    index_t i = 0;
-    friend class KVPool;
-  };
-
-  iterator_t begin() const {
-    return iterator_t(serial_p_kvs);
+  size_t size() const {
+    return kvs.size();
   }
 
-  iterator_t random_begin() const {
-    return iterator_t(random_p_kvs);
+  iterator_t begin() {
+    return serial_p_kvs.begin();
+  }
+  iterator_t end() {
+    return serial_p_kvs.end();
+  }
+  iterator_t random_begin() {
+    return random_p_kvs.begin();
+  }
+  iterator_t random_end() {
+    return random_p_kvs.end();
   }
 
-  size_t size() const {
-    return kvs.size();
+  void shuffle() {
+    std::random_shuffle(random_p_kvs.begin(), random_p_kvs.end());
   }
 
   static KVPool create_raw_range(
@@ -196,6 +171,20 @@ class KVPool {
     return KVPool(std::move(kvs));
   }
 
+  static KVPool create_range(
+      const std::pair<index_t, index_t>& range_i,
+      const std::vector<size_t>& value_sizes) {
+    kv_vector_t kvs;
+    std::random_device rd;
+    for (index_t i = range_i.first; i < range_i.second; ++i) {
+      auto value_size = value_sizes[rd() % value_sizes.size()];
+      kvs.emplace_back(
+          kv_t{make_oid(i), ValueItem::create(value_size, i)}
+      );
+    }
+    return KVPool(std::move(kvs));
+  }
+
  private:
   KVPool(kv_vector_t&& _kvs)
       : kvs(std::move(_kvs)), serial_p_kvs(kvs.size()), random_p_kvs(kvs.size()) {
@@ -203,10 +192,7 @@ class KVPool {
                    [] (kv_t& item) { return &item; });
     std::transform(kvs.begin(), kvs.end(), random_p_kvs.begin(),
                    [] (kv_t& item) { return &item; });
-    std::random_shuffle(random_p_kvs.begin(), random_p_kvs.end());
-    std::cout << "size: " << kvs.size()
-              << ", " << serial_p_kvs.size()
-              << ", " << random_p_kvs.size() << std::endl;
+    shuffle();
   }
 
   static ghobject_t make_raw_oid(
@@ -234,6 +220,16 @@ class KVPool {
                       os_ns.str(), os_oid.str(), index0, index0);
   }
 
+  static ghobject_t make_oid(index_t i) {
+    std::stringstream ss;
+    ss << "object_" << i;
+    auto ret = ghobject_t(
+      hobject_t(
+        sobject_t(ss.str(), CEPH_NOSNAP)));
+    ret.hobj.nspace = "asdf";
+    return ret;
+  }
+
   kv_vector_t kvs;
   kvptr_vector_t serial_p_kvs;
   kvptr_vector_t random_p_kvs;
@@ -281,16 +277,18 @@ class TreeBuilder {
     logger().warn("start inserting {} kvs ...", kvs.size());
     auto start_time = mono_clock::now();
     return crimson::do_until([&t, this, cursors]() -> future<bool> {
-      if (kv_iter.is_end()) {
+      if (kv_iter == kvs.random_end()) {
         return ertr::template make_ready_future<bool>(true);
       }
-      auto p_kv = kv_iter.get_p_kv();
+      auto p_kv = *kv_iter;
       logger().debug("[{}] {} -> {}",
-                     kv_iter.index(), key_hobj_t{p_kv->key}, p_kv->value);
+                     kv_iter - kvs.random_begin(),
+                     key_hobj_t{p_kv->key},
+                     p_kv->value);
       return tree->insert(
           t, p_kv->key, {p_kv->value.get_payload_size()}
       ).safe_then([&t, this, cursors](auto ret) {
-        auto p_kv = kv_iter.get_p_kv();
+        auto p_kv = *kv_iter;
         auto& [cursor, success] = ret;
         initialize_cursor_from_item(t, p_kv->key, p_kv->value, cursor, success);
         if constexpr (TRACK) {
@@ -301,7 +299,7 @@ class TreeBuilder {
         return tree->find(t, p_kv->key
         ).safe_then([this, cursor](auto cursor_) mutable {
           assert(!cursor_.is_end());
-          auto p_kv = kv_iter.get_p_kv();
+          auto p_kv = *kv_iter;
           ceph_assert(cursor_.get_ghobj() == p_kv->key);
           ceph_assert(cursor_.value() == cursor.value());
           validate_cursor_from_item(p_kv->key, p_kv->value, cursor_);
@@ -322,15 +320,15 @@ class TreeBuilder {
         return seastar::do_with(
             cursors->begin(), [&t, this, cursors](auto& c_iter) {
           return crimson::do_until([&t, this, &c_iter, cursors]() -> future<bool> {
-            if (kv_iter.is_end()) {
+            if (kv_iter == kvs.random_end()) {
               logger().info("Verify done!");
               return ertr::template make_ready_future<bool>(true);
             }
             assert(c_iter != cursors->end());
-            auto p_kv = kv_iter.get_p_kv();
+            auto p_kv = *kv_iter;
             // validate values in tree keep intact
             return tree->find(t, p_kv->key).safe_then([this, &c_iter](auto cursor) {
-              auto p_kv = kv_iter.get_p_kv();
+              auto p_kv = *kv_iter;
               validate_cursor_from_item(p_kv->key, p_kv->value, cursor);
               // validate values in cursors keep intact
               validate_cursor_from_item(p_kv->key, p_kv->value, *c_iter);
@@ -360,23 +358,17 @@ class TreeBuilder {
   future<> validate(Transaction& t) {
     return seastar::async([this, &t] {
       logger().info("Verifing insertion ...");
-      auto iter = kvs.begin();
-      while (!iter.is_end()) {
-        auto p_kv = iter.get_p_kv();
+      for (auto& p_kv : kvs) {
         auto cursor = tree->find(t, p_kv->key).unsafe_get0();
         validate_cursor_from_item(p_kv->key, p_kv->value, cursor);
-        ++iter;
       }
 
       logger().info("Verifing range query ...");
-      iter = kvs.begin();
       auto cursor = tree->begin(t).unsafe_get0();
-      while (!iter.is_end()) {
+      for (auto& p_kv : kvs) {
         assert(!cursor.is_end());
-        auto p_kv = iter.get_p_kv();
         validate_cursor_from_item(p_kv->key, p_kv->value, cursor);
         cursor = cursor.get_next(t).unsafe_get0();
-        ++iter;
       }
       assert(cursor.is_end());
 
index b48aa0fa32a98e1510aae1be87ea76b6382425bf..3dad60850975fc781473f4c72b8d4ecc6162046a 100644 (file)
@@ -1,16 +1,14 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
 // vim: ts=8 sw=2 smarttab
 
-#include <string>
-#include <iostream>
-#include <sstream>
+#include <boost/range/combine.hpp>
 
 #include "test/crimson/gtest_seastar.h"
 
 #include "test/crimson/seastore/transaction_manager_test_state.h"
 
-#include "crimson/os/futurized_collection.h"
 #include "crimson/os/seastore/onode_manager/staged-fltree/fltree_onode_manager.h"
+#include "crimson/os/seastore/onode_manager/staged-fltree/tree_utils.h"
 
 using namespace crimson;
 using namespace crimson::os;
@@ -25,19 +23,41 @@ namespace {
   }
 }
 
-ghobject_t make_oid(unsigned i) {
-  stringstream ss;
-  ss << "object_" << i;
-  auto ret = ghobject_t(
-    hobject_t(
-      sobject_t(ss.str(), CEPH_NOSNAP)));
-  ret.hobj.nspace = "asdf";
-  return ret;
-}
+struct onode_item_t {
+  uint32_t size;
+  uint64_t id;
+  uint32_t cnt_modify = 0;
+
+  void initialize(Transaction& t, Onode& value) const {
+    auto& layout = value.get_mutable_layout(t);
+    layout.size = size;
+    layout.omap_root.update(omap_root_t(id, cnt_modify));
+    validate(value);
+  }
+
+  void validate(Onode& value) const {
+    auto& layout = value.get_layout();
+    ceph_assert(laddr_t(layout.size) == laddr_t{size});
+    ceph_assert(layout.omap_root.get().addr == id);
+    ceph_assert(layout.omap_root.get().depth == cnt_modify);
+  }
+
+  void modify(Transaction& t, Onode& value) {
+    validate(value);
+    ++cnt_modify;
+    initialize(t, value);
+  }
+
+  static onode_item_t create(std::size_t size, std::size_t id) {
+    ceph_assert(size <= std::numeric_limits<uint32_t>::max());
+    return {(uint32_t)size, id};
+  }
+};
+
+struct fltree_onode_manager_test_t
+    : public seastar_test_suite_t, TMTestState {
+  using iterator_t = typename KVPool<onode_item_t>::iterator_t;
 
-struct fltree_onode_manager_test_t :
-  public seastar_test_suite_t,
-  TMTestState {
   FLTreeOnodeManagerRef manager;
 
   seastar::future<> set_up_fut() final {
@@ -63,73 +83,143 @@ struct fltree_onode_manager_test_t :
     return TMTestState::_mkfs(
     ).then([this] {
       return seastar::do_with(
-       tm->create_transaction(),
-       [this](auto &t) {
-         return manager->mkfs(*t
-         ).safe_then([this, &t] {
-           return tm->submit_transaction(std::move(t));
-         }).handle_error(
-           crimson::ct_error::assert_all{
-             "Invalid error in _mkfs"
-           }
-         );
-       });
+        tm->create_transaction(),
+        [this](auto &t) {
+          return manager->mkfs(*t
+          ).safe_then([this, &t] {
+            return tm->submit_transaction(std::move(t));
+          }).handle_error(
+            crimson::ct_error::assert_all{
+              "Invalid error in _mkfs"
+            }
+          );
+        });
     });
   }
 
   template <typename F>
-  void with_onodes_write(
-    std::vector<ghobject_t> oids,
-    F &&f) {
+  void with_transaction(F&& f) {
     auto t = tm->create_transaction();
-    auto onodes = manager->get_or_create_onodes(
-      *t,
-      oids).unsafe_get0();
-    std::invoke(f, *t, onodes);
-    manager->write_dirty(
-      *t,
-      onodes
-    ).unsafe_get0();
+    std::invoke(f, *t);
     tm->submit_transaction(std::move(t)).unsafe_get0();
   }
 
   template <typename F>
-  void with_onodes_write_range(
-    unsigned start,
-    unsigned end,
-    unsigned stride,
-    F &&f) {
+  void with_onode_write(iterator_t& it, F&& f) {
+    with_transaction([this, &it, f=std::move(f)] (auto& t) {
+      auto p_kv = *it;
+      auto onode = manager->get_or_create_onode(
+          t, p_kv->key).unsafe_get0();
+      std::invoke(f, t, *onode, p_kv->value);
+      manager->write_dirty(t, {onode}).unsafe_get0();
+    });
+  }
+
+  void validate_onode(iterator_t& it) {
+    with_transaction([this, &it] (auto& t) {
+      auto p_kv = *it;
+      auto onode = manager->get_onode(
+          t, p_kv->key).unsafe_get0();
+      p_kv->value.validate(*onode);
+    });
+  }
+
+  template <typename F>
+  void with_onodes_process(
+      iterator_t& start, iterator_t& end, F&& f) {
     std::vector<ghobject_t> oids;
-    for (unsigned i = start; i < end; i += stride) {
-      oids.emplace_back(make_oid(i));
+    std::vector<onode_item_t*> items;
+    auto it = start;
+    while(it != end) {
+      auto p_kv = *it;
+      oids.emplace_back(p_kv->key);
+      items.emplace_back(&p_kv->value);
+      ++it;
     }
-    with_onodes_write(std::move(oids), std::forward<F>(f));
+    with_transaction([this, &oids, &items, f=std::move(f)] (auto& t) mutable {
+      std::invoke(f, t, oids, items);
+    });
   }
 
   template <typename F>
-  void with_onode_write(unsigned i, F &&f) {
-    with_onodes_write_range(
-      i,
-      i + 1,
-      1, [this, f=std::forward<F>(f)](auto &t, auto &onodes) {
-       assert(onodes.size() == 1);
-       std::invoke(f, t, *onodes[0]);
-      });
+  void with_onodes_write(
+      iterator_t& start, iterator_t& end, F&& f) {
+    with_onodes_process(start, end,
+        [this, f=std::move(f)] (auto& t, auto& oids, auto& items) {
+      auto onodes = manager->get_or_create_onodes(
+          t, oids).unsafe_get0();
+      for (auto tup : boost::combine(onodes, items)) {
+        OnodeRef onode;
+        onode_item_t* p_item;
+        boost::tie(onode, p_item) = tup;
+        std::invoke(f, t, *onode, *p_item);
+      }
+      manager->write_dirty(t, onodes).unsafe_get0();
+    });
+  }
+
+  void validate_onodes(
+      iterator_t& start, iterator_t& end) {
+    with_onodes_process(start, end,
+        [this] (auto& t, auto& oids, auto& items) {
+      for (auto tup : boost::combine(oids, items)) {
+        ghobject_t oid;
+        onode_item_t* p_item;
+        boost::tie(oid, p_item) = tup;
+        auto onode = manager->get_onode(t, oid).unsafe_get0();
+        p_item->validate(*onode);
+      }
+    });
   }
 
   fltree_onode_manager_test_t() {}
 };
 
-TEST_F(fltree_onode_manager_test_t, touch)
+TEST_F(fltree_onode_manager_test_t, 1_single)
 {
   run_async([this] {
-    with_onode_write(0, [](auto &t, auto &onode) {
-      onode.get_mutable_layout(t);
+    auto pool = KVPool<onode_item_t>::create_range({0, 1}, {128, 256});
+    auto iter = pool.begin();
+    with_onode_write(iter, [](auto& t, auto& onode, auto& item) {
+      item.initialize(t, onode);
+    });
+    validate_onode(iter);
+
+    with_onode_write(iter, [](auto& t, auto& onode, auto& item) {
+      item.modify(t, onode);
+    });
+    validate_onode(iter);
+  });
+}
+
+TEST_F(fltree_onode_manager_test_t, 2_synthetic)
+{
+  run_async([this] {
+    auto pool = KVPool<onode_item_t>::create_range(
+        {0, 100}, {32, 64, 128, 256, 512});
+    auto start = pool.begin();
+    auto end = pool.end();
+    with_onodes_write(start, end,
+        [](auto& t, auto& onode, auto& item) {
+      item.initialize(t, onode);
+    });
+    validate_onodes(start, end);
+
+    auto rd_start = pool.random_begin();
+    auto rd_end = rd_start + 50;
+    with_onodes_write(rd_start, rd_end,
+        [](auto& t, auto& onode, auto& item) {
+      item.modify(t, onode);
     });
-    /* Disabled pending fix
-    with_onode_write(0, [](auto &t, auto &onode) {
-      onode.get_mutable_layout(t);
+    validate_onodes(start, end);
+
+    pool.shuffle();
+    rd_start = pool.random_begin();
+    rd_end = rd_start + 50;
+    with_onodes_write(rd_start, rd_end,
+        [](auto& t, auto& onode, auto& item) {
+      item.modify(t, onode);
     });
-    */
+    validate_onodes(start, end);
   });
 }