]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
crimson/os/seastore: demote/promote background processes are also
authorXuehan Xu <xuxuehan@qianxin.com>
Mon, 18 May 2026 09:55:35 +0000 (17:55 +0800)
committerXuehan Xu <xuxuehan@qianxin.com>
Tue, 7 Jul 2026 08:15:31 +0000 (16:15 +0800)
rewrite transactions

Signed-off-by: Xuehan Xu <xuxuehan@qianxin.com>
src/crimson/os/seastore/cache.cc
src/crimson/os/seastore/cache.h
src/crimson/os/seastore/cached_extent.cc
src/crimson/os/seastore/cached_extent.h
src/crimson/os/seastore/lba/btree_lba_manager.cc
src/crimson/os/seastore/lba/lba_btree_node.h
src/crimson/os/seastore/logical_child_node.h
src/crimson/os/seastore/seastore_types.h
src/crimson/os/seastore/transaction.h
src/crimson/os/seastore/transaction_manager.cc
src/crimson/os/seastore/transaction_manager.h

index 1146c994362ffa9a09dd43d20d7af40649dab065..033fc4b4a0281e5fb3907d4ac79aaca49eeb2d2e 100644 (file)
@@ -1810,7 +1810,7 @@ record_t Cache::prepare_record(
 
     if (i->is_exist_clean()) {
       assert(i->version == 0);
-      assert(!i->prior_instance);
+      assert(!i->prior_instance || t.get_src() == transaction_type_t::DEMOTE);
       // no set_io_wait(), skip complete_commit()
       assert(!i->is_pending_io());
       i->pending_for_transaction = TRANS_ID_NULL;
@@ -1821,13 +1821,24 @@ record_t Cache::prepare_record(
                      should_use_no_conflict_publish(t, i->get_type()));
     }
 
-    // exist mutation pending extents must be in t.mutated_block_list
-    add_extent(i);
-    const auto t_src = t.get_src();
-    if (i->is_stable_dirty()) {
-      add_to_dirty(i, &t_src);
+    assert(i->is_logical());
+    if (t.get_src() == transaction_type_t::DEMOTE) {
+      assert(!i->committer);
+      assert(!i->get_prior_instance()->committer);
+      i->new_committer(t);
+      assert(i->committer);
+      i->get_prior_instance()->committer = i->committer;
+      auto &committer = *i->committer;
+      committer.block_trans(t);
     } else {
-      touch_extent_fully(*i, &t_src, t.get_cache_hint());
+      // exist mutation pending extents must be in t.mutated_block_list
+      add_extent(i);
+      const auto t_src = t.get_src();
+      if (i->is_stable_dirty()) {
+        add_to_dirty(i, &t_src);
+      } else {
+        touch_extent_fully(*i, &t_src, t.get_cache_hint());
+      }
     }
 
     alloc_delta.alloc_blk_ranges.emplace_back(
@@ -2103,6 +2114,9 @@ void Cache::complete_commit(
       }
       if (i->is_logical()) {
         committer.maybe_sync_copied_lba_key();
+        if (t.get_src() == transaction_type_t::PROMOTE) {
+          committer.commit_shadow_promote(t);
+        }
       }
       touch_extent_fully(prior, &t_src, t.get_cache_hint());
       committer.sync_version();
@@ -2213,6 +2227,31 @@ void Cache::complete_commit(
       continue;
     }
     epm.mark_space_used(i->get_paddr(), i->get_length());
+    assert(i->is_logical());
+    auto t_src = t.get_src();
+    if (t.get_src() == transaction_type_t::DEMOTE) {
+      assert(i->committer);
+      auto &committer = *i->committer;
+      auto &prior = static_cast<LogicalChildNode&>(
+        *i->get_prior_instance());
+      ceph_assert(prior.is_valid());
+      TRACET("committing rewritten extent into "
+             "existing -- {}, prior={}",
+             t, *i, prior);
+      prior.pending_for_transaction = TRANS_ID_NULL;
+      if (auto shadow = prior.get_shadow(); shadow) {
+        committer.commit_shadow_demote(t);
+        prior.reset_shadow();
+      }
+      committer.commit_state();
+      committer.sync_checksum();
+      committer.commit_and_share_paddr();
+      touch_extent_fully(prior, &t_src, t.get_cache_hint());
+      committer.sync_version();
+      committer.unblock_trans(t);
+      i->committer.reset();
+      prior.committer.reset();
+    }
   }
   for (auto &i: t.pre_alloc_list) {
     if (!i->is_valid()) {
index 327f206f6c7cc0fd48852a028b99377953e505ec..119f71bfc2ea5ff0e084701bb89250166ff9e288 100644 (file)
@@ -1731,6 +1731,9 @@ public:
       read_extent_futs, [](auto &fut) { return std::move(fut); });
   }
 
+  bool is_on_cold_tier(paddr_t paddr) const {
+    return epm.is_cold_device(paddr.get_device_id());
+  }
 private:
   void touch_extent_fully(
       CachedExtent &ext,
index d6a230ca7752f0e9c2693d8aace5e5c646cffb6c..622a331f2e02b794e37c64ec80e3933abbe2a0ba 100644 (file)
@@ -557,4 +557,48 @@ void ExtentCommitter::unblock_trans(Transaction &t) {
   }
 }
 
+void ExtentCommitter::commit_shadow_demote(Transaction &t) {
+  LOG_PREFIX(ExtentCommitter::commit_shadow_demote);
+  assert(t.get_src() == transaction_type_t::DEMOTE);
+  auto &prior = *extent.prior_instance->template cast<LogicalChildNode>();
+  auto shadow = prior.get_shadow();
+  assert(shadow);
+  for (auto &trans_view : prior.retired_transactions) {
+    assert(trans_view.t != nullptr);
+    auto view_tid = trans_view.t->get_trans_id();
+    if (view_tid == t.get_trans_id()) {
+      continue;
+    }
+    TRACET("removing shadow {} from retired_set of t.{}", t, *shadow, view_tid);
+    [[maybe_unused]] bool removed =
+      trans_view.t->remove_from_retired_set(*shadow);
+    assert(removed);
+    trans_view.t->remove_shadow_from_write_set(
+      shadow->get_paddr(), shadow->get_length());
+  }
+}
+
+void ExtentCommitter::commit_shadow_promote(Transaction &t) {
+  LOG_PREFIX(ExtentCommitter::commit_shadow_promote);
+  assert(t.get_src() == transaction_type_t::PROMOTE);
+  assert(extent.is_logical());
+  auto &lprior = static_cast<LogicalChildNode&>(*extent.prior_instance);
+  ceph_assert(lprior.get_pin_state() == extent_pin_state_t::Promoting);
+  auto &lext = static_cast<LogicalChildNode&>(extent);
+  auto shadow = lext.get_shadow();
+  assert(shadow);
+  assert(shadow->is_shadow_extent());
+  lprior.set_shadow(shadow);
+  for (auto &trans_view : lprior.retired_transactions) {
+    assert(trans_view.t != nullptr);
+    auto view_tid = trans_view.t->get_trans_id();
+    if (view_tid == t.get_trans_id()) {
+      continue;
+    }
+    TRACET("adding shadow {} from t.{}", t, *shadow, view_tid);
+    trans_view.t->add_absent_to_retired_set(shadow);
+  }
+  lprior.set_pin_state(extent_pin_state_t::Fresh);
+}
+
 }
index 96496f44d44f676bafb0c1a2e8ef728b6b4f5fb3..7115494d1672684314871d5651d76689c47d458e 100644 (file)
@@ -301,6 +301,8 @@ public:
   void commit_and_share_paddr();
 
   void maybe_sync_copied_lba_key();
+  void commit_shadow_demote(Transaction&);
+  void commit_shadow_promote(Transaction&);
 private:
   // the rewritten extent
   CachedExtent &extent;
index 03cceabbd6d534474a775444d15b484fd7fdba5b..37a6e91f249d5cd309e1123c7e214f00d9168a04 100644 (file)
@@ -966,13 +966,22 @@ BtreeLBAManager::update_mappings(
          return this->_update_mapping(
            c.trans,
            *cursor,
-           [prev_addr, addr, len, checksum](
+           [prev_addr, addr, len, checksum, extent, c](
              const lba_map_val_t &in) {
              lba_map_val_t ret = in;
              ceph_assert(in.pladdr.is_paddr());
-             ceph_assert(in.pladdr.get_paddr() == prev_addr);
              ceph_assert(in.len == len);
-             ret.pladdr = addr;
+             if (likely(in.pladdr.get_paddr() == prev_addr)) {
+                ret.pladdr = addr;
+              } else {
+                // this can only happen when the extent is EXIST_CLEAN
+                // and is demoted onto the cold tier by a DEMOTE trans.
+                assert(in.shadow_paddr == P_ADDR_NULL);
+                assert(extent->is_exist_clean());
+                assert(extent->get_paddr() == in.pladdr.get_paddr());
+                assert(c.cache.is_on_cold_tier(extent->get_paddr()));
+                assert(!c.cache.is_on_cold_tier(prev_addr));
+              }
              ret.checksum = checksum;
              return ret;
            },
index a79950b64c4bcbefeff0b62410de107bc1a61b0c..49df7813c01e7baaa690bed72fb5521712a57bfe 100644 (file)
@@ -324,6 +324,7 @@ struct LBALeafNode
     iterator &iter)
   {
     LOG_PREFIX(LBALeafNode::merge_content_to);
+    SUBTRACET(seastore_lba, "merging with {}", t, pending_version);
     std::map<laddr_t, pladdr_t> modified;
     auto it = pending_version.begin();
     while (it != pending_version.end() && iter != this->end()) {
@@ -345,14 +346,20 @@ struct LBALeafNode
         ceph_abort();
       }
       if (is_valid_child_ptr(child)) {
-        if ((child->_is_mutable() || child->_is_pending_io())) {
-          // skip the ones that the pending version is also modifying
+        if (// skip the ones that the pending version is also modifying
+           (child->_is_mutable() || child->_is_pending_io()) ||
+           // EXIST_CLEAN extents created by DEMOTE transactions also
+           // updates their paddrs, so they should also be skpped.
+           (pending_version.t->get_src() == transaction_type_t::DEMOTE)) {
+          SUBTRACET(seastore_lba, "skipping {}~{}", t, it->get_key(), it->get_val());
           it++;
           continue;
         } else {
           assert(child->_is_exist_clean() || child->_is_exist_mutation_pending());
         }
       }
+      SUBTRACET(seastore_lba, "examing v2: {}~{}, v1: {}~{}",
+        t, it->get_key(), it->get_val(), iter->get_key(), iter->get_val());
       auto pending_key = it->get_key();
       auto stable_key = iter->get_key();
       auto stable_end = stable_key + v1.len;
@@ -362,13 +369,21 @@ struct LBALeafNode
         if (pending_key != stable_key) {
           assert(v2.pladdr != v1.pladdr);
           assert(is_valid_child_ptr(child));
+          assert(child->_is_exist_clean());
         }
         if (v2.pladdr != v1.pladdr) {
           auto m_v2 = v2;
           auto off = pending_key.get_byte_distance<extent_len_t>(stable_key);
           auto paddr = v1.pladdr.get_paddr();
           paddr = paddr + off;
+          SUBTRACET(seastore_lba, "merging to {}, paddr: {} -> {}",
+            t, pending_version, m_v2.pladdr, paddr);
           m_v2.pladdr = paddr;
+          if (v1.shadow_paddr == P_ADDR_NULL) {
+            m_v2.shadow_paddr = P_ADDR_NULL;
+          } else {
+            m_v2.shadow_paddr = (v1.shadow_paddr + off);
+          }
           SUBTRACET(seastore_lba, "merging to {}, paddr: {} -> {}",
             t, pending_version, m_v2.pladdr, paddr);
           if (!is_valid_child_ptr(child)) {
index ea4bb9c6a763be72b1357cd52ff0dbd2a8eda3f3..977b96aaf21d8ea7c4d6246f1c6556aac0c59029 100644 (file)
@@ -44,6 +44,20 @@ public:
   laddr_t get_end() const {
     return (get_laddr() + get_length()).checked_to_laddr();
   }
+
+  TCachedExtentRef<LogicalChildNode> get_shadow() const {
+    return shadow;
+  }
+
+  void set_shadow(TCachedExtentRef<LogicalChildNode> &s) {
+    assert(!shadow);
+    shadow = s;
+  }
+  
+  void reset_shadow() {
+    shadow.reset();
+  }
+
 protected:
   void on_replace_prior(Transaction &t) final {
     assert(is_seen_by_users());
@@ -56,6 +70,8 @@ protected:
   void on_data_commit() final {
     ceph_abort("impossible");
   }
+private:
+  TCachedExtentRef<LogicalChildNode> shadow;
 };
 using LogicalChildNodeRef = TCachedExtentRef<LogicalChildNode>;
 } // namespace crimson::os::seastore
index f4e11936af181838990b2d18f6a64d52a9da36cb..f27cfb123b283c5786e873fac0904cc5db86df34 100644 (file)
@@ -2757,7 +2757,9 @@ constexpr bool is_background_transaction(transaction_type_t type) {
 constexpr bool is_rewrite_transaction(transaction_type_t type) {
   return type == transaction_type_t::TRIM_DIRTY ||
     type == transaction_type_t::CLEANER_MAIN ||
-    type == transaction_type_t::CLEANER_COLD;
+    type == transaction_type_t::CLEANER_COLD ||
+    type == transaction_type_t::DEMOTE ||
+    type == transaction_type_t::PROMOTE;
 }
 
 constexpr bool is_trim_transaction(transaction_type_t type) {
index 3f5ff0fa75a7bec304d2deff1a92d2a2ad997b3f..ed1af43bd9474dd113201f054c3bc7163235fefc 100644 (file)
@@ -364,6 +364,21 @@ public:
     }
   }
 
+  bool remove_from_retired_set(CachedExtent &ext) {
+    auto it = retired_set.find(ext.get_paddr());
+    if (it == retired_set.end()) {
+      return false;
+    }
+    auto &extent = it->extent;
+    if (extent->get_paddr() != ext.get_paddr()) {
+      return false;
+    } else {
+      assert(ext.get_length() == extent->get_length());
+      retired_set.erase(it);
+      return true;
+    }
+  }
+
   std::pair<bool, bool> pre_stable_extent_paddr_mod(
     read_set_item_t<Transaction> &item)
   {
@@ -432,6 +447,24 @@ public:
       write_set.insert(mextent);
     }
   }
+  void remove_shadow_from_write_set(
+    const paddr_t &shadow_paddr, extent_len_t len) {
+    std::vector<CachedExtent*> exts;
+    for (auto [bottom, top] = write_set.get_overlap(shadow_paddr, len);
+         bottom != top;
+         bottom++) {
+      auto &mextent = *bottom;
+      if (mextent.is_initial_pending()) {
+        assert(!mextent.is_shadow_extent());
+        continue;
+      }
+      assert(mextent.is_shadow_extent() && mextent.is_exist_clean());
+      exts.emplace_back(&mextent);
+    }
+    for (auto i :exts) {
+      write_set.erase(*i);
+    }
+  }
 
   template <typename F>
   auto for_each_finalized_fresh_block(F &&f) const {
index 851b9883461105f654eeef852a4b03c2930b515d..d32d753ee3887e8a36a934e53966d070689c30c3 100644 (file)
@@ -259,13 +259,14 @@ TransactionManager::ref_ret TransactionManager::remove(
         auto laddr = ref->get_laddr();
         cache->retire_absent_extent_addr_by_type(
           t, laddr, shadow_addr, length, ref->get_type(),
-          [laddr](auto &extent) {
+          [ref, laddr](auto &extent) {
             auto lextent = extent.template cast<LogicalChildNode>();
             assert(extent.is_logical());
             assert(!lextent->has_laddr());
             assert(!extent.has_been_invalidated());
             lextent->set_laddr(laddr);
             extent.set_shadow_extent(true);
+            ref->set_shadow(lextent);
           });
       }
     }
@@ -332,11 +333,32 @@ TransactionManager::_remove(
        LogicalChildNode
        >();
       ceph_assert(extent);
-      cache->retire_extent(t, std::move(extent));
+      cache->retire_extent(t, extent);
+      if (mapping.has_shadow_val()) {
+        if (auto shadow = extent->get_shadow(); shadow) {
+          cache->retire_extent(t, shadow);
+        } else {
+          auto laddr = mapping.get_intermediate_base();
+          std::ignore = cache->retire_absent_extent_addr_by_type(
+            t, laddr,
+            mapping.get_shadow_val(),
+            mapping.get_intermediate_length(),
+            mapping.get_extent_type(),
+            [extent, laddr](auto &ext) {
+              auto lextent = ext.template cast<LogicalChildNode>();
+              assert(ext.is_logical());
+              assert(!lextent->has_laddr());
+              assert(!ext.has_been_invalidated());
+              lextent->set_laddr(laddr);
+              ext.set_shadow_extent(true);
+              extent->set_shadow(lextent);
+            });
+        }
+      }
     } else {
       auto &child_pos = maybe_mapped_extent.get_child_pos();
       auto laddr = mapping.get_intermediate_base();
-      std::ignore = cache->retire_absent_extent_addr_by_type(
+      auto ext = cache->retire_absent_extent_addr_by_type(
        t, laddr,
        mapping.get_val(),
        mapping.get_intermediate_length(),
@@ -349,13 +371,23 @@ TransactionManager::_remove(
           child_pos.link_child(lextent.get());
           lextent->set_laddr(laddr);
         }
-      );
-    }
-    if (mapping.has_shadow_val()) {
-      cache->retire_absent_extent_addr(
-        t, mapping.get_intermediate_base(),
-        mapping.get_shadow_val(),
-        mapping.get_intermediate_length());
+      )->template cast<LogicalChildNode>();
+      if (mapping.has_shadow_val()) {
+        std::ignore = cache->retire_absent_extent_addr_by_type(
+          t, mapping.get_intermediate_base(),
+          mapping.get_shadow_val(),
+          mapping.get_intermediate_length(),
+          mapping.get_extent_type(),
+          [laddr, ext](auto &extent) {
+            auto lextent = extent.template cast<LogicalChildNode>();
+            assert(extent.is_logical());
+            assert(!lextent->has_laddr());
+            assert(!extent.has_been_invalidated());
+            lextent->set_laddr(laddr);
+            extent.set_shadow_extent(true);
+            ext->set_shadow(lextent);
+          });
+      }
     }
   }
 
@@ -465,7 +497,7 @@ TransactionManager::refs_ret TransactionManager::remove(
 
 base_iertr::future<LogicalChildNodeRef>
 TransactionManager::relocate_logical_extent(
-  Transaction &t, LBAMapping mapping)
+  Transaction &t, LBAMapping mapping, laddr_t new_laddr)
 {
   LOG_PREFIX(TransactionManager::relocate_logical_extent);
   SUBDEBUGT(seastore_tm, "relocate {}", t, mapping);
@@ -476,7 +508,7 @@ TransactionManager::relocate_logical_extent(
   if (!v.has_child()) {
     auto &child_pos = v.get_child_pos();
     auto laddr = mapping.get_key();
-    std::ignore = cache->retire_absent_extent_addr_by_type(
+    auto extent = cache->retire_absent_extent_addr_by_type(
       t,
       laddr,
       mapping.get_val(),
@@ -490,29 +522,53 @@ TransactionManager::relocate_logical_extent(
         child_pos.link_child(lextent.get());
         lextent->set_laddr(laddr);
       }
-    );
-    co_return cache->alloc_remapped_extent_by_type(
-      t, mapping.get_extent_type(), mapping.get_key(),
-      mapping.get_val(), 0, mapping.get_length(), std::nullopt
     )->cast<LogicalChildNode>();
-  }
-
-  auto extent = co_await v.get_child_fut().si_then([](auto ext) {
-    return ext;
-  });
+    if (mapping.has_shadow_val()) {
+      std::ignore = cache->retire_absent_extent_addr_by_type(
+        t, laddr,
+        mapping.get_shadow_val(),
+        mapping.get_intermediate_length(),
+        mapping.get_extent_type(),
+        [extent, laddr](auto &ext) {
+          auto lextent = ext.template cast<LogicalChildNode>();
+          assert(ext.is_logical());
+          assert(!lextent->has_laddr());
+          assert(!ext.has_been_invalidated());
+          lextent->set_laddr(laddr);
+          ext.set_shadow_extent(true);
+          extent->set_shadow(lextent);
+        });
+    }
+  } else {
+    auto extent = co_await v.get_child_fut_as<LogicalChildNode>();
 
-  if (extent->is_stable()) {
-    cache->retire_extent(t, extent);
-    co_return cache->alloc_remapped_extent_by_type(
-      t, mapping.get_extent_type(), mapping.get_key(),
-      mapping.get_val(), 0, mapping.get_length(), std::nullopt
+    if (extent->is_stable()) {
+      cache->retire_extent(t, extent);
+    } else {
+      //TODO: relocating logical extents doesn't support
+      //      mutation pending extents yet.
+      assert(extent->is_initial_pending() || extent->is_exist_clean());
+      extent->set_laddr(new_laddr);
+      if (mapping.has_shadow_val()) {
+        assert(extent->get_shadow());
+        extent->get_shadow()->set_laddr(new_laddr);
+      }
+      co_return extent;
+    }
+  }
+  auto remapped_extent = cache->alloc_remapped_extent_by_type(
+    t, mapping.get_extent_type(), new_laddr,
+    mapping.get_val(), 0, mapping.get_length(), std::nullopt
+  )->cast<LogicalChildNode>();
+  if (mapping.has_shadow_val()) {
+    auto remapped_shadow = cache->alloc_remapped_extent_by_type(
+      t, mapping.get_extent_type(), new_laddr,
+      mapping.get_shadow_val(), 0, mapping.get_length(), std::nullopt
     )->cast<LogicalChildNode>();
-  } else {
-    //TODO: relocating logical extents doesn't support
-    //      mutation pending extents yet.
-    assert(extent->is_initial_pending() || extent->is_exist_clean());
-    co_return extent;
+    remapped_shadow->set_shadow_extent(true);
+    remapped_extent->set_shadow(remapped_shadow);
   }
+  co_return remapped_extent;
 }
 
 base_iertr::future<LogicalChildNodeRef>
@@ -525,8 +581,9 @@ TransactionManager::relocate_shadow_extent(
   assert(!mapping.is_zero_reserved());
   assert(mapping.is_viewable());
   assert(!mapping.is_indirect());
+  assert(t.get_src() == transaction_type_t::DEMOTE);
   auto v = get_extent_if_linked(t, *mapping.direct_cursor);
-  CachedExtentRef extent;
+  LogicalChildNodeRef extent;
   auto laddr = mapping.get_intermediate_base();
   if (!v.has_child()) {
     auto &child_pos = v.get_child_pos();
@@ -544,26 +601,35 @@ TransactionManager::relocate_shadow_extent(
         child_pos.link_child(lextent.get());
         lextent->set_laddr(laddr);
       }
-    );
+    )->template cast<LogicalChildNode>();
   } else {
-    auto extent = co_await std::move(v.get_child_fut());
+    extent = co_await std::move(v.get_child_fut());
     cache->retire_extent(t, extent);
   }
-  auto shadow_paddr = mapping.get_shadow_val();
-  std::ignore = cache->retire_absent_extent_addr_by_type(
-    t, laddr, shadow_paddr, mapping.get_length(), mapping.get_extent_type(),
-    [laddr](auto &ext) {
-      auto lextent = ext.template cast<LogicalChildNode>();
-      assert(ext.is_logical());
-      assert(!lextent->has_laddr());
-      assert(!ext.has_been_invalidated());
-      lextent->set_laddr(laddr);
-    }
-  );
-  co_return cache->alloc_remapped_extent_by_type(
+  if (auto shadow = extent->get_shadow(); shadow) {
+    cache->retire_extent(t, shadow);
+  } else {
+    auto shadow_paddr = mapping.get_shadow_val();
+    std::ignore = cache->retire_absent_extent_addr_by_type(
+      t, laddr, shadow_paddr, mapping.get_length(), mapping.get_extent_type(),
+      [laddr, extent](auto &ext) {
+        auto lextent = ext.template cast<LogicalChildNode>();
+        assert(ext.is_logical());
+        assert(!lextent->has_laddr());
+        assert(!ext.has_been_invalidated());
+        lextent->set_laddr(laddr);
+        ext.set_shadow_extent(true);
+        extent->set_shadow(lextent);
+      }
+    );
+  }
+  auto nextent =  cache->alloc_remapped_extent_by_type(
     t, mapping.get_extent_type(), laddr,
     mapping.get_shadow_val(), 0, mapping.get_length(), std::nullopt
   )->cast<LogicalChildNode>();
+  nextent->set_prior_instance(extent);
+  nextent->set_last_committed_crc(extent->get_last_committed_crc());
+  co_return nextent;
 }
 
 TransactionManager::submit_transaction_iertr::future<>
@@ -1141,9 +1207,9 @@ TransactionManager::move_region(
         dst = co_await dst.refresh();
       }
     } else if (!src.is_zero_reserved()) {
-      auto extent = co_await relocate_logical_extent(t, src);
       auto laddr = calc_dst_key();
-      extent->set_laddr(laddr);
+      auto extent = co_await relocate_logical_extent(t, src, laddr);
+      assert(extent->get_laddr() == laddr);
       auto ret = co_await lba_manager->move_direct_mapping(
         t, src.get_effective_cursor_ref(),
         laddr, dst.get_effective_cursor_ref(), *extent);
@@ -1247,6 +1313,8 @@ TransactionManager::promote_extent(
         slice_length,
         std::nullopt);
       remapped_cold_extent->set_shadow_extent(true);
+      auto lremapped = remapped_cold_extent->template cast<LogicalChildNode>();
+      lext->set_shadow(lremapped);
 
       offset += slice_length;
     }
@@ -1290,8 +1358,8 @@ TransactionManager::promote_extent(
       orig_ext->get_length(),
       std::nullopt);
     remapped_cold_extent->set_shadow_extent(true);
-
-    remapped_cold_extent->set_shadow_extent(true);
+    auto lremapped = remapped_cold_extent->template cast<LogicalChildNode>();
+    lext->set_shadow(lremapped);
   }
 
   auto cursor = co_await lba_manager->get_cursor(
index 0d99e31dd0ab92c816c1615bd832435e69f8632e..5edc797840d9b8d96a71a0fc9f16ffb7d514d504 100644 (file)
@@ -113,7 +113,8 @@ public:
    */
   base_iertr::future<LogicalChildNodeRef> relocate_logical_extent(
     Transaction &t,
-    LBAMapping mapping);
+    LBAMapping mapping,
+    laddr_t new_laddr);
 
   base_iertr::future<LogicalChildNodeRef> relocate_shadow_extent(
     Transaction &t,
@@ -1546,7 +1547,7 @@ private:
           SUBTRACET(seastore_tm, "retire extent place holder...", t);
           auto &child_pos = ret.get_child_pos();
           auto laddr = pin.get_key();
-          std::ignore = cache->retire_absent_extent_addr_by_type(
+          auto ext = cache->retire_absent_extent_addr_by_type(
             t, laddr, pin.get_val(), original_len, pin.get_extent_type(),
             [&child_pos, laddr](auto &extent) mutable {
               auto lextent = extent.template cast<LogicalChildNode>();
@@ -1556,17 +1557,19 @@ private:
               child_pos.link_child(lextent.get());
               lextent->set_laddr(laddr);
             }
-          );
+          )->template cast<LogicalChildNode>();
           if (pin.has_shadow_val()) {
             cache->retire_absent_extent_addr_by_type(
               t, pin.get_key(), pin.get_shadow_val(),
               original_len, pin.get_extent_type(),
-              [laddr](auto &extent) {
+              [laddr, ext](auto &extent) {
                 auto lextent = extent.template cast<LogicalChildNode>();
                 assert(extent.is_logical());
                 assert(!lextent->has_laddr());
                 assert(!extent.has_been_invalidated());
                 lextent->set_laddr(laddr);
+                extent.set_shadow_extent(true);
+                ext->set_shadow(lextent);
               }
             );
           }
@@ -1594,6 +1597,26 @@ private:
         SUBTRACET(seastore_tm, "retire extent...", t);
         assert(extent->is_seen_by_users());
         cache->retire_extent(t, extent);
+        if (pin.has_shadow_val()) {
+          if (auto shadow = extent->get_shadow()) {
+            cache->retire_extent(t, shadow);
+          } else {
+            auto laddr = pin.get_key();
+            cache->retire_absent_extent_addr_by_type(
+              t, laddr, pin.get_shadow_val(),
+              original_len, pin.get_extent_type(),
+              [laddr, extent](auto &ext) {
+                auto lextent = ext.template cast<LogicalChildNode>();
+                assert(ext.is_logical());
+                assert(!lextent->has_laddr());
+                assert(!ext.has_been_invalidated());
+                lextent->set_laddr(laddr);
+                ext.set_shadow_extent(true);
+                extent->set_shadow(lextent);
+              }
+            );
+          }
+        }
       }
       for (auto &remap : remaps) {
         auto remap_offset = remap.offset;
@@ -1629,6 +1652,10 @@ private:
             remap_len,
             std::nullopt);
           cold_ext->set_shadow_extent(true);
+          auto &lremapped = static_cast<
+            LogicalChildNode&>(*remapped_extent);
+          auto lcold_ext = cold_ext->template cast<LogicalChildNode>();
+          lremapped.set_shadow(lcold_ext);
         }
         // user must initialize the logical extent themselves.
         remapped_extent->set_seen_by_users();