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
//! [`Mergeable`] — combine per-shard state from sharded
//! per-RSS-queue workers.
//!
//! The highest-impact perf pattern for passive analysis (Retina
//! SIGCOMM '22, RSS++ CoNEXT '19) is **lockless RSS-sharded
//! per-core flow tables**: each RX queue / worker owns a thread-
//! local flow table + correlate state, and shards are unioned
//! **off the hot path** — removing locks/atomics from per-packet
//! work.
//!
//! netring already shards capture per RX queue (`XdpShardedRunner`
//! / `ShardedRunner` with the `merge_state` seam). For that to
//! actually work, flowscope's stateful primitives need a `merge`
//! operation. This trait makes the contract explicit.
//!
//! ## Contract
//!
//! Implementations must be **commutative + associative**:
//!
//! ```text
//! a.merge(b).merge(c) == a.merge(c).merge(b) // commutative
//! (a.merge(b)).merge(c) == a.merge(b.merge(c)) // associative
//! ```
//!
//! This lets consumers union N shards in any order and get the
//! same result — required for the sharded-aggregation pattern
//! where shards finish at different times.
//!
//! ## When the contract is non-obvious
//!
//! - **`Ewma` merge has TWO defensible semantics** (sample-count
//! weighted vs reset-and-fold). Implementations document which
//! one is shipped.
//! - **`TimeBucketedCounter` / `RollingRate` require matching
//! bucket boundaries** — `(bucket_width, window)` must match
//! across shards. We panic on mismatch rather than silently
//! realign, which would hide config bugs.
//! - **`TopK` (Misra-Gries / Space-Saving) merge** is from
//! Metwally et al. PODS '05 — pairwise minimum of counters,
//! then re-truncate to capacity. Documented in the impl.
//!
//! Issue #19 (Release A).
/// Combine sharded per-RSS-queue state off the hot path.
///
/// **Contract**: implementations MUST be commutative + associative
/// so consumers can union shards in any order. See the module
/// docs for the per-primitive semantics.
///
/// `merge_all` has a default delegating to pairwise [`Self::merge`];
/// primitives with a faster N-way union (HLL sketches, etc.) may
/// override.