]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/seastore: convert onode unit test to use interruptible future.
authorchunmei-liu <chunmei.liu@intel.com>
Wed, 28 Jul 2021 01:23:25 +0000 (18:23 -0700)
committerchunmei-liu <chunmei.liu@intel.com>
Thu, 29 Jul 2021 09:05:36 +0000 (02:05 -0700)
Signed-off-by: chunmei-liu <chunmei.liu@intel.com>
src/test/crimson/seastore/onode_tree/test_fltree_onode_manager.cc
src/test/crimson/seastore/onode_tree/test_staged_fltree.cc

index 9804c9746d92be9e059d8866cf568c61afa22d70..294e1626a78f9c5ad1e0c46315c001b96d555321 100644 (file)
@@ -71,7 +71,7 @@ struct fltree_onode_manager_test_t
 
   virtual void _init() final {
     TMTestState::_init();
-    manager.reset(new FLTreeOnodeManager(itm));
+    manager.reset(new FLTreeOnodeManager(*tm));
   }
 
   virtual void _destroy() final {
@@ -112,18 +112,22 @@ struct fltree_onode_manager_test_t
   void with_onode_write(iterator_t& it, F&& f) {
     with_transaction([this, &it, f=std::move(f)] (auto& t) {
       auto p_kv = *it;
-      auto onode = manager->get_or_create_onode(
-          t, p_kv->key).unsafe_get0();
+      auto onode = with_trans_intr(t, [&](auto &t) {
+        return manager->get_or_create_onode(t, p_kv->key);
+      }).unsafe_get0();
       std::invoke(f, t, *onode, p_kv->value);
-      manager->write_dirty(t, {onode}).unsafe_get0();
+      with_trans_intr(t, [&](auto &t) {
+        return manager->write_dirty(t, {onode});
+      }).unsafe_get0();
     });
   }
 
   void validate_onode(iterator_t& it) {
     with_transaction([this, &it] (auto& t) {
       auto p_kv = *it;
-      auto onode = manager->get_onode(
-          t, p_kv->key).unsafe_get0();
+      auto onode = with_trans_intr(t, [&](auto &t) {
+        return manager->get_onode(t,  p_kv->key);
+      }).unsafe_get0();
       p_kv->value.validate(*onode);
     });
   }
@@ -131,8 +135,9 @@ struct fltree_onode_manager_test_t
   void validate_erased(iterator_t& it) {
     with_transaction([this, &it] (auto& t) {
       auto p_kv = *it;
-      auto exist = manager->contains_onode(
-          t, p_kv->key).unsafe_get0();
+      auto exist = with_trans_intr(t, [&](auto &t) {
+        return manager->contains_onode(t, p_kv->key);
+      }).unsafe_get0();
       ceph_assert(exist == false);
     });
   }
@@ -159,15 +164,18 @@ struct fltree_onode_manager_test_t
       const iterator_t& start, const iterator_t& end, F&& f) {
     with_onodes_process(start, end,
         [this, f=std::move(f)] (auto& t, auto& oids, auto& items) {
-      auto onodes = manager->get_or_create_onodes(
-          t, oids).unsafe_get0();
+      auto onodes = with_trans_intr(t, [&](auto &t) {
+        return manager->get_or_create_onodes(t, oids);
+      }).unsafe_get0();
       for (auto tup : boost::combine(onodes, items)) {
         OnodeRef onode;
         onode_item_t* p_item;
         boost::tie(onode, p_item) = tup;
         std::invoke(f, t, *onode, *p_item);
       }
-      manager->write_dirty(t, onodes).unsafe_get0();
+      with_trans_intr(t, [&](auto &t) {
+        return manager->write_dirty(t, onodes);
+      }).unsafe_get0();
     });
   }
 
@@ -179,7 +187,9 @@ struct fltree_onode_manager_test_t
         ghobject_t oid;
         onode_item_t* p_item;
         boost::tie(oid, p_item) = tup;
-        auto onode = manager->get_onode(t, oid).unsafe_get0();
+        auto onode = with_trans_intr(t, [&](auto &t) {
+          return manager->get_onode(t, oid);
+        }).unsafe_get0();
         p_item->validate(*onode);
       }
     });
@@ -190,8 +200,9 @@ struct fltree_onode_manager_test_t
     with_onodes_process(start, end,
         [this] (auto& t, auto& oids, auto& items) {
       for (auto& oid : oids) {
-        auto exist = manager->contains_onode(
-            t, oid).unsafe_get0();
+        auto exist = with_trans_intr(t, [&](auto &t) {
+          return manager->contains_onode(t, oid);
+        }).unsafe_get0();
         ceph_assert(exist == false);
       }
     });
@@ -208,8 +219,9 @@ struct fltree_onode_manager_test_t
       assert(start < oids[0]);
       assert(oids[0] < end);
       while (start != end) {
-        auto [list_ret, list_end] = manager->list_onodes(
-            t, start, end, LIST_LIMIT).unsafe_get0();
+        auto [list_ret, list_end] = with_trans_intr(t, [&](auto &t) {
+          return manager->list_onodes(t, start, end, LIST_LIMIT);
+        }).unsafe_get0();
         listed_oids.insert(listed_oids.end(), list_ret.begin(), list_ret.end());
         start = list_end;
       }
@@ -239,7 +251,9 @@ TEST_F(fltree_onode_manager_test_t, 1_single)
 
     with_onode_write(iter, [this](auto& t, auto& onode, auto& item) {
       OnodeRef onode_ref = &onode;
-      manager->erase_onode(t, onode_ref).unsafe_get0();
+      with_trans_intr(t, [&](auto &t) {
+        return manager->erase_onode(t, onode_ref);
+      }).unsafe_get0();
     });
     validate_erased(iter);
   });
@@ -283,7 +297,9 @@ TEST_F(fltree_onode_manager_test_t, 2_synthetic)
     with_onodes_write(rd_start, rd_end,
         [this](auto& t, auto& onode, auto& item) {
       OnodeRef onode_ref = &onode;
-      manager->erase_onode(t, onode_ref).unsafe_get0();
+      with_trans_intr(t, [&](auto &t) {
+        return manager->erase_onode(t, onode_ref);
+      }).unsafe_get0();
     });
     validate_erased(rd_start, rd_end);
     pool.erase_from_random(rd_start, rd_end);
index e77df0c6b2b7685cedd20eb8a7d439dc36a88906..b6cf810639971e0ae1e308ca865f54062601341a 100644 (file)
 
 using namespace crimson::os::seastore::onode;
 
+#define INTR(fun, t)            \
+  with_trans_intr(              \
+    t,                          \
+    [&] (auto &tr) {            \
+      return fun(tr);           \
+    }                           \
+  )
+
+#define INTR_R(fun, t, args...)         \
+  with_trans_intr(                      \
+    t,                                  \
+    [&] (auto &tr) {                    \
+      return fun(tr, args);             \
+    }                                   \
+  )
+
+#define INTR_WITH_PARAM(fun, c, b, v)   \
+  with_trans_intr(                      \
+    c.t,                                \
+    [=] (auto &t) {                     \
+      return fun(c, b, v);              \
+    }                                   \
+  )
+
 namespace {
   constexpr bool IS_DUMMY_SYNC = false;
   using DummyManager = DummyNodeExtentManager<IS_DUMMY_SYNC>;
@@ -145,22 +169,22 @@ TEST_F(a_basic_test_t, 2_node_sizes)
     ValueBuilderImpl<UnboundedValue> vb;
     context_t c{*nm, vb, *t};
     std::array<std::pair<NodeImplURef, NodeExtentMutable>, 16> nodes = {
-      InternalNode0::allocate(c, false, 1u).unsafe_get0().make_pair(),
-      InternalNode1::allocate(c, false, 1u).unsafe_get0().make_pair(),
-      InternalNode2::allocate(c, false, 1u).unsafe_get0().make_pair(),
-      InternalNode3::allocate(c, false, 1u).unsafe_get0().make_pair(),
-      InternalNode0::allocate(c, true, 1u).unsafe_get0().make_pair(),
-      InternalNode1::allocate(c, true, 1u).unsafe_get0().make_pair(),
-      InternalNode2::allocate(c, true, 1u).unsafe_get0().make_pair(),
-      InternalNode3::allocate(c, true, 1u).unsafe_get0().make_pair(),
-      LeafNode0::allocate(c, false, 0u).unsafe_get0().make_pair(),
-      LeafNode1::allocate(c, false, 0u).unsafe_get0().make_pair(),
-      LeafNode2::allocate(c, false, 0u).unsafe_get0().make_pair(),
-      LeafNode3::allocate(c, false, 0u).unsafe_get0().make_pair(),
-      LeafNode0::allocate(c, true, 0u).unsafe_get0().make_pair(),
-      LeafNode1::allocate(c, true, 0u).unsafe_get0().make_pair(),
-      LeafNode2::allocate(c, true, 0u).unsafe_get0().make_pair(),
-      LeafNode3::allocate(c, true, 0u).unsafe_get0().make_pair()
+      INTR_WITH_PARAM(InternalNode0::allocate, c, false, 1u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(InternalNode1::allocate, c, false, 1u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(InternalNode2::allocate, c, false, 1u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(InternalNode3::allocate, c, false, 1u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(InternalNode0::allocate, c, true, 1u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(InternalNode1::allocate, c, true, 1u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(InternalNode2::allocate, c, true, 1u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(InternalNode3::allocate, c, true, 1u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(LeafNode0::allocate, c, false, 0u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(LeafNode1::allocate, c, false, 0u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(LeafNode2::allocate, c, false, 0u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(LeafNode3::allocate, c, false, 0u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(LeafNode0::allocate, c, true, 0u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(LeafNode1::allocate, c, true, 0u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(LeafNode2::allocate, c, true, 0u).unsafe_get0().make_pair(),
+      INTR_WITH_PARAM(LeafNode3::allocate, c, true, 0u).unsafe_get0().make_pair()
     };
     std::ostringstream oss;
     oss << "\nallocated nodes:";
@@ -204,20 +228,21 @@ TEST_F(b_dummy_tree_test_t, 3_random_insert_erase_leaf_node)
                   "\nrandomized leaf node insert:\n");
     auto key_s = ghobject_t();
     auto key_e = ghobject_t::get_max();
-    ASSERT_TRUE(tree.find(t, key_s).unsafe_get0().is_end());
-    ASSERT_TRUE(tree.begin(t).unsafe_get0().is_end());
-    ASSERT_TRUE(tree.last(t).unsafe_get0().is_end());
+    ASSERT_TRUE(INTR_R(tree.find, t, key_s).unsafe_get0().is_end());
+    ASSERT_TRUE(INTR(tree.begin, t).unsafe_get0().is_end());
+    ASSERT_TRUE(INTR(tree.last, t).unsafe_get0().is_end());
 
     std::map<ghobject_t,
              std::tuple<test_item_t, UnboundedBtree::Cursor>> insert_history;
 
     auto f_validate_insert_new = [this, &insert_history] (
         const ghobject_t& key, const test_item_t& value) {
-      auto [cursor, success] = tree.insert(
-          t, key, {value.get_payload_size()}).unsafe_get0();
+      auto conf = UnboundedBtree::tree_value_config_t{value.get_payload_size()};
+      auto [cursor, success] = INTR_R(tree.insert,
+          t, key, conf).unsafe_get0();
       initialize_cursor_from_item(t, key, value, cursor, success);
       insert_history.emplace(key, std::make_tuple(value, cursor));
-      auto cursor_ = tree.find(t, key).unsafe_get0();
+      auto cursor_ = INTR_R(tree.find, t, key).unsafe_get0();
       ceph_assert(cursor_ != tree.end());
       ceph_assert(cursor_.value() == cursor.value());
       validate_cursor_from_item(key, value, cursor_);
@@ -225,12 +250,12 @@ TEST_F(b_dummy_tree_test_t, 3_random_insert_erase_leaf_node)
     };
 
     auto f_validate_erase = [this, &insert_history] (const ghobject_t& key) {
-      auto cursor_erase = tree.find(t, key).unsafe_get0();
-      auto cursor_next = cursor_erase.get_next(t).unsafe_get0();
-      auto cursor_ret = tree.erase(t, cursor_erase).unsafe_get0();
+      auto cursor_erase = INTR_R(tree.find, t, key).unsafe_get0();
+      auto cursor_next = INTR(cursor_erase.get_next, t).unsafe_get0();
+      auto cursor_ret = INTR_R(tree.erase, t, cursor_erase).unsafe_get0();
       ceph_assert(cursor_erase.is_end());
       ceph_assert(cursor_ret == cursor_next);
-      auto cursor_lb = tree.lower_bound(t, key).unsafe_get0();
+      auto cursor_lb = INTR_R(tree.lower_bound, t, key).unsafe_get0();
       ceph_assert(cursor_lb == cursor_next);
       auto it = insert_history.find(key);
       ceph_assert(std::get<1>(it->second).is_end());
@@ -253,18 +278,19 @@ TEST_F(b_dummy_tree_test_t, 3_random_insert_erase_leaf_node)
 
     // validate lookup
     {
-      auto cursor1_s = tree.lower_bound(t, key_s).unsafe_get0();
+      auto cursor1_s = INTR_R(tree.lower_bound, t, key_s).unsafe_get0();
       ASSERT_EQ(cursor1_s.get_ghobj(), key1);
       ASSERT_EQ(cursor1_s.value(), test_value1);
-      auto cursor1_e = tree.lower_bound(t, key_e).unsafe_get0();
+      auto cursor1_e = INTR_R(tree.lower_bound, t, key_e).unsafe_get0();
       ASSERT_TRUE(cursor1_e.is_end());
     }
 
     // insert the same key1 with a different value
     {
       auto value1_dup = values.pick();
-      auto [cursor1_dup, ret1_dup] = tree.insert(
-          t, key1, {value1_dup.get_payload_size()}).unsafe_get0();
+      auto conf = UnboundedBtree::tree_value_config_t{value1_dup.get_payload_size()};
+      auto [cursor1_dup, ret1_dup] = INTR_R(tree.insert,
+          t, key1, conf).unsafe_get0();
       ASSERT_FALSE(ret1_dup);
       validate_cursor_from_item(key1, value1, cursor1_dup);
     }
@@ -345,28 +371,28 @@ TEST_F(b_dummy_tree_test_t, 3_random_insert_erase_leaf_node)
     std::for_each(kvs.begin(), kvs.end(), [&f_insert_erase_insert] (auto& kv) {
       f_insert_erase_insert(kv.first, kv.second);
     });
-    ASSERT_EQ(tree.height(t).unsafe_get0(), 1);
+    ASSERT_EQ(INTR(tree.height, t).unsafe_get0(), 1);
     ASSERT_FALSE(tree.test_is_clean());
 
     for (auto& [k, val] : insert_history) {
       auto& [v, c] = val;
       // validate values in tree keep intact
-      auto cursor = tree.find(t, k).unsafe_get0();
+      auto cursor = INTR_R(tree.find, t, k).unsafe_get0();
       EXPECT_NE(cursor, tree.end());
       validate_cursor_from_item(k, v, cursor);
       // validate values in cursors keep intact
       validate_cursor_from_item(k, v, c);
     }
     {
-      auto cursor = tree.lower_bound(t, key_s).unsafe_get0();
+      auto cursor = INTR_R(tree.lower_bound, t, key_s).unsafe_get0();
       validate_cursor_from_item(smallest_key, smallest_value, cursor);
     }
     {
-      auto cursor = tree.begin(t).unsafe_get0();
+      auto cursor = INTR(tree.begin, t).unsafe_get0();
       validate_cursor_from_item(smallest_key, smallest_value, cursor);
     }
     {
-      auto cursor = tree.last(t).unsafe_get0();
+      auto cursor = INTR(tree.last, t).unsafe_get0();
       validate_cursor_from_item(largest_key, largest_value, cursor);
     }
 
@@ -381,11 +407,11 @@ TEST_F(b_dummy_tree_test_t, 3_random_insert_erase_leaf_node)
       std::sort(kvs.begin(), kvs.end(), [](auto& l, auto& r) {
         return l.first < r.first;
       });
-      auto cursor = tree.begin(t).unsafe_get0();
+      auto cursor = INTR(tree.begin, t).unsafe_get0();
       for (auto& [k, v] : kvs) {
         ASSERT_FALSE(cursor.is_end());
         validate_cursor_from_item(k, v, cursor);
-        cursor = cursor.get_next(t).unsafe_get0();
+        cursor = INTR(cursor.get_next, t).unsafe_get0();
       }
       ASSERT_TRUE(cursor.is_end());
     }
@@ -397,12 +423,12 @@ TEST_F(b_dummy_tree_test_t, 3_random_insert_erase_leaf_node)
     // randomized erase until empty
     std::random_shuffle(kvs.begin(), kvs.end());
     for (auto& [k, v] : kvs) {
-      auto e_size = tree.erase(t, k).unsafe_get0();
+      auto e_size = INTR_R(tree.erase, t, k).unsafe_get0();
       ASSERT_EQ(e_size, 1);
     }
-    auto cursor = tree.begin(t).unsafe_get0();
+    auto cursor = INTR(tree.begin, t).unsafe_get0();
     ASSERT_TRUE(cursor.is_end());
-    ASSERT_EQ(tree.height(t).unsafe_get0(), 1);
+    ASSERT_EQ(INTR(tree.height, t).unsafe_get0(), 1);
   });
 }
 
@@ -457,7 +483,7 @@ class TestTree {
         auto value = values.create(value_size);
         insert_tree(key, value).get0();
       }
-      ASSERT_EQ(tree.height(t).unsafe_get0(), 1);
+      ASSERT_EQ(INTR(tree.height, t).unsafe_get0(), 1);
       ASSERT_FALSE(tree.test_is_clean());
       //std::ostringstream oss;
       //tree.dump(t, oss);
@@ -479,7 +505,7 @@ class TestTree {
         ++key_iter;
         ++value_iter;
       }
-      ASSERT_EQ(tree.height(t).unsafe_get0(), 1);
+      ASSERT_EQ(INTR(tree.height, t).unsafe_get0(), 1);
       ASSERT_FALSE(tree.test_is_clean());
       //std::ostringstream oss;
       //tree.dump(t, oss);
@@ -499,12 +525,13 @@ class TestTree {
       UnboundedBtree tree_clone(std::move(ref_dummy));
       auto ref_t_clone = make_test_transaction();
       Transaction& t_clone = *ref_t_clone;
-      tree_clone.test_clone_from(t_clone, t, tree).unsafe_get0();
+      INTR_R(tree_clone.test_clone_from, t_clone, t, tree).unsafe_get0();
 
       // insert and split
       logger().info("\n\nINSERT-SPLIT {}:", key_hobj_t(key));
-      auto [cursor, success] = tree_clone.insert(
-          t_clone, key, {value.get_payload_size()}).unsafe_get0();
+      auto conf = UnboundedBtree::tree_value_config_t{value.get_payload_size()};
+      auto [cursor, success] = INTR_R(tree_clone.insert,
+          t_clone, key, conf).unsafe_get0();
       initialize_cursor_from_item(t, key, value, cursor, success);
 
       {
@@ -512,15 +539,15 @@ class TestTree {
         tree_clone.dump(t_clone, oss);
         logger().info("dump new root:\n{}", oss.str());
       }
-      EXPECT_EQ(tree_clone.height(t_clone).unsafe_get0(), 2);
+      EXPECT_EQ(INTR(tree_clone.height, t_clone).unsafe_get0(), 2);
 
       for (auto& [k, val] : insert_history) {
         auto& [v, c] = val;
-        auto result = tree_clone.find(t_clone, k).unsafe_get0();
+        auto result = INTR_R(tree_clone.find, t_clone, k).unsafe_get0();
         EXPECT_NE(result, tree_clone.end());
         validate_cursor_from_item(k, v, result);
       }
-      auto result = tree_clone.find(t_clone, key).unsafe_get0();
+      auto result = INTR_R(tree_clone.find, t_clone, key).unsafe_get0();
       EXPECT_NE(result, tree_clone.end());
       validate_cursor_from_item(key, value, result);
       EXPECT_TRUE(last_split.match(expected));
@@ -528,11 +555,11 @@ class TestTree {
 
       // erase and merge
       logger().info("\n\nERASE-MERGE {}:", key_hobj_t(key));
-      auto nxt_cursor = cursor.erase<true>(t_clone).unsafe_get0();
+      auto nxt_cursor = INTR(cursor.erase<true>, t_clone).unsafe_get0();
 
       {
         // track root again to dump
-        auto begin = tree_clone.begin(t_clone).unsafe_get0();
+        auto begin = INTR(tree_clone.begin, t_clone).unsafe_get0();
         std::ignore = begin;
         std::ostringstream oss;
         tree_clone.dump(t_clone, oss);
@@ -550,12 +577,11 @@ class TestTree {
 
       for (auto& [k, val] : insert_history) {
         auto& [v, c] = val;
-        auto result = tree_clone.find(t_clone, k).unsafe_get0();
+        auto result = INTR_R(tree_clone.find, t_clone, k).unsafe_get0();
         EXPECT_NE(result, tree_clone.end());
         validate_cursor_from_item(k, v, result);
       }
-
-      EXPECT_EQ(tree_clone.height(t_clone).unsafe_get0(), 1);
+      EXPECT_EQ(INTR(tree_clone.height, t_clone).unsafe_get0(), 1);
       EXPECT_EQ(p_dummy->size(), 1);
     });
   }
@@ -567,8 +593,9 @@ class TestTree {
  private:
   seastar::future<> insert_tree(const ghobject_t& key, const test_item_t& value) {
     return seastar::async([this, &key, &value] {
-      auto [cursor, success] = tree.insert(
-          t, key, {value.get_payload_size()}).unsafe_get0();
+      auto conf = UnboundedBtree::tree_value_config_t{value.get_payload_size()};
+      auto [cursor, success] = INTR_R(tree.insert,
+          t, key, conf).unsafe_get0();
       initialize_cursor_from_item(t, key, value, cursor, success);
       insert_history.emplace(key, std::make_tuple(value, cursor));
     });
@@ -835,10 +862,10 @@ class DummyChildPool {
       build_name();
       return search_position_t::end();
     }
-    eagain_future<> retire_extent(context_t) override {
+    eagain_ifuture<> retire_extent(context_t) override {
       assert(!_is_extent_retired);
       _is_extent_retired = true;
-      return seastar::now();
+      return eagain_iertr::now();
     }
 
    protected:
@@ -871,7 +898,7 @@ class DummyChildPool {
       ceph_abort("impossible path"); }
     search_position_t merge(NodeExtentMutable&, NodeImpl&, match_stage_t, extent_len_t) override {
       ceph_abort("impossible path"); }
-    eagain_future<NodeExtentMutable> rebuild_extent(context_t) override {
+    eagain_ifuture<NodeExtentMutable> rebuild_extent(context_t) override {
       ceph_abort("impossible path"); }
     node_stats_t get_stats() const override {
       ceph_abort("impossible path"); }
@@ -913,7 +940,7 @@ class DummyChildPool {
 
     key_view_t get_pivot_key() const { return *impl->get_pivot_index(); }
 
-    eagain_future<> populate_split(
+    eagain_ifuture<> populate_split(
         context_t c, std::set<Ref<DummyChild>>& splitable_nodes) {
       ceph_assert(can_split());
       ceph_assert(splitable_nodes.find(this) != splitable_nodes.end());
@@ -941,10 +968,10 @@ class DummyChildPool {
       }
       Ref<Node> this_ref = this;
       return apply_split_to_parent(
-          c, std::move(this_ref), std::move(right_child), false);
+            c, std::move(this_ref), std::move(right_child), false);
     }
 
-    eagain_future<> insert_and_split(
+    eagain_ifuture<> insert_and_split(
         context_t c, const ghobject_t& insert_key,
         std::set<Ref<DummyChild>>& splitable_nodes) {
       const auto& keys = impl->get_keys();
@@ -964,9 +991,9 @@ class DummyChildPool {
       return fut;
     }
 
-    eagain_future<> merge(context_t c, Ref<DummyChild>&& this_ref) {
+    eagain_ifuture<> merge(context_t c, Ref<DummyChild>&& this_ref) {
       return parent_info().ptr->get_child_peers(c, parent_info().position
-      ).safe_then([c, this_ref = std::move(this_ref), this] (auto lr_nodes) mutable {
+      ).si_then([c, this_ref = std::move(this_ref), this] (auto lr_nodes) mutable {
         auto& [lnode, rnode] = lr_nodes;
         if (rnode) {
           lnode.reset();
@@ -985,7 +1012,7 @@ class DummyChildPool {
       });
     }
 
-    eagain_future<> fix_key(context_t c, const ghobject_t& new_key) {
+    eagain_ifuture<> fix_key(context_t c, const ghobject_t& new_key) {
       const auto& keys = impl->get_keys();
       ceph_assert(keys.size() == 1);
       assert(impl->is_level_tail() == false);
@@ -1015,24 +1042,24 @@ class DummyChildPool {
       return create(keys, is_level_tail, seed++, pool);
     }
 
-    static eagain_future<Ref<DummyChild>> create_initial(
+    static eagain_ifuture<Ref<DummyChild>> create_initial(
         context_t c, const std::set<ghobject_t>& keys,
         DummyChildPool& pool, RootNodeTracker& root_tracker) {
       auto initial = create_new(keys, true, pool);
       return c.nm.get_super(c.t, root_tracker
-      ).handle_error(
-        eagain_ertr::pass_further{},
+      ).handle_error_interruptible(
+        eagain_iertr::pass_further{},
         crimson::ct_error::assert_all{"Invalid error during create_initial()"}
-      ).safe_then([c, &pool, initial](auto super) {
+      ).si_then([c, &pool, initial](auto super) {
         initial->make_root_new(c, std::move(super));
-        return initial->upgrade_root(c).safe_then([initial] {
+        return initial->upgrade_root(c).si_then([initial] {
           return initial;
         });
       });
     }
 
    protected:
-    eagain_future<> test_clone_non_root(
+    eagain_ifuture<> test_clone_non_root(
         context_t, Ref<InternalNode> new_parent) const override {
       ceph_assert(!is_root());
       auto p_pool_clone = pool.pool_clone_in_progress;
@@ -1040,18 +1067,18 @@ class DummyChildPool {
       auto clone = create(
           impl->get_keys(), impl->is_level_tail(), impl->laddr(), *p_pool_clone);
       clone->as_child(parent_info().position, new_parent);
-      return seastar::now();
+      return eagain_iertr::now();
     }
-    eagain_future<Ref<tree_cursor_t>> lookup_smallest(context_t) override {
+    eagain_ifuture<Ref<tree_cursor_t>> lookup_smallest(context_t) override {
       ceph_abort("impossible path"); }
-    eagain_future<Ref<tree_cursor_t>> lookup_largest(context_t) override {
+    eagain_ifuture<Ref<tree_cursor_t>> lookup_largest(context_t) override {
       ceph_abort("impossible path"); }
-    eagain_future<> test_clone_root(context_t, RootNodeTracker&) const override {
+    eagain_ifuture<> test_clone_root(context_t, RootNodeTracker&) const override {
       ceph_abort("impossible path"); }
-    eagain_future<search_result_t> lower_bound_tracked(
+    eagain_ifuture<search_result_t> lower_bound_tracked(
         context_t, const key_hobj_t&, MatchHistory&) override {
       ceph_abort("impossible path"); }
-    eagain_future<> do_get_tree_stats(context_t, tree_stats_t&) override {
+    eagain_ifuture<> do_get_tree_stats(context_t, tree_stats_t&) override {
       ceph_abort("impossible path"); }
     bool is_tracking() const override { return false; }
     void track_merge(Ref<Node>, match_stage_t, search_position_t&) override {
@@ -1065,7 +1092,7 @@ class DummyChildPool {
 
     bool can_split() const { return impl->get_keys().size() > 1; }
 
-    static eagain_future<> do_merge(
+    static eagain_ifuture<> do_merge(
         context_t c, Ref<DummyChild>&& left, Ref<DummyChild>&& right, bool stole_key) {
       assert(right->use_count() == 1);
       assert(left->impl->get_keys().size() == 1);
@@ -1094,37 +1121,38 @@ class DummyChildPool {
 
   eagain_future<> build_tree(const std::set<ghobject_t>& keys) {
     reset();
-
     // create tree
     auto ref_dummy = NodeExtentManager::create_dummy(IS_DUMMY_SYNC);
     p_dummy = static_cast<DummyManager*>(ref_dummy.get());
     p_btree.emplace(std::move(ref_dummy));
-    return DummyChild::create_initial(get_context(), keys, *this, *p_btree->root_tracker
-    ).safe_then([this](auto initial_child) {
-      // split
-      splitable_nodes.insert(initial_child);
-      return crimson::repeat([this] ()
-        -> eagain_future<seastar::stop_iteration> {
-        if (splitable_nodes.empty()) {
-          return seastar::make_ready_future<seastar::stop_iteration>(
-            seastar::stop_iteration::yes);
-        }
-        auto index = rd() % splitable_nodes.size();
-        auto iter = splitable_nodes.begin();
-        std::advance(iter, index);
-        Ref<DummyChild> child = *iter;
-        return child->populate_split(get_context(), splitable_nodes
-        ).safe_then([] {
-          return seastar::stop_iteration::no;
+    return with_trans_intr(get_context().t, [this, &keys] (auto &tr) {
+      return DummyChild::create_initial(get_context(), keys, *this, *p_btree->root_tracker
+      ).si_then([this](auto initial_child) {
+        // split
+        splitable_nodes.insert(initial_child);
+        return trans_intr::repeat([this] ()
+          -> eagain_ifuture<seastar::stop_iteration> {
+          if (splitable_nodes.empty()) {
+            return seastar::make_ready_future<seastar::stop_iteration>(
+              seastar::stop_iteration::yes);
+          }
+          auto index = rd() % splitable_nodes.size();
+          auto iter = splitable_nodes.begin();
+          std::advance(iter, index);
+          Ref<DummyChild> child = *iter;
+          return child->populate_split(get_context(), splitable_nodes
+          ).si_then([] {
+            return seastar::stop_iteration::no;
+          });
         });
-      });
-    }).safe_then([this] {
+      }).si_then([this] {
       //std::ostringstream oss;
       //p_btree->dump(t(), oss);
       //logger().info("\n{}\n", oss.str());
-      return p_btree->height(t());
-    }).safe_then([](auto height) {
-      ceph_assert(height == 2);
+        return p_btree->height(t());
+      }).si_then([](auto height) {
+        ceph_assert(height == 2);
+      });
     });
   }
 
@@ -1137,14 +1165,17 @@ class DummyChildPool {
       // insert and split
       logger().info("\n\nINSERT-SPLIT {} at pos({}):", key_hobj_t(key), pos);
       auto node_to_split = pool_clone.get_node_by_pos(pos);
-      node_to_split->insert_and_split(
-        pool_clone.get_context(), key, pool_clone.splitable_nodes).unsafe_get0();
+      with_trans_intr(pool_clone.get_context().t, [&] (auto &t) {
+        return node_to_split->insert_and_split(
+          pool_clone.get_context(), key, pool_clone.splitable_nodes);
+      }).unsafe_get0();
       {
         std::ostringstream oss;
         pool_clone.p_btree->dump(pool_clone.t(), oss);
         logger().info("dump new root:\n{}", oss.str());
       }
-      EXPECT_EQ(pool_clone.p_btree->height(pool_clone.t()).unsafe_get0(), 3);
+      auto &pt = pool_clone.t();
+      EXPECT_EQ(INTR(pool_clone.p_btree->height, pt).unsafe_get0(), 3);
       EXPECT_TRUE(last_split.match(expected));
       EXPECT_EQ(pool_clone.p_dummy->size(), 3);
 
@@ -1152,9 +1183,12 @@ class DummyChildPool {
       auto pivot_key = node_to_split->get_pivot_key();
       logger().info("\n\nERASE-MERGE {}:", node_to_split->get_name());
       assert(pivot_key.compare_to(key_hobj_t(key)) == MatchKindCMP::EQ);
-      node_to_split->merge(
-          pool_clone.get_context(), std::move(node_to_split)).unsafe_get0();
-      EXPECT_EQ(pool_clone.p_btree->height(pool_clone.t()).unsafe_get0(), 2);
+      with_trans_intr(pool_clone.get_context().t, [&] (auto &t) {
+        return node_to_split->merge(
+          pool_clone.get_context(), std::move(node_to_split));
+      }).unsafe_get0();
+      auto &pt2 = pool_clone.t();
+      EXPECT_EQ(INTR(pool_clone.p_btree->height ,pt2).unsafe_get0(), 2);
       EXPECT_EQ(pool_clone.p_dummy->size(), 1);
     });
   }
@@ -1170,23 +1204,30 @@ class DummyChildPool {
       auto old_key = node_to_fix->get_pivot_key().to_ghobj();
       logger().info("\n\nFIX pos({}) from {} to {}, expect_split={}:",
                     pos, node_to_fix->get_name(), key_hobj_t(new_key), expect_split);
-      node_to_fix->fix_key(pool_clone.get_context(), new_key).unsafe_get0();
+      with_trans_intr(pool_clone.get_context().t, [&] (auto &t) {
+        return node_to_fix->fix_key(pool_clone.get_context(), new_key);
+      }).unsafe_get0();
       if (expect_split) {
         std::ostringstream oss;
         pool_clone.p_btree->dump(pool_clone.t(), oss);
         logger().info("dump new root:\n{}", oss.str());
-        EXPECT_EQ(pool_clone.p_btree->height(pool_clone.t()).unsafe_get0(), 3);
+        auto &pt = pool_clone.t();
+        EXPECT_EQ(INTR(pool_clone.p_btree->height, pt).unsafe_get0(), 3);
         EXPECT_EQ(pool_clone.p_dummy->size(), 3);
       } else {
-        EXPECT_EQ(pool_clone.p_btree->height(pool_clone.t()).unsafe_get0(), 2);
+        auto &pt = pool_clone.t();
+        EXPECT_EQ(INTR(pool_clone.p_btree->height, pt).unsafe_get0(), 2);
         EXPECT_EQ(pool_clone.p_dummy->size(), 1);
       }
 
       // fix back
       logger().info("\n\nFIX pos({}) from {} back to {}:",
                     pos, node_to_fix->get_name(), key_hobj_t(old_key));
-      node_to_fix->fix_key(pool_clone.get_context(), old_key).unsafe_get0();
-      EXPECT_EQ(pool_clone.p_btree->height(pool_clone.t()).unsafe_get0(), 2);
+      with_trans_intr(pool_clone.get_context().t, [&] (auto &t) {
+          return node_to_fix->fix_key(pool_clone.get_context(), old_key);
+      }).unsafe_get0();
+      auto &pt = pool_clone.t();
+      EXPECT_EQ(INTR(pool_clone.p_btree->height, pt).unsafe_get0(), 2);
       EXPECT_EQ(pool_clone.p_dummy->size(), 1);
     });
   }
@@ -1197,8 +1238,10 @@ class DummyChildPool {
     auto ref_dummy = NodeExtentManager::create_dummy(IS_DUMMY_SYNC);
     pool_clone.p_dummy = static_cast<DummyManager*>(ref_dummy.get());
     pool_clone.p_btree.emplace(std::move(ref_dummy));
-    pool_clone.p_btree->test_clone_from(
-      pool_clone.t(), t(), *p_btree).unsafe_get0();
+    auto &pt = pool_clone.t();
+    [[maybe_unused]] auto &tr = t();
+    INTR_R(pool_clone.p_btree->test_clone_from,
+      pt, tr, *p_btree).unsafe_get0();
     pool_clone_in_progress = nullptr;
   }
 
@@ -1528,14 +1571,14 @@ TEST_F(d_seastore_tm_test_t, 6_random_tree_insert_erase)
         {8, 11,  64, 256, 301, 320},
         {8, 16, 128, 512, 576, 640},
         {0, 16}, {0, 10}, {0, 4});
-    auto moved_nm = (TEST_SEASTORE ? NodeExtentManager::create_seastore(itm)
+    auto moved_nm = (TEST_SEASTORE ? NodeExtentManager::create_seastore(*tm)
                                    : NodeExtentManager::create_dummy(IS_DUMMY_SYNC));
     auto p_nm = moved_nm.get();
     auto tree = std::make_unique<TreeBuilder<TRACK_CURSORS, BoundedValue>>(
         kvs, std::move(moved_nm));
     {
       auto t = create_mutate_transaction();
-      tree->bootstrap(*t).unsafe_get();
+      INTR(tree->bootstrap, *t).unsafe_get();
       submit_transaction(std::move(t));
       segment_cleaner->run_until_halt().get0();
     }
@@ -1543,69 +1586,71 @@ TEST_F(d_seastore_tm_test_t, 6_random_tree_insert_erase)
     // test insert
     {
       auto t = create_mutate_transaction();
-      tree->insert(*t).unsafe_get();
+      INTR(tree->insert, *t).unsafe_get();
       submit_transaction(std::move(t));
       segment_cleaner->run_until_halt().get0();
     }
     {
       auto t = create_read_transaction();
-      tree->get_stats(*t).unsafe_get();
+      INTR(tree->get_stats, *t).unsafe_get();
     }
     if constexpr (TEST_SEASTORE) {
       logger().info("seastore replay insert begin");
       restart();
-      tree->reload(NodeExtentManager::create_seastore(itm));
+      tree->reload(NodeExtentManager::create_seastore(*tm));
       logger().info("seastore replay insert end");
     }
     {
       // Note: create_weak_transaction() can also work, but too slow.
       auto t = create_read_transaction();
-      tree->validate(*t).unsafe_get();
+      INTR(tree->validate, *t).unsafe_get();
     }
 
     // test erase 3/4
     {
       auto t = create_mutate_transaction();
-      tree->erase(*t, kvs.size() / 4 * 3).unsafe_get();
+      auto size = kvs.size() / 4 * 3;
+      INTR_R(tree->erase, *t, size).unsafe_get();
       submit_transaction(std::move(t));
       segment_cleaner->run_until_halt().get0();
     }
     {
       auto t = create_read_transaction();
-      tree->get_stats(*t).unsafe_get();
+      INTR(tree->get_stats, *t).unsafe_get();
     }
     if constexpr (TEST_SEASTORE) {
       logger().info("seastore replay erase-1 begin");
       restart();
-      tree->reload(NodeExtentManager::create_seastore(itm));
+      tree->reload(NodeExtentManager::create_seastore(*tm));
       logger().info("seastore replay erase-1 end");
     }
     {
       auto t = create_read_transaction();
-      tree->validate(*t).unsafe_get();
+      INTR(tree->validate, *t).unsafe_get();
     }
 
     // test erase remaining
     {
       auto t = create_mutate_transaction();
-      tree->erase(*t, kvs.size()).unsafe_get();
+      auto size = kvs.size();
+      INTR_R(tree->erase, *t, size).unsafe_get();
       submit_transaction(std::move(t));
       segment_cleaner->run_until_halt().get0();
     }
     {
       auto t = create_read_transaction();
-      tree->get_stats(*t).unsafe_get();
+      INTR(tree->get_stats, *t).unsafe_get();
     }
     if constexpr (TEST_SEASTORE) {
       logger().info("seastore replay erase-2 begin");
       restart();
-      tree->reload(NodeExtentManager::create_seastore(itm));
+      tree->reload(NodeExtentManager::create_seastore(*tm));
       logger().info("seastore replay erase-2 end");
     }
     {
       auto t = create_read_transaction();
-      tree->validate(*t).unsafe_get();
-      EXPECT_EQ(tree->height(*t).unsafe_get0(), 1);
+      INTR(tree->validate, *t).unsafe_get();
+      EXPECT_EQ(INTR(tree->height, *t).unsafe_get0(), 1);
     }
 
     if constexpr (!TEST_SEASTORE) {
@@ -1627,7 +1672,7 @@ TEST_F(d_seastore_tm_test_t, 7_tree_insert_erase_eagain)
         {8, 16, 128, 576,  992, 1200},
         {0, 8}, {0, 10}, {0, 4});
     auto moved_nm = NodeExtentManager::create_seastore(
-        itm, L_ADDR_MIN, EAGAIN_PROBABILITY);
+        *tm, L_ADDR_MIN, EAGAIN_PROBABILITY);
     auto p_nm = static_cast<SeastoreNodeExtentManager<true>*>(moved_nm.get());
     auto tree = std::make_unique<TreeBuilder<TRACK_CURSORS, ExtendedValue>>(
         kvs, std::move(moved_nm));
@@ -1641,7 +1686,7 @@ TEST_F(d_seastore_tm_test_t, 7_tree_insert_erase_eagain)
       return seastar::do_with(
        create_mutate_transaction(),
        [this, &tree](auto &t) {
-         return tree->bootstrap(*t
+         return INTR(tree->bootstrap, *t
          ).safe_then([this, &t] {
            return submit_transaction_fut(*t);
          });
@@ -1660,7 +1705,7 @@ TEST_F(d_seastore_tm_test_t, 7_tree_insert_erase_eagain)
          return seastar::do_with(
            create_mutate_transaction(),
            [this, &tree, &iter](auto &t) {
-             return tree->insert_one(*t, iter
+             return INTR_R(tree->insert_one, *t, iter
              ).safe_then([this, &t](auto cursor) {
                cursor.invalidate();
                return submit_transaction_fut(*t);
@@ -1675,7 +1720,7 @@ TEST_F(d_seastore_tm_test_t, 7_tree_insert_erase_eagain)
     {
       p_nm->set_generate_eagain(false);
       auto t = create_read_transaction();
-      tree->get_stats(*t).unsafe_get0();
+      INTR(tree->get_stats, *t).unsafe_get0();
       p_nm->set_generate_eagain(true);
     }
 
@@ -1688,7 +1733,7 @@ TEST_F(d_seastore_tm_test_t, 7_tree_insert_erase_eagain)
         repeat_eagain2([this, &tree, &num_ops_eagain, &iter] {
           ++num_ops_eagain;
           auto t = create_read_transaction();
-          return tree->validate_one(*t, iter
+          return INTR_R(tree->validate_one, *t, iter
           ).safe_then([t=std::move(t)]{});
         }).get0();
         ++iter;
@@ -1707,7 +1752,7 @@ TEST_F(d_seastore_tm_test_t, 7_tree_insert_erase_eagain)
          return seastar::do_with(
            create_mutate_transaction(),
            [this, &tree, &iter](auto &t) {
-             return tree->erase_one(*t, iter
+             return INTR_R(tree->erase_one, *t, iter
              ).safe_then([this, &t] () mutable {
                return submit_transaction_fut(*t);
              });
@@ -1722,9 +1767,9 @@ TEST_F(d_seastore_tm_test_t, 7_tree_insert_erase_eagain)
     {
       p_nm->set_generate_eagain(false);
       auto t = create_read_transaction();
-      tree->get_stats(*t).unsafe_get0();
-      tree->validate(*t).unsafe_get0();
-      EXPECT_EQ(tree->height(*t).unsafe_get0(), 1);
+      INTR(tree->get_stats, *t).unsafe_get0();
+      INTR(tree->validate, *t).unsafe_get0();
+      EXPECT_EQ(INTR(tree->height,*t).unsafe_get0(), 1);
     }
 
     // we can adjust EAGAIN_PROBABILITY to get a proper eagain_rate