|
3 | 3 |
|
4 | 4 | #pragma once |
5 | 5 |
|
| 6 | +#include <concepts> |
6 | 7 | #include <limits> |
| 8 | +#include <optional> |
| 9 | +#include <type_traits> |
| 10 | +#include <vector> |
7 | 11 |
|
| 12 | +#include <seastar/core/shared_future.hh> |
8 | 13 | #include <seastar/core/smp.hh> |
9 | 14 |
|
| 15 | +#include "common/likely.h" |
10 | 16 | #include "crimson/common/errorator.h" |
11 | 17 | #include "crimson/common/utility.h" |
12 | 18 |
|
@@ -89,4 +95,142 @@ auto sharded_map_seq(T &t, F &&f) { |
89 | 95 | }); |
90 | 96 | } |
91 | 97 |
|
92 | | -} |
| 98 | +enum class crosscore_type_t { |
| 99 | + ONE, // from 1 to 1 core |
| 100 | + ONE_N, // from 1 to n cores |
| 101 | + N_ONE, // from n to 1 core |
| 102 | +}; |
| 103 | + |
| 104 | +/** |
| 105 | + * smp_crosscore_ordering_t |
| 106 | + * |
| 107 | + * To preserve the event order from source to target core(s). |
| 108 | + */ |
| 109 | +template <crosscore_type_t CTypeValue> |
| 110 | +class smp_crosscore_ordering_t { |
| 111 | + static constexpr bool IS_ONE = (CTypeValue == crosscore_type_t::ONE); |
| 112 | + static constexpr bool IS_ONE_N = (CTypeValue == crosscore_type_t::ONE_N); |
| 113 | + static constexpr bool IS_N_ONE = (CTypeValue == crosscore_type_t::N_ONE); |
| 114 | + static_assert(IS_ONE || IS_ONE_N || IS_N_ONE); |
| 115 | + |
| 116 | +public: |
| 117 | + using seq_t = uint64_t; |
| 118 | + |
| 119 | + smp_crosscore_ordering_t() requires IS_ONE |
| 120 | + : out_seqs(0) { } |
| 121 | + |
| 122 | + smp_crosscore_ordering_t() requires (!IS_ONE) |
| 123 | + : out_seqs(seastar::smp::count, 0), |
| 124 | + in_controls(seastar::smp::count) {} |
| 125 | + |
| 126 | + ~smp_crosscore_ordering_t() = default; |
| 127 | + |
| 128 | + /* |
| 129 | + * Called by the original core to get the ordering sequence |
| 130 | + */ |
| 131 | + |
| 132 | + seq_t prepare_submit() requires IS_ONE { |
| 133 | + return do_prepare_submit(out_seqs); |
| 134 | + } |
| 135 | + |
| 136 | + seq_t prepare_submit(core_id_t target_core) requires IS_ONE_N { |
| 137 | + return do_prepare_submit(out_seqs[target_core]); |
| 138 | + } |
| 139 | + |
| 140 | + seq_t prepare_submit() requires IS_N_ONE { |
| 141 | + return do_prepare_submit(out_seqs[seastar::this_shard_id()]); |
| 142 | + } |
| 143 | + |
| 144 | + /* |
| 145 | + * Called by the target core to preserve the ordering |
| 146 | + */ |
| 147 | + |
| 148 | + seq_t get_in_seq() const requires IS_ONE { |
| 149 | + return in_controls.seq; |
| 150 | + } |
| 151 | + |
| 152 | + seq_t get_in_seq() const requires IS_ONE_N { |
| 153 | + return in_controls[seastar::this_shard_id()].seq; |
| 154 | + } |
| 155 | + |
| 156 | + seq_t get_in_seq(core_id_t source_core) const requires IS_N_ONE { |
| 157 | + return in_controls[source_core].seq; |
| 158 | + } |
| 159 | + |
| 160 | + bool proceed_or_wait(seq_t seq) requires IS_ONE { |
| 161 | + return in_controls.proceed_or_wait(seq); |
| 162 | + } |
| 163 | + |
| 164 | + bool proceed_or_wait(seq_t seq) requires IS_ONE_N { |
| 165 | + return in_controls[seastar::this_shard_id()].proceed_or_wait(seq); |
| 166 | + } |
| 167 | + |
| 168 | + bool proceed_or_wait(seq_t seq, core_id_t source_core) requires IS_N_ONE { |
| 169 | + return in_controls[source_core].proceed_or_wait(seq); |
| 170 | + } |
| 171 | + |
| 172 | + seastar::future<> wait(seq_t seq) requires IS_ONE { |
| 173 | + return in_controls.wait(seq); |
| 174 | + } |
| 175 | + |
| 176 | + seastar::future<> wait(seq_t seq) requires IS_ONE_N { |
| 177 | + return in_controls[seastar::this_shard_id()].wait(seq); |
| 178 | + } |
| 179 | + |
| 180 | + seastar::future<> wait(seq_t seq, core_id_t source_core) requires IS_N_ONE { |
| 181 | + return in_controls[source_core].wait(seq); |
| 182 | + } |
| 183 | + |
| 184 | + void reset_wait() requires IS_N_ONE { |
| 185 | + for (auto &in_control : in_controls) { |
| 186 | + in_control.reset_wait(); |
| 187 | + } |
| 188 | + } |
| 189 | + |
| 190 | +private: |
| 191 | + struct in_control_t { |
| 192 | + seq_t seq = 0; |
| 193 | + std::optional<seastar::shared_promise<>> pr_wait; |
| 194 | + |
| 195 | + bool proceed_or_wait(seq_t in_seq) { |
| 196 | + if (in_seq == seq + 1) { |
| 197 | + ++seq; |
| 198 | + reset_wait(); |
| 199 | + return true; |
| 200 | + } else { |
| 201 | + return false; |
| 202 | + } |
| 203 | + } |
| 204 | + |
| 205 | + seastar::future<> wait(seq_t in_seq) { |
| 206 | + assert(in_seq != seq + 1); |
| 207 | + if (!pr_wait.has_value()) { |
| 208 | + pr_wait = seastar::shared_promise<>(); |
| 209 | + } |
| 210 | + return pr_wait->get_shared_future(); |
| 211 | + } |
| 212 | + |
| 213 | + void reset_wait() { |
| 214 | + if (unlikely(pr_wait.has_value())) { |
| 215 | + pr_wait->set_value(); |
| 216 | + pr_wait = std::nullopt; |
| 217 | + } |
| 218 | + } |
| 219 | + }; |
| 220 | + |
| 221 | + seq_t do_prepare_submit(seq_t &out_seq) { |
| 222 | + return ++out_seq; |
| 223 | + } |
| 224 | + |
| 225 | + std::conditional_t< |
| 226 | + IS_ONE, |
| 227 | + seq_t, std::vector<seq_t> |
| 228 | + > out_seqs; |
| 229 | + |
| 230 | + std::conditional_t< |
| 231 | + IS_ONE, |
| 232 | + in_control_t, std::vector<in_control_t> |
| 233 | + > in_controls; |
| 234 | +}; |
| 235 | + |
| 236 | +} // namespace crimson |
0 commit comments