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}