1515// specific language governing permissions and limitations
1616// under the License.
1717
18- use iggy_common:: IggyDuration ;
1918use serde:: { Deserialize , Serialize } ;
20- use serde_with:: { DisplayFromStr , serde_as} ;
21- use std:: time:: Duration ;
2219
20+ use super :: defaults:: SERVER_CONFIG ;
2321use configs:: ConfigEnv ;
2422
2523// `CpuAllocation`/`NumaConfig` are pure config types and live in their own
@@ -28,96 +26,9 @@ use configs::ConfigEnv;
2826// `configs::sharding::*` path stable for existing callers.
2927pub use cpu_allocation:: { CpuAllocation , NumaConfig } ;
3028
31- /// Default capacity of the per-shard inter-shard inbox channel. Sized
32- /// comfortably above the consensus working set, which is roughly
33- /// `PIPELINE_PREPARE_QUEUE_MAX (= 32) * replica_count * directions`
34- /// frames in flight per shard, without allowing a runaway producer to
35- /// eat unbounded memory. Tunable via `[system.sharding] inbox_capacity`
36- /// in TOML.
37- ///
38- /// The capacity must also absorb the worst-case cross-shard client
39- /// Reply burst. Unlike consensus frames, client Replies have no VSR
40- /// retransmit path: a Reply lost on full inbox is gone and the client
41- /// times out. A reasonable lower bound is
42- /// `max_inflight_client_requests / num_shards` (assuming requests are
43- /// distributed evenly across owning shards) plus the consensus
44- /// headroom above.
45- ///
46- /// Consensus frames and client-reply forwards share this one channel,
47- /// so the two headrooms are not independent: a consensus burst or
48- /// retransmit storm can fill the inbox with consensus frames exactly
49- /// when a client Reply needs the space. A single `inbox_capacity` knob
50- /// cannot isolate the two frame classes - size it for the sum of both
51- /// worst cases occurring together. Watch the drop-site `tracing` logs
52- /// (and, once a per-shard exporter lands, the `frame_drops_total`
53- /// `{variant="forward_client_send"}` counter) to detect when the bound
54- /// is too low in production.
55- pub const DEFAULT_INBOX_CAPACITY : usize = 1024 ;
56-
57- /// Maximum permitted per-shard inbox depth. The channel is allocated
58- /// up-front per shard, so a runaway value here OOMs the process at boot.
59- /// `1 << 20` (~1M frames) is several orders of magnitude above any
60- /// realistic backpressure target and still fits comfortably in process
61- /// address space.
62- pub const INBOX_CAPACITY_MAX : usize = 1 << 20 ;
63-
64- /// Default bus shutdown drain timeout. Sized larger than typical TCP RTT
65- /// times in-flight write-batch so writers receive their full last
66- /// `write_vectored_all` budget before the connection registry kicks in.
67- pub const DEFAULT_SHUTDOWN_DRAIN_TIMEOUT : Duration = Duration :: from_secs ( 10 ) ;
68-
69- /// Default watchdog poll cadence for the cross-thread shutdown flag.
70- /// 50ms keeps Ctrl-C latency operator-visible without measurable wakeup
71- /// overhead.
72- pub const DEFAULT_SHUTDOWN_POLL_INTERVAL : Duration = Duration :: from_millis ( 50 ) ;
73-
74- /// Hard upper bound on `shutdown_drain_timeout`. A drain that never
75- /// completes wedges process exit; capping at 10 minutes guarantees the
76- /// watchdog eventually force-tears the bus even with a pathological
77- /// config typo.
78- pub const SHUTDOWN_DRAIN_TIMEOUT_MAX : Duration = Duration :: from_secs ( 600 ) ;
79-
80- /// Hard upper bound on `shutdown_poll_interval`. A pollerinterval longer
81- /// than the drain timeout makes the flag effectively unobservable; cap
82- /// at 5s so Ctrl-C latency stays bounded regardless of config.
83- pub const SHUTDOWN_POLL_INTERVAL_MAX : Duration = Duration :: from_secs ( 5 ) ;
84-
85- /// Default safety-tick cadence for the partition reconciliation loop.
86- /// The reconciler also wakes on every `LifecycleFrame::MetadataCommitTick`
87- /// broadcast by shard 0; this fallback covers dropped wake-ups (the wake
88- /// channel is intentionally capacity-1) and the initial post-bootstrap
89- /// convergence window before shard 0's first tick. One second is
90- /// invisible to operators yet keeps idle clusters from burning CPU
91- /// re-reading the same target snapshot.
92- pub const DEFAULT_RECONCILE_PERIODIC_INTERVAL : Duration = Duration :: from_secs ( 1 ) ;
93-
94- /// Hard upper bound on `reconcile_periodic_interval`. A tick longer
95- /// than ~30s makes post-failure recovery latency operator-visible; the
96- /// cap reins in pathological typos without disturbing reasonable
97- /// production values.
98- pub const RECONCILE_PERIODIC_INTERVAL_MAX : Duration = Duration :: from_secs ( 30 ) ;
99-
100- const fn default_inbox_capacity ( ) -> usize {
101- DEFAULT_INBOX_CAPACITY
102- }
103-
104- const fn default_pin_cores ( ) -> bool {
105- true
106- }
107-
108- fn default_shutdown_drain_timeout ( ) -> IggyDuration {
109- IggyDuration :: new ( DEFAULT_SHUTDOWN_DRAIN_TIMEOUT )
110- }
111-
112- fn default_shutdown_poll_interval ( ) -> IggyDuration {
113- IggyDuration :: new ( DEFAULT_SHUTDOWN_POLL_INTERVAL )
114- }
115-
116- fn default_reconcile_periodic_interval ( ) -> IggyDuration {
117- IggyDuration :: new ( DEFAULT_RECONCILE_PERIODIC_INTERVAL )
118- }
119-
120- #[ serde_as]
29+ /// Sharding config for the legacy `core/server`. That server consumes only
30+ /// `cpu_allocation` and `pin_cores`; the bus / shutdown / reconcile knobs are
31+ /// server-ng concepts and live in [`crate::server_ng_config::sharding`].
12132#[ derive( Debug , Deserialize , Serialize , ConfigEnv ) ]
12233pub struct ShardingConfig {
12334 #[ serde( default ) ]
@@ -133,70 +44,14 @@ pub struct ShardingConfig {
13344 /// threads freely within the allowed set. With a NUMA-aware allocation,
13445 /// `false` drops both the CPU and memory-node bindings (and logs a
13546 /// warning, since NUMA placement without pinning is meaningless).
136- #[ serde( default = "default_pin_cores" ) ]
13747 pub pin_cores : bool ,
138- /// Per-shard inter-shard inbox channel capacity. Bounded by design.
139- /// Drops on full inbox of consensus frames are recovered by VSR
140- /// retransmit. Drops of cross-shard client Reply frames are terminal:
141- /// the client never receives the reply (no in-protocol retransmit).
142- /// Both frame classes share this one channel, so a consensus burst
143- /// can starve client-reply forwards: size against the worst-case sum
144- /// of consensus working set + peak client-reply fan-out per shard
145- /// occurring together; see `DEFAULT_INBOX_CAPACITY` for the
146- /// rationale. Used by `core/server-ng`; the legacy server uses its
147- /// own hard-coded inbox sizing.
148- ///
149- // TODO(hubcio): split into two priority lanes - one bounded queue for
150- // consensus frames (drops recovered by VSR retransmit) and one for
151- // client `Reply` frames (drops terminal, must be sized for worst-case
152- // fan-out). Current single-channel design is the minimum-viable
153- // wiring so `frame_drops_total{variant,reason}` surfaces under load
154- // and yields real numbers to size the split against.
155- #[ serde( default = "default_inbox_capacity" ) ]
156- pub inbox_capacity : usize ,
157- /// Wall-clock budget for a single shard's bus drain on shutdown.
158- /// Drives `IggyMessageBus::shutdown(..)` from the per-shard watchdog
159- /// and the parallel-join survivor path. Sized larger than typical
160- /// TCP RTT times in-flight write-batch so writers receive their full
161- /// last `write_vectored_all` budget before the connection registry
162- /// force-tears the bus. Slow-fsync hosts may need to extend this past
163- /// the default; the cap is `SHUTDOWN_DRAIN_TIMEOUT_MAX` so a config
164- /// typo cannot wedge process exit.
165- #[ serde( default = "default_shutdown_drain_timeout" ) ]
166- #[ serde_as( as = "DisplayFromStr" ) ]
167- #[ config_env( leaf) ]
168- pub shutdown_drain_timeout : IggyDuration ,
169- /// Poll cadence for the cross-thread shutdown flag and for the
170- /// `await_metadata_bundle` / `broadcast_metadata_bundle` poll loops.
171- /// Trades off Ctrl-C latency against idle wakeup cost; the default
172- /// keeps shutdown observably prompt without measurable scheduler
173- /// overhead. Capped at `SHUTDOWN_POLL_INTERVAL_MAX` so the flag
174- /// remains effectively observable regardless of config.
175- #[ serde( default = "default_shutdown_poll_interval" ) ]
176- #[ serde_as( as = "DisplayFromStr" ) ]
177- #[ config_env( leaf) ]
178- pub shutdown_poll_interval : IggyDuration ,
179- /// Safety-tick cadence for the partition reconciliation loop; the
180- /// reconciler also wakes immediately on every
181- /// `LifecycleFrame::MetadataCommitTick` from shard 0. See
182- /// [`DEFAULT_RECONCILE_PERIODIC_INTERVAL`] for the rationale; values
183- /// above [`RECONCILE_PERIODIC_INTERVAL_MAX`] are rejected by the
184- /// validator.
185- #[ serde( default = "default_reconcile_periodic_interval" ) ]
186- #[ serde_as( as = "DisplayFromStr" ) ]
187- #[ config_env( leaf) ]
188- pub reconcile_periodic_interval : IggyDuration ,
18948}
19049
19150impl Default for ShardingConfig {
19251 fn default ( ) -> Self {
19352 Self {
19453 cpu_allocation : CpuAllocation :: default ( ) ,
195- pin_cores : default_pin_cores ( ) ,
196- inbox_capacity : DEFAULT_INBOX_CAPACITY ,
197- shutdown_drain_timeout : default_shutdown_drain_timeout ( ) ,
198- shutdown_poll_interval : default_shutdown_poll_interval ( ) ,
199- reconcile_periodic_interval : default_reconcile_periodic_interval ( ) ,
54+ pin_cores : SERVER_CONFIG . system . sharding . pin_cores ,
20055 }
20156 }
20257}
0 commit comments