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
use crate::SessionId;
use std::{sync::Arc, time::Duration};

use crate::nodes::{NodeCount, NodeIndex};

pub type DelaySchedule = Arc<dyn Fn(usize) -> Duration + Sync + Send + 'static>;

#[derive(Clone)]
pub struct DelayConfig {
    //Tick frequency of the Member.
    pub tick_interval: Duration,
    //After what delay, we repeat a request for a coord or parents.
    pub requests_interval: Duration,
    //f(k) represents the delay between the kth and (k+1)th broadcast.
    pub unit_broadcast_delay: DelaySchedule,
    //f(k) represents the delay between creating the kth and (k+1)th unit.
    pub unit_creation_delay: DelaySchedule,
}

#[derive(Clone)]
pub struct Config {
    pub node_ix: NodeIndex,
    pub session_id: SessionId,
    pub n_members: NodeCount,
    pub delay_config: DelayConfig,
    //All units (except alerted ones) that are higher by >= rounds_margin then our local round number, are ignored.
    pub rounds_margin: usize,
    //Maximum number of units that can be attached to an alert.
    pub max_units_per_alert: usize,
    //Maximum allowable round of a unit.
    pub max_round: usize,
}

pub(crate) fn exponential_slowdown(
    t: usize,
    base_delay: f64,
    start_exp_delay: usize,
    exp_base: f64,
) -> Duration {
    // This gives:
    // base_delay, for t <= start_exp_delay,
    // base_delay * exp_base^(t - start_exp_delay), for t > start_exp_delay.
    let delay = if t < start_exp_delay {
        base_delay
    } else {
        let power = t - start_exp_delay;
        base_delay * exp_base.powf(power as f64)
    };
    let delay = delay.round() as u64;
    // the above will make it u64::MAX if it exceeds u64
    Duration::from_millis(delay)
}

pub fn default_config(n_members: NodeCount, node_ix: NodeIndex, session_id: SessionId) -> Config {
    let delay_config = DelayConfig {
        tick_interval: Duration::from_millis(100),
        requests_interval: Duration::from_millis(3000),
        unit_broadcast_delay: Arc::new(|t| exponential_slowdown(t, 4000.0, 0, 2.0)),
        // 4000, 8000, 16000, 32000, ...
        unit_creation_delay: Arc::new(|t| exponential_slowdown(t, 500.0, 3000, 1.005)),
        // 500, 500, 500, ... (till step 3000), 500, 500*1.005, 500*(1.005)^2, 500*(1.005)^3, ..., 10742207 (last step)
    };
    Config {
        node_ix,
        session_id,
        n_members,
        delay_config,
        rounds_margin: 200,
        max_units_per_alert: 200,
        max_round: 5000,
    }
}