#include <utility>
#include <vector>
+#include <seastar/core/thread.hh>
+
#include "crimson/common/log.h"
#include "stages/key_layout.h"
#include "tree.h"
namespace crimson::os::seastore::onode {
-class Onodes {
+/**
+ * templates to work with tree utility classes:
+ *
+ * struct ValueItem {
+ * <public members>
+ *
+ * value_size_t get_payload_size() const;
+ * static ValueItem create(std::size_t expected_size, std::size_t id);
+ * };
+ * std::ostream& operator<<(std::ostream& os, const ValueItem& item);
+ *
+ * class ValueImpl final : public Value {
+ * ...
+ *
+ * using item_t = ValueItem;
+ * void initialize(Transaction& t, const item_t& item);
+ * void validate(const item_t& item);
+ * };
+ *
+ */
+
+template <typename CursorType>
+void initialize_cursor_from_item(
+ Transaction& t,
+ const ghobject_t& key,
+ const typename decltype(std::declval<CursorType>().value())::item_t& item,
+ CursorType& cursor,
+ bool insert_success) {
+ ceph_assert(insert_success);
+ ceph_assert(!cursor.is_end());
+ ceph_assert(cursor.get_ghobj() == key);
+ auto tree_value = cursor.value();
+ tree_value.initialize(t, item);
+}
+
+
+template <typename CursorType>
+void validate_cursor_from_item(
+ const ghobject_t& key,
+ const typename decltype(std::declval<CursorType>().value())::item_t& item,
+ CursorType& cursor) {
+ ceph_assert(!cursor.is_end());
+ ceph_assert(cursor.get_ghobj() == key);
+ auto tree_value = cursor.value();
+ tree_value.validate(item);
+}
+
+template <typename ValueItem>
+class Values {
public:
- Onodes(size_t n) {
+ Values(size_t n) {
for (size_t i = 1; i <= n; ++i) {
- auto p_onode = &create(i * 8);
- onodes.push_back(p_onode);
+ auto item = create(i * 8);
+ values.push_back(item);
}
}
- Onodes(std::vector<size_t> sizes) {
+ Values(std::vector<size_t> sizes) {
for (auto& size : sizes) {
- auto p_onode = &create(size);
- onodes.push_back(p_onode);
+ auto item = create(size);
+ values.push_back(item);
}
}
- ~Onodes() = default;
+ ~Values() = default;
- const onode_t& create(size_t size) {
- ceph_assert(size <= std::numeric_limits<uint16_t>::max());
- onode_t config{static_cast<uint16_t>(size), id++};
- auto onode = onode_t::allocate(config);
- auto p_onode = onode.get();
- tracked_onodes.push_back(std::move(onode));
- return *reinterpret_cast<onode_t*>(p_onode);
+ ValueItem create(size_t size) {
+ return ValueItem::create(size, id++);
}
- const onode_t& pick() const {
- auto index = rd() % onodes.size();
- return *onodes[index];
- }
-
- const onode_t& pick_largest() const {
- return *onodes[onodes.size() - 1];
- }
-
- static void validate_cursor(
- const Btree::Cursor& cursor, const ghobject_t& key, const onode_t& onode) {
- ceph_assert(!cursor.is_end());
- ceph_assert(cursor.get_ghobj() == key);
- ceph_assert(cursor.value());
- ceph_assert(cursor.value() != &onode);
- ceph_assert(*cursor.value() == onode);
- onode_t::validate_tail_magic(*cursor.value());
+ ValueItem pick() const {
+ auto index = rd() % values.size();
+ return values[index];
}
private:
- uint16_t id = 0;
+ std::size_t id = 0;
mutable std::random_device rd;
- std::vector<const onode_t*> onodes;
- std::vector<std::unique_ptr<char[]>> tracked_onodes;
+ std::vector<ValueItem> values;
};
+template <typename ValueItem>
class KVPool {
- struct kv_conf_t {
- unsigned index2;
- unsigned index1;
- unsigned index0;
- size_t ns_size;
- size_t oid_size;
- const onode_t* p_value;
-
- ghobject_t get_ghobj() const {
- assert(index1 < 10);
- std::ostringstream os_ns;
- os_ns << "ns" << index1;
- unsigned current_size = (unsigned)os_ns.tellp();
- assert(ns_size >= current_size);
- os_ns << std::string(ns_size - current_size, '_');
+ public:
+ struct kv_t {
+ ghobject_t key;
+ ValueItem value;
+ };
+ using kv_vector_t = std::vector<kv_t>;
+ using kvptr_vector_t = std::vector<kv_t*>;
+ using iterator_t = typename kvptr_vector_t::iterator;
- std::ostringstream os_oid;
- os_oid << "oid" << index1;
- current_size = (unsigned)os_oid.tellp();
- assert(oid_size >= current_size);
- os_oid << std::string(oid_size - current_size, '_');
+ size_t size() const {
+ return kvs.size();
+ }
+
+ 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();
+ }
- return ghobject_t(shard_id_t(index2), index2, index2,
- os_ns.str(), os_oid.str(), index0, index0);
+ void shuffle() {
+ std::random_shuffle(random_p_kvs.begin(), random_p_kvs.end());
+ }
+
+ void erase_from_random(iterator_t begin, iterator_t end) {
+ random_p_kvs.erase(begin, end);
+ kv_vector_t new_kvs;
+ for (auto p_kv : random_p_kvs) {
+ new_kvs.emplace_back(*p_kv);
}
- };
- using kv_vector_t = std::vector<kv_conf_t>;
+ std::sort(new_kvs.begin(), new_kvs.end(), [](auto& l, auto& r) {
+ return l.key < r.key;
+ });
- public:
- using kv_t = std::pair<ghobject_t, const onode_t*>;
-
- KVPool(const std::vector<size_t>& str_sizes,
- const std::vector<size_t>& onode_sizes,
- const std::pair<unsigned, unsigned>& range2,
- const std::pair<unsigned, unsigned>& range1,
- const std::pair<unsigned, unsigned>& range0)
- : str_sizes{str_sizes}, onodes{onode_sizes} {
+ kvs.swap(new_kvs);
+ serial_p_kvs.resize(kvs.size());
+ random_p_kvs.resize(kvs.size());
+ init();
+ }
+
+ static KVPool create_raw_range(
+ const std::vector<size_t>& ns_sizes,
+ const std::vector<size_t>& oid_sizes,
+ const std::vector<size_t>& value_sizes,
+ const std::pair<index_t, index_t>& range2,
+ const std::pair<index_t, index_t>& range1,
+ const std::pair<index_t, index_t>& range0) {
ceph_assert(range2.first < range2.second);
- ceph_assert(range2.second - 1 <= (unsigned)std::numeric_limits<shard_t>::max());
- ceph_assert(range2.second - 1 <= std::numeric_limits<crush_hash_t>::max());
+ ceph_assert(range2.second - 1 <= MAX_SHARD);
+ ceph_assert(range2.second - 1 <= MAX_CRUSH);
ceph_assert(range1.first < range1.second);
ceph_assert(range1.second - 1 <= 9);
ceph_assert(range0.first < range0.second);
+
+ kv_vector_t kvs;
std::random_device rd;
- for (unsigned i = range2.first; i < range2.second; ++i) {
- for (unsigned j = range1.first; j < range1.second; ++j) {
- auto ns_size = (unsigned)str_sizes[rd() % str_sizes.size()];
- auto oid_size = (unsigned)str_sizes[rd() % str_sizes.size()];
- for (unsigned k = range0.first; k < range0.second; ++k) {
- kvs.emplace_back(kv_conf_t{i, j, k, ns_size, oid_size, &onodes.pick()});
+ Values<ValueItem> values{value_sizes};
+ for (index_t i = range2.first; i < range2.second; ++i) {
+ for (index_t j = range1.first; j < range1.second; ++j) {
+ size_t ns_size;
+ size_t oid_size;
+ if (j == 0) {
+ // store ns0, oid0 as empty strings for test purposes
+ ns_size = 0;
+ oid_size = 0;
+ } else {
+ ns_size = ns_sizes[rd() % ns_sizes.size()];
+ oid_size = oid_sizes[rd() % oid_sizes.size()];
+ assert(ns_size && oid_size);
+ }
+ for (index_t k = range0.first; k < range0.second; ++k) {
+ kvs.emplace_back(
+ kv_t{make_raw_oid(i, j, k, ns_size, oid_size), values.pick()}
+ );
}
}
}
- random_kvs = kvs;
- std::random_shuffle(random_kvs.begin(), random_kvs.end());
+ return KVPool(std::move(kvs));
}
- 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_kv() const {
- assert(!is_end());
- auto& conf = (*p_kvs)[i];
- return std::make_pair(conf.get_ghobj(), conf.p_value);
- }
- bool is_end() const { return !p_kvs || i >= p_kvs->size(); }
- size_t index() const { return i; }
-
- iterator_t& operator++() {
- assert(!is_end());
- ++i;
- return *this;
+ 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));
+ }
- iterator_t operator++(int) {
- iterator_t tmp = *this;
- ++*this;
- return tmp;
- }
+ private:
+ KVPool(kv_vector_t&& _kvs)
+ : kvs(std::move(_kvs)), serial_p_kvs(kvs.size()), random_p_kvs(kvs.size()) {
+ init();
+ }
- private:
- iterator_t(const kv_vector_t& kvs) : p_kvs{&kvs} {}
+ void init() {
+ std::transform(kvs.begin(), kvs.end(), serial_p_kvs.begin(),
+ [] (kv_t& item) { return &item; });
+ std::transform(kvs.begin(), kvs.end(), random_p_kvs.begin(),
+ [] (kv_t& item) { return &item; });
+ shuffle();
+ }
- const kv_vector_t* p_kvs = nullptr;
- size_t i = 0;
- friend class KVPool;
- };
+ static ghobject_t make_raw_oid(
+ index_t index2, index_t index1, index_t index0,
+ size_t ns_size, size_t oid_size) {
+ assert(index1 < 10);
+ std::ostringstream os_ns;
+ std::ostringstream os_oid;
+ if (index1 == 0) {
+ assert(!ns_size);
+ assert(!oid_size);
+ } else {
+ os_ns << "ns" << index1;
+ auto current_size = (size_t)os_ns.tellp();
+ assert(ns_size >= current_size);
+ os_ns << std::string(ns_size - current_size, '_');
- iterator_t begin() const {
- return iterator_t(kvs);
- }
+ os_oid << "oid" << index1;
+ current_size = (size_t)os_oid.tellp();
+ assert(oid_size >= current_size);
+ os_oid << std::string(oid_size - current_size, '_');
+ }
- iterator_t random_begin() const {
- return iterator_t(random_kvs);
+ return ghobject_t(shard_id_t(index2), index2, index2,
+ os_ns.str(), os_oid.str(), index0, index0);
}
- size_t size() const {
- return kvs.size();
+ 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.set_shard(shard_id_t(0));
+ ret.hobj.nspace = "asdf";
+ return ret;
}
- private:
- std::vector<size_t> str_sizes;
- Onodes onodes;
kv_vector_t kvs;
- kv_vector_t random_kvs;
+ kvptr_vector_t serial_p_kvs;
+ kvptr_vector_t random_p_kvs;
};
-template <bool TRACK>
+template <bool TRACK, typename ValueImpl>
class TreeBuilder {
public:
- using ertr = Btree::btree_ertr;
- template <class ValueT=void>
- using future = ertr::future<ValueT>;
+ using BtreeImpl = Btree<ValueImpl>;
+ using BtreeCursor = typename BtreeImpl::Cursor;
+ using ValueItem = typename ValueImpl::item_t;
+ using iterator_t = typename KVPool<ValueItem>::iterator_t;
- TreeBuilder(KVPool& kvs, NodeExtentManagerURef&& nm)
+ TreeBuilder(KVPool<ValueItem>& kvs, NodeExtentManagerURef&& nm)
: kvs{kvs} {
tree.emplace(std::move(nm));
}
- future<> bootstrap(Transaction& t) {
+ eagain_ifuture<> bootstrap(Transaction& t) {
std::ostringstream oss;
#ifndef NDEBUG
oss << "debug=on, ";
return tree->mkfs(t);
}
- future<> insert(Transaction& t) {
- kv_iter = kvs.random_begin();
- auto cursors = seastar::make_lw_shared<std::vector<Btree::Cursor>>();
- 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()) {
- return ertr::make_ready_future<bool>(true);
- }
- auto [key, p_value] = kv_iter.get_kv();
- logger().debug("[{}] {} -> {}", kv_iter.index(), key_hobj_t{key}, *p_value);
- return tree->insert(t, key, *p_value
- ).safe_then([&t, this, cursors](auto ret) {
- auto& [cursor, success] = ret;
- assert(success == true);
- if constexpr (TRACK) {
- cursors->emplace_back(cursor);
- }
+ eagain_ifuture<BtreeCursor> insert_one(
+ Transaction& t, const iterator_t& iter_rd) {
+ auto p_kv = *iter_rd;
+ logger().debug("[{}] insert {} -> {}",
+ iter_rd - 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()}
+ ).si_then([&t, this, p_kv](auto ret) {
+ auto success = ret.second;
+ auto cursor = std::move(ret.first);
+ initialize_cursor_from_item(t, p_kv->key, p_kv->value, cursor, success);
#ifndef NDEBUG
- auto [key, p_value] = kv_iter.get_kv();
- Onodes::validate_cursor(cursor, key, *p_value);
- return tree->lower_bound(t, key).safe_then([this, cursor](auto cursor_) {
- auto [key, p_value] = kv_iter.get_kv();
- ceph_assert(cursor_.get_ghobj() == key);
- ceph_assert(cursor_.value() == cursor.value());
- ++kv_iter;
- return ertr::make_ready_future<bool>(false);
- });
+ validate_cursor_from_item(p_kv->key, p_kv->value, cursor);
+ return tree->find(t, p_kv->key
+ ).si_then([cursor, p_kv](auto cursor_) mutable {
+ assert(!cursor_.is_end());
+ 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_);
+ return cursor;
+ });
#else
- ++kv_iter;
- return ertr::make_ready_future<bool>(false);
+ return eagain_iertr::make_ready_future<BtreeCursor>(cursor);
#endif
- });
- }).safe_then([&t, this, start_time, cursors] {
- std::chrono::duration<double> duration = mono_clock::now() - start_time;
- logger().warn("Insert done! {}s", duration.count());
+ }).handle_error_interruptible(
+ [] (const crimson::ct_error::value_too_large& e) {
+ ceph_abort("impossible path");
+ },
+ crimson::ct_error::pass_further_all{}
+ );
+ }
+
+ eagain_ifuture<> insert(Transaction& t) {
+ auto ref_kv_iter = seastar::make_lw_shared<iterator_t>();
+ *ref_kv_iter = kvs.random_begin();
+ auto cursors = seastar::make_lw_shared<std::vector<BtreeCursor>>();
+ logger().warn("start inserting {} kvs ...", kvs.size());
+ auto start_time = mono_clock::now();
+ return trans_intr::repeat([&t, this, cursors, ref_kv_iter,
+ start_time]()
+ -> eagain_ifuture<seastar::stop_iteration> {
+ if (*ref_kv_iter == kvs.random_end()) {
+ std::chrono::duration<double> duration = mono_clock::now() - start_time;
+ logger().warn("Insert done! {}s", duration.count());
+ return seastar::make_ready_future<seastar::stop_iteration>(
+ seastar::stop_iteration::yes);
+ } else {
+ return insert_one(t, *ref_kv_iter
+ ).si_then([cursors, ref_kv_iter] (auto cursor) {
+ if constexpr (TRACK) {
+ cursors->emplace_back(cursor);
+ }
+ ++(*ref_kv_iter);
+ return seastar::stop_iteration::no;
+ });
+ }
+ }).si_then([&t, this, cursors, ref_kv_iter] {
if (!cursors->empty()) {
logger().info("Verifing tracked cursors ...");
- kv_iter = kvs.random_begin();
+ *ref_kv_iter = kvs.random_begin();
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()) {
+ cursors->begin(),
+ [&t, this, cursors, ref_kv_iter] (auto& c_iter) {
+ return trans_intr::repeat(
+ [&t, this, &c_iter, cursors, ref_kv_iter] ()
+ -> eagain_ifuture<seastar::stop_iteration> {
+ if (*ref_kv_iter == kvs.random_end()) {
logger().info("Verify done!");
- return ertr::make_ready_future<bool>(true);
+ return seastar::make_ready_future<seastar::stop_iteration>(
+ seastar::stop_iteration::yes);
}
assert(c_iter != cursors->end());
- auto [k, v] = kv_iter.get_kv();
+ auto p_kv = **ref_kv_iter;
// validate values in tree keep intact
- return tree->lower_bound(t, k).safe_then([this, &c_iter](auto cursor) {
- auto [k, v] = kv_iter.get_kv();
- Onodes::validate_cursor(cursor, k, *v);
+ return tree->find(t, p_kv->key).si_then([&c_iter, ref_kv_iter](auto cursor) {
+ auto p_kv = **ref_kv_iter;
+ validate_cursor_from_item(p_kv->key, p_kv->value, cursor);
// validate values in cursors keep intact
- Onodes::validate_cursor(*c_iter, k, *v);
- ++kv_iter;
+ validate_cursor_from_item(p_kv->key, p_kv->value, *c_iter);
+ ++(*ref_kv_iter);
++c_iter;
- return ertr::make_ready_future<bool>(false);
+ return seastar::stop_iteration::no;
});
});
});
} else {
- return ertr::now();
+ return eagain_iertr::now();
}
});
}
- future<> get_stats(Transaction& t) {
+ eagain_ifuture<> erase_one(
+ Transaction& t, const iterator_t& iter_rd) {
+ auto p_kv = *iter_rd;
+ logger().debug("[{}] erase {} -> {}",
+ iter_rd - kvs.random_begin(),
+ key_hobj_t{p_kv->key},
+ p_kv->value);
+ return tree->erase(t, p_kv->key
+ ).si_then([&t, this, p_kv] (auto size) {
+ ceph_assert(size == 1);
+#ifndef NDEBUG
+ return tree->contains(t, p_kv->key
+ ).si_then([] (bool ret) {
+ ceph_assert(ret == false);
+ });
+#else
+ return eagain_iertr::now();
+#endif
+ });
+ }
+
+ eagain_ifuture<> erase(Transaction& t, std::size_t erase_size) {
+ assert(erase_size <= kvs.size());
+ kvs.shuffle();
+ auto erase_end = kvs.random_begin() + erase_size;
+ auto ref_kv_iter = seastar::make_lw_shared<iterator_t>();
+ auto cursors = seastar::make_lw_shared<std::map<ghobject_t, BtreeCursor>>();
+ return eagain_iertr::now().si_then([&t, this, cursors, ref_kv_iter] {
+ (void)this; // silence clang warning for !TRACK
+ (void)t; // silence clang warning for !TRACK
+ if constexpr (TRACK) {
+ logger().info("Tracking cursors before erase ...");
+ *ref_kv_iter = kvs.begin();
+ auto start_time = mono_clock::now();
+ return trans_intr::repeat(
+ [&t, this, cursors, ref_kv_iter, start_time] ()
+ -> eagain_ifuture<seastar::stop_iteration> {
+ if (*ref_kv_iter == kvs.end()) {
+ std::chrono::duration<double> duration = mono_clock::now() - start_time;
+ logger().info("Track done! {}s", duration.count());
+ return seastar::make_ready_future<seastar::stop_iteration>(
+ seastar::stop_iteration::yes);
+ }
+ auto p_kv = **ref_kv_iter;
+ return tree->find(t, p_kv->key).si_then([cursors, ref_kv_iter](auto cursor) {
+ auto p_kv = **ref_kv_iter;
+ validate_cursor_from_item(p_kv->key, p_kv->value, cursor);
+ cursors->emplace(p_kv->key, cursor);
+ ++(*ref_kv_iter);
+ return seastar::stop_iteration::no;
+ });
+ });
+ } else {
+ return eagain_iertr::now();
+ }
+ }).si_then([&t, this, ref_kv_iter, erase_end] {
+ *ref_kv_iter = kvs.random_begin();
+ logger().warn("start erasing {}/{} kvs ...",
+ erase_end - kvs.random_begin(), kvs.size());
+ auto start_time = mono_clock::now();
+ return trans_intr::repeat([&t, this, ref_kv_iter,
+ start_time, erase_end] ()
+ -> eagain_ifuture<seastar::stop_iteration> {
+ if (*ref_kv_iter == erase_end) {
+ std::chrono::duration<double> duration = mono_clock::now() - start_time;
+ logger().warn("Erase done! {}s", duration.count());
+ return seastar::make_ready_future<seastar::stop_iteration>(
+ seastar::stop_iteration::yes);
+ } else {
+ return erase_one(t, *ref_kv_iter
+ ).si_then([ref_kv_iter] {
+ ++(*ref_kv_iter);
+ return seastar::stop_iteration::no;
+ });
+ }
+ });
+ }).si_then([this, cursors, ref_kv_iter, erase_end] {
+ if constexpr (TRACK) {
+ logger().info("Verifing tracked cursors ...");
+ *ref_kv_iter = kvs.random_begin();
+ while (*ref_kv_iter != erase_end) {
+ auto p_kv = **ref_kv_iter;
+ auto c_it = cursors->find(p_kv->key);
+ ceph_assert(c_it != cursors->end());
+ ceph_assert(c_it->second.is_end());
+ cursors->erase(c_it);
+ ++(*ref_kv_iter);
+ }
+ }
+ kvs.erase_from_random(kvs.random_begin(), erase_end);
+ if constexpr (TRACK) {
+ *ref_kv_iter = kvs.begin();
+ for (auto& [k, c] : *cursors) {
+ assert(*ref_kv_iter != kvs.end());
+ auto p_kv = **ref_kv_iter;
+ validate_cursor_from_item(p_kv->key, p_kv->value, c);
+ ++(*ref_kv_iter);
+ }
+ logger().info("Verify done!");
+ }
+ });
+ }
+
+ eagain_ifuture<> get_stats(Transaction& t) {
return tree->get_stats_slow(t
- ).safe_then([this](auto stats) {
+ ).si_then([](auto stats) {
logger().warn("{}", stats);
});
}
+ eagain_ifuture<std::size_t> height(Transaction& t) {
+ return tree->height(t);
+ }
+
void reload(NodeExtentManagerURef&& nm) {
tree.emplace(std::move(nm));
}
- future<> validate(Transaction& t) {
- logger().info("Verifing insertion ...");
+ eagain_ifuture<> validate_one(
+ Transaction& t, const iterator_t& iter_seq) {
+ assert(iter_seq != kvs.end());
+ auto next_iter = iter_seq + 1;
+ auto p_kv = *iter_seq;
+ return tree->find(t, p_kv->key
+ ).si_then([p_kv, &t] (auto cursor) {
+ validate_cursor_from_item(p_kv->key, p_kv->value, cursor);
+ return cursor.get_next(t);
+ }).si_then([next_iter, this] (auto cursor) {
+ if (next_iter == kvs.end()) {
+ ceph_assert(cursor.is_end());
+ } else {
+ auto p_kv = *next_iter;
+ validate_cursor_from_item(p_kv->key, p_kv->value, cursor);
+ }
+ });
+ }
+
+ eagain_ifuture<> validate(Transaction& t) {
+ logger().info("Verifing inserted ...");
return seastar::do_with(
- kvs.begin(), [&t, this] (auto& kvs_iter) {
- return crimson::do_until([&t, this, &kvs_iter]() -> future<bool> {
- if (kvs_iter.is_end()) {
- logger().info("Verify done!");
- return ertr::make_ready_future<bool>(true);
+ kvs.begin(),
+ [this, &t] (auto &iter) {
+ return trans_intr::repeat(
+ [this, &t, &iter]() ->eagain_iertr::future<seastar::stop_iteration> {
+ if (iter == kvs.end()) {
+ return seastar::make_ready_future<seastar::stop_iteration>(
+ seastar::stop_iteration::yes);
}
- auto [k, v] = kvs_iter.get_kv();
- return tree->lower_bound(t, k
- ).safe_then([&kvs_iter, k=k, v=v] (auto cursor) {
- Onodes::validate_cursor(cursor, k, *v);
- ++kvs_iter;
- return ertr::make_ready_future<bool>(false);
+ return validate_one(t, iter).si_then([&iter] {
+ ++iter;
+ return seastar::make_ready_future<seastar::stop_iteration>(
+ seastar::stop_iteration::no);
});
});
});
private:
static seastar::logger& logger() {
- return crimson::get_logger(ceph_subsys_filestore);
+ return crimson::get_logger(ceph_subsys_test);
}
- KVPool& kvs;
- std::optional<Btree> tree;
- KVPool::iterator_t kv_iter;
+ KVPool<ValueItem>& kvs;
+ std::optional<BtreeImpl> tree;
};
}