distant_net/common/transport/framed/
backup.rs

1use std::collections::VecDeque;
2
3use super::{Frame, OwnedFrame};
4
5/// Maximum size (in bytes) for saved frames (256MiB)
6const MAX_BACKUP_SIZE: usize = 256 * 1024 * 1024;
7
8/// Stores [`Frame`]s for reuse later.
9///
10/// ### Note
11///
12/// Empty [`Frame`]s are an exception and are not stored within the backup nor
13/// are they tracked in terms of sent/received counts.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct Backup {
16    /// Maximum size (in bytes) to save frames in case we need to backup them
17    ///
18    /// NOTE: If 0, no frames will be stored.
19    max_backup_size: usize,
20
21    /// Tracker for the total size (in bytes) of stored frames
22    current_backup_size: usize,
23
24    /// Storage used to hold outgoing frames in case they need to be reused
25    frames: VecDeque<OwnedFrame>,
26
27    /// Counter keeping track of total frames sent
28    sent_cnt: u64,
29
30    /// Counter keeping track of total frames received
31    received_cnt: u64,
32
33    /// Indicates whether the backup is frozen, which indicates that mutations are ignored
34    frozen: bool,
35}
36
37impl Default for Backup {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43impl Backup {
44    /// Creates a new, unfrozen backup.
45    pub fn new() -> Self {
46        Self {
47            max_backup_size: MAX_BACKUP_SIZE,
48            current_backup_size: 0,
49            frames: VecDeque::new(),
50            sent_cnt: 0,
51            received_cnt: 0,
52            frozen: false,
53        }
54    }
55
56    /// Clears the backup of any stored data and resets the state to being new.
57    ///
58    /// ### Note
59    ///
60    /// Like all other modifications, this will do nothing if the backup is frozen.
61    pub fn clear(&mut self) {
62        if !self.frozen {
63            self.current_backup_size = 0;
64            self.frames.clear();
65            self.sent_cnt = 0;
66            self.received_cnt = 0;
67        }
68    }
69
70    /// Returns true if the backup is frozen, meaning that modifications will be ignored.
71    #[inline]
72    pub fn is_frozen(&self) -> bool {
73        self.frozen
74    }
75
76    /// Sets the frozen status.
77    #[inline]
78    pub fn set_frozen(&mut self, frozen: bool) {
79        self.frozen = frozen;
80    }
81
82    /// Marks the backup as frozen.
83    #[inline]
84    pub fn freeze(&mut self) {
85        self.frozen = true;
86    }
87
88    /// Marks the backup as no longer frozen.
89    #[inline]
90    pub fn unfreeze(&mut self) {
91        self.frozen = false;
92    }
93
94    /// Sets the maximum size (in bytes) of collective frames stored in case a backup is needed
95    /// during reconnection. Setting the `size` to 0 will result in no frames being stored.
96    ///
97    /// ### Note
98    ///
99    /// Like all other modifications, this will do nothing if the backup is frozen.
100    pub fn set_max_backup_size(&mut self, size: usize) {
101        if !self.frozen {
102            self.max_backup_size = size;
103        }
104    }
105
106    /// Returns the maximum size (in bytes) of collective frames stored in case a backup is needed
107    /// during reconnection.
108    pub fn max_backup_size(&self) -> usize {
109        self.max_backup_size
110    }
111
112    /// Increments (by 1) the total sent frames.
113    ///
114    /// ### Note
115    ///
116    /// Like all other modifications, this will do nothing if the backup is frozen.
117    pub(crate) fn increment_sent_cnt(&mut self) {
118        if !self.frozen {
119            self.sent_cnt += 1;
120        }
121    }
122
123    /// Returns how many frames have been sent.
124    pub(crate) fn sent_cnt(&self) -> u64 {
125        self.sent_cnt
126    }
127
128    /// Increments (by 1) the total received frames.
129    ///
130    /// ### Note
131    ///
132    /// Like all other modifications, this will do nothing if the backup is frozen.
133    pub(super) fn increment_received_cnt(&mut self) {
134        if !self.frozen {
135            self.received_cnt += 1;
136        }
137    }
138
139    /// Returns how many frames have been received.
140    pub(crate) fn received_cnt(&self) -> u64 {
141        self.received_cnt
142    }
143
144    /// Sets the total received frames to the specified `cnt`.
145    ///
146    /// ### Note
147    ///
148    /// Like all other modifications, this will do nothing if the backup is frozen.
149    pub(super) fn set_received_cnt(&mut self, cnt: u64) {
150        if !self.frozen {
151            self.received_cnt = cnt;
152        }
153    }
154
155    /// Pushes a new frame to the end of the internal queue.
156    ///
157    /// ### Note
158    ///
159    /// Like all other modifications, this will do nothing if the backup is frozen.
160    pub(crate) fn push_frame(&mut self, frame: Frame) {
161        if self.max_backup_size > 0 && !self.frozen {
162            self.current_backup_size += frame.len();
163            self.frames.push_back(frame.into_owned());
164            while self.current_backup_size > self.max_backup_size {
165                match self.frames.pop_front() {
166                    Some(frame) => {
167                        self.current_backup_size -= frame.len();
168                    }
169
170                    // If we have exhausted all frames, then we have reached
171                    // an internal size of 0 and should exit the loop
172                    None => {
173                        self.current_backup_size = 0;
174                        break;
175                    }
176                }
177            }
178        }
179    }
180
181    /// Returns the total frames being kept for potential reuse.
182    pub(super) fn frame_cnt(&self) -> usize {
183        self.frames.len()
184    }
185
186    /// Returns an iterator over the frames contained in the backup.
187    pub(super) fn frames(&self) -> impl Iterator<Item = &Frame> {
188        self.frames.iter()
189    }
190
191    /// Truncates the stored frames to be no larger than `size` total frames by popping from the
192    /// front rather than the back of the list.
193    ///
194    /// ### Note
195    ///
196    /// Like all other modifications, this will do nothing if the backup is frozen.
197    pub(super) fn truncate_front(&mut self, size: usize) {
198        if !self.frozen {
199            while self.frames.len() > size {
200                if let Some(frame) = self.frames.pop_front() {
201                    self.current_backup_size -=
202                        std::cmp::min(frame.len(), self.current_backup_size);
203                }
204            }
205        }
206    }
207}