]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/onode-staged-tree: sizing related fixes and cleanup
authorYingxin Cheng <yingxin.cheng@intel.com>
Sat, 10 Oct 2020 06:07:28 +0000 (14:07 +0800)
committerYingxin Cheng <yingxin.cheng@intel.com>
Tue, 1 Dec 2020 04:50:54 +0000 (12:50 +0800)
* assert filled size matches during dump;
* assert estimate_split_size matches the left node size after split;
* related fixes to pass the added assertions;
* use node_offset_t where possible;

Signed-off-by: Yingxin Cheng <yingxin.cheng@intel.com>
src/crimson/os/seastore/onode_manager/staged-fltree/node_layout.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/item_iterator_stage.cc
src/crimson/os/seastore/onode_manager/staged-fltree/stages/item_iterator_stage.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/key_layout.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/node_stage.cc
src/crimson/os/seastore/onode_manager/staged-fltree/stages/node_stage.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/node_stage_layout.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/stage.h
src/crimson/os/seastore/onode_manager/staged-fltree/stages/sub_items_stage.cc
src/crimson/os/seastore/onode_manager/staged-fltree/stages/sub_items_stage.h

index c90a08b59416cffa7b277f1f3a5f01d57d3d167c..6757966c0435a6115b9186e25be1318ef3229f0a 100644 (file)
@@ -108,14 +108,9 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
     if (node_stage.keys()) {
       STAGE_T::dump(node_stage, os, "  ", size, p_start);
     } else {
-      if constexpr (NODE_TYPE == node_type_t::LEAF) {
-        return os << " empty!";
-      } else { // internal node
-        if (!node_stage.is_level_tail()) {
-          return os << " empty!";
-        } else {
-          size += node_stage_t::header_size();
-        }
+      size += node_stage_t::header_size();
+      if (NODE_TYPE == node_type_t::LEAF || !node_stage.is_level_tail()) {
+        os << " empty!";
       }
     }
     if constexpr (NODE_TYPE == node_type_t::INTERNAL) {
@@ -129,6 +124,7 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
            << "  @" << offset << "B";
       }
     }
+    assert(size == filled_size());
     return os;
   }
 
@@ -139,7 +135,7 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
        << "+" << node_stage_t::EXTENT_SIZE << std::dec
        << (node_stage.is_level_tail() ? "$" : "")
        << "(level=" << (unsigned)node_stage.level()
-       << ", filled=" << node_stage.total_size() - node_stage.free_size() << "B"
+       << ", filled=" << filled_size() << "B"
        << ", free=" << node_stage.free_size() << "B"
        << ")";
     return os;
@@ -279,11 +275,10 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
     auto& node_stage = extent.read();
     typename STAGE_T::StagedIterator split_at;
     bool is_insert_left;
+    size_t split_size = 0;
     {
       size_t empty_size = node_stage.size_before(0);
-      size_t total_size = node_stage.total_size();
-      size_t available_size = total_size - empty_size;
-      size_t filled_size = total_size - node_stage.free_size() - empty_size;
+      size_t filled_kv_size = filled_size() - empty_size;
       /** NODE_BLOCK_SIZE considerations
        *
        * Generally,
@@ -355,10 +350,9 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
        *
        * (TODO) Implement smarter logics to check when "double split" happens.
        */
-      size_t target_split_size = empty_size + (filled_size + insert_size) / 2;
-      assert(insert_size < available_size / 2);
+      size_t target_split_size = empty_size + (filled_kv_size + insert_size) / 2;
+      assert(insert_size < (node_stage.total_size() - empty_size) / 2);
 
-      size_t split_size = 0;
       std::optional<bool> _is_insert_left;
       split_at.set(node_stage);
       bool locate_nxt = STAGE_T::recursively_locate_split_inserted(
@@ -369,7 +363,7 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
                 << "), is_insert_left=" << is_insert_left
                 << ", estimated_split_size=" << split_size
                 << "(target=" << target_split_size
-                << ", current=" << node_stage.size_before(node_stage.keys())
+                << ", current=" << filled_size()
                 << ")" << std::endl;
       // split_size can be larger than target_split_size in strategy B
       // assert(split_size <= target_split_size);
@@ -435,6 +429,7 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
               << "), insert_stage=" << (int)insert_stage
               << ", insert_size=" << insert_size
               << std::endl << std::endl;
+    assert(split_size == filled_size());
     return {split_pos, is_insert_left, p_value};
   }
 
@@ -508,6 +503,13 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
   NodeLayoutT(typename extent_t::state_t state, NodeExtentRef extent)
     : extent{state, extent} {}
 
+  node_offset_t filled_size() const {
+    auto& node_stage = extent.read();
+    auto ret = node_stage.size_before(node_stage.keys());
+    assert(ret == node_stage.total_size() - node_stage.free_size());
+    return ret;
+  }
+
   extent_t extent;
 };
 
index fa006687408d282861c71a37c61a3f5e26da914e..826de16631bdd7552db80c5d1938598aa4fd26bb 100644 (file)
@@ -56,22 +56,25 @@ template <node_type_t NODE_TYPE>
 void ITER_T::update_size(
     NodeExtentMutable& mut, const ITER_T& iter, int change) {
   node_offset_t offset = iter.get_back_offset();
-  assert(change + offset > 0);
-  assert(change + offset < NODE_BLOCK_SIZE);
+  int new_size = change + offset;
+  assert(new_size > 0 && new_size < NODE_BLOCK_SIZE);
   mut.copy_in_absolute(
-      (void*)iter.get_item_range().p_end, node_offset_t(offset + change));
+      (void*)iter.get_item_range().p_end, node_offset_t(new_size));
 }
 
 template <node_type_t NODE_TYPE>
-size_t ITER_T::trim_until(NodeExtentMutable&, const ITER_T& iter) {
+node_offset_t ITER_T::trim_until(NodeExtentMutable&, const ITER_T& iter) {
   assert(iter.index() != 0);
-  return iter.p_end() - iter.p_items_start;
+  size_t ret = iter.p_end() - iter.p_items_start;
+  assert(ret < NODE_BLOCK_SIZE);
+  return ret;
 }
 
 template <node_type_t NODE_TYPE>
-size_t ITER_T::trim_at(
-    NodeExtentMutable& mut, const ITER_T& iter, size_t trimmed) {
+node_offset_t ITER_T::trim_at(
+    NodeExtentMutable& mut, const ITER_T& iter, node_offset_t trimmed) {
   size_t trim_size = iter.p_start() - iter.p_items_start + trimmed;
+  assert(trim_size < NODE_BLOCK_SIZE);
   assert(iter.get_back_offset() > trimmed);
   node_offset_t new_offset = iter.get_back_offset() - trimmed;
   mut.copy_in_absolute((void*)iter.item_range.p_end, new_offset);
index e2783c8eccd59a4ff8d4cf3dfe6c39b0a06ecf5b..745986c00092fa680ead17243137b47f3f3d479f 100644 (file)
@@ -50,11 +50,15 @@ class item_iterator_t {
     }
     return *key;
   }
-  size_t size() const {
-    return item_range.p_end - item_range.p_start + sizeof(node_offset_t);
+  node_offset_t size() const {
+    size_t ret = item_range.p_end - item_range.p_start + sizeof(node_offset_t);
+    assert(ret < NODE_BLOCK_SIZE);
+    return ret;
   };
-  size_t size_to_nxt() const {
-    return get_key().size() + sizeof(node_offset_t);
+  node_offset_t size_to_nxt() const {
+    size_t ret = get_key().size() + sizeof(node_offset_t);
+    assert(ret < NODE_BLOCK_SIZE);
+    return ret;
   }
   memory_range_t get_nxt_container() const {
     return {item_range.p_start, get_key().p_start()};
@@ -88,9 +92,9 @@ class item_iterator_t {
   static void update_size(
       NodeExtentMutable& mut, const item_iterator_t<NODE_TYPE>& iter, int change);
 
-  static size_t trim_until(NodeExtentMutable&, const item_iterator_t<NODE_TYPE>&);
-  static size_t trim_at(
-      NodeExtentMutable&, const item_iterator_t<NODE_TYPE>&, size_t trimmed);
+  static node_offset_t trim_until(NodeExtentMutable&, const item_iterator_t<NODE_TYPE>&);
+  static node_offset_t trim_at(
+      NodeExtentMutable&, const item_iterator_t<NODE_TYPE>&, node_offset_t trimmed);
 
   template <KeyT KT>
   class Appender;
index 2334c4c349830ebf63faf3ccc498f7df44a4ccf2..5c494679b87ac77086205d8b2a905d7df379abfb 100644 (file)
@@ -159,7 +159,11 @@ struct string_key_view_t {
       return p_length + sizeof(string_size_t);
     }
   }
-  size_t size() const { return length + sizeof(string_size_t); }
+  node_offset_t size() const {
+    size_t ret = length + sizeof(string_size_t);
+    assert(ret < NODE_BLOCK_SIZE);
+    return ret;
+  }
   std::string_view to_string_view() const {
     assert(type() == Type::STR);
     return {p_key, length};
@@ -283,9 +287,11 @@ struct ns_oid_view_t {
   ns_oid_view_t(const char* p_end) : nspace(p_end), oid(nspace.p_next_end()) {}
   Type type() const { return oid.type(); }
   const char* p_start() const { return oid.p_start(); }
-  size_t size() const {
+  node_offset_t size() const {
     if (type() == Type::STR) {
-      return nspace.size() + oid.size();
+      size_t ret = nspace.size() + oid.size();
+      assert(ret < NODE_BLOCK_SIZE);
+      return ret;
     } else {
       return sizeof(string_size_t);
     }
index f7f326daeac24d8ed9e997c7e077730df5099e62..817df33cd0c16b6727de45a32b9647234900a35b 100644 (file)
@@ -37,7 +37,7 @@ const char* NODE_T::p_left_bound() const {
 }
 
 template <typename FieldType, node_type_t NODE_TYPE>
-size_t NODE_T::size_to_nxt_at(size_t index) const {
+node_offset_t NODE_T::size_to_nxt_at(size_t index) const {
   assert(index < keys());
   if constexpr (FIELD_TYPE == field_type_t::N0 ||
                 FIELD_TYPE == field_type_t::N1) {
@@ -137,7 +137,7 @@ void NODE_T::update_size_at(
 }
 
 template <typename FieldType, node_type_t NODE_TYPE>
-size_t NODE_T::trim_until(
+node_offset_t NODE_T::trim_until(
     NodeExtentMutable& mut, const node_extent_t& node, size_t index) {
   assert(!node.is_level_tail());
   auto keys = node.keys();
@@ -156,18 +156,20 @@ size_t NODE_T::trim_until(
 }
 
 template <typename FieldType, node_type_t NODE_TYPE>
-size_t NODE_T::trim_at(
-    NodeExtentMutable& mut, const node_extent_t& node, size_t index, size_t trimmed) {
+node_offset_t NODE_T::trim_at(
+    NodeExtentMutable& mut, const node_extent_t& node,
+    size_t index, node_offset_t trimmed) {
   assert(!node.is_level_tail());
   auto keys = node.keys();
   assert(index < keys);
   if constexpr (std::is_same_v<FieldType, internal_fields_3_t>) {
     assert(false && "not implemented");
   } else {
-    auto offset = node.p_fields->get_item_start_offset(index);
-    assert(offset + trimmed < node.p_fields->get_item_end_offset(index));
+    node_offset_t offset = node.p_fields->get_item_start_offset(index);
+    size_t new_offset = offset + trimmed;
+    assert(new_offset < node.p_fields->get_item_end_offset(index));
     mut.copy_in_absolute(const_cast<void*>(node.p_fields->p_offset(index)),
-                         node_offset_t(offset + trimmed));
+                         node_offset_t(new_offset));
     mut.copy_in_absolute(
         (void*)&node.p_fields->num_keys, num_keys_t(index + 1));
   }
index 4edeab5912ff3eb94bf4e9a981d155549e2f0792..c39f115a63b30053ffc09e95089f34b05dc795e2 100644 (file)
@@ -45,10 +45,10 @@ class node_extent_t {
 
   bool is_level_tail() const { return p_fields->is_level_tail(); }
   level_t level() const { return p_fields->header.level; }
-  size_t free_size() const {
+  node_offset_t free_size() const {
     return p_fields->template free_size_before<NODE_TYPE>(keys());
   }
-  size_t total_size() const { return p_fields->total_size(); }
+  node_offset_t total_size() const { return p_fields->total_size(); }
   const char* p_left_bound() const;
   template <node_type_t T = NODE_TYPE>
   std::enable_if_t<T == node_type_t::INTERNAL, const laddr_packed_t*>
@@ -70,12 +70,12 @@ class node_extent_t {
   static constexpr auto CONTAINER_TYPE = ContainerType::INDEXABLE;
   size_t keys() const { return p_fields->num_keys; }
   key_get_type operator[] (size_t index) const { return p_fields->get_key(index); }
-  size_t size_before(size_t index) const {
+  node_offset_t size_before(size_t index) const {
     auto free_size = p_fields->template free_size_before<NODE_TYPE>(index);
     assert(total_size() >= free_size);
     return total_size() - free_size;
   }
-  size_t size_to_nxt_at(size_t index) const;
+  node_offset_t size_to_nxt_at(size_t index) const;
   memory_range_t get_nxt_container(size_t index) const;
 
   template <typename T = FieldType>
@@ -145,9 +145,10 @@ class node_extent_t {
   static void update_size_at(
       NodeExtentMutable&, const node_extent_t&, size_t index, int change);
 
-  static size_t trim_until(NodeExtentMutable&, const node_extent_t&, size_t index);
-  static size_t trim_at(NodeExtentMutable&, const node_extent_t&,
-                        size_t index, size_t trimmed);
+  static node_offset_t trim_until(
+      NodeExtentMutable&, const node_extent_t&, size_t index);
+  static node_offset_t trim_at(NodeExtentMutable&, const node_extent_t&,
+                        size_t index, node_offset_t trimmed);
 
   template <KeyT KT>
   class Appender;
index a79a364b3d69379564ffbdc1c579e653984bb8f5..ef31957fbb7ed74552dd48d9b15c32746f730ae7 100644 (file)
@@ -112,7 +112,7 @@ struct _node_fields_013_t {
     sizeof(node_header_t) + sizeof(num_keys_t);
 
   bool is_level_tail() const { return header.get_is_level_tail(); }
-  size_t total_size() const { return SIZE; }
+  node_offset_t total_size() const { return SIZE; }
   key_get_type get_key(size_t index) const {
     assert(index < num_keys);
     return slots[index].key;
@@ -199,7 +199,7 @@ struct node_fields_2_t {
     sizeof(node_header_t) + sizeof(num_keys_t);
 
   bool is_level_tail() const { return header.get_is_level_tail(); }
-  size_t total_size() const { return SIZE; }
+  node_offset_t total_size() const { return SIZE; }
   key_get_type get_key(size_t index) const {
     assert(index < num_keys);
     node_offset_t item_end_offset =
@@ -295,7 +295,7 @@ struct _internal_fields_3_t {
     sizeof(node_header_t) + sizeof(num_keys_t);
 
   bool is_level_tail() const { return header.get_is_level_tail(); }
-  size_t total_size() const {
+  node_offset_t total_size() const {
     if (is_level_tail()) {
       return SIZE - sizeof(snap_gen_t);
     } else {
index ef2e80a1d6348cc5d48e4ede49e55a3c1a82e5e6..7ed176eb7b360ed3fd22e13b2b2c01db888df885 100644 (file)
@@ -190,7 +190,7 @@ struct staged {
     *   operator[](size_t) const -> key_get_type
     *   size_before(size_t) const -> size_t
     *   (IS_BOTTOM) get_p_value(size_t) const -> const value_t*
-    *   (!IS_BOTTOM) size_to_nxt_at(size_t) const -> size_t
+    *   (!IS_BOTTOM) size_to_nxt_at(size_t) const -> node_offset_t
     *   (!IS_BOTTOM) get_nxt_container(size_t) const
     * static:
     *   header_size() -> node_offset_t
@@ -219,7 +219,7 @@ struct staged {
       assert(!is_end());
       return container[_index];
     }
-    size_t size_to_nxt() const {
+    node_offset_t size_to_nxt() const {
       assert(!is_end());
       return container.size_to_nxt_at(_index);
     }
@@ -237,9 +237,10 @@ struct staged {
       return _index + 1 == container.keys();
     }
     bool is_end() const { return _index == container.keys(); }
-    size_t size() const {
+    node_offset_t size() const {
       assert(!is_end());
       assert(header_size() == container.size_before(0));
+      assert(container.size_before(_index + 1) > container.size_before(_index));
       return container.size_before(_index + 1) -
              container.size_before(_index);
     }
@@ -409,13 +410,13 @@ struct staged {
       }
     }
 
-    size_t trim_until(NodeExtentMutable& mut) {
+    node_offset_t trim_until(NodeExtentMutable& mut) {
       return container_t::trim_until(mut, container, _index);
     }
 
-    template <typename T = size_t>
+    template <typename T = node_offset_t>
     std::enable_if_t<!IS_BOTTOM, T>
-    trim_at(NodeExtentMutable& mut, size_t trimmed) {
+    trim_at(NodeExtentMutable& mut, node_offset_t trimmed) {
       return container_t::trim_at(mut, container, _index, trimmed);
     }
 
@@ -424,7 +425,8 @@ struct staged {
     }
 
     template <KeyT KT>
-    static size_t estimate_insert(const full_key_t<KT>& key, const value_t& value) {
+    static node_offset_t estimate_insert(
+        const full_key_t<KT>& key, const value_t& value) {
       return container_t::template estimate_insert<KT>(key, value);
     }
 
@@ -440,8 +442,8 @@ struct staged {
      *   CONTAINER_TYPE = ContainerType::ITERATIVE
      *   index() const -> size_t
      *   get_key() const -> key_get_type
-     *   size() const -> size_t
-     *   size_to_nxt() const -> size_t
+     *   size() const -> node_offset_t
+     *   size_to_nxt() const -> node_offset_t
      *   get_nxt_container() const
      *   has_next() const -> bool
      *   operator++()
@@ -474,7 +476,7 @@ struct staged {
       assert(!is_end());
       return container.get_key();
     }
-    size_t size_to_nxt() const {
+    node_offset_t size_to_nxt() const {
       assert(!is_end());
       return container.size_to_nxt();
     }
@@ -487,7 +489,7 @@ struct staged {
       return !container.has_next();
     }
     bool is_end() const { return _is_end; }
-    size_t size() const {
+    node_offset_t size() const {
       assert(!is_end());
       return container.size();
     }
@@ -694,14 +696,14 @@ struct staged {
       to_index = index();
     }
 
-    size_t trim_until(NodeExtentMutable& mut) {
+    node_offset_t trim_until(NodeExtentMutable& mut) {
       if (is_end()) {
         return 0;
       }
       return container_t::trim_until(mut, container);
     }
 
-    size_t trim_at(NodeExtentMutable& mut, size_t trimmed) {
+    node_offset_t trim_at(NodeExtentMutable& mut, node_offset_t trimmed) {
       assert(!is_end());
       return container_t::trim_at(mut, container, trimmed);
     }
@@ -730,10 +732,10 @@ struct staged {
    *   get_key() -> key_get_type (const reference or value type)
    *   is_last() -> bool
    *   is_end() -> bool
-   *   size() -> size_t
+   *   size() -> node_offset_t
    *   (IS_BOTTOM) get_p_value() -> const value_t*
    *   (!IS_BOTTOM) get_nxt_container() -> nxt_stage::container_t
-   *   (!IS_BOTTOM) size_to_nxt() -> size_t
+   *   (!IS_BOTTOM) size_to_nxt() -> node_offset_t
    * seek:
    *   operator++() -> iterator_t&
    *   seek_at(index)
@@ -1483,7 +1485,15 @@ struct staged {
       assert(is_insert_left.has_value());
       assert(current_size <= target_size);
       if (split_iter.index() == 0) {
-        extra_size += iterator_t::header_size();
+        if (insert_index == 0) {
+          if (*is_insert_left == false) {
+            extra_size += iterator_t::header_size();
+          } else {
+            extra_size = 0;
+          }
+        } else {
+          extra_size += iterator_t::header_size();
+        }
       } else {
         extra_size = 0;
       }
@@ -1868,7 +1878,7 @@ struct staged {
    *   AT: trim happens in the current container, and the according higher
    *       stage iterator needs to be adjusted by the trimmed size.
    */
-  static std::tuple<TrimType, size_t>
+  static std::tuple<TrimType, node_offset_t>
   recursively_trim(NodeExtentMutable& mut, StagedIterator& trim_at) {
     if (!trim_at.valid()) {
       return {TrimType::BEFORE, 0u};
@@ -1881,7 +1891,7 @@ struct staged {
     if constexpr (!IS_BOTTOM) {
       auto [type, trimmed] = NXT_STAGE_T::recursively_trim(
           mut, trim_at.get_nxt());
-      size_t trim_size;
+      node_offset_t trim_size;
       if (type == TrimType::AFTER) {
         if (iter.is_last()) {
           return {TrimType::AFTER, 0u};
index 7788d283b8009a34e72aa5dc8a2abe0dd1f716df..bb3c64b97e3b98a0852297354469f63b832d1ef5 100644 (file)
@@ -28,12 +28,14 @@ template const laddr_packed_t* internal_sub_items_t::insert_at<KeyT::VIEW>(
     NodeExtentMutable&, const internal_sub_items_t&, const full_key_t<KeyT::VIEW>&,
     const laddr_packed_t&, size_t, node_offset_t, const char*);
 
-size_t internal_sub_items_t::trim_until(
+node_offset_t internal_sub_items_t::trim_until(
     NodeExtentMutable&, internal_sub_items_t& items, size_t index) {
   assert(index != 0);
   auto keys = items.keys();
   assert(index <= keys);
-  return sizeof(internal_sub_item_t) * (keys - index);
+  size_t ret = sizeof(internal_sub_item_t) * (keys - index);
+  assert(ret < NODE_BLOCK_SIZE);
+  return ret;
 }
 
 template class internal_sub_items_t::Appender<KeyT::VIEW>;
@@ -112,7 +114,7 @@ template const onode_t* leaf_sub_items_t::insert_at<KeyT::HOBJ>(
     NodeExtentMutable&, const leaf_sub_items_t&, const full_key_t<KeyT::HOBJ>&,
     const onode_t&, size_t, node_offset_t, const char*);
 
-size_t leaf_sub_items_t::trim_until(
+node_offset_t leaf_sub_items_t::trim_until(
     NodeExtentMutable& mut, leaf_sub_items_t& items, size_t index) {
   assert(index != 0);
   auto keys = items.keys();
@@ -128,7 +130,9 @@ size_t leaf_sub_items_t::trim_until(
   mut.shift_absolute(p_shift_start, p_shift_end - p_shift_start,
                      size_trim_offsets);
   mut.copy_in_absolute((void*)items.p_num_keys, num_keys_t(index));
-  return size_trim_offsets + (p_shift_start - p_items_start);
+  size_t ret = size_trim_offsets + (p_shift_start - p_items_start);
+  assert(ret < NODE_BLOCK_SIZE);
+  return ret;
 }
 
 // helper type for the visitor
index 12594d183c0d382125129829b036cdc71cd59081..cac4c48e8ac411d80bd8f1defc58539990ce0f72 100644 (file)
@@ -52,8 +52,10 @@ class internal_sub_items_t {
     assert(index < num_items);
     return (p_first_item - index)->get_key();
   }
-  size_t size_before(size_t index) const {
-    return index * sizeof(internal_sub_item_t);
+  node_offset_t size_before(size_t index) const {
+    size_t ret = index * sizeof(internal_sub_item_t);
+    assert(ret < NODE_BLOCK_SIZE);
+    return ret;
   }
   const laddr_packed_t* get_p_value(size_t index) const {
     assert(index < num_items);
@@ -74,7 +76,7 @@ class internal_sub_items_t {
       const full_key_t<KT>&, const laddr_packed_t&,
       size_t index, node_offset_t size, const char* p_left_bound);
 
-  static size_t trim_until(NodeExtentMutable&, internal_sub_items_t&, size_t);
+  static node_offset_t trim_until(NodeExtentMutable&, internal_sub_items_t&, size_t);
 
   template <KeyT KT>
   class Appender;
@@ -170,15 +172,18 @@ class leaf_sub_items_t {
     assert(get_item_start(index) < pointer);
     return *reinterpret_cast<const snap_gen_t*>(pointer);
   }
-  size_t size_before(size_t index) const {
+  node_offset_t size_before(size_t index) const {
     assert(index <= keys());
+    size_t ret;
     if (index == 0) {
-      return sizeof(num_keys_t);
+      ret = sizeof(num_keys_t);
+    } else {
+      --index;
+      ret = sizeof(num_keys_t) +
+            (index + 1) * sizeof(node_offset_t) +
+            get_offset(index).value;
     }
-    --index;
-    auto ret = sizeof(num_keys_t) +
-               (index + 1) * sizeof(node_offset_t) +
-               get_offset(index).value;
+    assert(ret < NODE_BLOCK_SIZE);
     return ret;
   }
   const onode_t* get_p_value(size_t index) const {
@@ -202,7 +207,7 @@ class leaf_sub_items_t {
       const full_key_t<KT>&, const onode_t&,
       size_t index, node_offset_t size, const char* p_left_bound);
 
-  static size_t trim_until(NodeExtentMutable&, leaf_sub_items_t&, size_t index);
+  static node_offset_t trim_until(NodeExtentMutable&, leaf_sub_items_t&, size_t index);
 
   template <KeyT KT>
   class Appender;