Skip to main content

maybenot_simulator/
queue.rs

1//! The main queue of events in the simulator.
2
3use std::time::{Duration, Instant};
4
5use maybenot::event::TriggerEvent;
6
7use crate::{
8    SimEvent, event_to_usize,
9    queue_event::{EventQueue, Queue},
10};
11
12/// SimQueue represents the queue of events that are to be processed by the
13/// simulator. It is a wrapper around an EventQueue for the client and an
14/// EventQueue for the server. The goal is to never have to search through
15/// any of the queues, but to be able to directly access the next event
16/// that is to be processed with as little work as possible.
17#[derive(Debug, Clone)]
18pub struct SimQueue {
19    pub(crate) client: EventQueue,
20    pub(crate) server: EventQueue,
21    // The maximum number of packets/cells (depends on trace) per second before
22    // adding delay due to a simulated bottleneck. None means no limit.
23    pub(crate) max_pps: Option<usize>,
24}
25
26impl Default for SimQueue {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32impl SimQueue {
33    pub fn new() -> SimQueue {
34        SimQueue {
35            client: EventQueue::new(),
36            server: EventQueue::new(),
37            max_pps: None,
38        }
39    }
40
41    pub fn len(&self) -> usize {
42        self.client.len() + self.server.len()
43    }
44
45    pub fn is_empty(&self) -> bool {
46        self.len() == 0
47    }
48
49    pub fn no_normal_packets(&self) -> bool {
50        self.client.no_normal_packets() && self.server.no_normal_packets()
51    }
52
53    pub fn get_max_pps(&self) -> Option<usize> {
54        self.max_pps
55    }
56
57    pub fn push(
58        &mut self,
59        event: TriggerEvent,
60        is_client: bool,
61        contains_padding: bool,
62        time: Instant,
63        delay: Duration,
64    ) {
65        self.push_sim(SimEvent {
66            event,
67            time,
68            integration_delay: delay,
69            client: is_client,
70            contains_padding,
71            bypass: false,
72            replace: false,
73            debug_note: None,
74        });
75    }
76
77    pub fn push_sim(&mut self, item: SimEvent) {
78        match item.client {
79            true => self.client.push(item),
80            false => self.server.push(item),
81        }
82    }
83
84    pub fn peek(
85        &self,
86        client_network_delay_sum: Duration,
87        server_network_delay_sum: Duration,
88        current_time: Instant,
89    ) -> (Option<&SimEvent>, Queue, Duration) {
90        match self.len() {
91            0 => (None, Queue::Blocking, Duration::default()),
92            _ => {
93                // peek all, per def, it's one of them
94                let (client, client_queue, client_duration) =
95                    self.client.peek(client_network_delay_sum, current_time);
96                let (server, server_queue, server_duration) =
97                    self.server.peek(server_network_delay_sum, current_time);
98
99                // if one of the queues is empty, return the other, otherwise
100                // compare based on the smallest duration, and if equal, based
101                // on the event type: this is needed due to peek() above
102                // accounting for the network delay sum for base events
103                match (client, server) {
104                    (Some(_), None) => (client, client_queue, client_duration),
105                    (None, Some(_)) => (server, server_queue, server_duration),
106                    (None, None) => (None, Queue::Blocking, Duration::default()),
107                    (Some(client_event), Some(server_event)) => {
108                        let ordering = client_duration.cmp(&server_duration).then_with(|| {
109                            event_to_usize(&client_event.event)
110                                .cmp(&event_to_usize(&server_event.event))
111                        });
112                        if ordering == std::cmp::Ordering::Less
113                            || ordering == std::cmp::Ordering::Equal
114                        {
115                            (client, client_queue, client_duration)
116                        } else {
117                            (server, server_queue, server_duration)
118                        }
119                    }
120                }
121            }
122        }
123    }
124
125    pub fn pop(
126        &mut self,
127        q: Queue,
128        is_client: bool,
129        network_delay_sum: Duration,
130    ) -> Option<SimEvent> {
131        match is_client {
132            true => self.client.pop(q, network_delay_sum),
133            false => self.server.pop(q, network_delay_sum),
134        }
135    }
136
137    pub fn peek_blocking(
138        &self,
139        active_blocking_bypassable: bool,
140        is_client: bool,
141    ) -> (Option<&SimEvent>, Queue) {
142        match is_client {
143            true => peek_blocking(&self.client, active_blocking_bypassable),
144            false => peek_blocking(&self.server, active_blocking_bypassable),
145        }
146    }
147
148    pub fn pop_blocking(
149        &mut self,
150        q: Queue,
151        bypassable: bool,
152        is_client: bool,
153        network_delay_sum: Duration,
154    ) -> Option<SimEvent> {
155        if bypassable {
156            match is_client {
157                true => self.client.blocking.pop(),
158                false => self.server.blocking.pop(),
159            }
160        } else {
161            self.pop(q, is_client, network_delay_sum)
162        }
163    }
164
165    pub fn peek_non_blocking(
166        &self,
167        bypassable: bool,
168        is_client: bool,
169        network_delay_sum: Duration,
170    ) -> (Option<&SimEvent>, Queue) {
171        match is_client {
172            true => peek_non_blocking(&self.client, bypassable, network_delay_sum),
173            false => peek_non_blocking(&self.server, bypassable, network_delay_sum),
174        }
175    }
176
177    pub fn get_first_time(&self) -> Option<Instant> {
178        let c = self.client.get_first_base_time();
179        let s = self.server.get_first_base_time();
180
181        match (c, s) {
182            (Some(ct), Some(st)) => Some(ct.min(st)),
183            (Some(ct), None) => Some(ct),
184            (None, Some(st)) => Some(st),
185            (None, None) => None,
186        }
187    }
188}
189
190fn peek_blocking(
191    queue: &EventQueue,
192    active_blocking_bypassable: bool,
193) -> (Option<&SimEvent>, Queue) {
194    if active_blocking_bypassable {
195        // only blocking events are then blocking
196        (queue.peek_blocking(), Queue::Blocking)
197    } else {
198        // if the current blocking is not bypassable, then we need to
199        // consider bypassable events as also blocking
200        let b = queue.peek_blocking();
201        let bb = queue.peek_bypassable();
202
203        if b > bb {
204            (b, Queue::Blocking)
205        } else {
206            (bb, Queue::Bypassable)
207        }
208    }
209}
210
211fn peek_non_blocking(
212    queue: &EventQueue,
213    bypassable: bool,
214    network_delay_sum: Duration,
215) -> (Option<&SimEvent>, Queue) {
216    if bypassable {
217        // if the current blocking is bypassable, then we need to consider
218        // bypassable as non-blocking
219        let bb = queue.peek_bypassable();
220        let (n, nq) = queue.peek_non_blocking(network_delay_sum);
221
222        if bb > n {
223            (bb, Queue::Bypassable)
224        } else {
225            (n, nq)
226        }
227    } else {
228        queue.peek_non_blocking(network_delay_sum)
229    }
230}