SUBTRACET(seastore_t, "", t);
assert(!t.conflicted);
t.conflicted = true;
+ // count is only *sampled* for the user-MUTATE do_transaction path,
+ // where the transaction is reused across retries
+ ++t.num_replays;
auto& efforts = get_by_src(stats.invalidated_efforts_by_src,
t.get_src());
);
}
+ stats.conflict_replays.buckets.resize(REPLAY_BUCKETS);
+ for (std::size_t i = 0; i < REPLAY_BUCKETS; ++i) {
+ stats.conflict_replays.buckets[i].upper_bound = i;
+ stats.conflict_replays.buckets[i].count = 0;
+ }
+ metrics.add_group(
+ "seastore",
+ {
+ sm::make_histogram(
+ "conflict_replay_distribution",
+ [this]() -> seastar::metrics::histogram& {
+ return stats.conflict_replays;
+ },
+ sm::description("distribution of per-transaction conflict/replay counts "
+ "before commit, for user transactions submitted via "
+ "do_transaction (the reused-transaction / "
+ "with_repeat_trans_intr path); not all MUTATE transactions"),
+ {sm::label_instance("shard_store_index", std::to_string(store_index))}
+ )
+ }
+ );
+
metrics.add_group(
"seastore",
{
);
DEBUGT("done", *ctx.transaction);
+ add_conflict_replay_sample(ctx.transaction->get_num_replays());
add_latency_sample(
op_type_t::DO_TRANSACTION,
std::chrono::steady_clock::now() - ctx.begin_timestamp);
100000
};
+ // Buckets for the per-transaction conflict/replay distribution.
+ static constexpr std::size_t REPLAY_BUCKETS = 16;
struct {
std::array<seastar::metrics::histogram, LAT_MAX> op_lat;
+ seastar::metrics::histogram conflict_replays;
} stats;
seastar::metrics::histogram& get_latency(
}
}
+ // Record how many times a just-completed transaction was conflicted/replayed.
+ // Called only from the do_transaction_no_callbacks() completion path.
+ void add_conflict_replay_sample(std::size_t num_replays) {
+ auto& hist = stats.conflict_replays;
+ if (hist.buckets.empty()) {
+ // register_metrics() did not run (store inactive); nothing to record.
+ return;
+ }
+ std::size_t idx = num_replays < REPLAY_BUCKETS ?
+ num_replays : REPLAY_BUCKETS - 1;
+ ++hist.buckets[idx].count;
+ ++hist.sample_count;
+ hist.sample_sum += num_replays;
+ }
+
/*
* omaptree interfaces
*/
return conflicted;
}
+ // Number of times this transaction was conflicted and replayed before
+ // finally committing. do_transaction_no_callbacks() (user MUTATE writes)
+ std::size_t get_num_replays() const {
+ return num_replays;
+ }
+
auto &get_handle() {
return handle;
}
bool conflicted = false;
+ std::size_t num_replays = 0;
+
bool has_reset = false;
OrderingHandle handle;