rustfs_config/constants/internode.rs
1// Copyright 2024 RustFS Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/// Timeout for establishing a new internode gRPC connection.
16pub const ENV_INTERNODE_CONNECT_TIMEOUT_SECS: &str = "RUSTFS_INTERNODE_CONNECT_TIMEOUT_SECS";
17pub const DEFAULT_INTERNODE_CONNECT_TIMEOUT_SECS: u64 = 3;
18
19/// TCP keepalive interval for internode gRPC channels.
20pub const ENV_INTERNODE_TCP_KEEPALIVE_SECS: &str = "RUSTFS_INTERNODE_TCP_KEEPALIVE_SECS";
21pub const DEFAULT_INTERNODE_TCP_KEEPALIVE_SECS: u64 = 10;
22
23/// HTTP/2 keepalive interval for internode gRPC channels.
24pub const ENV_INTERNODE_HTTP2_KEEPALIVE_INTERVAL_SECS: &str = "RUSTFS_INTERNODE_HTTP2_KEEPALIVE_INTERVAL_SECS";
25pub const DEFAULT_INTERNODE_HTTP2_KEEPALIVE_INTERVAL_SECS: u64 = 5;
26
27/// HTTP/2 keepalive timeout for internode gRPC channels.
28///
29/// This is the time a peer has to ACK a keepalive PING before the whole channel
30/// (and every RPC/stream multiplexed on it) is torn down. A very aggressive value
31/// misfires under load: on a saturated node the PING ACK is legitimately delayed,
32/// the channel is wrongly declared dead, in-flight peer reads fail, and large-object
33/// GETs truncate mid-stream (client "unexpected EOF"). See backlog#832. Keep this
34/// generous enough to tolerate transient load while still detecting truly dead peers.
35pub const ENV_INTERNODE_HTTP2_KEEPALIVE_TIMEOUT_SECS: &str = "RUSTFS_INTERNODE_HTTP2_KEEPALIVE_TIMEOUT_SECS";
36pub const DEFAULT_INTERNODE_HTTP2_KEEPALIVE_TIMEOUT_SECS: u64 = 20;
37
38/// Overall timeout for a single internode gRPC request.
39pub const ENV_INTERNODE_RPC_TIMEOUT_SECS: &str = "RUSTFS_INTERNODE_RPC_TIMEOUT_SECS";
40pub const DEFAULT_INTERNODE_RPC_TIMEOUT_SECS: u64 = 30;
41
42/// Total budget for one admin peer probe round, including any reconnect retry.
43///
44/// This is intentionally separate from the transport-level RPC timeout: admin
45/// probes may retry once, but the retry must consume the same round budget.
46pub const ENV_ADMIN_PEER_PROBE_TIMEOUT_SECS: &str = "RUSTFS_ADMIN_PEER_PROBE_TIMEOUT_SECS";
47pub const DEFAULT_ADMIN_PEER_PROBE_TIMEOUT_SECS: u64 = 10;
48pub const MAX_ADMIN_PEER_PROBE_TIMEOUT_SECS: u64 = 60;
49const _: () = assert!(DEFAULT_ADMIN_PEER_PROBE_TIMEOUT_SECS <= MAX_ADMIN_PEER_PROBE_TIMEOUT_SECS);
50
51// ── Client-side internode gRPC channel tuning (P0) ──
52// These mirror the server-side HTTP/2 transport tuning in `rustfs/src/server/http.rs`
53// on the *client* `tonic` `Endpoint` used for internode control-plane RPCs. Prior to
54// this, the client channel only set timeouts/keepalive, leaving Nagle enabled and the
55// default 64KiB HTTP/2 window in place — hurting small lock-RPC latency and large
56// metadata-response throughput respectively.
57
58/// Disable Nagle's algorithm on internode gRPC client sockets.
59///
60/// Latency-sensitive control-plane RPCs (locks, health, small metadata) send tiny
61/// frames; Nagle batching adds avoidable delay. Defaults to `true` (nodelay on),
62/// matching the server socket configuration.
63pub const ENV_INTERNODE_RPC_TCP_NODELAY: &str = "RUSTFS_INTERNODE_RPC_TCP_NODELAY";
64pub const DEFAULT_INTERNODE_RPC_TCP_NODELAY: bool = true;
65
66// Compile-time invariant: nodelay defaults on so latency-sensitive control-plane RPCs are not
67// batched by Nagle, matching the server socket configuration.
68const _: () = assert!(DEFAULT_INTERNODE_RPC_TCP_NODELAY);
69
70/// HTTP/2 initial stream window size (bytes) for internode gRPC client channels.
71///
72/// The library default (64KiB) throttles larger unary responses (e.g. `ReadMultiple`,
73/// `BatchReadVersion`) by the bandwidth-delay product. Set to 0 to fall back to the
74/// `tonic`/`hyper` default. Defaults to 1MiB.
75pub const ENV_INTERNODE_RPC_HTTP2_STREAM_WINDOW_SIZE: &str = "RUSTFS_INTERNODE_RPC_HTTP2_STREAM_WINDOW_SIZE";
76pub const DEFAULT_INTERNODE_RPC_HTTP2_STREAM_WINDOW_SIZE: u32 = 1024 * 1024;
77
78/// HTTP/2 initial connection window size (bytes) for internode gRPC client channels.
79///
80/// Should be >= the stream window so multiple concurrent streams are not starved by the
81/// connection-level flow-control window. Set to 0 to fall back to the library default.
82/// Defaults to 2MiB.
83pub const ENV_INTERNODE_RPC_HTTP2_CONN_WINDOW_SIZE: &str = "RUSTFS_INTERNODE_RPC_HTTP2_CONN_WINDOW_SIZE";
84pub const DEFAULT_INTERNODE_RPC_HTTP2_CONN_WINDOW_SIZE: u32 = 2 * 1024 * 1024;
85
86// Compile-time invariant: the connection-level window must be >= the per-stream window, or
87// concurrent streams would be starved by the connection-level flow-control budget.
88const _: () = assert!(DEFAULT_INTERNODE_RPC_HTTP2_CONN_WINDOW_SIZE >= DEFAULT_INTERNODE_RPC_HTTP2_STREAM_WINDOW_SIZE);
89
90/// Maximum encoded message size (bytes) for internode gRPC, applied to both the client
91/// `NodeServiceClient` and the server `NodeServiceServer`.
92///
93/// Without this, `tonic`'s default 4MiB decode limit silently caps `bytes`-carrying
94/// unary RPCs (`ReadAll`/`WriteAll`/`ReadMultiple`/`BatchReadVersion`); a large multi-version
95/// `xl.meta` or an aggregated response then fails with `out_of_range`. The default comes
96/// from `rustfs_protos::DEFAULT_GRPC_SERVER_MESSAGE_LEN` (100MiB) at the call sites.
97pub const ENV_INTERNODE_RPC_MAX_MESSAGE_SIZE: &str = "RUSTFS_INTERNODE_RPC_MAX_MESSAGE_SIZE";
98
99/// Payload-size threshold (bytes) above which a unary internode gRPC response counts as a
100/// "large payload" for alerting.
101///
102/// Large `ReadAll`/`ReadMultiple` responses share the control-plane channel with
103/// latency-sensitive lock/health RPCs and can head-of-line block them (see grpc-optimization
104/// G2). This threshold drives the `rustfs_system_network_internode_operation_large_payloads_total`
105/// counter so operators can size which paths need channel isolation in P1. Defaults to 8MiB.
106pub const ENV_INTERNODE_RPC_LARGE_PAYLOAD_WARN_BYTES: &str = "RUSTFS_INTERNODE_RPC_LARGE_PAYLOAD_WARN_BYTES";
107pub const DEFAULT_INTERNODE_RPC_LARGE_PAYLOAD_WARN_BYTES: usize = 8 * 1024 * 1024;
108
109/// Request stopping the JSON compatibility strings on internode metadata RPCs and sending only the
110/// msgpack `_bin` payloads (grpc-optimization P2-1).
111///
112/// Defaults to `false` (dual-write, byte-for-byte legacy behavior). This is only a request; RustFS
113/// keeps JSON compatibility fields unless [`ENV_INTERNODE_RPC_MSGPACK_ONLY_FLEET_CONFIRMED`] is also
114/// true after the release-window convergence and rollback gates pass. See
115/// `docs/operations/internode-msgpack-json-convergence-runbook.md`.
116pub const ENV_INTERNODE_RPC_MSGPACK_ONLY: &str = "RUSTFS_INTERNODE_RPC_MSGPACK_ONLY";
117pub const DEFAULT_INTERNODE_RPC_MSGPACK_ONLY: bool = false;
118
119/// Explicit fleet-wide confirmation gate for [`ENV_INTERNODE_RPC_MSGPACK_ONLY`].
120///
121/// This separate default-off guard prevents a single legacy flag from accidentally emptying JSON
122/// fields in a mixed-version fleet where an older peer still reads the JSON field.
123pub const ENV_INTERNODE_RPC_MSGPACK_ONLY_FLEET_CONFIRMED: &str = "RUSTFS_INTERNODE_RPC_MSGPACK_ONLY_FLEET_CONFIRMED";
124pub const DEFAULT_INTERNODE_RPC_MSGPACK_ONLY_FLEET_CONFIRMED: bool = false;
125
126// Compile-time invariants: dual-write by default so the base build is byte-for-byte legacy behavior.
127const _: () = assert!(!DEFAULT_INTERNODE_RPC_MSGPACK_ONLY);
128const _: () = assert!(!DEFAULT_INTERNODE_RPC_MSGPACK_ONLY_FLEET_CONFIRMED);
129
130/// Require target-bound v2 signatures on every internode gRPC request, rejecting the legacy
131/// constant-target fallback instead of accepting it (<https://github.com/rustfs/backlog/issues/1327>).
132///
133/// Defaults to `false` (fail-open): a request without any v2 auth headers keeps authenticating
134/// through the legacy signature, so legacy-only peers survive rolling upgrades with byte-for-byte
135/// the pre-gate acceptance behavior. This is a rollout lever, not a wire-format change: it may only
136/// be enabled **after** the v1-fallback counter
137/// (`rustfs_system_network_internode_signature_v1_fallback_total`) has read zero across a release
138/// window fleet-wide, confirming every peer already sends v2 authentication on every internode gRPC
139/// request. Single-env rollback. Requests that do carry v2 headers are unaffected by this switch:
140/// they are always verified as v2 with no downgrade, strict or not.
141pub const ENV_INTERNODE_RPC_SIGNATURE_STRICT: &str = "RUSTFS_INTERNODE_RPC_SIGNATURE_STRICT";
142pub const DEFAULT_INTERNODE_RPC_SIGNATURE_STRICT: bool = false;
143
144// Compile-time invariant: fail-open by default so legacy-only peers keep authenticating during
145// rolling upgrades until the fleet-wide v1-fallback counter reads zero.
146const _: () = assert!(!DEFAULT_INTERNODE_RPC_SIGNATURE_STRICT);
147
148/// Require a signature-bound canonical body digest on every mutating internode disk RPC
149/// (RenameData, DeleteVersion, DeleteVersions, WriteMetadata, UpdateMetadata, WriteAll, Delete,
150/// DeletePaths, RenameFile, RenamePart, DeleteVolume, MakeVolume, MakeVolumes), rejecting requests
151/// that authenticate without one (<https://github.com/rustfs/backlog/issues/1327>).
152///
153/// Defaults to `false` (fail-open): a mutating request without a body digest keeps authenticating
154/// through the method-bound v2 (or legacy) signature, so peers from releases that predate
155/// body-digest signing survive rolling upgrades unchanged. Requests that do carry a digest are
156/// always verified with no downgrade, strict or not — the digest value is part of the signed v2
157/// scope, so an on-path attacker cannot strip it without invalidating the signature. This is a
158/// rollout lever gated on the body-digest fallback counter
159/// (`rustfs_system_network_internode_body_digest_fallback_total`) reading zero across a release
160/// window fleet-wide. Single-env rollback. It is deliberately separate from
161/// [`ENV_INTERNODE_RPC_SIGNATURE_STRICT`]: the two enforcement flips converge on different
162/// counters and must not gate each other.
163pub const ENV_INTERNODE_RPC_BODY_DIGEST_STRICT: &str = "RUSTFS_INTERNODE_RPC_BODY_DIGEST_STRICT";
164pub const DEFAULT_INTERNODE_RPC_BODY_DIGEST_STRICT: bool = false;
165
166// Compile-time invariant: fail-open by default so digestless peers keep authenticating during
167// rolling upgrades until the fleet-wide body-digest fallback counter reads zero.
168const _: () = assert!(!DEFAULT_INTERNODE_RPC_BODY_DIGEST_STRICT);
169
170/// Require the replay-scoped internode RPC signature after the fleet has converged on it.
171///
172/// The default keeps v1/v2 peers available during a rolling upgrade. Operators may set this only
173/// after `rustfs_system_network_internode_replay_scope_fallback_total` remains zero for a full
174/// release window. The node still accepts a v2-authenticated `Ping` carrying an epoch challenge:
175/// that narrowly scoped bootstrap lets an upgraded client learn the receiving process epoch and
176/// immediately retry with the replay-scoped signature after a peer restart.
177pub const ENV_INTERNODE_RPC_REPLAY_SCOPE_STRICT: &str = "RUSTFS_INTERNODE_RPC_REPLAY_SCOPE_STRICT";
178pub const DEFAULT_INTERNODE_RPC_REPLAY_SCOPE_STRICT: bool = false;
179
180// Compile-time invariant: mixed-version clusters must remain available until operators make the
181// observed fallback counter an explicit strictness decision.
182const _: () = assert!(!DEFAULT_INTERNODE_RPC_REPLAY_SCOPE_STRICT);
183
184/// Capacity (distinct nonces) of the process-local internode RPC replay cache that enforces
185/// one-time consumption of authenticated RPC signatures.
186///
187/// The cache retains each nonce for the ~10-minute signature freshness envelope. Once peers use
188/// replay-scoped v3 authentication, every authenticated RPC consumes one entry, so the steady
189/// state holds roughly `authenticated RPC RPS x 601s` entries. This default is the minimum floor:
190/// explicit operator values and resource-aware auto sizing both clamp upward to at least this
191/// value. Overflow fails closed — legitimate signed traffic is the only thing that can fill the
192/// cache (replays are rejected before insertion, and an attacker cannot mint valid nonces without
193/// the shared secret) — and increments
194/// `rustfs_system_network_internode_replay_cache_overflow_total`, so a sustained non-zero overflow
195/// counter means this capacity is undersized for the node's peak authenticated RPC rate.
196pub const ENV_INTERNODE_RPC_REPLAY_CACHE_CAPACITY: &str = "RUSTFS_INTERNODE_RPC_REPLAY_CACHE_CAPACITY";
197pub const DEFAULT_INTERNODE_RPC_REPLAY_CACHE_CAPACITY: usize = 1_048_576;
198
199/// Consecutive-failure threshold after which an internode peer is marked offline (grpc-optimization
200/// P3 observability).
201///
202/// A peer accrues a failure on each dial failure or RPC-triggered connection eviction, and flips
203/// back online on the next successful dial. Drives the `rustfs_cluster_servers_offline_total` gauge
204/// (parity with MinIO's `minio_cluster_servers_offline_total`). Clamped to at least 1. Defaults to 3.
205pub const ENV_INTERNODE_OFFLINE_FAILURE_THRESHOLD: &str = "RUSTFS_INTERNODE_OFFLINE_FAILURE_THRESHOLD";
206pub const DEFAULT_INTERNODE_OFFLINE_FAILURE_THRESHOLD: u32 = 3;
207
208/// Prewarm internode control channels in the background at remote-disk construction, moving the
209/// connect cost off the first RPC (grpc-optimization P3-1).
210///
211/// Best-effort and deduped per peer; failures fall through to the existing lazy connect + recovery
212/// monitor. Defaults to `false` (opt-in): enabling it dials every peer at startup, and it is not yet
213/// validated against a cold-start baseline.
214pub const ENV_INTERNODE_PREWARM: &str = "RUSTFS_INTERNODE_PREWARM";
215pub const DEFAULT_INTERNODE_PREWARM: bool = false;
216
217/// Fast-fail (bypass) internode RPCs to a peer already marked offline, instead of paying the connect
218/// timeout, letting quorum proceed sooner (grpc-optimization P3-2).
219///
220/// Defaults to `false` (opt-in): this touches peer routing (consistency-sensitive) and must be
221/// validated with the failover bench before rollout. It does NOT change quorum. The bypass is
222/// self-healing — one request per [`ENV_INTERNODE_OFFLINE_REPROBE_SECS`] is let through to recover a
223/// peer even without a background monitor. Single-env rollback.
224pub const ENV_INTERNODE_OFFLINE_BYPASS: &str = "RUSTFS_INTERNODE_OFFLINE_BYPASS";
225pub const DEFAULT_INTERNODE_OFFLINE_BYPASS: bool = false;
226
227/// Re-probe interval (seconds) for the offline bypass: while a peer is offline, one request is let
228/// through this often to attempt recovery. Clamped to a small minimum by callers. Defaults to 5s.
229pub const ENV_INTERNODE_OFFLINE_REPROBE_SECS: &str = "RUSTFS_INTERNODE_OFFLINE_REPROBE_SECS";
230pub const DEFAULT_INTERNODE_OFFLINE_REPROBE_SECS: u64 = 5;
231
232// Compile-time invariant: prewarm and offline-bypass are opt-in so the base build is unchanged.
233const _: () = assert!(!DEFAULT_INTERNODE_PREWARM);
234const _: () = assert!(!DEFAULT_INTERNODE_OFFLINE_BYPASS);
235
236/// Extra attempts for idempotent, read-only/reentrant control-plane and object-read RPCs
237/// (`DiskInfo`, `ReadAll`, `ReadMetadata`, `ReadVersion`) on transient network failures, with
238/// exponential backoff (grpc-optimization P3-3).
239///
240/// Defaults to `1`: a freshly-committed object lives on only `write_quorum` disks until heal
241/// reconstructs the rest, so a single reset-by-peer on a metadata read during that
242/// read-after-write window can erode the read quorum and surface as a spurious
243/// `InsufficientReadQuorum` (issue #2761). One bounded retry absorbs that transient failure.
244/// **Only** idempotent reads use this; write/lock RPCs (`WriteAll`/`RenameData`/`Delete*`/`Lock`
245/// /`UnLock`) must never auto-retry, to preserve quorum and idempotency semantics (see `CLAUDE.md`).
246pub const ENV_INTERNODE_IDEMPOTENT_READ_RETRIES: &str = "RUSTFS_INTERNODE_IDEMPOTENT_READ_RETRIES";
247pub const DEFAULT_INTERNODE_IDEMPOTENT_READ_RETRIES: usize = 1;
248
249// ── Control/bulk channel isolation (P1) ──
250// Large `bytes`-carrying unary RPCs (ReadAll/WriteAll/ReadMultiple/BatchReadVersion) otherwise
251// share the control-plane HTTP/2 connection with latency-sensitive lock/health RPCs; a large
252// transfer can head-of-line block a lock RPC (G2/G5). When isolation is enabled these bulk RPCs
253// are routed onto a separate per-peer channel pool. See grpc-optimization P1.
254
255/// Enable control/bulk internode gRPC channel isolation.
256///
257/// Defaults to `false`: this touches lock-RPC transport routing (consistency-sensitive), so it
258/// is opt-in and validated against a baseline before rollout. When `false`, bulk RPCs reuse the
259/// control channel exactly as before, so the switch is a single-env rollback.
260pub const ENV_INTERNODE_CHANNEL_ISOLATION: &str = "RUSTFS_INTERNODE_CHANNEL_ISOLATION";
261pub const DEFAULT_INTERNODE_CHANNEL_ISOLATION: bool = false;
262
263// Compile-time invariant: isolation is opt-in so the default build behaves exactly as before P1.
264const _: () = assert!(!DEFAULT_INTERNODE_CHANNEL_ISOLATION);
265
266/// Number of bulk channels maintained per peer when channel isolation is enabled.
267///
268/// A tonic `Channel` is a single TCP/HTTP2 connection; multiple bulk channels are round-robined
269/// to relieve the single-connection throughput ceiling for large transfers. Kept small (default
270/// 2) to avoid a connection storm; clamped to at least 1. Set to 1 to isolate bulk onto a single
271/// dedicated connection (still separate from control).
272pub const ENV_INTERNODE_BULK_CHANNELS: &str = "RUSTFS_INTERNODE_BULK_CHANNELS";
273pub const DEFAULT_INTERNODE_BULK_CHANNELS: usize = 2;
274
275/// Profile selector for conservative internode HTTP data-plane client tuning.
276pub const ENV_INTERNODE_HTTP_TUNING_PROFILE: &str = "RUSTFS_INTERNODE_HTTP_TUNING_PROFILE";
277pub const DEFAULT_INTERNODE_HTTP_TUNING_PROFILE: &str = "legacy";
278
279/// Internode HTTP connection pool maximum idle connections per host.
280pub const ENV_INTERNODE_HTTP_POOL_MAX_IDLE_PER_HOST: &str = "RUSTFS_INTERNODE_HTTP_POOL_MAX_IDLE_PER_HOST";
281
282/// Internode HTTP connection pool idle timeout in seconds.
283pub const ENV_INTERNODE_HTTP_POOL_IDLE_TIMEOUT_SECS: &str = "RUSTFS_INTERNODE_HTTP_POOL_IDLE_TIMEOUT_SECS";
284
285/// Internode HTTP/2 initial stream window size in bytes.
286///
287/// NOTE (backlog#805-C3): all `RUSTFS_INTERNODE_HTTP2_*` tuning (window sizes,
288/// adaptive window, keepalive timeout) only takes effect when the internode
289/// connection actually negotiates HTTP/2, which happens via TLS-ALPN. Over
290/// plaintext internode transport the connection is HTTP/1.1 and these settings
291/// are silently inert — enable internode TLS to use them.
292pub const ENV_INTERNODE_HTTP2_INITIAL_STREAM_WINDOW_SIZE: &str = "RUSTFS_INTERNODE_HTTP2_INITIAL_STREAM_WINDOW_SIZE";
293
294/// Internode HTTP/2 initial connection window size in bytes.
295pub const ENV_INTERNODE_HTTP2_INITIAL_CONNECTION_WINDOW_SIZE: &str = "RUSTFS_INTERNODE_HTTP2_INITIAL_CONNECTION_WINDOW_SIZE";
296
297/// Whether internode HTTP/2 adaptive window sizing is enabled.
298pub const ENV_INTERNODE_HTTP2_ADAPTIVE_WINDOW: &str = "RUSTFS_INTERNODE_HTTP2_ADAPTIVE_WINDOW";
299
300/// Internode HTTP proxy mode: legacy, off, or system.
301pub const ENV_INTERNODE_HTTP_PROXY: &str = "RUSTFS_INTERNODE_HTTP_PROXY";
302
303/// Environment variable for selecting the internode data-plane transport backend.
304pub const ENV_RUSTFS_INTERNODE_DATA_TRANSPORT: &str = "RUSTFS_INTERNODE_DATA_TRANSPORT";
305pub const DEFAULT_INTERNODE_DATA_TRANSPORT: &str = "tcp-http";
306
307/// Legacy alias for "tcp-http". Both values select the TCP/HTTP transport backend.
308pub const INTERNODE_DATA_TRANSPORT_TCP: &str = "tcp";
309
310/// Known internode transport backend names accepted by the config parser.
311pub const KNOWN_INTERNODE_DATA_TRANSPORT_BACKENDS: &[&str] = &[DEFAULT_INTERNODE_DATA_TRANSPORT, INTERNODE_DATA_TRANSPORT_TCP];
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316
317 #[test]
318 fn internode_timeout_defaults_stay_in_expected_bounds() {
319 assert_eq!(DEFAULT_INTERNODE_CONNECT_TIMEOUT_SECS, 3);
320 assert_eq!(DEFAULT_INTERNODE_TCP_KEEPALIVE_SECS, 10);
321 assert_eq!(DEFAULT_INTERNODE_HTTP2_KEEPALIVE_INTERVAL_SECS, 5);
322 assert_eq!(DEFAULT_INTERNODE_HTTP2_KEEPALIVE_TIMEOUT_SECS, 20);
323 assert_eq!(DEFAULT_INTERNODE_RPC_TIMEOUT_SECS, 30);
324 assert_eq!(DEFAULT_ADMIN_PEER_PROBE_TIMEOUT_SECS, 10);
325 assert_eq!(DEFAULT_INTERNODE_HTTP_TUNING_PROFILE, "legacy");
326 }
327
328 #[test]
329 fn internode_rpc_channel_tuning_defaults() {
330 assert_eq!(DEFAULT_INTERNODE_RPC_HTTP2_STREAM_WINDOW_SIZE, 1024 * 1024);
331 assert_eq!(DEFAULT_INTERNODE_RPC_HTTP2_CONN_WINDOW_SIZE, 2 * 1024 * 1024);
332 // The nodelay-on and connection-window >= stream-window invariants are enforced at
333 // compile time next to the constant definitions.
334 }
335
336 #[test]
337 fn internode_rpc_channel_tuning_env_names_are_stable() {
338 assert_eq!(ENV_INTERNODE_RPC_TCP_NODELAY, "RUSTFS_INTERNODE_RPC_TCP_NODELAY");
339 assert_eq!(
340 ENV_INTERNODE_RPC_HTTP2_STREAM_WINDOW_SIZE,
341 "RUSTFS_INTERNODE_RPC_HTTP2_STREAM_WINDOW_SIZE"
342 );
343 assert_eq!(ENV_INTERNODE_RPC_HTTP2_CONN_WINDOW_SIZE, "RUSTFS_INTERNODE_RPC_HTTP2_CONN_WINDOW_SIZE");
344 assert_eq!(ENV_INTERNODE_RPC_MAX_MESSAGE_SIZE, "RUSTFS_INTERNODE_RPC_MAX_MESSAGE_SIZE");
345 assert_eq!(
346 ENV_INTERNODE_RPC_LARGE_PAYLOAD_WARN_BYTES,
347 "RUSTFS_INTERNODE_RPC_LARGE_PAYLOAD_WARN_BYTES"
348 );
349 assert_eq!(DEFAULT_INTERNODE_RPC_LARGE_PAYLOAD_WARN_BYTES, 8 * 1024 * 1024);
350 }
351
352 #[test]
353 fn internode_channel_isolation_defaults_and_env_names() {
354 // The isolation-off default is asserted at compile time next to the constant definition.
355 assert_eq!(DEFAULT_INTERNODE_BULK_CHANNELS, 2);
356 assert_eq!(ENV_INTERNODE_CHANNEL_ISOLATION, "RUSTFS_INTERNODE_CHANNEL_ISOLATION");
357 assert_eq!(ENV_INTERNODE_BULK_CHANNELS, "RUSTFS_INTERNODE_BULK_CHANNELS");
358 }
359
360 #[test]
361 fn internode_msgpack_only_env_name_is_stable() {
362 // The dual-write-by-default invariants are asserted at compile time next to the definitions.
363 assert_eq!(ENV_INTERNODE_RPC_MSGPACK_ONLY, "RUSTFS_INTERNODE_RPC_MSGPACK_ONLY");
364 assert_eq!(
365 ENV_INTERNODE_RPC_MSGPACK_ONLY_FLEET_CONFIRMED,
366 "RUSTFS_INTERNODE_RPC_MSGPACK_ONLY_FLEET_CONFIRMED"
367 );
368 }
369
370 #[test]
371 fn internode_signature_strict_env_name_is_stable() {
372 // The fail-open default invariant is asserted at compile time next to the definition.
373 assert_eq!(ENV_INTERNODE_RPC_SIGNATURE_STRICT, "RUSTFS_INTERNODE_RPC_SIGNATURE_STRICT");
374 }
375
376 #[test]
377 fn internode_body_digest_strict_env_name_is_stable() {
378 // The fail-open default invariant is asserted at compile time next to the definition.
379 assert_eq!(ENV_INTERNODE_RPC_BODY_DIGEST_STRICT, "RUSTFS_INTERNODE_RPC_BODY_DIGEST_STRICT");
380 }
381
382 #[test]
383 fn internode_replay_scope_strict_env_name_is_stable() {
384 // The fail-open default invariant is asserted at compile time next to the definition.
385 assert_eq!(ENV_INTERNODE_RPC_REPLAY_SCOPE_STRICT, "RUSTFS_INTERNODE_RPC_REPLAY_SCOPE_STRICT");
386 }
387
388 #[test]
389 fn internode_replay_cache_capacity_defaults_and_env_name() {
390 assert_eq!(ENV_INTERNODE_RPC_REPLAY_CACHE_CAPACITY, "RUSTFS_INTERNODE_RPC_REPLAY_CACHE_CAPACITY");
391 assert_eq!(DEFAULT_INTERNODE_RPC_REPLAY_CACHE_CAPACITY, 1_048_576);
392 }
393
394 #[test]
395 fn internode_offline_failure_threshold_defaults_and_env_name() {
396 assert_eq!(DEFAULT_INTERNODE_OFFLINE_FAILURE_THRESHOLD, 3);
397 assert_eq!(ENV_INTERNODE_OFFLINE_FAILURE_THRESHOLD, "RUSTFS_INTERNODE_OFFLINE_FAILURE_THRESHOLD");
398 }
399
400 #[test]
401 fn internode_p3_lifecycle_defaults_are_opt_in() {
402 // The opt-in (default-off) invariants are asserted at compile time next to the definitions.
403 assert_eq!(DEFAULT_INTERNODE_OFFLINE_REPROBE_SECS, 5);
404 // One bounded retry for idempotent reads to absorb read-after-write transient failures (#2761).
405 assert_eq!(DEFAULT_INTERNODE_IDEMPOTENT_READ_RETRIES, 1);
406 assert_eq!(ENV_INTERNODE_PREWARM, "RUSTFS_INTERNODE_PREWARM");
407 assert_eq!(ENV_INTERNODE_OFFLINE_BYPASS, "RUSTFS_INTERNODE_OFFLINE_BYPASS");
408 assert_eq!(ENV_INTERNODE_OFFLINE_REPROBE_SECS, "RUSTFS_INTERNODE_OFFLINE_REPROBE_SECS");
409 assert_eq!(ENV_INTERNODE_IDEMPOTENT_READ_RETRIES, "RUSTFS_INTERNODE_IDEMPOTENT_READ_RETRIES");
410 }
411
412 #[test]
413 fn internode_timeout_env_names_are_stable() {
414 assert_eq!(ENV_INTERNODE_CONNECT_TIMEOUT_SECS, "RUSTFS_INTERNODE_CONNECT_TIMEOUT_SECS");
415 assert_eq!(ENV_INTERNODE_TCP_KEEPALIVE_SECS, "RUSTFS_INTERNODE_TCP_KEEPALIVE_SECS");
416 assert_eq!(
417 ENV_INTERNODE_HTTP2_KEEPALIVE_INTERVAL_SECS,
418 "RUSTFS_INTERNODE_HTTP2_KEEPALIVE_INTERVAL_SECS"
419 );
420 assert_eq!(
421 ENV_INTERNODE_HTTP2_KEEPALIVE_TIMEOUT_SECS,
422 "RUSTFS_INTERNODE_HTTP2_KEEPALIVE_TIMEOUT_SECS"
423 );
424 assert_eq!(ENV_INTERNODE_RPC_TIMEOUT_SECS, "RUSTFS_INTERNODE_RPC_TIMEOUT_SECS");
425 assert_eq!(ENV_ADMIN_PEER_PROBE_TIMEOUT_SECS, "RUSTFS_ADMIN_PEER_PROBE_TIMEOUT_SECS");
426 assert_eq!(ENV_INTERNODE_HTTP_TUNING_PROFILE, "RUSTFS_INTERNODE_HTTP_TUNING_PROFILE");
427 assert_eq!(ENV_INTERNODE_HTTP_POOL_MAX_IDLE_PER_HOST, "RUSTFS_INTERNODE_HTTP_POOL_MAX_IDLE_PER_HOST");
428 assert_eq!(ENV_INTERNODE_HTTP_POOL_IDLE_TIMEOUT_SECS, "RUSTFS_INTERNODE_HTTP_POOL_IDLE_TIMEOUT_SECS");
429 assert_eq!(
430 ENV_INTERNODE_HTTP2_INITIAL_STREAM_WINDOW_SIZE,
431 "RUSTFS_INTERNODE_HTTP2_INITIAL_STREAM_WINDOW_SIZE"
432 );
433 assert_eq!(
434 ENV_INTERNODE_HTTP2_INITIAL_CONNECTION_WINDOW_SIZE,
435 "RUSTFS_INTERNODE_HTTP2_INITIAL_CONNECTION_WINDOW_SIZE"
436 );
437 assert_eq!(ENV_INTERNODE_HTTP2_ADAPTIVE_WINDOW, "RUSTFS_INTERNODE_HTTP2_ADAPTIVE_WINDOW");
438 assert_eq!(ENV_INTERNODE_HTTP_PROXY, "RUSTFS_INTERNODE_HTTP_PROXY");
439 assert_eq!(ENV_RUSTFS_INTERNODE_DATA_TRANSPORT, "RUSTFS_INTERNODE_DATA_TRANSPORT");
440 assert_eq!(DEFAULT_INTERNODE_DATA_TRANSPORT, "tcp-http");
441 assert_eq!(INTERNODE_DATA_TRANSPORT_TCP, "tcp");
442 assert_eq!(KNOWN_INTERNODE_DATA_TRANSPORT_BACKENDS, &["tcp-http", "tcp"]);
443 }
444}