]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/seastore: replace L_ADDR_MIN by obj hash in Onode
authorChunmei Liu <chunmei.liu@intel.com>
Mon, 16 Aug 2021 20:54:07 +0000 (13:54 -0700)
committerChunmei Liu <chunmei.liu@intel.com>
Mon, 16 Aug 2021 20:54:07 +0000 (13:54 -0700)
Signed-off-by: Chunmei Liu <chunmei.liu@intel.com>
14 files changed:
src/crimson/os/seastore/onode.h
src/crimson/os/seastore/onode_manager/staged-fltree/fltree_onode_manager.h
src/crimson/os/seastore/onode_manager/staged-fltree/node.cc
src/crimson/os/seastore/onode_manager/staged-fltree/node.h
src/crimson/os/seastore/onode_manager/staged-fltree/node_extent_accessor.h
src/crimson/os/seastore/onode_manager/staged-fltree/node_extent_manager.h
src/crimson/os/seastore/onode_manager/staged-fltree/node_extent_manager/dummy.h
src/crimson/os/seastore/onode_manager/staged-fltree/node_extent_manager/seastore.h
src/crimson/os/seastore/onode_manager/staged-fltree/node_impl.cc
src/crimson/os/seastore/onode_manager/staged-fltree/node_impl.h
src/crimson/os/seastore/onode_manager/staged-fltree/node_layout.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/key_layout.h
src/crimson/os/seastore/onode_manager/staged-fltree/value.cc
src/crimson/os/seastore/onode_manager/staged-fltree/value.h

index c556dcd36d70ee0793a44fe2d49444dca4681a83..04de0caaeaac43abf7d8cadde2912569cf530386 100644 (file)
@@ -58,6 +58,7 @@ public:
   virtual const onode_layout_t &get_layout() const = 0;
   virtual onode_layout_t &get_mutable_layout(Transaction &t) = 0;
   virtual ~Onode() = default;
+  virtual laddr_t get_hint() const = 0;
 };
 
 
index 47106a8c3466c4077cf8ee728be9a58046a660e1..814471fffbc9b0296aee95713f810f8f8c5254e5 100644 (file)
@@ -94,6 +94,9 @@ struct FLTreeOnode final : Onode, Value {
     status = status_t::DELETED;
   }
 
+  laddr_t get_hint() const final {
+    return Value::get_hint();
+  }
   ~FLTreeOnode() final {}
 };
 
index b6feac38e283c03b886892fe0d9fd87df8eaee40..da324075b172fb455c0d82cee16aad44d3478a42 100644 (file)
@@ -400,7 +400,7 @@ void Node::test_make_destructable(
 eagain_ifuture<> Node::mkfs(context_t c, RootNodeTracker& root_tracker)
 {
   LOG_PREFIX(OTree::Node::mkfs);
-  return LeafNode::allocate_root(c, root_tracker
+  return LeafNode::allocate_root(c, L_ADDR_MIN, root_tracker
   ).si_then([c, FNAME](auto ret) {
     INFOT("allocated root {}", c.t, ret->get_name());
   });
@@ -462,13 +462,13 @@ Super::URef Node::deref_super()
   return ret;
 }
 
-eagain_ifuture<> Node::upgrade_root(context_t c)
+eagain_ifuture<> Node::upgrade_root(context_t c, laddr_t hint)
 {
   LOG_PREFIX(OTree::Node::upgrade_root);
   assert(impl->field_type() == field_type_t::N0);
   auto super_to_move = deref_super();
   return InternalNode::allocate_root(
-      c, impl->level(), impl->laddr(), std::move(super_to_move)
+      c, hint, impl->level(), impl->laddr(), std::move(super_to_move)
   ).si_then([this, c, FNAME](auto new_root) {
     as_child(search_position_t::end(), new_root);
     INFOT("upgraded from {} to {}",
@@ -604,7 +604,7 @@ Node::try_merge_adjacent(
         // so use rebuild_extent() as a workaround to rebuild the node from a
         // fresh extent, thus no need to generate delta.
         auto left_addr = left_for_merge->impl->laddr();
-        return left_for_merge->rebuild_extent(c
+        return left_for_merge->rebuild_extent(c, L_ADDR_MIN
         ).si_then([c, update_index_after_merge,
                      left_addr,
                      merge_stage = merge_stage,
@@ -743,7 +743,7 @@ eagain_ifuture<Ref<Node>> Node::load(
   });
 }
 
-eagain_ifuture<NodeExtentMutable> Node::rebuild_extent(context_t c)
+eagain_ifuture<NodeExtentMutable> Node::rebuild_extent(context_t c, laddr_t hint)
 {
   LOG_PREFIX(OTree::Node::rebuild_extent);
   DEBUGT("{} ...", c.t, get_name());
@@ -752,7 +752,7 @@ eagain_ifuture<NodeExtentMutable> Node::rebuild_extent(context_t c)
 
   // note: laddr can be changed after rebuild, but we don't fix the parent
   // mapping as it is part of the merge process.
-  return impl->rebuild_extent(c);
+  return impl->rebuild_extent(c, hint);
 }
 
 eagain_ifuture<> Node::retire(context_t c, Ref<Node>&& this_ref)
@@ -1214,12 +1214,12 @@ eagain_ifuture<std::pair<Ref<Node>, Ref<Node>>> InternalNode::get_child_peers(
 }
 
 eagain_ifuture<Ref<InternalNode>> InternalNode::allocate_root(
-    context_t c, level_t old_root_level,
+    context_t c, laddr_t hint, level_t old_root_level,
     laddr_t old_root_addr, Super::URef&& super)
 {
   // support tree height up to 256
   ceph_assert(old_root_level < MAX_LEVEL);
-  return InternalNode::allocate(c, field_type_t::N0, true, old_root_level + 1
+  return InternalNode::allocate(c, hint, field_type_t::N0, true, old_root_level + 1
   ).si_then([c, old_root_addr,
                super = std::move(super)](auto fresh_node) mutable {
     auto root = fresh_node.node;
@@ -1379,7 +1379,7 @@ eagain_ifuture<> InternalNode::test_clone_root(
   assert(impl->is_level_tail());
   assert(impl->field_type() == field_type_t::N0);
   Ref<const Node> this_ref = this;
-  return InternalNode::allocate(c_other, field_type_t::N0, true, impl->level()
+  return InternalNode::allocate(c_other, L_ADDR_MIN, field_type_t::N0, true, impl->level()
   ).si_then([this, c_other, &tracker_other](auto fresh_other) {
     impl->test_copy_to(fresh_other.mut);
     auto cloned_root = fresh_other.node;
@@ -1489,10 +1489,11 @@ eagain_ifuture<Ref<InternalNode>> InternalNode::insert_or_split(
 
   // proceed to split with insert
   // assume I'm already ref-counted by caller
-  return (is_root() ? upgrade_root(c) : eagain_iertr::now()
-  ).si_then([this, c] {
+  auto hint = insert_key.get_hint();
+  return (is_root() ? upgrade_root(c, hint) : eagain_iertr::now()
+  ).si_then([this, c, hint] {
     return InternalNode::allocate(
-        c, impl->field_type(), impl->is_level_tail(), impl->level());
+        c, hint, impl->field_type(), impl->is_level_tail(), impl->level());
   }).si_then([this, insert_key, insert_child, insert_pos,
                 insert_stage=insert_stage, insert_size=insert_size,
                 outdated_child, c, FNAME](auto fresh_right) mutable {
@@ -1735,9 +1736,9 @@ void InternalNode::validate_child_inconsistent(const Node& child) const
 }
 
 eagain_ifuture<InternalNode::fresh_node_t> InternalNode::allocate(
-    context_t c, field_type_t field_type, bool is_level_tail, level_t level)
+    context_t c, laddr_t hint, field_type_t field_type, bool is_level_tail, level_t level)
 {
-  return InternalNodeImpl::allocate(c, field_type, is_level_tail, level
+  return InternalNodeImpl::allocate(c, hint, field_type, is_level_tail, level
   ).si_then([](auto&& fresh_impl) {
     auto node = Ref<InternalNode>(new InternalNode(
           fresh_impl.impl.get(), std::move(fresh_impl.impl)));
@@ -2013,7 +2014,7 @@ eagain_ifuture<> LeafNode::test_clone_root(
   assert(impl->is_level_tail());
   assert(impl->field_type() == field_type_t::N0);
   Ref<const Node> this_ref = this;
-  return LeafNode::allocate(c_other, field_type_t::N0, true
+  return LeafNode::allocate(c_other, L_ADDR_MIN, field_type_t::N0, true
   ).si_then([this, c_other, &tracker_other](auto fresh_other) {
     impl->test_copy_to(fresh_other.mut);
     auto cloned_root = fresh_other.node;
@@ -2060,9 +2061,10 @@ eagain_ifuture<Ref<tree_cursor_t>> LeafNode::insert_value(
   }
   // split and insert
   Ref<Node> this_ref = this;
-  return (is_root() ? upgrade_root(c) : eagain_iertr::now()
-  ).si_then([this, c] {
-    return LeafNode::allocate(c, impl->field_type(), impl->is_level_tail());
+  auto hint = key.get_hint();
+  return (is_root() ? upgrade_root(c, hint) : eagain_iertr::now()
+  ).si_then([this, c, hint] {
+    return LeafNode::allocate(c, hint, impl->field_type(), impl->is_level_tail());
   }).si_then([this_ref = std::move(this_ref), this, c, &key, vconf, FNAME,
                 insert_pos, insert_stage=insert_stage, insert_size=insert_size](auto fresh_right) mutable {
     auto right_node = fresh_right.node;
@@ -2096,10 +2098,10 @@ eagain_ifuture<Ref<tree_cursor_t>> LeafNode::insert_value(
 }
 
 eagain_ifuture<Ref<LeafNode>> LeafNode::allocate_root(
-    context_t c, RootNodeTracker& root_tracker)
+    context_t c, laddr_t hint, RootNodeTracker& root_tracker)
 {
   LOG_PREFIX(OTree::LeafNode::allocate_root);
-  return LeafNode::allocate(c, field_type_t::N0, true
+  return LeafNode::allocate(c, hint, field_type_t::N0, true
   ).si_then([c, &root_tracker, FNAME](auto fresh_node) {
     auto root = fresh_node.node;
     return c.nm.get_super(c.t, root_tracker
@@ -2221,9 +2223,9 @@ void LeafNode::track_erase(
 }
 
 eagain_ifuture<LeafNode::fresh_node_t> LeafNode::allocate(
-    context_t c, field_type_t field_type, bool is_level_tail)
+    context_t c, laddr_t hint, field_type_t field_type, bool is_level_tail)
 {
-  return LeafNodeImpl::allocate(c, field_type, is_level_tail
+  return LeafNodeImpl::allocate(c, hint, field_type, is_level_tail
   ).si_then([](auto&& fresh_impl) {
     auto node = Ref<LeafNode>(new LeafNode(
           fresh_impl.impl.get(), std::move(fresh_impl.impl)));
index 7597b0cf6937d31ce38c3ff6d828ca01a57a49cc..6392da50d37f18f7da2e760dd6e5f41fdf349cf9 100644 (file)
@@ -405,7 +405,7 @@ class Node
     make_root(c, std::move(_super));
   }
   void as_root(Super::URef&& _super);
-  eagain_ifuture<> upgrade_root(context_t);
+  eagain_ifuture<> upgrade_root(context_t, laddr_t);
 
   Super::URef deref_super();
 
@@ -428,7 +428,7 @@ class Node
   eagain_ifuture<> erase_node(context_t, Ref<Node>&&);
   template <bool FORCE_MERGE = false>
   eagain_ifuture<> fix_parent_index(context_t, Ref<Node>&&, bool);
-  eagain_ifuture<NodeExtentMutable> rebuild_extent(context_t);
+  eagain_ifuture<NodeExtentMutable> rebuild_extent(context_t, laddr_t);
   eagain_ifuture<> retire(context_t, Ref<Node>&&);
   void make_tail(context_t);
 
@@ -539,7 +539,7 @@ class InternalNode final : public Node {
   void track_make_tail(const search_position_t&);
 
   static eagain_ifuture<Ref<InternalNode>> allocate_root(
-      context_t, level_t, laddr_t, Super::URef&&);
+      context_t, laddr_t, level_t, laddr_t, Super::URef&&);
 
  protected:
   eagain_ifuture<Ref<tree_cursor_t>> lookup_smallest(context_t) override;
@@ -580,7 +580,7 @@ class InternalNode final : public Node {
       return std::make_pair(Ref<Node>(node), mut);
     }
   };
-  static eagain_ifuture<fresh_node_t> allocate(context_t, field_type_t, bool, level_t);
+  static eagain_ifuture<fresh_node_t> allocate(context_t, laddr_t, field_type_t, bool, level_t);
 
  private:
   /**
@@ -681,7 +681,7 @@ class LeafNode final : public Node {
       context_t, const key_hobj_t&, value_config_t,
       const search_position_t&, const MatchHistory&,
       match_stat_t mstat);
-  static eagain_ifuture<Ref<LeafNode>> allocate_root(context_t, RootNodeTracker&);
+  static eagain_ifuture<Ref<LeafNode>> allocate_root(context_t, laddr_t, RootNodeTracker&);
   friend class Node;
 
  private:
@@ -712,7 +712,7 @@ class LeafNode final : public Node {
       return std::make_pair(Ref<Node>(node), mut);
     }
   };
-  static eagain_ifuture<fresh_node_t> allocate(context_t, field_type_t, bool);
+  static eagain_ifuture<fresh_node_t> allocate(context_t, laddr_t, field_type_t, bool);
 
  private:
   /**
index b6a2f0315893a13801a4ca9897d4054033aa6810..3f8f78d3900ae48b16ca6ee368993c500f78ef37 100644 (file)
@@ -505,7 +505,7 @@ class NodeExtentAccessorT {
     std::memcpy(to.get_write(), extent->get_read(), get_length());
   }
 
-  eagain_ifuture<NodeExtentMutable> rebuild(context_t c) {
+  eagain_ifuture<NodeExtentMutable> rebuild(context_t c, laddr_t hint) {
     LOG_PREFIX(OTree::Extent::rebuild);
     assert(!is_retired());
     if (state == nextent_state_t::FRESH) {
@@ -515,7 +515,7 @@ class NodeExtentAccessorT {
     }
     assert(!extent->is_initial_pending());
     auto alloc_size = get_length();
-    return c.nm.alloc_extent(c.t, alloc_size
+    return c.nm.alloc_extent(c.t, hint, alloc_size
     ).handle_error_interruptible(
       eagain_iertr::pass_further{},
       crimson::ct_error::input_output_error::handle(
index b33c9d539b10170f20edba71d6f691b8aeb07c7c..6f7ae9245d6dca57ac2c9e7e0baf0bd2bdfb02c9 100644 (file)
@@ -77,7 +77,7 @@ class NodeExtentManager {
 
   using alloc_iertr = base_iertr;
   virtual alloc_iertr::future<NodeExtentRef> alloc_extent(
-      Transaction&, extent_len_t) = 0;
+      Transaction&, laddr_t hint, extent_len_t) = 0;
 
   using retire_iertr = base_iertr::extend<
     crimson::ct_error::enoent>;
index 2d3b3fb636dbe521335de92492897460c33b80cf..53115ba171eaebcd477a8c8f64bc022cf06477bb 100644 (file)
@@ -89,7 +89,7 @@ class DummyNodeExtentManager final: public NodeExtentManager {
   }
 
   alloc_iertr::future<NodeExtentRef> alloc_extent(
-      Transaction& t, extent_len_t len) override {
+      Transaction& t, laddr_t hint, extent_len_t len) override {
     TRACET("allocating {}B ...", t, len);
     if constexpr (SYNC) {
       return alloc_extent_sync(t, len);
index 262c10bb3fd2583cddf7d51220b24eb259513266..3ff51d0542e3be8f2488a4e2140a7ba35b40c556 100644 (file)
@@ -121,7 +121,7 @@ class SeastoreNodeExtentManager final: public TransactionManagerHandle {
   }
 
   alloc_iertr::future<NodeExtentRef> alloc_extent(
-      Transaction& t, extent_len_t len) override {
+      Transaction& t, laddr_t hint, extent_len_t len) override {
     TRACET("allocating {}B ...", t, len);
     if constexpr (INJECT_EAGAIN) {
       if (trigger_eagain()) {
@@ -130,7 +130,7 @@ class SeastoreNodeExtentManager final: public TransactionManagerHandle {
         return alloc_iertr::make_ready_future<NodeExtentRef>();
       }
     }
-    return tm.alloc_extent<SeastoreNodeExtent>(t, addr_min, len
+    return tm.alloc_extent<SeastoreNodeExtent>(t, hint, len
     ).si_then([len, &t](auto extent) {
       DEBUGT("allocated {}B at {:#x} -- {}",
              t, extent->get_length(), extent->get_laddr(), *extent);
index be1ac9b78230e57c00fdcfcf26e863e295f11eca..5db0f83dda6167d19dafed3c4a56127e0bb9795f 100644 (file)
@@ -13,16 +13,16 @@ last_split_info_t last_split = {};
 // XXX: branchless allocation
 eagain_ifuture<InternalNodeImpl::fresh_impl_t>
 InternalNodeImpl::allocate(
-    context_t c, field_type_t type, bool is_level_tail, level_t level)
+    context_t c, laddr_t hint, field_type_t type, bool is_level_tail, level_t level)
 {
   if (type == field_type_t::N0) {
-    return InternalNode0::allocate(c, is_level_tail, level);
+    return InternalNode0::allocate(c, hint, is_level_tail, level);
   } else if (type == field_type_t::N1) {
-    return InternalNode1::allocate(c, is_level_tail, level);
+    return InternalNode1::allocate(c, hint, is_level_tail, level);
   } else if (type == field_type_t::N2) {
-    return InternalNode2::allocate(c, is_level_tail, level);
+    return InternalNode2::allocate(c, hint, is_level_tail, level);
   } else if (type == field_type_t::N3) {
-    return InternalNode3::allocate(c, is_level_tail, level);
+    return InternalNode3::allocate(c, hint, is_level_tail, level);
   } else {
     ceph_abort("impossible path");
   }
@@ -30,16 +30,16 @@ InternalNodeImpl::allocate(
 
 eagain_ifuture<LeafNodeImpl::fresh_impl_t>
 LeafNodeImpl::allocate(
-    context_t c, field_type_t type, bool is_level_tail)
+    context_t c, laddr_t hint, field_type_t type, bool is_level_tail)
 {
   if (type == field_type_t::N0) {
-    return LeafNode0::allocate(c, is_level_tail, 0);
+    return LeafNode0::allocate(c, hint, is_level_tail, 0);
   } else if (type == field_type_t::N1) {
-    return LeafNode1::allocate(c, is_level_tail, 0);
+    return LeafNode1::allocate(c, hint, is_level_tail, 0);
   } else if (type == field_type_t::N2) {
-    return LeafNode2::allocate(c, is_level_tail, 0);
+    return LeafNode2::allocate(c, hint, is_level_tail, 0);
   } else if (type == field_type_t::N3) {
-    return LeafNode3::allocate(c, is_level_tail, 0);
+    return LeafNode3::allocate(c, hint, is_level_tail, 0);
   } else {
     ceph_abort("impossible path");
   }
index 8bac60bac533e6d00fc3c6206837f19c9f37b1a7..f8a8aaa1cd4bd0d8283492353108cda9acb00c9b 100644 (file)
@@ -90,7 +90,7 @@ class NodeImpl {
   virtual std::tuple<match_stage_t, search_position_t> erase(const search_position_t&) = 0;
   virtual std::tuple<match_stage_t, std::size_t> evaluate_merge(NodeImpl&) = 0;
   virtual search_position_t merge(NodeExtentMutable&, NodeImpl&, match_stage_t, extent_len_t) = 0;
-  virtual eagain_ifuture<NodeExtentMutable> rebuild_extent(context_t) = 0;
+  virtual eagain_ifuture<NodeExtentMutable> rebuild_extent(context_t, laddr_t) = 0;
   virtual eagain_ifuture<> retire_extent(context_t) = 0;
   virtual search_position_t make_tail() = 0;
 
@@ -179,7 +179,7 @@ class InternalNodeImpl : public NodeImpl {
       return {std::move(impl), mut};
     }
   };
-  static eagain_ifuture<fresh_impl_t> allocate(context_t, field_type_t, bool, level_t);
+  static eagain_ifuture<fresh_impl_t> allocate(context_t, laddr_t, field_type_t, bool, level_t);
 
   static InternalNodeImplURef load(NodeExtentRef, field_type_t);
 
@@ -259,7 +259,7 @@ class LeafNodeImpl : public NodeImpl {
       return {std::move(impl), mut};
     }
   };
-  static eagain_ifuture<fresh_impl_t> allocate(context_t, field_type_t, bool);
+  static eagain_ifuture<fresh_impl_t> allocate(context_t, laddr_t, field_type_t, bool);
 
   static LeafNodeImplURef load(NodeExtentRef, field_type_t);
 
index 4c55d49475da546d051e939a2e40a5fd217aa02e..cc1841ce9fbf9ce554373a0bd7cb78d63ab5ddea 100644 (file)
@@ -66,7 +66,7 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
   }
 
   static eagain_ifuture<typename parent_t::fresh_impl_t> allocate(
-      context_t c, bool is_level_tail, level_t level) {
+      context_t c, laddr_t hint, bool is_level_tail, level_t level) {
     LOG_PREFIX(OTree::Layout::allocate);
     extent_len_t extent_size;
     if constexpr (NODE_TYPE == node_type_t::LEAF) {
@@ -74,7 +74,7 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
     } else {
       extent_size = c.vb.get_internal_node_size();
     }
-    return c.nm.alloc_extent(c.t, extent_size
+    return c.nm.alloc_extent(c.t, hint, extent_size
     ).handle_error_interruptible(
       eagain_iertr::pass_further{},
       crimson::ct_error::input_output_error::handle(
@@ -306,8 +306,8 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
   }
 
   eagain_ifuture<NodeExtentMutable>
-  rebuild_extent(context_t c) override {
-    return extent.rebuild(c).si_then([this] (auto mut) {
+  rebuild_extent(context_t c, laddr_t hint) override {
+    return extent.rebuild(c, hint).si_then([this] (auto mut) {
       // addr may change
       build_name();
       return mut;
index e9305416c10dd9a50faa4a1d1e171479695d9d14..2bfa9efdeb9a745b1f6fbc9e2582c945e236e9d0 100644 (file)
@@ -41,6 +41,16 @@ template<> struct _full_key_type<KeyT::HOBJ> { using type = key_hobj_t; };
 template <KeyT type>
 using full_key_t = typename _full_key_type<type>::type;
 
+static laddr_t get_lba_hint(shard_t shard, pool_t pool, crush_hash_t crush)
+{
+  if (shard == shard_id_t::NO_SHARD) {
+    return (uint64_t)(pool & 0xFF)<<56 | (uint64_t)(crush)<<24;
+  } else {
+    return (uint64_t)(shard & 0X7F)<<56 | (uint64_t)(pool& 0xFF)<<48 |
+          (uint64_t)(crush)<<16;
+  }
+}
+
 struct node_offset_packed_t {
   node_offset_t value;
 } __attribute__((packed));
@@ -515,6 +525,9 @@ class key_hobj_t {
   crush_hash_t crush() const {
     return ghobj.hobj.get_hash();
   }
+  laddr_t get_hint() const {
+    return get_lba_hint(shard(), pool(), crush());
+  }
   std::string_view nspace() const {
     // TODO(cross-node string dedup)
     return ghobj.hobj.nspace;
@@ -608,6 +621,9 @@ class key_view_t {
   crush_hash_t crush() const {
     return crush_packed().crush;
   }
+  laddr_t get_hint() const {
+    return get_lba_hint(shard(), pool(), crush());
+  }
   std::string_view nspace() const {
     // TODO(cross-node string dedup)
     return ns_oid_view().nspace.to_string_view();
index 78c370b605673a09b4aea38b243a43c41f6f2d19..e71ce06453acd741fd5fbc622c2745182be17e48 100644 (file)
@@ -82,6 +82,11 @@ Value::do_prepare_mutate_payload(Transaction& t)
    return p_cursor->prepare_mutate_value_payload(get_context(t));
 }
 
+laddr_t Value::get_hint() const
+{
+  return p_cursor->get_key_view(vb.get_header_magic()).get_hint();
+}
+
 std::unique_ptr<ValueDeltaRecorder>
 build_value_recorder_by_type(ceph::bufferlist& encoded,
                              const value_magic_t& magic)
index 2bb069d1d53f85dab60c84d40074178c95792ae5..18d459969785d0f06e8a0baee67f07244899fab1 100644 (file)
@@ -201,6 +201,8 @@ class Value {
     return read_value_header()->payload_size;
   }
 
+  laddr_t get_hint() const;
+
   bool operator==(const Value& v) const { return p_cursor == v.p_cursor; }
   bool operator!=(const Value& v) const { return !(*this == v); }
 
@@ -240,7 +242,9 @@ class Value {
 
  private:
   const value_header_t* read_value_header() const;
-  context_t get_context(Transaction& t) { return {nm, vb, t}; }
+  context_t get_context(Transaction& t) {
+    return {nm, vb, t};
+  }
 
   std::pair<NodeExtentMutable&, ValueDeltaRecorder*>
   do_prepare_mutate_payload(Transaction&);