#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"
);
}
+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,
auto
SeaStore::omap_get_values(
CollectionRef ch,
- const ghobject_t& oid,
- const omap_keys_t& keys)
+ 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(
"{}: {} {} 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(
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(
logger().debug(
"{} {} first={} last={}",
__func__, *onode, first, last);
+ assert(0 == "not supported yet");
return tm_ertr::now();
}
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) {
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);
});
}