///|
pub(all) struct Config {
limits : Limits
ack_timeout_ms : Int64
ack_random_factor_permille : Int
max_retransmit : Int
exchange_lifetime_ms : Int64
non_lifetime_ms : Int64
response_timeout_ms : Int64
max_peers : Int
max_exchanges : Int
max_dedup : Int
max_mid_leases : Int
max_queue : Int
max_actions : Int
nstart : Int
initial_mid : Int
token_seed : Int64
} derive(Eq, Debug)
///|
pub extend Config with Eq::{equal, not_equal}
///|
pub extend Config with @debug.Debug::{to_repr}
///|
pub fn Config::default() -> Config {
{
limits: Limits::default(),
ack_timeout_ms: 2000L,
ack_random_factor_permille: 1500,
max_retransmit: 4,
exchange_lifetime_ms: 247000L,
non_lifetime_ms: 145000L,
response_timeout_ms: 247000L,
max_peers: 64,
max_exchanges: 128,
max_dedup: 256,
max_mid_leases: 4096,
max_queue: 128,
max_actions: 1024,
nstart: 1,
initial_mid: 0,
token_seed: 1L,
}
}
///|
pub fn Config::validate(self : Config) -> Result[Unit, Failure] {
match self.limits.validate() {
Err(error) => return Err(error)
Ok(_) => ()
}
if self.ack_timeout_ms < 1L || self.ack_timeout_ms > 60000L {
return Err(Invalid("ACK timeout must be 1..60000 milliseconds"))
}
if self.ack_random_factor_permille < 1000 ||
self.ack_random_factor_permille > 2000 {
return Err(Invalid("random factor must be 1000..2000 permille"))
}
if self.max_retransmit < 0 || self.max_retransmit > 8 {
return Err(Invalid("max_retransmit must be 0..8"))
}
if self.exchange_lifetime_ms < 1L || self.exchange_lifetime_ms > 604800000L {
return Err(
Invalid("exchange lifetime must be positive and at most one week"),
)
}
if self.non_lifetime_ms < 1L ||
self.non_lifetime_ms > self.exchange_lifetime_ms {
return Err(Invalid("NON lifetime must not exceed exchange lifetime"))
}
if self.response_timeout_ms < self.ack_timeout_ms ||
self.response_timeout_ms > self.exchange_lifetime_ms {
return Err(Invalid("response timeout outside exchange lifetime"))
}
if self.max_peers < 1 || self.max_peers > 4096 {
return Err(Invalid("peer count must be 1..4096"))
}
if self.max_exchanges < 1 || self.max_exchanges > 4096 {
return Err(Invalid("exchange count must be 1..4096"))
}
if self.max_dedup < 1 || self.max_dedup > 65536 {
return Err(Invalid("deduplication count must be 1..65536"))
}
if self.max_mid_leases < self.max_exchanges || self.max_mid_leases > 65536 {
return Err(Invalid("MID lease capacity outside supported range"))
}
if self.max_queue < 0 || self.max_queue > self.max_exchanges {
return Err(Invalid("queue count must not exceed exchange count"))
}
if self.max_actions < 2 * self.max_exchanges + self.max_dedup + 4 ||
self.max_actions > 131072 {
return Err(Invalid("action capacity must cover a complete polling batch"))
}
if self.nstart < 1 || self.nstart > self.max_exchanges {
return Err(Invalid("NSTART outside supported range"))
}
if self.initial_mid < 0 || self.initial_mid > 65535 || self.token_seed < 0L {
return Err(Invalid("invalid allocator seed"))
}
let maximum_interval = self.ack_timeout_ms *
self.ack_random_factor_permille.to_int64() /
1000L
let transmit_wait = maximum_interval *
((1L << (self.max_retransmit + 1)) - 1L)
if self.exchange_lifetime_ms < transmit_wait {
return Err(
Invalid("exchange lifetime is shorter than maximum transmit wait"),
)
}
Ok(())
}
///|
pub fn retry_interval(
config : Config,
random_sample : Int,
) -> Result[Int64, Failure] {
match config.validate() {
Err(error) => return Err(error)
Ok(_) => ()
}
if random_sample < 0 || random_sample > 1000000 {
return Err(Invalid("random sample must be 0..1000000"))
}
let maximum_extra = config.ack_timeout_ms *
(config.ack_random_factor_permille - 1000).to_int64() /
1000L
Ok(
config.ack_timeout_ms + maximum_extra * random_sample.to_int64() / 1000000L,
)
}
///|
pub fn deadline_after(now : Int64, delay : Int64) -> Result[Int64, Failure] {
if now < 0L || delay < 0L || now > 9223372036854775807L - delay {
return Err(Clock("negative time or deadline overflow"))
}
Ok(now + delay)
}
///|
pub fn Config::max_transmit_span(self : Config) -> Int64 {
self.ack_timeout_ms *
((1L << self.max_retransmit) - 1L) *
self.ack_random_factor_permille.to_int64() /
1000L
}