ozzy_replication/flow/
receiver.rs1#[cfg(test)]
2mod tests;
3
4use super::{
5 Channel, FlowError, Operation, PipelineLimits, Prefix, ReceiveEpoch, Report, VecDeque, batch,
6 capacities, ledger,
7};
8
9#[derive(Debug)]
12pub struct Receiver {
13 report: Report,
14 released: Prefix,
15 released_bytes: u64,
16 retained: VecDeque<Operation>,
17 limits: PipelineLimits,
18}
19
20impl Receiver {
21 pub fn new(channel: Channel, base: Prefix, limits: PipelineLimits) -> Result<Self, FlowError> {
23 capacities(limits)?;
24 let report = Report {
25 channel,
26 revision: 1,
27 base,
28 received: base,
29 received_bytes: 0,
30 };
31 report.validate_shape()?;
32 Ok(Self {
33 report,
34 released: base,
35 released_bytes: 0,
36 retained: ledger(limits)?,
37 limits,
38 })
39 }
40
41 pub const fn report(&self) -> Report {
43 self.report
44 }
45
46 pub fn available(&self) -> PipelineLimits {
48 PipelineLimits {
49 max_operations: self.limits.max_operations - self.retained.len(),
50 max_body_bytes: self.limits.max_body_bytes
51 - (self.report.received_bytes - self.released_bytes) as usize,
52 }
53 }
54
55 pub fn reinitialize(&mut self, channel: Channel, applied: Prefix) -> Result<(), FlowError> {
57 if channel.epoch == self.report.channel.epoch {
58 return Err(FlowError::Channel);
59 }
60 let report = Report {
61 channel,
62 revision: 1,
63 base: applied,
64 received: applied,
65 received_bytes: 0,
66 };
67 report.validate_shape()?;
68 self.retained.clear();
69 self.released = applied;
70 self.released_bytes = 0;
71 self.report = report;
72 Ok(())
73 }
74
75 pub fn retract(&mut self, epoch: ReceiveEpoch, through: Prefix) -> Result<(), FlowError> {
78 if epoch == self.report.channel.epoch {
79 return Err(FlowError::Channel);
80 }
81 let count = if through == self.released {
82 0
83 } else {
84 self.retained
85 .iter()
86 .position(|op| op.prefix == through)
87 .ok_or(FlowError::History)?
88 + 1
89 };
90 let received_bytes = self
91 .retained
92 .iter()
93 .take(count)
94 .try_fold(0u64, |sum, op| sum.checked_add(op.body_bytes))
95 .ok_or(FlowError::Exhausted)?;
96 let report = Report {
97 channel: Channel {
98 epoch,
99 ..self.report.channel
100 },
101 revision: 1,
102 base: self.released,
103 received: through,
104 received_bytes,
105 };
106 report.validate_shape()?;
107 self.retained.truncate(count);
108 self.released_bytes = 0;
109 self.report = report;
110 Ok(())
111 }
112
113 pub fn retain(&mut self, channel: Channel, operations: &[Operation]) -> Result<(), FlowError> {
116 if channel != self.report.channel {
117 return Err(FlowError::Channel);
118 }
119 let (end, bytes) = batch(operations, self.report.received)?;
120 let available = self.available();
121 if operations.len() > available.max_operations || bytes > available.max_body_bytes as u64 {
122 return Err(FlowError::Capacity);
123 }
124 let total = self
125 .report
126 .received_bytes
127 .checked_add(bytes)
128 .ok_or(FlowError::Exhausted)?;
129 let revision = self
130 .report
131 .revision
132 .checked_add(1)
133 .ok_or(FlowError::Exhausted)?;
134 self.retained.extend(operations.iter().copied());
135 self.report.received = end;
136 self.report.received_bytes = total;
137 self.report.revision = revision;
138 Ok(())
139 }
140
141 pub fn release(&mut self, through: Prefix) -> Result<(), FlowError> {
144 if through == self.released {
145 return Ok(());
146 }
147 let count = self
148 .retained
149 .iter()
150 .position(|op| op.prefix == through)
151 .ok_or(FlowError::History)?
152 + 1;
153 let bytes: u64 = self
154 .retained
155 .iter()
156 .take(count)
157 .map(|op| op.body_bytes)
158 .sum();
159 let released_bytes = self
160 .released_bytes
161 .checked_add(bytes)
162 .ok_or(FlowError::Exhausted)?;
163 self.retained.drain(..count);
164 self.released = through;
165 self.released_bytes = released_bytes;
166 Ok(())
167 }
168}