From: Samuel Just Date: Tue, 9 Jun 2020 19:44:41 +0000 (-0700) Subject: crimson/os/common/fixed_kv_node_layout: fix const and add replay support X-Git-Tag: v16.1.0~1882^2~13 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=e4b0e15b00e0d64707795893a10aa4c5bda32012;p=ceph.git crimson/os/common/fixed_kv_node_layout: fix const and add replay support Distinguishes between const and mutable iterators. Reworks external interface to enforce journaled mutations. Signed-off-by: Samuel Just --- diff --git a/src/crimson/common/fixed_kv_node_layout.h b/src/crimson/common/fixed_kv_node_layout.h index 874edb5744a0..422e47553586 100644 --- a/src/crimson/common/fixed_kv_node_layout.h +++ b/src/crimson/common/fixed_kv_node_layout.h @@ -11,6 +11,19 @@ namespace crimson::common { +template +struct maybe_const_t { +}; +template +struct maybe_const_t { + using type = const T*; +}; +template +struct maybe_const_t { + using type = T*; +}; + + /** * FixedKVNodeLayout * @@ -19,7 +32,7 @@ namespace crimson::common { * * Uses absl::container_internal::Layout for the actual memory layout. * - * The primary interface exposed is centered on the fixed_node_iter_t + * The primary interface exposed is centered on the iterator * and related methods. * * Also included are helpers for doing splits and merges as for a btree. @@ -29,7 +42,8 @@ template < typename K, typename KINT, typename V, - typename VINT> + typename VINT, + bool VALIDATE_INVARIANTS=true> class FixedKVNodeLayout { char *buf = nullptr; @@ -37,57 +51,65 @@ class FixedKVNodeLayout { static constexpr L layout{1, CAPACITY, CAPACITY}; public: - struct fixed_node_iter_t { + template + struct iter_t { friend class FixedKVNodeLayout; - FixedKVNodeLayout *node; + using parent_t = typename maybe_const_t::type; + + parent_t node; uint16_t offset; - fixed_node_iter_t( - FixedKVNodeLayout *parent, + iter_t( + parent_t parent, uint16_t offset) : node(parent), offset(offset) {} - fixed_node_iter_t(const fixed_node_iter_t &) = default; - fixed_node_iter_t(fixed_node_iter_t &&) = default; - fixed_node_iter_t &operator=(const fixed_node_iter_t &) = default; - fixed_node_iter_t &operator=(fixed_node_iter_t &&) = default; + iter_t(const iter_t &) = default; + iter_t(iter_t &&) = default; + iter_t &operator=(const iter_t &) = default; + iter_t &operator=(iter_t &&) = default; + + operator iter_t() const { + static_assert(!is_const); + return iter_t(node, offset); + } // Work nicely with for loops without requiring a nested type. - fixed_node_iter_t &operator*() { return *this; } - fixed_node_iter_t *operator->() { return this; } + iter_t &operator*() { return *this; } + iter_t *operator->() { return this; } - fixed_node_iter_t operator++(int) { + iter_t operator++(int) { auto ret = *this; ++offset; return ret; } - fixed_node_iter_t &operator++() { + iter_t &operator++() { ++offset; return *this; } - uint16_t operator-(const fixed_node_iter_t &rhs) const { + uint16_t operator-(const iter_t &rhs) const { assert(rhs.node == node); return offset - rhs.offset; } - fixed_node_iter_t operator+(uint16_t off) const { - return fixed_node_iter_t( + iter_t operator+(uint16_t off) const { + return iter_t( node, offset + off); } - fixed_node_iter_t operator-(uint16_t off) const { - return fixed_node_iter_t( + iter_t operator-(uint16_t off) const { + return iter_t( node, offset - off); } - bool operator==(const fixed_node_iter_t &rhs) const { + bool operator==(const iter_t &rhs) const { assert(node == rhs.node); return rhs.offset == offset; } - bool operator!=(const fixed_node_iter_t &rhs) const { + bool operator!=(const iter_t &rhs) const { return !(*this == rhs); } @@ -95,12 +117,6 @@ public: return K(node->get_key_ptr()[offset]); } - void set_key(K _lb) { - KINT lb; - lb = _lb; - node->get_key_ptr()[offset] = lb; - } - K get_next_key_or_max() const { auto next = *this + 1; if (next == node->end()) @@ -113,11 +129,7 @@ public: return V(node->get_val_ptr()[offset]); }; - void set_val(V val) { - node->get_val_ptr()[offset] = VINT(val); - } - - bool contains(K addr) { + bool contains(K addr) const { return (get_key() <= addr) && (get_next_key_or_max() > addr); } @@ -126,38 +138,223 @@ public: } private: - char *get_key_ptr() { - return reinterpret_cast(node->get_key_ptr() + offset); + void set_key(K _lb) const { + static_assert(!is_const); + KINT lb; + lb = _lb; + node->get_key_ptr()[offset] = lb; } - char *get_val_ptr() { - return reinterpret_cast(node->get_val_ptr() + offset); + void set_val(V val) const { + static_assert(!is_const); + node->get_val_ptr()[offset] = VINT(val); + } + + typename maybe_const_t::type get_key_ptr() const { + return reinterpret_cast< + typename maybe_const_t::type>( + node->get_key_ptr() + offset); + } + + typename maybe_const_t::type get_val_ptr() const { + return reinterpret_cast< + typename maybe_const_t::type>( + node->get_val_ptr() + offset); + } + }; + using const_iterator = iter_t; + using iterator = iter_t; + + struct delta_t { + enum class op_t : uint8_t { + INSERT, + REMOVE, + UPDATE, + } op; + KINT key; + VINT val; + + void replay(FixedKVNodeLayout &l) { + switch (op) { + case op_t::INSERT: { + l.insert(l.lower_bound(key), key, val); + break; + } + case op_t::REMOVE: { + auto iter = l.find(key); + assert(iter != l.end()); + l.remove(iter); + break; + } + case op_t::UPDATE: { + auto iter = l.find(key); + assert(iter != l.end()); + l.update(iter, val); + break; + } + default: + assert(0 == "Impossible"); + } + } + + bool operator==(const delta_t &rhs) const { + return op == rhs.op && + key == rhs.key && + val == rhs.val; } }; public: + class delta_buffer_t { + friend class FixedKVNode; + std::vector buffer; + public: + bool empty() const { + return buffer.empty(); + } + void insert( + const K &key, + const V &val) { + KINT k; + k = key; + buffer.push_back( + delta_t{ + delta_t::op_t::INSERT, + k, + VINT(val) + }); + } + void update( + const K &key, + const V &val) { + KINT k; + k = key; + buffer.push_back( + delta_t{ + delta_t::op_t::UPDATE, + k, + VINT(val) + }); + } + void remove(const K &key) { + KINT k; + k = key; + buffer.push_back( + delta_t{ + delta_t::op_t::REMOVE, + k, + VINT() + }); + } + void replay(FixedKVNodeLayout &node) { + for (auto &i: buffer) { + i.replay(node); + } + } + size_t get_bytes() const { + return buffer.size() * sizeof(delta_t); + } + void copy_out(char *out, size_t len) { + assert(len == get_bytes()); + ::memcpy(out, reinterpret_cast(buffer.data()), get_bytes()); + buffer.clear(); + } + void copy_in(const char *out, size_t len) { + assert(empty()); + assert(len % sizeof(delta_t) == 0); + buffer = std::vector( + reinterpret_cast(out), + reinterpret_cast(out + len)); + } + bool operator==(const delta_buffer_t &rhs) const { + return buffer == rhs.buffer; + } + }; + + void journal_insert( + const_iterator _iter, + const K &key, + const V &val, + delta_buffer_t *recorder) { + auto iter = iterator(this, _iter.offset); + if (recorder) { + recorder->insert( + key, + val); + } + insert(iter, key, val); + } + + void journal_update( + const_iterator _iter, + const V &val, + delta_buffer_t *recorder) { + auto iter = iterator(this, _iter.offset); + if (recorder) { + recorder->update(iter->get_key(), val); + } + update(iter, val); + } + + void journal_replace( + const_iterator _iter, + const K &key, + const V &val, + delta_buffer_t *recorder) { + auto iter = iterator(this, _iter.offset); + if (recorder) { + recorder->remove(iter->get_key()); + recorder->insert(key, val); + } + replace(iter, key, val); + } + + + void journal_remove( + const_iterator _iter, + delta_buffer_t *recorder) { + auto iter = iterator(this, _iter.offset); + if (recorder) { + recorder->remove(iter->get_key()); + } + remove(iter); + } + + FixedKVNodeLayout(char *buf) : buf(buf) {} - fixed_node_iter_t begin() { - return fixed_node_iter_t( + const_iterator begin() const { + return const_iterator( + this, + 0); + } + + const_iterator end() const { + return const_iterator( + this, + get_size()); + } + + iterator begin() { + return iterator( this, 0); } - fixed_node_iter_t end() { - return fixed_node_iter_t( + iterator end() { + return iterator( this, get_size()); } - fixed_node_iter_t iter_idx(uint16_t off) { - return fixed_node_iter_t( + const_iterator iter_idx(uint16_t off) const { + return const_iterator( this, off); } - fixed_node_iter_t find(K l) { + const_iterator find(K l) const { auto ret = begin(); for (; ret != end(); ++ret) { if (ret->get_key() == l) @@ -165,74 +362,65 @@ public: } return ret; } + iterator find(K l) { + const auto &tref = *this; + return iterator(this, tref.find(l).offset); + } - fixed_node_iter_t get_split_pivot() { - return iter_idx(get_size() / 2); + const_iterator lower_bound(K l) const { + auto ret = begin(); + for (; ret != end(); ++ret) { + if (ret->get_key() > l) + break; + } + return ret; + } + iterator lower_bound(K l) { + const auto &tref = *this; + return iterator(this, tref.lower_bound(l).offset); } -private: - KINT *get_key_ptr() { - return layout.template Pointer<1>(buf); + const_iterator upper_bound(K l) const { + auto ret = begin(); + for (; ret != end(); ++ret) { + if (ret->get_key() > l) + break; + } + return ret; + } + iterator upper_bound(K l) { + const auto &tref = *this; + return iterator(this, tref.upper_bound(l).offset); } - VINT *get_val_ptr() { - return layout.template Pointer<2>(buf); + const_iterator get_split_pivot() const { + return iter_idx(get_size() / 2); } -public: uint16_t get_size() const { return *layout.template Pointer<0>(buf); } - void set_size(uint16_t size) { - *layout.template Pointer<0>(buf) = size; - } - constexpr static size_t get_capacity() { return CAPACITY; } - /** - * copy_from_foreign - * - * Copies entries from [from_src, to_src) to tgt. - * - * tgt and from_src must be from different nodes. - * from_src and to_src must be from the same node. - */ - static void copy_from_foreign( - fixed_node_iter_t tgt, - fixed_node_iter_t from_src, - fixed_node_iter_t to_src) { - assert(tgt->node != from_src->node); - assert(to_src->node == from_src->node); - memcpy( - tgt->get_val_ptr(), from_src->get_val_ptr(), - to_src->get_val_ptr() - from_src->get_val_ptr()); - memcpy( - tgt->get_key_ptr(), from_src->get_key_ptr(), - to_src->get_key_ptr() - from_src->get_key_ptr()); - } + bool operator==(const FixedKVNodeLayout &rhs) const { + if (get_size() != rhs.get_size()) { + return false; + } - /** - * copy_from_local - * - * Copies entries from [from_src, to_src) to tgt. - * - * tgt, from_src, and to_src must be from the same node. - */ - static void copy_from_local( - fixed_node_iter_t tgt, - fixed_node_iter_t from_src, - fixed_node_iter_t to_src) { - assert(tgt->node == from_src->node); - assert(to_src->node == from_src->node); - memmove( - tgt->get_val_ptr(), from_src->get_val_ptr(), - to_src->get_val_ptr() - from_src->get_val_ptr()); - memmove( - tgt->get_key_ptr(), from_src->get_key_ptr(), - to_src->get_key_ptr() - from_src->get_key_ptr()); + auto iter = begin(); + auto iter2 = rhs.begin(); + while (iter != end()) { + if (iter->get_key() != iter2->get_key() || + iter->get_val() != iter2->get_val()) { + return false; + } + iter++; + iter2++; + } + return true; } /** @@ -242,7 +430,7 @@ public: */ K split_into( FixedKVNodeLayout &left, - FixedKVNodeLayout &right) { + FixedKVNodeLayout &right) const { auto piviter = get_split_pivot(); left.copy_from_foreign(left.begin(), begin(), piviter); @@ -262,8 +450,8 @@ public: * precondition: left.size() + right.size() < CAPACITY */ void merge_from( - FixedKVNodeLayout &left, - FixedKVNodeLayout &right) + const FixedKVNodeLayout &left, + const FixedKVNodeLayout &right) { copy_from_foreign( end(), @@ -286,8 +474,8 @@ public: * the left side iff prefer_left. */ static K balance_into_new_nodes( - FixedKVNodeLayout &left, - FixedKVNodeLayout &right, + const FixedKVNodeLayout &left, + const FixedKVNodeLayout &right, bool prefer_left, FixedKVNodeLayout &replacement_left, FixedKVNodeLayout &replacement_right) @@ -341,6 +529,133 @@ public: return replacement_pivot; } + +private: + void insert( + iterator iter, + const K &key, + const V &val) { + if (VALIDATE_INVARIANTS) { + if (iter != begin()) { + assert((iter - 1)->get_key() < key); + } + if (iter != end()) { + assert(iter->get_key() > key); + } + assert(get_size() < CAPACITY); + } + copy_from_local(iter + 1, iter, end()); + iter->set_key(key); + iter->set_val(val); + set_size(get_size() + 1); + } + + void update( + iterator iter, + V val) { + assert(iter != end()); + iter->set_val(val); + } + + void replace( + iterator iter, + const K &key, + const V &val) { + assert(iter != end()); + if (VALIDATE_INVARIANTS) { + if (iter != begin()) { + assert((iter - 1)->get_key() < key); + } + if ((iter + 1) != end()) { + assert((iter + 1)->get_key() > key); + } + } + iter->set_key(key); + iter->set_val(val); + } + + void remove(iterator iter) { + assert(iter != end()); + copy_from_local(iter, iter + 1, end()); + set_size(get_size() - 1); + } + + /** + * get_key_ptr + * + * Get pointer to start of key array + */ + KINT *get_key_ptr() { + return layout.template Pointer<1>(buf); + } + const KINT *get_key_ptr() const { + return layout.template Pointer<1>(buf); + } + + /** + * get_val_ptr + * + * Get pointer to start of val array + */ + VINT *get_val_ptr() { + return layout.template Pointer<2>(buf); + } + const VINT *get_val_ptr() const { + return layout.template Pointer<2>(buf); + } + + /** + * set_size + * + * Set size representation to match size + */ + void set_size(uint16_t size) { + *layout.template Pointer<0>(buf) = size; + } + + + /** + * copy_from_foreign + * + * Copies entries from [from_src, to_src) to tgt. + * + * tgt and from_src must be from different nodes. + * from_src and to_src must be from the same node. + */ + static void copy_from_foreign( + iterator tgt, + const_iterator from_src, + const_iterator to_src) { + assert(tgt->node != from_src->node); + assert(to_src->node == from_src->node); + memcpy( + tgt->get_val_ptr(), from_src->get_val_ptr(), + to_src->get_val_ptr() - from_src->get_val_ptr()); + memcpy( + tgt->get_key_ptr(), from_src->get_key_ptr(), + to_src->get_key_ptr() - from_src->get_key_ptr()); + } + + /** + * copy_from_local + * + * Copies entries from [from_src, to_src) to tgt. + * + * tgt, from_src, and to_src must be from the same node. + */ + static void copy_from_local( + iterator tgt, + iterator from_src, + iterator to_src) { + assert(tgt->node == from_src->node); + assert(to_src->node == from_src->node); + memmove( + tgt->get_val_ptr(), from_src->get_val_ptr(), + to_src->get_val_ptr() - from_src->get_val_ptr()); + memmove( + tgt->get_key_ptr(), from_src->get_key_ptr(), + to_src->get_key_ptr() - from_src->get_key_ptr()); + } }; } diff --git a/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.cc b/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.cc index beb69d1d5209..0a5c9d1fa159 100644 --- a/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.cc +++ b/src/crimson/os/seastore/lba_manager/btree/btree_lba_manager.cc @@ -194,9 +194,11 @@ BtreeLBAManager::insert_mapping_ret BtreeLBAManager::insert_mapping( } auto nroot = cache.alloc_new_extent(t, LBA_BLOCK_SIZE); nroot->set_depth(root->depth + 1); - nroot->begin()->set_key(L_ADDR_MIN); - nroot->begin()->set_val(root->get_paddr()); - nroot->set_size(1); + nroot->journal_insert( + nroot->begin(), + L_ADDR_MIN, + root->get_paddr(), + nullptr); croot->get_lba_root().lba_root_addr = nroot->get_paddr(); croot->get_lba_root().lba_depth = root->depth + 1; return nroot->split_entry(cache, t, laddr, nroot->begin(), root); diff --git a/src/crimson/os/seastore/lba_manager/btree/lba_btree_node_impl.cc b/src/crimson/os/seastore/lba_manager/btree/lba_btree_node_impl.cc index f221f68a09a9..deb9758fa9b2 100644 --- a/src/crimson/os/seastore/lba_manager/btree/lba_btree_node_impl.cc +++ b/src/crimson/os/seastore/lba_manager/btree/lba_btree_node_impl.cc @@ -206,16 +206,8 @@ LBAInternalNode::split_entry( ceph_assert(!at_max_capacity()); auto [left, right, pivot] = entry->make_split_children(c, t); - journal_remove(iter->get_key()); - journal_insert(iter->get_key(), left->get_paddr()); - journal_insert(pivot, right->get_paddr()); - - copy_from_local(iter + 1, iter, end()); - iter->set_val(maybe_generate_relative(left->get_paddr())); - iter++; - iter->set_key(pivot); - iter->set_val(maybe_generate_relative(right->get_paddr())); - set_size(get_size() + 1); + journal_update(iter, left->get_paddr(), maybe_get_delta_buffer()); + journal_insert(iter + 1, pivot, right->get_paddr(), maybe_get_delta_buffer()); c.retire_extent(t, entry); @@ -230,19 +222,6 @@ LBAInternalNode::split_entry( ); } -void LBAInternalNode::journal_remove( - laddr_t to_remove) -{ - // TODO -} - -void LBAInternalNode::journal_insert( - laddr_t to_insert, - paddr_t val) -{ - // TODO -} - LBAInternalNode::merge_ret LBAInternalNode::merge_entry( Cache &c, Transaction &t, laddr_t addr, @@ -272,13 +251,8 @@ LBAInternalNode::merge_entry( t, r); - journal_remove(riter->get_key()); - journal_remove(liter->get_key()); - journal_insert(liter->get_key(), replacement->get_paddr()); - - liter->set_val(maybe_generate_relative(replacement->get_paddr())); - copy_from_local(riter, riter + 1, end()); - set_size(get_size() - 1); + journal_update(liter, replacement->get_paddr(), maybe_get_delta_buffer()); + journal_remove(riter, maybe_get_delta_buffer()); c.retire_extent(t, l); c.retire_extent(t, r); @@ -295,16 +269,15 @@ LBAInternalNode::merge_entry( r, !donor_is_left); - journal_remove(liter->get_key()); - journal_remove(riter->get_key()); - journal_insert(liter->get_key(), replacement_l->get_paddr()); - journal_insert(pivot, replacement_r->get_paddr()); - - liter->set_val( - maybe_generate_relative(replacement_l->get_paddr())); - riter->set_key(pivot); - riter->set_val( - maybe_generate_relative(replacement_r->get_paddr())); + journal_update( + liter, + replacement_l->get_paddr(), + maybe_get_delta_buffer()); + journal_replace( + riter, + pivot, + replacement_r->get_paddr(), + maybe_get_delta_buffer()); c.retire_extent(t, l); c.retire_extent(t, r); @@ -365,25 +338,22 @@ LBALeafNode::insert_ret LBALeafNode::insert( lba_map_val_t val) { ceph_assert(!at_max_capacity()); - auto insert_pt = upper_bound(laddr); - if (insert_pt != end()) { - copy_from_local(insert_pt + 1, insert_pt, end()); - } - set_size(get_size() + 1); - insert_pt.set_key(laddr); + val.paddr = maybe_generate_relative(val.paddr); logger().debug( "LBALeafNode::insert: inserting {}~{} -> {}", laddr, val.len, val.paddr); - insert_pt.set_val(val); + + auto insert_pt = lower_bound(laddr); + journal_insert(insert_pt, laddr, val, maybe_get_delta_buffer()); + logger().debug( "LBALeafNode::insert: inserted {}~{} -> {}", insert_pt.get_key(), insert_pt.get_val().len, insert_pt.get_val().paddr); - journal_insertion(laddr, val); return insert_ret( insert_ertr::ready_future_marker{}, std::make_unique( @@ -409,41 +379,18 @@ LBALeafNode::mutate_mapping_ret LBALeafNode::mutate_mapping( auto mutated = f(mutation_pt.get_val()); if (mutated) { - mutation_pt.set_val(*mutated); - journal_mutated(laddr, *mutated); + journal_update(mutation_pt, *mutated, maybe_get_delta_buffer()); return mutate_mapping_ret( mutate_mapping_ertr::ready_future_marker{}, mutated); } else { - journal_removal(laddr); - copy_from_local(mutation_pt, mutation_pt + 1, end()); - set_size(get_size() - 1); + journal_remove(mutation_pt, maybe_get_delta_buffer()); return mutate_mapping_ret( mutate_mapping_ertr::ready_future_marker{}, mutated); } } -void LBALeafNode::journal_mutated( - laddr_t laddr, - lba_map_val_t val) -{ - // TODO -} - -void LBALeafNode::journal_insertion( - laddr_t laddr, - lba_map_val_t val) -{ - // TODO -} - -void LBALeafNode::journal_removal( - laddr_t laddr) -{ - // TODO -} - LBALeafNode::find_hole_ret LBALeafNode::find_hole( Cache &cache, Transaction &t, diff --git a/src/crimson/os/seastore/lba_manager/btree/lba_btree_node_impl.h b/src/crimson/os/seastore/lba_manager/btree/lba_btree_node_impl.h index 49611d7b299e..9d419a4138be 100644 --- a/src/crimson/os/seastore/lba_manager/btree/lba_btree_node_impl.h +++ b/src/crimson/os/seastore/lba_manager/btree/lba_btree_node_impl.h @@ -44,7 +44,7 @@ struct LBAInternalNode INTERNAL_NODE_CAPACITY, laddr_t, laddr_le_t, paddr_t, paddr_le_t> { - using internal_iterator_t = fixed_node_iter_t; + using internal_iterator_t = const_iterator; template LBAInternalNode(T&&... t) : LBANode(std::forward(t)...), @@ -53,9 +53,15 @@ struct LBAInternalNode static constexpr extent_types_t type = extent_types_t::LADDR_INTERNAL; CachedExtentRef duplicate_for_write() final { + assert(delta_buffer.empty()); return CachedExtentRef(new LBAInternalNode(*this)); }; + delta_buffer_t delta_buffer; + delta_buffer_t *maybe_get_delta_buffer() { + return is_mutation_pending() ? &delta_buffer : nullptr; + } + lookup_range_ret lookup_range( Cache &cache, Transaction &transaction, @@ -212,13 +218,6 @@ struct LBAInternalNode /// returns iterator for subtree containing laddr internal_iterator_t get_containing_child(laddr_t laddr); - - // delta operations (TODO) - void journal_remove( - laddr_t to_remove); - void journal_insert( - laddr_t to_insert, - paddr_t val); }; /** @@ -267,7 +266,7 @@ struct LBALeafNode LEAF_NODE_CAPACITY, laddr_t, laddr_le_t, lba_map_val_t, lba_map_val_le_t> { - using internal_iterator_t = fixed_node_iter_t; + using internal_iterator_t = const_iterator; template LBALeafNode(T&&... t) : LBANode(std::forward(t)...), @@ -276,9 +275,15 @@ struct LBALeafNode static constexpr extent_types_t type = extent_types_t::LADDR_LEAF; CachedExtentRef duplicate_for_write() final { + assert(delta_buffer.empty()); return CachedExtentRef(new LBALeafNode(*this)); }; + delta_buffer_t delta_buffer; + delta_buffer_t *maybe_get_delta_buffer() { + return is_mutation_pending() ? &delta_buffer : nullptr; + } + lookup_range_ret lookup_range( Cache &cache, Transaction &transaction, @@ -400,27 +405,9 @@ struct LBALeafNode } return std::make_pair(retl, retr); } - internal_iterator_t upper_bound(laddr_t l) { - auto ret = begin(); - for (; ret != end(); ++ret) { - if (ret->get_key() > l) - break; - } - return ret; - } std::pair get_leaf_entries(laddr_t addr, extent_len_t len); - - // delta operations (TODO) - void journal_mutated( - laddr_t laddr, - lba_map_val_t val); - void journal_insertion( - laddr_t laddr, - lba_map_val_t val); - void journal_removal( - laddr_t laddr); }; using LBALeafNodeRef = TCachedExtentRef; diff --git a/src/test/crimson/test_fixed_kv_node_layout.cc b/src/test/crimson/test_fixed_kv_node_layout.cc index 2ca3d3a49327..5970f0b4ebcf 100644 --- a/src/test/crimson/test_fixed_kv_node_layout.cc +++ b/src/test/crimson/test_fixed_kv_node_layout.cc @@ -2,6 +2,8 @@ // vim: ts=8 sw=2 smarttab #include +#include + #include "gtest/gtest.h" #include "crimson/common/fixed_kv_node_layout.h" @@ -16,6 +18,9 @@ struct test_val_t { bool operator==(const test_val_t &rhs) const { return rhs.t1 == t1 && rhs.t2 == t2; } + bool operator!=(const test_val_t &rhs) const { + return !(*this == rhs); + } }; struct test_val_le_t { @@ -27,9 +32,16 @@ struct test_val_le_t { test_val_le_t(const test_val_t &nv) : t1(init_le32(nv.t1)), t2(init_les32(nv.t2)) {} - operator test_val_t() { + operator test_val_t() const { return test_val_t{t1, t2}; } + + bool operator==(const test_val_t &rhs) const { + return rhs.t1 == t1 && rhs.t2 == t2; + } + bool operator!=(const test_val_t &rhs) const { + return !(*this == rhs); + } }; constexpr size_t CAPACITY = 341; @@ -42,20 +54,27 @@ struct TestNode : FixedKVNodeLayout< TestNode() : FixedKVNodeLayout(buf) { memset(buf, 0, sizeof(buf)); } + TestNode(const TestNode &rhs) + : FixedKVNodeLayout(buf) { + ::memcpy(buf, rhs.buf, sizeof(buf)); + } + + TestNode &operator=(const TestNode &rhs) { + memcpy(buf, rhs.buf, sizeof(buf)); + return *this; + } }; TEST(FixedKVNodeTest, basic) { auto node = TestNode(); ASSERT_EQ(node.get_size(), 0); - node.set_size(1); + + auto val = test_val_t{ 1, 1 }; + node.journal_insert(node.begin(), 1, val, nullptr); ASSERT_EQ(node.get_size(), 1); auto iter = node.begin(); - iter.set_key(1); ASSERT_EQ(iter.get_key(), 1); - - auto val = test_val_t{ 1, 1 }; - iter.set_val(val); ASSERT_EQ(val, iter.get_val()); ASSERT_EQ(std::numeric_limits::max(), iter.get_next_key_or_max()); @@ -66,15 +85,15 @@ TEST(FixedKVNodeTest, at_capacity) { ASSERT_EQ(CAPACITY, node.get_capacity()); ASSERT_EQ(node.get_size(), 0); - node.set_size(node.get_capacity()); - ASSERT_EQ(node.get_size(), CAPACITY); unsigned short num = 0; - for (auto &i : node) { - i.set_key(num); - i.set_val({ num, num}); + auto iter = node.begin(); + while (num < CAPACITY) { + node.journal_insert(iter, num, test_val_t{num, num}, nullptr); ++num; + ++iter; } + ASSERT_EQ(node.get_size(), CAPACITY); num = 0; for (auto &i : node) { @@ -94,14 +113,14 @@ TEST(FixedKVNodeTest, split) { ASSERT_EQ(node.get_size(), 0); - node.set_size(CAPACITY); - unsigned short num = 0; - for (auto &i : node) { - i.set_key(num); - i.set_val({ num, num}); + auto iter = node.begin(); + while (num < CAPACITY) { + node.journal_insert(iter, num, test_val_t{num, num}, nullptr); ++num; + ++iter; } + ASSERT_EQ(node.get_size(), CAPACITY); auto split_left = TestNode(); auto split_right = TestNode(); @@ -132,7 +151,6 @@ TEST(FixedKVNodeTest, split) { ASSERT_EQ(num, CAPACITY); } - TEST(FixedKVNodeTest, merge) { auto node = TestNode(); auto node2 = TestNode(); @@ -140,23 +158,25 @@ TEST(FixedKVNodeTest, merge) { ASSERT_EQ(node.get_size(), 0); ASSERT_EQ(node2.get_size(), 0); - node.set_size(CAPACITY / 2); - node2.set_size(CAPACITY / 2); - - auto total = node.get_size() + node2.get_size(); - unsigned short num = 0; - for (auto &i : node) { - i.set_key(num); - i.set_val({ num, num}); + auto iter = node.begin(); + while (num < CAPACITY/2) { + node.journal_insert(iter, num, test_val_t{num, num}, nullptr); ++num; + ++iter; } - for (auto &i : node2) { - i.set_key(num); - i.set_val({ num, num}); + iter = node2.begin(); + while (num < (2 * (CAPACITY / 2))) { + node2.journal_insert(iter, num, test_val_t{num, num}, nullptr); ++num; + ++iter; } + ASSERT_EQ(node.get_size(), CAPACITY / 2); + ASSERT_EQ(node2.get_size(), CAPACITY / 2); + + auto total = node.get_size() + node2.get_size(); + auto node_merged = TestNode(); node_merged.merge_from(node, node2); @@ -183,23 +203,25 @@ void run_balance_test(unsigned left, unsigned right, bool prefer_left) ASSERT_EQ(node.get_size(), 0); ASSERT_EQ(node2.get_size(), 0); - node.set_size(left); - node2.set_size(right); - - auto total = left + right; - unsigned short num = 0; - for (auto &i : node) { - i.set_key(num); - i.set_val({ num, num}); + auto iter = node.begin(); + while (num < left) { + node.journal_insert(iter, num, test_val_t{num, num}, nullptr); ++num; + ++iter; } - for (auto &i : node2) { - i.set_key(num); - i.set_val({ num, num}); + iter = node2.begin(); + while (num < (left + right)) { + node2.journal_insert(iter, num, test_val_t{num, num}, nullptr); ++num; + ++iter; } + ASSERT_EQ(node.get_size(), left); + ASSERT_EQ(node2.get_size(), right); + + auto total = node.get_size() + node2.get_size(); + auto node_balanced = TestNode(); auto node_balanced2 = TestNode(); TestNode::balance_into_new_nodes( @@ -253,3 +275,39 @@ TEST(FixedKVNodeTest, balanced) { run_balance_test(CAPACITY / 2, CAPACITY - 1, false); run_balance_test(CAPACITY / 2, CAPACITY / 2, false); } + +void run_replay_test( + std::vector> &&f +) { + TestNode node; + for (unsigned i = 0; i < f.size(); ++i) { + TestNode::delta_buffer_t buf; + TestNode replayed = node; + f[i](node, buf); + buf.replay(replayed); + ASSERT_EQ(node.get_size(), replayed.get_size()); + ASSERT_EQ(node, replayed); + } +} + +TEST(FixedKVNodeTest, replay) { + run_replay_test({ + [](auto &n, auto &b) { + n.journal_insert(n.lower_bound(1), 1, test_val_t{1, 1}, &b); + ASSERT_EQ(1, n.get_size()); + }, + [](auto &n, auto &b) { + n.journal_insert(n.lower_bound(3), 3, test_val_t{1, 2}, &b); + ASSERT_EQ(2, n.get_size()); + }, + [](auto &n, auto &b) { + n.journal_remove(n.find(3), &b); + ASSERT_EQ(1, n.get_size()); + }, + [](auto &n, auto &b) { + n.journal_insert(n.lower_bound(2), 2, test_val_t{5, 1}, &b); + ASSERT_EQ(2, n.get_size()); + } + }); + +}