std::vector<Child> list_children(const MasstreeIntermediatePage* page) {
  std::vector<Child> ret;
  for (MasstreeIntermediatePointerIterator it(page); it.is_valid(); it.next()) {
    VolatilePagePointer pointer = it.get_pointer().volatile_pointer_;
    Child child = {pointer, it.get_low_key(), it.get_high_key(), it.index_, it.index_mini_};
    ASSERT_ND(!pointer.is_null());
    ret.emplace_back(child);
  }
  return ret;
}
void describe_volatile_pointer(std::ostream* o_ptr, VolatilePagePointer pointer) {
  std::ostream& o = *o_ptr;
  if (pointer.is_null()) {
    o << "<VolatilePointer is_null=\"true\"/>";
    return;
  }
  o << "<VolatilePointer"
    << " node=\"" << static_cast<int>(pointer.get_numa_node())
    << "\" offset=\"" << pointer.get_offset()
    << "\" />";
}
void verify_new_root(
  thread::Thread* context,
  MasstreeIntermediatePage* new_root,
  const std::vector<Child>& new_children) {
  // this verification runs even in release mode. we must be super careful on root page.
  uint32_t count = new_children.size();
  uint32_t actual_count = count_children(new_root);
  ASSERT_ND(actual_count == count);
  if (actual_count != count) {
    LOG(FATAL) << "Child count doesn't match! expected=" << count << ", actual=" << actual_count;
  }

  ASSERT_ND(!new_root->is_border());
  ASSERT_ND(new_root->get_layer() == 0);
  ASSERT_ND(new_root->get_low_fence() == kInfimumSlice);
  ASSERT_ND(new_root->is_high_fence_supremum());

  uint32_t cur = 0;
  for (MasstreeIntermediatePointerIterator it(new_root); it.is_valid(); it.next()) {
    ASSERT_ND(it.get_pointer().snapshot_pointer_ == 0);
    VolatilePagePointer pointer = it.get_pointer().volatile_pointer_;
    ASSERT_ND(!pointer.is_null());
    if (pointer.is_null()) {
      LOG(FATAL) << "Nullptr? wtf";
    }

    const Child& child = new_children[cur];
    ASSERT_ND(pointer.is_equivalent(child.pointer_));
    ASSERT_ND(it.get_low_key() == child.low_);
    ASSERT_ND(it.get_high_key() == child.high_);
    if (!pointer.is_equivalent(child.pointer_)
        || it.get_low_key() != child.low_
        || it.get_high_key() != child.high_) {
      LOG(FATAL) << "Separator or pointer does not match!";
    }

    MasstreePage* page = context->resolve_cast<MasstreePage>(pointer);
    ASSERT_ND(page->get_low_fence() == child.low_);
    ASSERT_ND(page->get_high_fence() == child.high_);
    if (page->get_low_fence() != child.low_
      || page->get_high_fence() != child.high_) {
      LOG(FATAL) << "Fence key doesnt match!";
    }
    ++cur;
  }

  ASSERT_ND(cur == count);
}
ErrorStack MasstreeStoragePimpl::hcc_reset_all_temperature_stat_follow(
  VolatilePagePointer page_id) {
  if (page_id.is_null()) {
    MasstreePage* page = reinterpret_cast<MasstreePage*>(
      engine_->get_memory_manager()->get_global_volatile_page_resolver().resolve_offset(page_id));
    CHECK_ERROR(hcc_reset_all_temperature_stat_recurse(page));
  }
  return kRetOk;
}