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