#endif
}
+tree_cursor_t::future<Ref<tree_cursor_t>>
+tree_cursor_t::erase(context_t c, bool get_next)
+{
+ assert(is_tracked());
+ return ref_leaf_node->erase(c, position, get_next);
+}
+
MatchKindCMP tree_cursor_t::compare_to(
const tree_cursor_t& o, value_magic_t magic) const
{
);
}
+node_future<std::size_t> Node::erase(
+ context_t c, const key_hobj_t& key)
+{
+ return lower_bound(c, key).safe_then([c] (auto result) {
+ if (result.match() != MatchKindBS::EQ) {
+ return node_ertr::make_ready_future<std::size_t>(0);
+ }
+ auto ref_cursor = result.p_cursor;
+ return ref_cursor->erase(c, false
+ ).safe_then([ref_cursor] (auto next_cursor) {
+ assert(ref_cursor->is_invalid());
+ assert(!next_cursor);
+ return std::size_t(1);
+ });
+ });
+}
+
node_future<tree_stats_t> Node::get_tree_stats(context_t c)
{
return seastar::do_with(
}
}
+node_future<Ref<tree_cursor_t>>
+LeafNode::erase(context_t c, const search_position_t& pos, bool get_next)
+{
+ ceph_abort("not implemented");
+ return node_ertr::make_ready_future<Ref<tree_cursor_t>>(
+ tree_cursor_t::get_invalid());
+}
+
node_future<> LeafNode::extend_value(
context_t c, const search_position_t& pos, value_size_t extend_size)
{
/// Check that this is next to prv
void assert_next_to(const tree_cursor_t&, value_magic_t) const;
+ /// Erases the key-value pair from tree.
+ future<Ref<tree_cursor_t>> erase(context_t, bool get_next);
+
MatchKindCMP compare_to(const tree_cursor_t&, value_magic_t) const;
// public to Value
node_future<std::pair<Ref<tree_cursor_t>, bool>> insert(
context_t, const key_hobj_t&, value_config_t);
+ /**
+ * erase
+ *
+ * Removes a key-value pair from the sub-tree formed by this node.
+ *
+ * Returns the number of erased key-value pairs (0 or 1).
+ */
+ node_future<std::size_t> erase(context_t, const key_hobj_t&);
+
/// Recursively collects the statistics of the sub-tree formed by this node
node_future<tree_stats_t> get_tree_stats(context_t);
std::tuple<key_view_t, const value_header_t*> get_kv(const search_position_t&) const;
node_future<Ref<tree_cursor_t>> get_next_cursor(context_t, const search_position_t&);
+ /**
+ * erase
+ *
+ * Removes a key-value pair from the position.
+ *
+ * If get_next is true, returns the cursor pointing to the next key-value
+ * pair that followed the erased element, which can be nullptr if is end.
+ */
+ node_future<Ref<tree_cursor_t>> erase(
+ context_t, const search_position_t&, bool get_next);
+
template <bool VALIDATE>
void do_track_cursor(tree_cursor_t& cursor) {
if constexpr (VALIDATE) {
/**
* tree.h
*
- * An example implementation to expose tree interfaces to users. The current
- * interface design is based on:
- * - ceph::os::Transaction::create/touch/remove()
- * - ceph::ObjectStore::collection_list()
- * - ceph::BlueStore::get_onode()
- * - db->get_iterator(PREFIIX_OBJ) by ceph::BlueStore::fsck()
- *
- * TODO: Redesign the interfaces based on real onode manager requirements.
+ * A special-purpose and b-tree-based implementation that:
+ * - Fulfills requirements of OnodeManager to index ordered onode key-values;
+ * - Runs above seastore block and transaction layer;
+ * - Specially optimized for onode key structures and seastore
+ * delta/transaction semantics;
*/
namespace crimson::os::seastore::onode {
});
}
+ btree_future<Cursor> erase(Transaction& t) {
+ assert(!is_end());
+ auto this_obj = *this;
+ return p_cursor->erase(p_tree->get_context(t), true
+ ).safe_then([this_obj, this] (Ref<tree_cursor_t> next_cursor) {
+ assert(p_cursor->is_invalid());
+ if (next_cursor) {
+ assert(!next_cursor->is_end());
+ return Cursor{p_tree, next_cursor};
+ } else {
+ return Cursor{p_tree};
+ }
+ });
+ }
+
private:
Cursor(Btree* p_tree, Ref<tree_cursor_t> _p_cursor) : p_tree(p_tree) {
if (_p_cursor->is_invalid()) {
);
}
+ btree_future<Cursor> get_next(Transaction& t, Cursor& cursor) {
+ return cursor.get_next(t);
+ }
+
/*
* modifiers
*/
);
}
- btree_future<size_t> erase(Transaction& t, const ghobject_t& obj) {
- // TODO
- return btree_ertr::make_ready_future<size_t>(0u);
- }
-
- btree_future<Cursor> erase(Transaction &t, Cursor& pos) {
- // TODO
- return btree_ertr::make_ready_future<Cursor>(
- Cursor::make_end(this));
+ btree_future<std::size_t> erase(Transaction& t, const ghobject_t& obj) {
+ return seastar::do_with(
+ full_key_t<KeyT::HOBJ>(obj),
+ [this, &t](auto& key) -> btree_future<std::size_t> {
+ return get_root(t).safe_then([this, &t, &key](auto root) {
+ return root->erase(get_context(t), key);
+ });
+ }
+ );
}
- btree_future<Cursor> erase(Transaction &t, Cursor& first, Cursor& last) {
- // TODO
- return btree_ertr::make_ready_future<Cursor>(
- Cursor::make_end(this));
+ btree_future<Cursor> erase(Transaction& t, Cursor& pos) {
+ return pos.erase(t);
}
- btree_future<Cursor> erase(Transaction &t, Value &value) {
- // TODO
- return btree_ertr::make_ready_future<Cursor>(
- Cursor::make_end(this));
+ btree_future<> erase(Transaction& t, Value& value) {
+ assert(value.is_tracked());
+ auto ref_cursor = value.p_cursor;
+ return ref_cursor->erase(get_context(t), false
+ ).safe_then([ref_cursor] (auto next_cursor) {
+ assert(ref_cursor->is_invalid());
+ assert(!next_cursor);
+ });
}
/*