assert(next->get_paddr().is_absolute() || next->get_paddr().is_root());
assert(next->version == prev->version + 1);
const auto t_src = t.get_src();
- ceph_assert(should_use_no_conflict_publish(t_src, next->get_type()));
+ ceph_assert(should_use_no_conflict_publish(t, next->get_type()));
bool was_stable_dirty = prev->is_stable_dirty();
if (!was_stable_dirty) {
DEBUGT("invalid mutated extent -- {}", t, *i);
continue;
}
- if (should_use_no_conflict_publish(t.get_src(), i->get_type())) {
+ if (should_use_no_conflict_publish(t, i->get_type())) {
i->new_committer(t);
i->committer->block_trans(t);
}
}
if (i->is_mutation_pending()) {
- const bool use_no_conflict = should_use_no_conflict_publish(t.get_src(), i->get_type());
+ const bool use_no_conflict =
+ should_use_no_conflict_publish(t, i->get_type());
// Block the new extent readers until the journal commit completes.
i->set_io_wait(CachedExtent::extent_state_t::DIRTY, use_no_conflict);
retire_stat.increment(extent->get_length());
DEBUGT("retired and remove extent {}~0x{:x} -- {}",
t, extent->get_paddr(), extent->get_length(), *extent);
- if (should_use_no_conflict_publish(t.get_src(), extent->get_type())) {
+ if (should_use_no_conflict_publish(t, extent->get_type())) {
// avoid extent invalidation on retirement
// only adjust dirty bookkeeping
// we would invalidate them in complete_commit final stage
i->get_type()));
}
i->set_io_wait(CachedExtent::extent_state_t::CLEAN,
- should_use_no_conflict_publish(t.get_src(), i->get_type()));
+ should_use_no_conflict_publish(t, i->get_type()));
// Note, paddr is known until complete_commit(),
// so add_extent() later.
- if (should_use_no_conflict_publish(t.get_src(), i->get_type())) {
+ if (should_use_no_conflict_publish(t, i->get_type())) {
assert(i->get_prior_instance());
assert(!i->committer);
assert(!i->get_prior_instance()->committer);
auto &committer = *i->committer;
committer.block_trans(t);
i->get_prior_instance()->set_io_wait(
- CachedExtent::extent_state_t::CLEAN, should_use_no_conflict_publish(t.get_src(), i->get_type()));
+ CachedExtent::extent_state_t::CLEAN,
+ should_use_no_conflict_publish(t, i->get_type()));
}
}
i->get_length(),
i->get_type()));
}
- if (should_use_no_conflict_publish(t.get_src(), i->get_type())) {
+ if (should_use_no_conflict_publish(t, i->get_type())) {
assert(i->get_prior_instance());
assert(!i->committer);
assert(!i->get_prior_instance()->committer);
CachedExtent::extent_state_t::CLEAN, true);
}
i->set_io_wait(CachedExtent::extent_state_t::CLEAN,
- should_use_no_conflict_publish(t.get_src(), i->get_type()));
+ should_use_no_conflict_publish(t, i->get_type()));
// Note, paddr is (can be) known until complete_commit(),
// so add_extent() later.
}
} else {
assert(i->is_exist_mutation_pending());
i->set_io_wait(CachedExtent::extent_state_t::DIRTY,
- should_use_no_conflict_publish(t.get_src(), i->get_type()));
+ should_use_no_conflict_publish(t, i->get_type()));
}
// exist mutation pending extents must be in t.mutated_block_list
t, final_block_start, start_seq);
for (auto &i: t.retired_set) {
auto &extent = i.extent;
- auto trans_src = t.get_src();
- if (should_use_no_conflict_publish(trans_src, extent->get_type())) {
+ if (should_use_no_conflict_publish(t, extent->get_type())) {
// retired extents should remain valid through complete_commit().
// We only free space post-commit *AFTER* handoff.
assert(extent->is_valid());
i->pending_for_transaction = TRANS_ID_NULL;
i->on_initial_write();
const auto t_src = t.get_src();
- if (should_use_no_conflict_publish(t_src, i->get_type())) {
+ if (should_use_no_conflict_publish(t, i->get_type())) {
ceph_assert(i->committer);
auto &committer = *i->committer;
auto &prior = *i->get_prior_instance();
if (i->version == 1 || is_root_type(i->get_type())) {
i->dirty_from = start_seq;
DEBUGT("commit extent done, become dirty -- {}", t, *i);
- if (should_use_no_conflict_publish(t.get_src(), i->get_type())) {
+ if (should_use_no_conflict_publish(t, i->get_type())) {
auto &prior = *i->get_prior_instance();
prior.dirty_from = start_seq;
ceph_assert(i->committer);
DEBUGT("commit extent done -- {}", t, *i);
}
i->on_delta_write(final_block_start);
- if (should_use_no_conflict_publish(t.get_src(), i->get_type())) {
+ if (should_use_no_conflict_publish(t, i->get_type())) {
TRACET("committing paddr to prior for {}, prior={}",
t, *i, *i->prior_instance);
assert(i->committer);
}
t.for_each_finalized_fresh_block([&t](const CachedExtentRef &i) {
- if (should_use_no_conflict_publish(t.get_src(), i->get_type())) {
+ if (should_use_no_conflict_publish(t, i->get_type())) {
i->set_invalid(t);
}
});
for (auto &i: t.mutated_block_list) {
- if (should_use_no_conflict_publish(t.get_src(), i->get_type())) {
+ if (should_use_no_conflict_publish(t, i->get_type())) {
i->set_invalid(t);
}
}
rewrite_stats = {};
conflicted = false;
need_wait_visibility = false;
+ force_rewrite_conflict = false;
assert(backref_entries.empty());
if (!has_reset) {
has_reset = true;
btree_cursor_stats_t cursor_stats;
bool need_wait_visibility = false;
+ bool force_rewrite_conflict = false;
using update_copied_lba_key_func_t =
std::function<void (Transaction&, laddr_t, paddr_t)>;
CACHE_HINT_TOUCH)
);
}
+/**
+ * should_use_no_conflict_publish()
+ *
+ * Returns true when this (transaction source, extent type) pair should take
+ * the no-conflict publish path (i.e avoid invalidate-and-retry and use the
+ * committer + visibility hand-off).
+ *
+ * Currently true for:
+ * - rewrite (background) transactions, for any non-root extent
+ *
+ * To be expanded to:
+ * - user (txn_manager) transactions that mutate LBA nodes
+ * - Onode/Omap nodes
+ */
+constexpr bool should_use_no_conflict_publish(const Transaction &t,
+ extent_types_t ext_type) {
+ // keep classic handling for ROOT
+ if (is_root_type(ext_type)) {
+ return false;
+ }
+
+ // TODO: Extend this as support grows (e.g. Onode/OMAP nodes).
+ // is_user_transaction(txn_type) && is_lba_node(ext_type)
+
+ return !t.force_rewrite_conflict && is_rewrite_transaction(t.get_src());
+}
+
}