1use crate::storage::manager::RecordWriteBytes;
17use std::sync::Arc;
19use super::{RecoveryEntry, RecoverySnapshot};
23use crate::storage::manager::{
24 ENTRY_OVERHEAD, Inner, Operation, Pending, Target, encoded_size, recovery_preparation_bytes, recovery_resident_bytes,
25};
26use crate::storage::{ReadLimits, RecordWrite, StorageCursor, StorageManager, StoredRecord};
27use crate::{Error, Result};
28use harmos_domain::state::Position;
29
30pub struct Permit {
39 inner: Arc<Inner>,
40 bytes: usize,
41 target: Target,
42 first_record: StorageCursor,
43 records: Vec<StoredRecord>,
44 record_bytes: usize,
45 capture_bytes: usize,
46 payload: Vec<u8>,
47 active: bool,
48 snapshot: bool,
49}
50
51impl<C> StorageManager<C> {
58 pub async fn reserve_transition(&self, payload_bytes: usize, records: Option<ReadLimits>) -> Result<Permit> {
59 self.reserve_recovery(payload_bytes, records, false).await
60 }
61
62 pub async fn reserve_snapshot(&self, payload_bytes: usize) -> Result<Permit> {
63 self.reserve_recovery(payload_bytes, None, true).await
64 }
65
66 async fn reserve_recovery(&self, payload_bytes: usize, records: Option<ReadLimits>, snapshot: bool) -> Result<Permit> {
67 let recovery_bytes = recovery_preparation_bytes(payload_bytes, self.inner.recovery.history(), self.inner.primary.history())?;
68 let bytes = recovery_bytes;
69 let batches = 1 + usize::from(records.is_some());
70 if batches > self.inner.settings.request.max_pending_write_batches.get() {
71 return Err(Error::InvalidInput { field: "managed capture", reason: "requires two queue slots" });
72 }
73 if bytes > self.inner.settings.request.max_pending_write_bytes.get() {
74 return Err(Error::InvalidInput { field: "managed recovery", reason: "group exceeds memory budget" });
75 }
76 let mut changed = self.inner.changed.subscribe();
77 loop {
78 {
79 let mut state = self.inner.state.lock().unwrap();
80 if !snapshot && recovery_bytes > state.journal_limit {
81 return Err(Error::InvalidInput { field: "managed recovery", reason: "group exceeds recovery read bound" });
82 }
83 if state.status.closing {
84 return Err(Error::Closing { domain: "storage" });
85 }
86 if !state.ready || !state.status.running {
87 return Err(Error::NotReady { domain: "storage" });
88 }
89 if let Some(source) = &state.status.failure {
90 return Err(Error::Persistence { source: source.clone() });
91 }
92 state.collect();
93 if state.reserved == 0
94 && state.finishing.is_none()
95 && state.status.pending_bytes <= self.inner.settings.request.max_pending_write_bytes.get() - bytes
96 && state.status.pending_batches <= self.inner.settings.request.max_pending_write_batches.get() - batches
97 {
98 state
99 .next
100 .checked_add(batches as u64)
101 .ok_or(Error::InvalidInput { field: "managed capture", reason: "queue order overflow" })?;
102 let mut first_record = state.status.accepted.clone();
103 if let Some(limits) = records {
104 first_record
105 .sequence
106 .checked_add(limits.rows.get() as u64)
107 .ok_or(Error::InvalidInput { field: "managed capture", reason: "position overflow" })?;
108 first_record.sequence += 1;
109 }
110 let target = Target {
111 index: state
112 .next
113 .checked_add(1)
114 .ok_or(Error::InvalidInput { field: "managed recovery", reason: "queue order overflow" })?,
115 sequence: state
116 .status
117 .recovery_accepted
118 .sequence
119 .checked_add(u64::from(!snapshot))
120 .ok_or(Error::InvalidInput { field: "managed recovery", reason: "position overflow" })?,
121 };
122 state.reserved = bytes;
123 state.reserved_batches = batches;
124 state.collect();
125 return Ok(Permit {
126 inner: self.inner.clone(),
127 bytes: recovery_bytes,
128 target,
129 first_record,
130 records: Vec::new(),
131 record_bytes: 0,
132 capture_bytes: 0,
133 payload: Vec::new(),
134 active: true,
135 snapshot,
136 });
137 }
138 self.inner.relieve_pressure(&mut state, bytes, batches);
139 }
140 changed.changed().await.map_err(|_| Error::NotReady { domain: "storage" })?;
141 }
142 }
143
144 pub async fn settle_transition(&self) {
145 let mut changed = self.inner.changed.subscribe();
146 loop {
147 if self.inner.state.lock().unwrap().reserved == 0 {
148 return;
149 }
150 if changed.changed().await.is_err() {
151 return;
152 }
153 }
154 }
155}
156
157impl Permit {
158 pub fn snapshot_payload(&mut self, payload: Vec<u8>) -> Result<()> {
159 debug_assert!(self.snapshot);
160 let bytes = recovery_resident_bytes(payload.capacity(), self.inner.recovery.history(), self.inner.primary.history())?;
161 if bytes > self.bytes {
162 return Err(Error::InvalidInput { field: "state snapshot", reason: "payload exceeds reservation" });
163 }
164 self.payload = payload;
165 self.bytes = bytes;
166 let mut state = self.inner.state.lock().unwrap();
167 state.reserved = bytes;
168 state.collect();
169 self.inner.notify();
170 Ok(())
171 }
172
173 pub fn projected(&self) -> &[StoredRecord] {
174 &self.records
175 }
176
177 pub async fn push(&mut self, record: RecordWrite<'_>, limits: ReadLimits) -> Result<()> {
178 let invalid = || Error::InvalidInput { field: "record projection", reason: "capture limit exceeded" };
179 if self.records.len() >= limits.rows.get() {
180 return Err(invalid());
181 }
182 let capture = encoded_size(&record)?
183 .checked_add(encoded_size(&self.first_record.history)?)
184 .and_then(|bytes| bytes.checked_add(ENTRY_OVERHEAD))
185 .ok_or_else(invalid)?;
186 let capture_total = self.capture_bytes.checked_add(capture).ok_or_else(invalid)?;
187 let bytes =
191 record.resident_bytes(&self.first_record.history)?.checked_add(std::mem::size_of::<StoredRecord>() * 3).ok_or_else(invalid)?;
192 let total = self.record_bytes.checked_add(bytes).ok_or_else(invalid)?;
193 if capture_total > limits.bytes.get()
196 || self.bytes.checked_add(total).is_none_or(|total| total > self.inner.settings.request.max_pending_write_bytes.get())
197 {
198 return Err(invalid());
199 }
200 let mut position = self.first_record.clone();
201 position.sequence = position.sequence.checked_add(self.records.len() as u64).ok_or_else(invalid)?;
202 let capacity = self.inner.settings.request.max_pending_write_bytes.get();
203 self.inner
204 .admit_when(|state| {
205 super::super::capacity::admitting(state, super::super::capacity::Pool::Write)?;
206 state.collect();
207 if state.status.pending_bytes <= capacity - bytes {
208 state.reserved += bytes;
209 state.collect();
210 return Ok(Some(()));
211 }
212 let held = state.status.pending_bytes.saturating_sub(state.queue.bytes()).saturating_sub(state.scratch_bytes);
216 if held > capacity - bytes {
217 return Err(invalid());
218 }
219 self.inner.relieve_pressure(state, bytes, 0);
222 Ok(None)
223 })
224 .await?;
225 self.records.push(record.stored(position));
226 self.record_bytes = total;
227 self.capture_bytes = capture_total;
228 Ok(())
229 }
230
231 pub fn encode(&mut self, value: &impl serde::Serialize) -> Result<()> {
232 self.payload =
233 serde_json::to_vec(value).map_err(|_| Error::InvalidInput { field: "managed recovery", reason: "cannot encode group" })?;
234 let bytes = recovery_resident_bytes(self.payload.capacity(), self.inner.recovery.history(), self.inner.primary.history())?;
238 if bytes > self.bytes {
239 return Err(Error::InvalidInput { field: "managed recovery", reason: "encoded allocation exceeds reservation" });
240 }
241 self.bytes = bytes;
242 let mut state = self.inner.state.lock().unwrap();
243 state.reserved =
244 self.bytes.checked_add(self.record_bytes).ok_or(Error::InvalidInput { field: "managed recovery", reason: "size overflow" })?;
245 state.reserved_batches = 1 + usize::from(!self.records.is_empty());
246 state.collect();
247 self.inner.notify();
248 Ok(())
249 }
250
251 pub fn commit(mut self, frontier: Position) {
252 let mut state = self.inner.state.lock().unwrap();
253 let required_data = if self.snapshot {
254 state.journal_required_data.clone()
255 } else {
256 self.records.last().map_or_else(|| state.status.saved.clone(), |record| record.position.clone())
257 };
258 if required_data.sequence > state.journal_required_data.sequence {
259 state.journal_required_data = required_data.clone();
260 }
261 if let Some(last) = self.records.last() {
262 state.status.accepted = last.position.clone();
263 state.data_accepted = Target { index: self.target.index, sequence: last.position.sequence };
264 state.queue.push_back(Arc::new(Pending {
265 index: self.target.index,
266 bytes: self.record_bytes,
267 journal: None,
268 operation: Operation::Records(std::mem::take(&mut self.records)),
269 }));
270 self.target.index += 1; }
272 let position =
273 crate::storage::RecoveryPosition { history: state.status.recovery_accepted.history.clone(), sequence: self.target.sequence };
274 state.status.recovery_accepted = position.clone();
275 state.recovery_accepted = self.target;
276 state.next = self.target.index;
277 state.queue.push_back(Arc::new(Pending {
278 index: self.target.index,
279 bytes: self.bytes,
280 journal: (!self.snapshot).then_some(frontier),
281 operation: if self.snapshot {
282 Operation::Snapshot(RecoverySnapshot {
283 required_data: required_data.clone(),
284 through: position,
285 payload: std::mem::take(&mut self.payload),
286 })
287 } else {
288 Operation::Recovery(vec![RecoveryEntry { required_data, position, payload: std::mem::take(&mut self.payload) }])
289 },
290 }));
291 state.reserved = 0;
292 state.reserved_batches = 0;
293 self.active = false;
294 state.collect();
295 self.inner.notify();
296 }
297}
298
299impl Drop for Permit {
300 fn drop(&mut self) {
301 if self.active {
302 let mut state = self.inner.state.lock().unwrap();
303 state.reserved = 0;
304 state.reserved_batches = 0;
305 state.collect();
306 self.inner.notify();
307 }
308 }
309}
310
311