1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
//! `RingContract` - the declared operation envelope for a ring.
//!
//! A [`RingContract`] is the USER OVERRIDE on the otherwise fully
//! automatic ring: peer-count ceilings, an ordering contract, and a
//! capacity bound, declared as one validated artifact every attaching
//! party agrees on. An `AdaptiveRing` WITHOUT a declared contract is
//! unbounded - peers grow the ring on demand and registration never
//! fails; declaring a contract is the only thing that makes
//! `TooManyProducers` / `TooManyConsumers` possible.
//!
//! (Lineage: path expressions - Campbell & Habermann, 1974 - declare
//! the legal operation histories of a shared type, with enforcement
//! derived rather than hand-written. This module is the
//! counter-compilable fragment of that idea, expressed entirely as
//! data the rings already track.)
//!
//! Two jobs:
//!
//! 1. **One validated pin.** The peer ceilings
//! ([`from_counts`](RingContract::from_counts)) and the ordering /
//! capacity constraints live in a single declared artifact instead
//! of scattered flags.
//! 2. **Give the adaptive policy a feasible-region filter.** A policy
//! proposes a candidate `(shape, capacity)`; [`permits_config`]
//! rejects any move that would violate the declared envelope, so an
//! aggressive auto-morph cannot break the contract by construction.
//!
//! Enforcement cost on the hot path is zero - the contract is consulted
//! only at attach time and at policy-tick time. The
//! ordering-contract-to-shape rule is where it earns its keep: the
//! sharded [`Mpmc`](RingShape::Mpmc) shape (per-producer lanes)
//! delivers only per-producer FIFO, so it is illegal under a `Fifo`
//! (global-total-order) contract - which is exactly the
//! `GlobalFifo -> Vyukov` rule the QoS shape policy also applies,
//! derived here from the declared contract.
//!
//! [`permits_config`]: RingContract::permits_config
use crate::adaptive_ring::RingShape;
/// The ordering envelope a ring's consumers may observe.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OrderingContract {
/// Global total order across all producers (the strongest).
Fifo,
/// Per-producer FIFO; items from different producers may interleave
/// arbitrarily, but each producer's items arrive in push order.
FifoPerProducer,
/// Bounded reordering: an item is delivered at most `k` positions
/// from its global arrival order.
KOutOfOrder(u32),
/// No ordering guarantee.
Unordered,
}
/// Declared operation envelope for a ring. The two count bounds use
/// `0` to mean "unbounded".
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RingContract {
/// Max concurrently-registered producers (`0` = unbounded).
pub max_concurrent_push: u8,
/// Max concurrently-registered consumers (`0` = unbounded).
pub max_concurrent_pop: u8,
/// The ordering envelope the consumers may observe.
pub ordering: OrderingContract,
/// Optional hard ceiling on ring capacity (`None` = unbounded).
pub capacity_bound: Option<u32>,
}
impl RingContract {
/// A contract that PINS the peer counts: registration past
/// `max_producers` / `max_consumers` returns `TooManyProducers` /
/// `TooManyConsumers` instead of growing the ring. No ordering
/// constraint, no capacity bound. The common fixed-topology
/// declaration.
pub fn from_counts(max_producers: usize, max_consumers: usize) -> Self {
Self {
max_concurrent_push: max_producers.min(u8::MAX as usize) as u8,
max_concurrent_pop: max_consumers.min(u8::MAX as usize) as u8,
ordering: OrderingContract::Unordered,
capacity_bound: None,
}
}
/// The fully-unbounded contract: any peer counts, any capacity,
/// no ordering constraint. The DEFAULT for rings with no declared
/// contract - registration never fails under it (peers grow the
/// ring on demand up to the substrate slot ceilings).
pub fn unbounded() -> Self {
Self {
max_concurrent_push: 0,
max_concurrent_pop: 0,
ordering: OrderingContract::Unordered,
capacity_bound: None,
}
}
/// May another producer attach, given `active` are registered?
#[inline]
pub fn permits_producer(&self, active: usize) -> bool {
self.max_concurrent_push == 0 || active < self.max_concurrent_push as usize
}
/// May another consumer attach, given `active` are registered?
#[inline]
pub fn permits_consumer(&self, active: usize) -> bool {
self.max_concurrent_pop == 0 || active < self.max_concurrent_pop as usize
}
/// Is a ring of `capacity` slots legal under the contract?
#[inline]
pub fn permits_capacity(&self, capacity: usize) -> bool {
match self.capacity_bound {
None => true,
Some(bound) => capacity <= bound as usize,
}
}
/// Is `shape` legal under the ordering contract? Global total order
/// is preserved only by the single-stream [`Spsc`](RingShape::Spsc)
/// and the shared-sequence [`Vyukov`](RingShape::Vyukov); the
/// partitioned per-producer-lane shapes
/// ([`Mpsc`](RingShape::Mpsc), [`Mpmc`](RingShape::Mpmc)) interleave
/// producers, so both are illegal under a `Fifo` contract. Every
/// other contract permits every shape (`FifoPerProducer` is exactly
/// what the lanes deliver).
#[inline]
pub fn permits_shape(&self, shape: RingShape) -> bool {
match self.ordering {
OrderingContract::Fifo => {
matches!(shape, RingShape::Spsc | RingShape::Vyukov)
}
_ => true,
}
}
/// Feasible-region oracle for an adaptive policy: is a candidate
/// `(shape, capacity)` configuration legal? A policy filters every
/// move it proposes through this, so an aggressive auto-morph
/// cannot violate the declared envelope.
#[inline]
pub fn permits_config(&self, shape: RingShape, capacity: usize) -> bool {
self.permits_shape(shape) && self.permits_capacity(capacity)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_counts_pins_the_peer_ceilings() {
let g = RingContract::from_counts(4, 2);
assert_eq!(g.max_concurrent_push, 4);
assert_eq!(g.max_concurrent_pop, 2);
assert_eq!(g.ordering, OrderingContract::Unordered);
assert_eq!(g.capacity_bound, None);
// The pin: ids 0..4 permitted, a 5th producer rejected.
assert!(g.permits_producer(0) && g.permits_producer(3));
assert!(!g.permits_producer(4));
assert!(g.permits_consumer(0) && g.permits_consumer(1));
assert!(!g.permits_consumer(2));
}
#[test]
fn unbounded_counts_permit_any() {
let g = RingContract {
max_concurrent_push: 0,
max_concurrent_pop: 0,
ordering: OrderingContract::Unordered,
capacity_bound: None,
};
assert!(g.permits_producer(1000));
assert!(g.permits_consumer(1000));
}
#[test]
fn fifo_permits_only_order_preserving_shapes() {
let fifo = RingContract {
max_concurrent_push: 0,
max_concurrent_pop: 0,
ordering: OrderingContract::Fifo,
capacity_bound: None,
};
// Single-stream and shared-sequence preserve global total order.
assert!(fifo.permits_shape(RingShape::Spsc));
assert!(fifo.permits_shape(RingShape::Vyukov));
// Both partitioned per-producer-lane shapes reorder producers.
assert!(!fifo.permits_shape(RingShape::Mpsc));
assert!(!fifo.permits_shape(RingShape::Mpmc));
}
#[test]
fn relaxed_contracts_permit_every_shape() {
for ordering in [
OrderingContract::FifoPerProducer,
OrderingContract::KOutOfOrder(8),
OrderingContract::Unordered,
] {
let g = RingContract {
max_concurrent_push: 0,
max_concurrent_pop: 0,
ordering,
capacity_bound: None,
};
for shape in [
RingShape::Spsc,
RingShape::Mpsc,
RingShape::Mpmc,
RingShape::Vyukov,
] {
assert!(g.permits_shape(shape), "{ordering:?} should permit {shape:?}");
}
}
}
#[test]
fn capacity_bound_enforced() {
let g = RingContract {
max_concurrent_push: 0,
max_concurrent_pop: 0,
ordering: OrderingContract::Unordered,
capacity_bound: Some(1024),
};
assert!(g.permits_capacity(512) && g.permits_capacity(1024));
assert!(!g.permits_capacity(2048));
// permits_config combines shape + capacity.
assert!(g.permits_config(RingShape::Mpmc, 1024));
assert!(!g.permits_config(RingShape::Mpmc, 2048));
}
#[test]
fn fifo_with_capacity_combined_in_permits_config() {
let g = RingContract {
max_concurrent_push: 4,
max_concurrent_pop: 4,
ordering: OrderingContract::Fifo,
capacity_bound: Some(4096),
};
// Mpmc illegal regardless of capacity under Fifo.
assert!(!g.permits_config(RingShape::Mpmc, 1024));
// Vyukov legal at/under the capacity bound, illegal above it.
assert!(g.permits_config(RingShape::Vyukov, 4096));
assert!(!g.permits_config(RingShape::Vyukov, 8192));
}
}