1use std::collections::BTreeSet;
4use std::ops::Deref;
5
6use crate::error::{OpenError, PushError, TryPushError};
7use crate::store::{Op, Store};
8use crate::sync::{Arc, Condvar, Mutex};
9
10const META_KEY: [u8; 1] = [0x00];
14const ENTRY_PREFIX: u8 = 0x01;
15const ENTRY_LOW: [u8; 1] = [ENTRY_PREFIX];
16const ENTRY_HIGH: [u8; 9] = [ENTRY_PREFIX, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
17const FORMAT_VERSION: u8 = 1;
18
19#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
21pub enum Durability {
22 #[default]
24 Sync,
25 Group,
28 None,
31}
32
33impl Durability {
34 fn durable(self) -> bool {
35 !matches!(self, Durability::None)
36 }
37
38 fn group(self) -> bool {
39 matches!(self, Durability::Group)
40 }
41}
42
43struct Inner {
44 tail: u64,
45 head: u64,
50 acked_above: BTreeSet<u64>,
54 len: usize,
55 reserved: BTreeSet<u64>,
56 closed: bool,
57}
58
59struct Shared<S> {
60 store: S,
61 capacity: usize,
62 durable: bool,
63 group: bool,
64 inner: Mutex<Inner>,
65 room: Condvar,
66 group_state: Mutex<GroupState>,
67 group_ready: Condvar,
68}
69
70#[derive(Default)]
71struct GroupState {
72 pending: Vec<(u64, Vec<u8>)>,
73 flushing: bool,
74 done: std::collections::BTreeMap<u64, bool>,
75}
76
77impl<S: Store> Shared<S> {
78 fn group_commit(&self, seq: u64, value: &[u8]) -> Result<(), S::Error> {
82 let mut group = self.group_state.lock().unwrap();
83 group.pending.push((seq, value.to_vec()));
84
85 if group.flushing {
86 while !group.done.contains_key(&seq) {
87 group = self.group_ready.wait(group).unwrap();
88 }
89 } else {
90 group.flushing = true;
91 loop {
92 let batch = std::mem::take(&mut group.pending);
93 if batch.is_empty() {
94 group.flushing = false;
95 break;
96 }
97 drop(group);
98
99 let keys: Vec<[u8; 9]> = batch.iter().map(|(s, _)| entry_key(*s)).collect();
100 let ops: Vec<Op<'_>> = batch
101 .iter()
102 .zip(&keys)
103 .map(|((_, value), key)| Op::Put(key, value))
104 .collect();
105 let ok = self.store.commit(&ops, true).is_ok();
106
107 group = self.group_state.lock().unwrap();
108 for (flushed, _) in &batch {
109 group.done.insert(*flushed, ok);
110 }
111 self.group_ready.notify_all();
112 if group.pending.is_empty() {
113 group.flushing = false;
114 break;
115 }
116 }
117 }
118
119 let outcome = group.done.remove(&seq);
120 drop(group);
121 match outcome {
122 Some(true) => Ok(()),
123 _ => self.store.commit(&[Op::Put(&entry_key(seq), value)], true),
126 }
127 }
128}
129
130pub type Ends<S> = (Producer<S>, Consumer<S>);
132
133pub struct Builder<S> {
135 store: S,
136 capacity: usize,
137 durability: Durability,
138}
139
140impl<S: Store> Builder<S> {
141 pub fn new(store: S) -> Self {
143 Self {
144 store,
145 capacity: 1024,
146 durability: Durability::Sync,
147 }
148 }
149
150 pub fn capacity(mut self, capacity: usize) -> Self {
152 assert!(capacity > 0, "capacity must be greater than 0");
153 self.capacity = capacity;
154 self
155 }
156
157 pub fn durability(mut self, durability: Durability) -> Self {
159 self.durability = durability;
160 self
161 }
162
163 pub fn open(self) -> Result<Ends<S>, OpenError<S::Error>> {
165 let durable = self.durability.durable();
166 let group = self.durability.group();
167
168 match self.store.get(&META_KEY).map_err(OpenError::Store)? {
169 Some(meta) => {
170 let version = meta.first().copied().unwrap_or_default();
171 if version != FORMAT_VERSION {
172 return Err(OpenError::UnsupportedVersion(version));
173 }
174 }
175 None => self
176 .store
177 .commit(&[Op::Put(&META_KEY, &[FORMAT_VERSION])], durable)
178 .map_err(OpenError::Store)?,
179 }
180
181 let tail = match self
182 .store
183 .seek_back(&ENTRY_HIGH)
184 .map_err(OpenError::Store)?
185 {
186 Some((key, _)) if is_entry(&key) => seq_of(&key) + 1,
187 _ => 0,
188 };
189
190 let mut len = 0usize;
191 let mut head = tail;
192 let mut cursor = ENTRY_LOW.to_vec();
193 while let Some((key, _)) = self.store.seek(&cursor).map_err(OpenError::Store)? {
194 if !is_entry(&key) {
195 break;
196 }
197 if len == 0 {
198 head = seq_of(&key);
199 }
200 len += 1;
201 cursor = entry_key(seq_of(&key) + 1).to_vec();
202 }
203
204 let shared = Arc::new(Shared {
205 store: self.store,
206 capacity: self.capacity,
207 durable,
208 group,
209 inner: Mutex::new(Inner {
210 tail,
211 head,
212 acked_above: BTreeSet::new(),
213 len,
214 reserved: BTreeSet::new(),
215 closed: false,
216 }),
217 room: Condvar::new(),
218 group_state: Mutex::new(GroupState::default()),
219 group_ready: Condvar::new(),
220 });
221 Ok((
222 Producer {
223 shared: Arc::clone(&shared),
224 },
225 Consumer { shared },
226 ))
227 }
228}
229
230pub struct Producer<S> {
232 shared: Arc<Shared<S>>,
233}
234
235impl<S> Clone for Producer<S> {
236 fn clone(&self) -> Self {
237 Self {
238 shared: Arc::clone(&self.shared),
239 }
240 }
241}
242
243impl<S: Store> Producer<S> {
244 pub fn push(&self, value: &[u8]) -> Result<(), PushError<S::Error>> {
246 let seq = {
247 let mut inner = self.shared.inner.lock().unwrap();
248 loop {
249 if inner.closed {
250 return Err(PushError::Closed);
251 }
252 if inner.len < self.shared.capacity {
253 break;
254 }
255 inner = self.shared.room.wait(inner).unwrap();
256 }
257 let seq = inner.tail;
258 inner.tail += 1;
259 inner.len += 1;
260 seq
261 };
262 self.write(seq, value).map_err(PushError::Store)
263 }
264
265 pub fn try_push(&self, value: &[u8]) -> Result<(), TryPushError<S::Error>> {
267 let seq = {
268 let mut inner = self.shared.inner.lock().unwrap();
269 if inner.closed {
270 return Err(TryPushError::Closed);
271 }
272 if inner.len >= self.shared.capacity {
273 return Err(TryPushError::Full);
274 }
275 let seq = inner.tail;
276 inner.tail += 1;
277 inner.len += 1;
278 seq
279 };
280 self.write(seq, value).map_err(TryPushError::Store)
281 }
282
283 pub fn close(&self) {
285 {
286 let mut inner = self.shared.inner.lock().unwrap();
287 inner.closed = true;
288 }
289 self.shared.room.notify_all();
290 }
291
292 pub fn len(&self) -> usize {
294 self.shared.inner.lock().unwrap().len
295 }
296
297 pub fn is_empty(&self) -> bool {
299 self.len() == 0
300 }
301
302 fn write(&self, seq: u64, value: &[u8]) -> Result<(), S::Error> {
304 let result = if self.shared.group {
305 self.shared.group_commit(seq, value)
306 } else {
307 self.shared
308 .store
309 .commit(&[Op::Put(&entry_key(seq), value)], self.shared.durable)
310 };
311 match result {
312 Ok(()) => Ok(()),
313 Err(e) => {
314 {
315 let mut inner = self.shared.inner.lock().unwrap();
316 inner.len -= 1;
317 }
318 self.shared.room.notify_one();
319 Err(e)
320 }
321 }
322 }
323}
324
325pub struct Consumer<S> {
327 shared: Arc<Shared<S>>,
328}
329
330impl<S: Store> Consumer<S> {
331 pub fn reserve(&self) -> Result<Option<Reserved<S>>, S::Error> {
334 let mut cursor = entry_key(self.shared.inner.lock().unwrap().head).to_vec();
335 loop {
336 match self.shared.store.seek(&cursor)? {
337 Some((key, value)) if is_entry(&key) => {
338 let seq = seq_of(&key);
339 let mut inner = self.shared.inner.lock().unwrap();
340 if inner.reserved.contains(&seq) {
341 drop(inner);
342 cursor = entry_key(seq + 1).to_vec();
343 continue;
344 }
345 inner.reserved.insert(seq);
346 drop(inner);
347 return Ok(Some(Reserved {
348 shared: Arc::clone(&self.shared),
349 seq,
350 value,
351 done: false,
352 }));
353 }
354 _ => return Ok(None),
355 }
356 }
357 }
358}
359
360pub struct Reserved<S: Store> {
363 shared: Arc<Shared<S>>,
364 seq: u64,
365 value: Vec<u8>,
366 done: bool,
367}
368
369impl<S: Store> Reserved<S> {
370 pub fn seq(&self) -> u64 {
372 self.seq
373 }
374
375 pub fn ack(mut self) -> Result<(), S::Error> {
377 let key = entry_key(self.seq);
378 self.shared
379 .store
380 .commit(&[Op::Delete(&key)], self.shared.durable)?;
381 {
382 let mut inner = self.shared.inner.lock().unwrap();
383 inner.reserved.remove(&self.seq);
384 inner.len -= 1;
385 if self.seq == inner.head {
389 let mut next = inner.head + 1;
390 while inner.acked_above.remove(&next) {
391 next += 1;
392 }
393 inner.head = next;
394 } else {
395 inner.acked_above.insert(self.seq);
396 }
397 }
398 self.shared.room.notify_one();
399 self.done = true;
400 Ok(())
401 }
402
403 pub fn nack(mut self) {
405 self.release();
406 self.done = true;
407 }
408
409 fn release(&self) {
410 let mut inner = self.shared.inner.lock().unwrap();
411 inner.reserved.remove(&self.seq);
412 }
413}
414
415impl<S: Store> Deref for Reserved<S> {
416 type Target = [u8];
417
418 fn deref(&self) -> &Self::Target {
419 &self.value
420 }
421}
422
423impl<S: Store> Drop for Reserved<S> {
424 fn drop(&mut self) {
425 if !self.done {
426 self.release();
427 }
428 }
429}
430
431fn entry_key(seq: u64) -> [u8; 9] {
432 let mut key = [0u8; 9];
433 key[0] = ENTRY_PREFIX;
434 key[1..].copy_from_slice(&seq.to_be_bytes());
435 key
436}
437
438fn seq_of(key: &[u8]) -> u64 {
439 let mut bytes = [0u8; 8];
440 bytes.copy_from_slice(&key[1..9]);
441 u64::from_be_bytes(bytes)
442}
443
444fn is_entry(key: &[u8]) -> bool {
445 key.len() == 9 && key[0] == ENTRY_PREFIX
446}
447
448#[cfg(test)]
449mod tests {
450 use super::*;
451 use crate::store::MemStore;
452
453 #[test]
454 fn key_roundtrip() {
455 for seq in [0u64, 1, 255, 256, u32::MAX as u64, u64::MAX] {
456 let key = entry_key(seq);
457 assert!(is_entry(&key));
458 assert_eq!(seq_of(&key), seq);
459 }
460 }
461
462 #[test]
463 fn keys_sort_by_seq_after_meta() {
464 assert!(META_KEY[..] < ENTRY_LOW[..]);
465 assert!(ENTRY_LOW[..] < entry_key(0)[..]);
466 assert!(entry_key(1) < entry_key(2));
467 assert!(entry_key(255) < entry_key(256));
468 assert!(entry_key(u64::MAX)[..] <= ENTRY_HIGH[..]);
469 }
470
471 #[test]
474 fn store_orders_keys_by_numeric_seq() {
475 let store = MemStore::new();
476 for &seq in &[300u64, 1, 256, 255, 2, 65_536, 65_535] {
477 store
478 .commit(&[Op::Put(&entry_key(seq), b"x")], false)
479 .unwrap();
480 }
481 assert_eq!(
482 collect_seqs(&store),
483 vec![1, 2, 255, 256, 300, 65_535, 65_536]
484 );
485 }
486
487 #[test]
488 fn open_recovers_tail_len_and_skips_gaps() {
489 let store = MemStore::new();
490 store
491 .commit(
492 &[
493 Op::Put(&entry_key(5), b"five"),
494 Op::Put(&entry_key(7), b"seven"),
495 ],
496 false,
497 )
498 .unwrap();
499
500 let (tx, rx) = Builder::new(store).capacity(8).open().unwrap();
501 assert_eq!(tx.len(), 2);
502
503 tx.push(b"eight").unwrap(); let a = rx.reserve().unwrap().unwrap();
505 assert_eq!((a.seq(), &*a), (5, &b"five"[..]));
506 a.ack().unwrap();
507 let b = rx.reserve().unwrap().unwrap();
508 assert_eq!(b.seq(), 7); b.ack().unwrap();
510 assert_eq!(rx.reserve().unwrap().unwrap().seq(), 8);
511 }
512
513 #[test]
514 fn unsupported_version_is_rejected() {
515 let store = MemStore::new();
516 store.commit(&[Op::Put(&META_KEY, &[2])], false).unwrap();
517 match Builder::new(store).open() {
518 Err(OpenError::UnsupportedVersion(v)) => assert_eq!(v, 2),
519 _ => panic!("expected UnsupportedVersion"),
520 }
521 }
522
523 #[test]
524 fn try_push_is_full_at_capacity() {
525 let (tx, rx) = mem(1);
526 tx.push(b"a").unwrap();
527 assert!(matches!(tx.try_push(b"b"), Err(TryPushError::Full)));
528 rx.reserve().unwrap().unwrap().ack().unwrap();
529 tx.try_push(b"b").unwrap();
530 }
531
532 #[test]
533 fn close_rejects_further_push() {
534 let (tx, _rx) = mem(4);
535 tx.close();
536 assert!(matches!(tx.push(b"a"), Err(PushError::Closed)));
537 assert!(matches!(tx.try_push(b"a"), Err(TryPushError::Closed)));
538 }
539
540 #[test]
541 fn nack_returns_item_for_redelivery() {
542 let (tx, rx) = mem(4);
543 tx.push(b"a").unwrap();
544 rx.reserve().unwrap().unwrap().nack();
545 assert_eq!(rx.reserve().unwrap().unwrap().seq(), 0);
546 }
547
548 #[test]
549 fn drop_returns_item_for_redelivery() {
550 let (tx, rx) = mem(4);
551 tx.push(b"a").unwrap();
552 drop(rx.reserve().unwrap().unwrap());
553 assert_eq!(rx.reserve().unwrap().unwrap().seq(), 0);
554 }
555
556 #[test]
557 fn reserve_is_none_when_empty_or_all_reserved() {
558 let (tx, rx) = mem(4);
559 assert!(rx.reserve().unwrap().is_none());
560 tx.push(b"a").unwrap();
561 let _held = rx.reserve().unwrap().unwrap();
562 assert!(rx.reserve().unwrap().is_none());
563 }
564
565 #[test]
566 fn group_durability_delivers_in_order() {
567 let (tx, rx) = Builder::new(MemStore::new())
568 .capacity(8)
569 .durability(Durability::Group)
570 .open()
571 .unwrap();
572 for i in 0..4u8 {
573 tx.push(&[i]).unwrap();
574 }
575 for i in 0..4u8 {
576 let item = rx.reserve().unwrap().unwrap();
577 assert_eq!(&*item, &[i][..]);
578 item.ack().unwrap();
579 }
580 assert!(rx.reserve().unwrap().is_none());
581 }
582
583 fn mem(capacity: usize) -> (Producer<MemStore>, Consumer<MemStore>) {
584 Builder::new(MemStore::new())
585 .capacity(capacity)
586 .open()
587 .unwrap()
588 }
589
590 fn collect_seqs(store: &MemStore) -> Vec<u64> {
591 let mut seqs = Vec::new();
592 let mut cursor = ENTRY_LOW.to_vec();
593 while let Some((key, _)) = store.seek(&cursor).unwrap() {
594 if !is_entry(&key) {
595 break;
596 }
597 seqs.push(seq_of(&key));
598 cursor = entry_key(seq_of(&key) + 1).to_vec();
599 }
600 seqs
601 }
602}