]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
crimson/os/seastore/seastore.cc: wire up omap_manager
authorSamuel Just <sjust@redhat.com>
Tue, 23 Feb 2021 05:20:58 +0000 (21:20 -0800)
committerSamuel Just <sjust@redhat.com>
Wed, 10 Mar 2021 06:56:58 +0000 (22:56 -0800)
Signed-off-by: Samuel Just <sjust@redhat.com>
src/crimson/os/seastore/omap_manager.h
src/crimson/os/seastore/seastore.cc
src/crimson/os/seastore/seastore.h
src/crimson/os/seastore/seastore_types.h
src/test/crimson/seastore/test_seastore.cc

index 914d58562035a86306286be6d9607bdb91f72702..43e4b25a172e31432967921393b8e50703d67435 100644 (file)
@@ -86,18 +86,22 @@ public:
     const std::string &key) = 0;
 
   /**
-   * Ordered scan of key-> value mapping in omap tree
+   * omap_list
+   *
+   * Scans key/value pairs in order.
    *
    * @param omap_root: omap btree root information
    * @param t: current transaction
-   * @param start: the list keys range begin > start if present,
-   *        at beginning if std::nullopt
-   * @param max_result_size: the number of list keys,
-   *        it it is not set, list all keys after string start.
-   * @retval listed key->value mapping and next key
+   * @param start: nullopt sorts before any string, behavior
+   *        based on config.inclusive
+   * @param config: see below for params
+   * @retval listed key->value and bool indicating complete
    */
   struct omap_list_config_t {
+    /// max results to return
     size_t max_result_size = 128;
+
+    /// true denotes behavior like lower_bound, upper_bound otherwise
     bool inclusive = false;
 
     omap_list_config_t(
index 8edf97648a0f61b017c2d07b0d9f3a8e90f700d5..a38462b7cd77924e65b1e7a2cbc8ffe73072a45a 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "crimson/os/futurized_collection.h"
 
+#include "crimson/os/seastore/omap_manager/btree/btree_omap_manager.h"
 #include "crimson/os/seastore/segment_manager/ephemeral.h"
 #include "crimson/os/seastore/onode_manager.h"
 
@@ -223,6 +224,12 @@ seastar::future<struct stat> SeaStore::stat(
     );
 }
 
+using crimson::os::seastore::omap_manager::BtreeOMapManager;
+
+using omap_int_ertr_t = OMapManager::base_ertr::extend<
+  crimson::ct_error::enoent
+  >;
+
 auto
 SeaStore::omap_get_header(
   CollectionRef c,
@@ -235,36 +242,199 @@ SeaStore::omap_get_header(
 auto
 SeaStore::omap_get_values(
   CollectionRef ch,
-  const ghobject_toid,
-  const omap_keys_tkeys)
+  const ghobject_t &oid,
+  const omap_keys_t &keys)
   -> read_errorator::future<omap_values_t>
 {
+  using int_ret_t = omap_int_ertr_t::future<omap_values_t>;
   auto c = static_cast<SeastoreCollection*>(ch.get());
-  logger().debug("{} {} {}",
-                __func__, c->get_cid(), oid);
-  return seastar::make_ready_future<omap_values_t>();
+  return repeat_with_onode<omap_values_t>(
+    c,
+    oid,
+    [this, &oid, &keys](auto &t, auto &onode) -> int_ret_t {
+      auto omap_root = onode.get_layout().omap_root.get();
+      if (omap_root.is_null()) {
+       return seastar::make_ready_future<omap_values_t>();
+      } else {
+       return seastar::do_with(
+         BtreeOMapManager(*transaction_manager),
+         omap_root,
+         omap_values_t(),
+         [&, this](auto &manager, auto &root, auto &ret) -> int_ret_t {
+           return crimson::do_for_each(
+             keys.begin(),
+             keys.end(),
+             [&, this](auto &key) {
+               return manager.omap_get_value(
+                 root,
+                 t,
+                 key
+               ).safe_then([&ret, &key](auto &&p) {
+                 if (p) {
+                   bufferlist bl;
+                   bl.append(*p);
+                   ret.emplace(
+                     std::make_pair(
+                       std::move(key),
+                       std::move(bl)));
+                 }
+                 return seastar::now();
+               });
+             }).safe_then([&ret] {
+               return std::move(ret);
+             });
+         });
+      }
+    });
 }
 
-auto
-SeaStore::omap_get_values(
+SeaStore::omap_get_values_ret_t SeaStore::omap_list(
   CollectionRef ch,
   const ghobject_t &oid,
-  const std::optional<string> &start)
-  -> read_errorator::future<std::tuple<bool, SeaStore::omap_values_t>>
+  const std::optional<string> &start,
+  OMapManager::omap_list_config_t config)
 {
   auto c = static_cast<SeastoreCollection*>(ch.get());
   logger().debug(
     "{} {} {}",
     __func__, c->get_cid(), oid);
-  return seastar::make_ready_future<std::tuple<bool, omap_values_t>>(
-    std::make_tuple(false, omap_values_t()));
+  using ret_bare_t = std::tuple<bool, SeaStore::omap_values_t>;
+  using int_ret_t = omap_int_ertr_t::future<ret_bare_t>;
+  return repeat_with_onode<ret_bare_t>(
+    c,
+    oid,
+    [this, config, &oid, &start](auto &t, auto &onode) -> int_ret_t {
+      auto omap_root = onode.get_layout().omap_root.get();
+      if (omap_root.is_null()) {
+       return seastar::make_ready_future<ret_bare_t>(
+         true, omap_values_t{}
+       );
+      } else {
+       return seastar::do_with(
+         BtreeOMapManager(*transaction_manager),
+         omap_root,
+         [&, config, this](auto &manager, auto &root) -> int_ret_t {
+           return manager.omap_list(
+             root,
+             t,
+             start,
+             config
+           ).safe_then([](auto &&p) {
+             return seastar::make_ready_future<ret_bare_t>(
+               p.first, p.second
+             );
+           });
+         });
+      }
+    });
+}
+
+SeaStore::omap_get_values_ret_t SeaStore::omap_get_values(
+  CollectionRef ch,
+  const ghobject_t &oid,
+  const std::optional<string> &start)
+{
+  return omap_list(
+    ch, oid, start,
+    OMapManager::omap_list_config_t::with_inclusive(false));
 }
 
+class SeaStoreOmapIterator : public FuturizedStore::OmapIterator {
+  using omap_values_t = FuturizedStore::omap_values_t;
+
+  SeaStore &seastore;
+  CollectionRef ch;
+  const ghobject_t oid;
+
+  omap_values_t current;
+  omap_values_t::iterator iter;
+
+  seastar::future<> repopulate_from(
+    std::optional<std::string> from,
+    bool inclusive) {
+    return seastar::do_with(
+      from,
+      [this, inclusive](auto &from) {
+       return seastore.omap_list(
+         ch,
+         oid,
+         from,
+         OMapManager::omap_list_config_t::with_inclusive(inclusive)
+       ).safe_then([this](auto p) {
+         auto &[complete, values] = p;
+         current.swap(values);
+         if (current.empty()) {
+           assert(complete);
+         }
+         iter = current.begin();
+       });
+      }).handle_error(
+       crimson::ct_error::assert_all{
+         "Invalid error in SeaStoreOmapIterator::repopulate_from"
+        }
+      );
+  }
+public:
+  SeaStoreOmapIterator(
+    SeaStore &seastore,
+    CollectionRef ch,
+    const ghobject_t &oid) :
+    seastore(seastore),
+    ch(ch),
+    oid(oid),
+    iter(current.begin())
+  {}
+
+  seastar::future<> seek_to_first() final {
+    return repopulate_from(
+      std::nullopt,
+      false);
+  }
+  seastar::future<> upper_bound(const std::string &after) final {
+    return repopulate_from(
+      after,
+      false);
+  }
+  seastar::future<> lower_bound(const std::string &from) final {
+    return repopulate_from(
+      from,
+      true);
+  }
+  bool valid() const {
+    return iter != current.end();
+  }
+  seastar::future<> next() final {
+    assert(valid());
+    auto prev = iter++;
+    if (iter == current.end()) {
+      return repopulate_from(
+       prev->first,
+       false);
+    } else {
+      return seastar::now();
+    }
+  }
+  std::string key() {
+    return iter->first;
+  }
+  ceph::buffer::list value() {
+    return iter->second;
+  }
+  int status() const {
+    return 0;
+  }
+  ~SeaStoreOmapIterator() {}
+};
+
 seastar::future<FuturizedStore::OmapIteratorRef> SeaStore::get_omap_iterator(
   CollectionRef ch,
   const ghobject_t& oid)
 {
-  return seastar::make_ready_future<FuturizedStore::OmapIteratorRef>();
+  return seastar::make_ready_future<FuturizedStore::OmapIteratorRef>(
+    new SeaStoreOmapIterator(
+      *this,
+      ch,
+      oid));
 }
 
 seastar::future<std::map<uint64_t, uint64_t>> SeaStore::fiemap(
@@ -474,7 +644,42 @@ SeaStore::tm_ret SeaStore::_omap_set_values(
     "{}: {} {} keys",
     __func__, *onode, aset.size());
 
-  return tm_ertr::now();
+  return seastar::do_with(
+    BtreeOMapManager(*transaction_manager),
+    onode->get_layout().omap_root.get(),
+    std::move(aset),
+    [&ctx, &onode, this](
+      auto &omap_manager,
+      auto &onode_omap_root,
+      auto &keys
+    ) {
+
+      tm_ertr::future<> maybe_create_root =
+       !onode_omap_root.is_null() ?
+       tm_ertr::now() :
+       omap_manager.initialize_omap(*ctx.transaction
+       ).safe_then([&onode_omap_root](auto new_root) {
+         onode_omap_root = new_root;
+       });
+
+      return maybe_create_root.safe_then([&, this] {
+       return crimson::do_for_each(
+         keys.begin(),
+         keys.end(),
+         [&, this](auto &p) {
+           return omap_manager.omap_set_key(
+             onode_omap_root,
+             *ctx.transaction,
+             p.first,
+             p.second);
+         });
+      }).safe_then([&, this] {
+       if (onode_omap_root.must_update()) {
+         onode->get_mutable_layout(*ctx.transaction
+         ).omap_root.update(onode_omap_root);
+       }
+      });
+    });
 }
 
 SeaStore::tm_ret SeaStore::_omap_set_header(
@@ -485,18 +690,44 @@ SeaStore::tm_ret SeaStore::_omap_set_header(
   logger().debug(
     "{}: {} {} bytes",
     __func__, *onode, header.length());
+  assert(0 == "not supported yet");
   return tm_ertr::now();
 }
 
 SeaStore::tm_ret SeaStore::_omap_rmkeys(
   internal_context_t &ctx,
   OnodeRef &onode,
-  const omap_keys_t& aset)
+  const omap_keys_t& keys)
 {
   logger().debug(
     "{} {} {} keys",
-    __func__, *onode, aset.size());
-  return tm_ertr::now();
+    __func__, *onode, keys.size());
+  auto omap_root = onode->get_layout().omap_root.get();
+  if (omap_root.is_null()) {
+    return seastar::now();
+  } else {
+    return seastar::do_with(
+      BtreeOMapManager(*transaction_manager),
+      onode->get_layout().omap_root.get(),
+      [&ctx, &onode, &keys, this](
+       auto &omap_manager,
+       auto &omap_root) {
+       return crimson::do_for_each(
+         keys.begin(),
+         keys.end(),
+         [&, this](auto &p) {
+           return omap_manager.omap_rm_key(
+             omap_root,
+             *ctx.transaction,
+             p);
+         }).safe_then([&, this] {
+           if (omap_root.must_update()) {
+             onode->get_mutable_layout(*ctx.transaction
+             ).omap_root.update(omap_root);
+           }
+         });
+      });
+  }
 }
 
 SeaStore::tm_ret SeaStore::_omap_rmkeyrange(
@@ -508,6 +739,7 @@ SeaStore::tm_ret SeaStore::_omap_rmkeyrange(
   logger().debug(
     "{} {} first={} last={}",
     __func__, *onode, first, last);
+  assert(0 == "not supported yet");
   return tm_ertr::now();
 }
 
index 1d5627201e074a76cd70f7b8fd4d1235a4048741..120be167d9f35b75193e9c533dfd7791c9584f21 100644 (file)
@@ -19,6 +19,7 @@
 #include "crimson/os/futurized_store.h"
 #include "crimson/os/seastore/transaction.h"
 #include "crimson/os/seastore/onode_manager.h"
+#include "crimson/os/seastore/omap_manager.h"
 #include "crimson/os/seastore/collection_manager.h"
 
 namespace crimson::os::seastore {
@@ -79,7 +80,10 @@ public:
     const omap_keys_t& keys) final;
 
   /// Retrieves paged set of values > start (if present)
-  read_errorator::future<std::tuple<bool, omap_values_t>> omap_get_values(
+  using omap_get_values_ret_bare_t = std::tuple<bool, omap_values_t>;
+  using omap_get_values_ret_t = read_errorator::future<
+    omap_get_values_ret_bare_t>;
+  omap_get_values_ret_t omap_get_values(
     CollectionRef c,           ///< [in] collection
     const ghobject_t &oid,     ///< [in] oid
     const std::optional<std::string> &start ///< [in] start, empty for begin
@@ -195,6 +199,14 @@ private:
       });
   }
 
+
+  friend class SeaStoreOmapIterator;
+  omap_get_values_ret_t omap_list(
+    CollectionRef ch,
+    const ghobject_t &oid,
+    const std::optional<string> &_start,
+    OMapManager::omap_list_config_t config);
+
   TransactionManagerRef transaction_manager;
   CollectionManagerRef collection_manager;
   OnodeManagerRef onode_manager;
index ccffee9e5d78f6a2f28eca2a902ae45cd2c8d75b..4318d7f926ddacbd0aeada5abc7da7c52a320c8b 100644 (file)
@@ -372,6 +372,7 @@ struct omap_root_t {
   depth_t depth = 0;
   bool mutated = false;
 
+  omap_root_t() = default;
   omap_root_t(laddr_t addr, depth_t depth)
     : addr(addr),
       depth(depth) {}
index fd6f6452b504a28917f2830c789f1f0387226e5f..09d9d79c05976d5d328a36b304db0643b9c2c199 100644 (file)
@@ -52,6 +52,96 @@ struct seastore_test_t :
       coll,
       std::move(t)).get0();
   }
+
+  struct object_state_t {
+    const coll_t cid;
+    const CollectionRef coll;
+    const ghobject_t oid;
+
+    std::map<string, bufferlist> omap;
+
+    void set_omap(
+      CTransaction &t,
+      const string &key,
+      const bufferlist &val) {
+      omap[key] = val;
+      std::map<string, bufferlist> arg;
+      arg[key] = val;
+      t.omap_setkeys(
+       cid,
+       oid,
+       arg);
+    }
+
+    void set_omap(
+      SeaStore &seastore,
+      const string &key,
+      const bufferlist &val) {
+      CTransaction t;
+      set_omap(t, key, val);
+      seastore.do_transaction(
+       coll,
+       std::move(t)).get0();
+    }
+
+    void check_omap_key(
+      SeaStore &seastore,
+      const string &key) {
+      std::set<string> to_check;
+      to_check.insert(key);
+      auto result = seastore.omap_get_values(
+       coll,
+       oid,
+       to_check).unsafe_get0();
+      if (result.empty()) {
+       EXPECT_EQ(omap.find(key), omap.end());
+      } else {
+       auto iter = omap.find(key);
+       EXPECT_NE(iter, omap.end());
+       if (iter != omap.end()) {
+         EXPECT_EQ(result.size(), 1);
+         EXPECT_EQ(iter->second, result.begin()->second);
+       }
+      }
+    }
+
+    void check_omap(SeaStore &seastore) {
+      auto iter = seastore.get_omap_iterator(coll, oid).get0();
+      iter->seek_to_first().get0();
+      auto refiter = omap.begin();
+      while (true) {
+       if (!iter->valid() && refiter == omap.end())
+         break;
+
+       if (!iter->valid() || refiter->first < iter->key()) {
+         logger().debug(
+           "check_omap: misisng omap key {}",
+           refiter->first);
+         EXPECT_FALSE("missing omap key");
+         ++refiter;
+       } else if (refiter == omap.end() || refiter->first > iter->key()) {
+         logger().debug(
+           "check_omap: extra omap key {}",
+           iter->key());
+         EXPECT_FALSE("extra omap key");
+         iter->next().get0();
+       } else {
+         EXPECT_EQ(iter->value(), refiter->second);
+         iter->next().get0();
+         ++refiter;
+       }
+      }
+    }
+  };
+
+  map<ghobject_t, object_state_t> test_objects;
+  object_state_t &get_object(
+    const ghobject_t &oid) {
+    return test_objects.emplace(
+      std::make_pair(
+       oid,
+       object_state_t{coll_name, coll, oid})).first->second;
+  }
 };
 
 ghobject_t make_oid(int i) {
@@ -103,11 +193,51 @@ TEST_F(seastore_test_t, touch_stat)
       CTransaction t;
       t.touch(coll_name, test);
       do_transaction(std::move(t));
+    }
 
-      auto result = seastore->stat(
-       coll,
-       test).get0();
-      EXPECT_EQ(result.st_size, 0);
+    auto result = seastore->stat(
+      coll,
+      test).get0();
+    EXPECT_EQ(result.st_size, 0);
+  });
+}
+
+bufferlist make_bufferlist(size_t len) {
+  bufferptr ptr(len);
+  bufferlist bl;
+  bl.append(ptr);
+  return bl;
+}
+
+TEST_F(seastore_test_t, omap_test_simple)
+{
+  run_async([this] {
+    auto &test_obj = get_object(make_oid(0));
+    test_obj.set_omap(
+      *seastore,
+      "asdf",
+      make_bufferlist(128));
+    test_obj.check_omap_key(
+      *seastore,
+      "asdf");
+  });
+}
+
+TEST_F(seastore_test_t, omap_test_iterator)
+{
+  run_async([this] {
+    auto make_key = [](unsigned i) {
+      std::stringstream ss;
+      ss << "key" << i;
+      return ss.str();
+    };
+    auto &test_obj = get_object(make_oid(0));
+    for (unsigned i = 0; i < 20; ++i) {
+      test_obj.set_omap(
+       *seastore,
+       make_key(i),
+       make_bufferlist(128));
     }
+    test_obj.check_omap(*seastore);
   });
 }