1use std::ops::Range;
9use std::sync::Arc;
10use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
11use std::sync::{Mutex, OnceLock};
12use std::task::{Poll, ready};
13
14use arrayvec::ArrayVec;
15use bytes::Bytes;
16
17use crate::group::{self, GroupState};
18use crate::{Error, IntoBytes, Result, Timestamp, stats};
19
20#[derive(Clone, Copy, Debug)]
25pub struct Info {
26 pub size: u64,
28 pub timestamp: Timestamp,
34}
35
36#[derive(Clone, Debug)]
41pub struct Frame {
42 pub timestamp: Timestamp,
44 pub payload: Bytes,
46}
47
48#[derive(Debug, Default)]
70pub struct Buffer<const N: usize = 8>(ArrayVec<Frame, N>);
71
72impl<const N: usize> Buffer<N> {
73 pub fn new() -> Self {
75 Self(ArrayVec::new())
76 }
77
78 pub const fn capacity(&self) -> usize {
80 N
81 }
82
83 pub fn len(&self) -> usize {
85 self.0.len()
86 }
87
88 pub fn is_empty(&self) -> bool {
90 self.0.is_empty()
91 }
92
93 pub fn is_full(&self) -> bool {
95 self.0.is_full()
96 }
97
98 pub fn filled(&self) -> &[Frame] {
100 &self.0
101 }
102
103 pub fn filled_mut(&mut self) -> &mut [Frame] {
105 &mut self.0
106 }
107
108 pub fn push(&mut self, frame: Frame) -> std::result::Result<(), Frame> {
113 self.0.try_push(frame).map_err(|err| err.element())
114 }
115
116 pub fn drain(&mut self) -> impl ExactSizeIterator<Item = Frame> + '_ {
121 self.0.drain(..)
122 }
123
124 pub fn clear(&mut self) {
126 self.0.clear();
127 }
128}
129
130#[derive(Clone)]
139pub(crate) struct Budget(Arc<AtomicUsize>);
140
141impl Budget {
142 const DEFAULT: usize = 16 * 1024 * 1024;
144
145 pub(crate) fn new(bytes: usize) -> Self {
146 Self(Arc::new(AtomicUsize::new(bytes)))
147 }
148
149 pub(crate) fn reserve(&self, size: usize) -> Option<Reservation> {
151 self.0
152 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |left| left.checked_sub(size))
153 .ok()?;
154 Some(Reservation {
155 budget: self.clone(),
156 size,
157 })
158 }
159}
160
161impl Default for Budget {
162 fn default() -> Self {
163 Self::new(Self::DEFAULT)
164 }
165}
166
167pub(crate) struct Reservation {
169 budget: Budget,
170 size: usize,
171}
172
173impl Drop for Reservation {
174 fn drop(&mut self) {
175 self.budget.0.fetch_add(self.size, Ordering::Relaxed);
176 }
177}
178
179#[derive(Clone)]
188pub(crate) struct FrameBuf(Arc<FrameBufInner>);
189
190struct FrameBufInner {
191 size: usize,
192 grow: bool,
193 written: AtomicUsize,
194 storage: OnceLock<FrameStorage>,
195}
196
197enum FrameStorage {
198 Shared(Bytes),
199 Fixed(Arc<Segment>),
200 Growing(Mutex<Arc<Segment>>),
203}
204
205struct Segment {
207 data: *mut u8,
208 capacity: usize,
209}
210
211unsafe impl Send for Segment {}
214unsafe impl Sync for Segment {}
215
216impl Drop for Segment {
217 fn drop(&mut self) {
218 unsafe {
221 let slice = std::ptr::slice_from_raw_parts_mut(self.data, self.capacity);
222 drop(Box::from_raw(slice));
223 }
224 }
225}
226
227impl Segment {
228 fn new(capacity: usize) -> Self {
229 let boxed: Box<[u8]> = vec![0u8; capacity].into_boxed_slice();
230 let capacity = boxed.len();
231 let data = Box::into_raw(boxed) as *mut u8;
232 Self { data, capacity }
233 }
234
235 unsafe fn write(&self, offset: usize, src: &[u8]) {
240 debug_assert!(offset + src.len() <= self.capacity);
241 unsafe { std::ptr::copy_nonoverlapping(src.as_ptr(), self.data.add(offset), src.len()) };
242 }
243}
244
245struct Filled {
248 segment: Arc<Segment>,
249 len: usize,
250}
251
252impl AsRef<[u8]> for Filled {
253 fn as_ref(&self) -> &[u8] {
254 unsafe { std::slice::from_raw_parts(self.segment.data, self.len) }
258 }
259}
260
261impl FrameBuf {
262 pub(crate) fn new(size: usize) -> Self {
267 Self::with_growth(size, false)
268 }
269
270 pub(crate) fn growing(size: usize) -> Self {
272 Self::with_growth(size, true)
273 }
274
275 fn with_growth(size: usize, grow: bool) -> Self {
276 Self(Arc::new(FrameBufInner {
277 size,
278 grow,
279 written: AtomicUsize::new(0),
280 storage: OnceLock::new(),
281 }))
282 }
283
284 pub(crate) fn size(&self) -> usize {
286 self.0.size
287 }
288
289 pub(crate) fn written(&self, ord: Ordering) -> usize {
290 self.0.written.load(ord)
291 }
292
293 fn try_set_bytes(&self, bytes: Bytes) -> std::result::Result<(), Bytes> {
294 if bytes.len() != self.size() || self.written(Ordering::Acquire) != 0 {
295 return Err(bytes);
296 }
297 self.0
298 .storage
299 .set(FrameStorage::Shared(bytes))
300 .map_err(|storage| match storage {
301 FrameStorage::Shared(bytes) => bytes,
302 _ => unreachable!("try_set_bytes only installs shared storage"),
303 })
304 }
305
306 unsafe fn store_written(&self, new_written: usize) {
308 self.0.written.store(new_written, Ordering::Release);
310 }
311
312 fn append(&self, src: &[u8]) {
318 if src.is_empty() {
319 return;
320 }
321 let prev = self.written(Ordering::Relaxed);
322 let storage = self.0.storage.get_or_init(|| match self.0.grow {
323 true => FrameStorage::Growing(Mutex::new(Arc::new(Segment::new(0)))),
324 false => FrameStorage::Fixed(Arc::new(Segment::new(self.size()))),
325 });
326 match storage {
329 FrameStorage::Shared(_) => return,
332 FrameStorage::Fixed(segment) => unsafe { segment.write(prev, src) },
333 FrameStorage::Growing(current) => {
334 let mut current = current.lock().expect("mutex poisoned");
335 let needed = prev + src.len();
336 if current.capacity < needed {
337 let next = Segment::new(needed.max(current.capacity * 2).min(self.size()));
340 let filled = Filled {
341 segment: current.clone(),
342 len: prev,
343 };
344 unsafe { next.write(0, filled.as_ref()) };
345 *current = Arc::new(next);
346 }
347 unsafe { current.write(prev, src) };
348 }
349 }
350 unsafe { self.store_written(prev + src.len()) };
352 }
353
354 fn freeze(&self) -> Bytes {
359 self.slice(0, self.size())
360 }
361
362 fn slice(&self, start: usize, end: usize) -> Bytes {
367 let segment = match self.0.storage.get() {
368 Some(FrameStorage::Shared(bytes)) => return bytes.slice(start..end),
369 Some(FrameStorage::Fixed(segment)) => segment.clone(),
370 Some(FrameStorage::Growing(current)) => current.lock().expect("mutex poisoned").clone(),
371 None => return Bytes::new(),
373 };
374 debug_assert!(end <= segment.capacity);
375 Bytes::from_owner(Filled { segment, len: end }).slice(start..)
376 }
377
378 #[cfg(test)]
380 pub(crate) fn allocated(&self) -> usize {
381 match self.0.storage.get() {
382 Some(FrameStorage::Shared(bytes)) => bytes.len(),
383 Some(FrameStorage::Fixed(segment)) => segment.capacity,
384 Some(FrameStorage::Growing(current)) => current.lock().expect("mutex poisoned").capacity,
385 None => 0,
386 }
387 }
388}
389
390struct Raw<G: std::borrow::BorrowMut<group::Producer>> {
393 group: G,
394 buf: FrameBuf,
395 info: Info,
396 done: bool,
398 stats: stats::Meter,
401}
402
403impl<G: std::borrow::BorrowMut<group::Producer>> Raw<G> {
404 fn remaining(&self) -> usize {
405 self.buf.size() - self.buf.written(Ordering::Acquire)
406 }
407
408 fn write<B: IntoBytes>(&mut self, chunk: B) -> Result<()> {
409 let len = chunk.as_ref().len();
410 if len > self.remaining() {
411 return Err(Error::WrongSize);
412 }
413 self.stats.bytes(len as u64);
415 if len == self.buf.size() && self.buf.written(Ordering::Acquire) == 0 {
417 match self.buf.try_set_bytes(chunk.into_bytes()) {
418 Ok(()) => {
419 let size = self.buf.size();
420 unsafe { self.buf.store_written(size) };
423 }
424 Err(chunk) => self.buf.append(&chunk),
425 }
426 } else {
427 self.buf.append(chunk.as_ref());
428 }
429 Ok(())
430 }
431
432 fn finish(&mut self) -> Result<()> {
433 if self.buf.written(Ordering::Acquire) != self.buf.size() {
434 return Err(Error::WrongSize);
435 }
436 let payload = self.buf.freeze();
437 self.group.borrow_mut().frame_commit(Frame {
438 timestamp: self.info.timestamp,
439 payload,
440 })?;
441 self.done = true;
442 Ok(())
443 }
444
445 fn abort(&mut self, err: Error) -> Result<()> {
446 self.group.borrow_mut().frame_abort(err);
447 self.done = true;
448 Ok(())
449 }
450}
451
452impl<G: std::borrow::BorrowMut<group::Producer>> Drop for Raw<G> {
453 fn drop(&mut self) {
454 if !self.done {
455 let group = self.group.borrow_mut();
460 if !group.is_aborted() {
461 tracing::warn!(
462 group = group.info().sequence,
463 "frame::Producer dropped before writing all bytes"
464 );
465 }
466 group.frame_abort(Error::Dropped);
467 }
468 }
469}
470
471pub struct Producer<'a>(Raw<&'a mut group::Producer>);
482
483impl std::ops::Deref for Producer<'_> {
484 type Target = Info;
485
486 fn deref(&self) -> &Self::Target {
487 &self.0.info
488 }
489}
490
491impl<'a> Producer<'a> {
492 pub(crate) fn new(group: &'a mut group::Producer, buf: FrameBuf, info: Info) -> Self {
493 Self(Raw {
494 group,
495 buf,
496 info,
497 done: false,
498 stats: stats::Meter::default(),
499 })
500 }
501
502 pub(crate) fn with_meter(mut self, meter: stats::Meter) -> Self {
504 self.0.stats = meter;
505 self
506 }
507
508 pub fn group(&self) -> group::Info {
510 self.0.group.info()
511 }
512
513 pub fn remaining(&self) -> usize {
515 self.0.remaining()
516 }
517
518 pub fn write<B: IntoBytes>(&mut self, chunk: B) -> Result<()> {
522 self.0.write(chunk)?;
523 self.0.group.frame_notify();
524 Ok(())
525 }
526
527 pub fn finish(mut self) -> Result<()> {
531 self.0.finish()
532 }
533
534 pub fn abort(mut self, err: Error) -> Result<()> {
536 self.0.abort(err)
537 }
538}
539
540pub(crate) struct ProducerOwned {
549 raw: Raw<group::Producer>,
550 _reserved: Option<Reservation>,
551}
552
553impl std::ops::Deref for ProducerOwned {
554 type Target = Info;
555
556 fn deref(&self) -> &Self::Target {
557 &self.raw.info
558 }
559}
560
561impl ProducerOwned {
562 pub(crate) fn new(group: group::Producer, buf: FrameBuf, info: Info, reserved: Option<Reservation>) -> Self {
563 Self {
564 raw: Raw {
565 group,
566 buf,
567 info,
568 done: false,
569 stats: stats::Meter::default(),
570 },
571 _reserved: reserved,
572 }
573 }
574
575 pub(crate) fn with_meter(mut self, meter: stats::Meter) -> Self {
577 self.raw.stats = meter;
578 self
579 }
580
581 pub fn remaining(&self) -> usize {
583 self.raw.remaining()
584 }
585
586 pub(crate) fn write<B: IntoBytes>(&mut self, chunk: B) -> Result<()> {
595 self.raw.write(chunk)
596 }
597
598 pub(crate) fn notify(&self) {
600 self.raw.group.frame_notify();
601 }
602
603 pub fn finish(mut self) -> Result<()> {
605 self.raw.finish()
606 }
607
608 pub fn abort(mut self, err: Error) -> Result<()> {
610 self.raw.abort(err)
611 }
612
613 #[cfg(test)]
615 pub(crate) fn allocated(&self) -> usize {
616 self.raw.buf.allocated()
617 }
618}
619
620#[derive(Clone)]
623pub(crate) enum Source {
624 Complete(Bytes),
625 Partial(FrameBuf),
626}
627
628#[derive(Clone)]
630pub(crate) struct Expiry {
631 policy: Arc<dyn group::Expiry>,
632 stale_stats: stats::Meter,
633 stale_counted: Arc<AtomicBool>,
634 tail: Range<usize>,
635 count_payload: bool,
636}
637
638impl Expiry {
639 pub(crate) fn new(
640 policy: Arc<dyn group::Expiry>,
641 stale_stats: stats::Meter,
642 stale_counted: Arc<AtomicBool>,
643 ) -> Self {
644 Self {
645 policy,
646 stale_stats,
647 stale_counted,
648 tail: 0..0,
649 count_payload: false,
650 }
651 }
652
653 pub(crate) fn for_frame(mut self, tail: Range<usize>, count_payload: bool) -> Self {
654 self.tail = tail;
655 self.count_payload = count_payload;
656 self
657 }
658}
659
660#[derive(Clone)]
666pub struct Consumer {
667 state: kio::Consumer<GroupState>,
669 info: Info,
670 source: Source,
671 read_idx: usize,
673 stats: stats::Meter,
676 expiry: Option<Expiry>,
678 expired: bool,
679}
680
681impl std::ops::Deref for Consumer {
682 type Target = Info;
683
684 fn deref(&self) -> &Self::Target {
685 &self.info
686 }
687}
688
689impl Consumer {
690 pub(crate) fn new(state: kio::Consumer<GroupState>, info: Info, source: Source) -> Self {
691 Self {
692 state,
693 info,
694 source,
695 read_idx: 0,
696 stats: stats::Meter::default(),
697 expiry: None,
698 expired: false,
699 }
700 }
701
702 pub(crate) fn with_meter(mut self, meter: stats::Meter) -> Self {
705 self.stats = meter;
706 self
707 }
708
709 pub(crate) fn with_expiry(mut self, expiry: Expiry) -> Self {
710 self.expiry = Some(expiry);
711 self
712 }
713
714 fn size(&self) -> usize {
715 match &self.source {
716 Source::Complete(bytes) => bytes.len(),
717 Source::Partial(_) => self.info.size as usize,
718 }
719 }
720
721 fn poll_expired(&mut self, waiter: &kio::Waiter) -> bool {
727 if self.expired || self.read_idx >= self.size() {
728 return self.expired;
729 }
730 let Some(expiry) = &self.expiry else {
731 return false;
732 };
733 if !expiry.policy.is_expired(waiter) {
734 return false;
735 }
736
737 self.expired = true;
738 if !expiry.stale_counted.swap(true, Ordering::Relaxed) {
739 let mut stale = self.state.read().content_range(expiry.tail.start, expiry.tail.end);
740 if expiry.count_payload {
741 stale.bytes += self.size().saturating_sub(self.read_idx) as u64;
742 }
743 expiry.stale_stats.stale(stale);
744 }
745 true
746 }
747
748 pub fn poll_read_chunk(&mut self, waiter: &kio::Waiter) -> Poll<Result<Option<Bytes>>> {
752 if self.expired {
753 return Poll::Ready(Err(Error::Old));
754 }
755 let buf = match &self.source {
756 Source::Complete(bytes) => {
757 if self.read_idx >= bytes.len() {
758 return Poll::Ready(Ok(None));
759 }
760 let out = bytes.slice(self.read_idx..);
761 self.read_idx = bytes.len();
762 self.stats.bytes(out.len() as u64);
763 return Poll::Ready(Ok(Some(out)));
764 }
765 Source::Partial(buf) => buf.clone(),
766 };
767
768 let size = self.info.size as usize;
769 loop {
770 let written = buf.written(Ordering::Acquire);
771 if written > self.read_idx {
772 let out = buf.slice(self.read_idx, written);
773 self.read_idx = written;
774 self.stats.bytes(out.len() as u64);
775 return Poll::Ready(Ok(Some(out)));
776 }
777 if written >= size {
778 return Poll::Ready(Ok(None));
779 }
780 if self.poll_expired(waiter) {
783 return Poll::Ready(Err(Error::Old));
784 }
785 let read_idx = self.read_idx;
786 ready!(poll_state(&self.state, waiter, |state| {
789 if let Some(err) = &state.abort {
790 return Poll::Ready(Err(err.clone()));
791 }
792 let w = buf.written(Ordering::Acquire);
793 if w > read_idx || w >= size {
794 Poll::Ready(Ok(()))
795 } else {
796 Poll::Pending
797 }
798 })?);
799 }
800 }
801
802 pub async fn read_chunk(&mut self) -> Result<Option<Bytes>> {
804 kio::wait(|waiter| self.poll_read_chunk(waiter)).await
805 }
806
807 pub fn poll_read_all(&mut self, waiter: &kio::Waiter) -> Poll<Result<Bytes>> {
809 if self.expired {
810 return Poll::Ready(Err(Error::Old));
811 }
812 let buf = match &self.source {
813 Source::Complete(bytes) => {
814 let out = bytes.slice(self.read_idx..);
815 self.read_idx = bytes.len();
816 self.stats.bytes(out.len() as u64);
817 return Poll::Ready(Ok(out));
818 }
819 Source::Partial(buf) => buf.clone(),
820 };
821
822 let size = self.info.size as usize;
823 let read_idx = self.read_idx;
824 if buf.written(Ordering::Acquire) < size && self.poll_expired(waiter) {
826 return Poll::Ready(Err(Error::Old));
827 }
828 ready!(poll_state(&self.state, waiter, |state| {
829 if let Some(err) = &state.abort {
830 return Poll::Ready(Err(err.clone()));
831 }
832 if buf.written(Ordering::Acquire) >= size {
833 Poll::Ready(Ok(()))
834 } else {
835 Poll::Pending
836 }
837 })?);
838 let out = buf.slice(read_idx, size);
839 self.read_idx = size;
840 self.stats.bytes(out.len() as u64);
841 Poll::Ready(Ok(out))
842 }
843
844 pub async fn read_all(&mut self) -> Result<Bytes> {
846 kio::wait(|waiter| self.poll_read_all(waiter)).await
847 }
848}
849
850fn poll_state<F, R>(state: &kio::Consumer<GroupState>, waiter: &kio::Waiter, f: F) -> Poll<Result<R>>
853where
854 F: Fn(&kio::Ref<'_, GroupState>) -> Poll<Result<R>>,
855{
856 Poll::Ready(match ready!(state.poll(waiter, f)) {
857 Ok(res) => res,
858 Err(state) => Err(state.abort.clone().unwrap_or(Error::Dropped)),
859 })
860}
861
862#[cfg(test)]
863mod tests {
864 use super::*;
865
866 #[test]
869 fn growing_buffer_keeps_handed_out_slices() {
870 let buf = FrameBuf::growing(10);
871 buf.append(b"abc");
872 assert_eq!(buf.allocated(), 3);
873 let early = buf.slice(0, 3);
874
875 buf.append(b"defg");
876 assert_eq!(buf.allocated(), 7);
877 buf.append(b"hij");
878 assert_eq!(buf.allocated(), 10, "doubling stops at the declared size");
879
880 assert_eq!(early, &b"abc"[..]);
881 assert_eq!(buf.slice(3, 7), &b"defg"[..]);
882 assert_eq!(buf.freeze(), &b"abcdefghij"[..]);
883 }
884
885 #[test]
888 fn growing_buffer_reads_across_threads() {
889 const SIZE: usize = 256 * 1024;
890 let buf = FrameBuf::growing(SIZE);
891 let reader = std::thread::spawn({
892 let buf = buf.clone();
893 move || {
894 let mut read = 0;
895 while read < SIZE {
896 let written = buf.written(Ordering::Acquire);
897 let chunk = buf.slice(read, written);
898 for (i, byte) in chunk.iter().enumerate() {
899 assert_eq!(*byte, ((read + i) % 251) as u8);
900 }
901 read = written;
902 std::thread::yield_now();
903 }
904 }
905 });
906
907 let payload: Vec<u8> = (0..SIZE).map(|i| (i % 251) as u8).collect();
908 for chunk in payload.chunks(1000) {
909 buf.append(chunk);
910 }
911 reader.join().unwrap();
912 assert_eq!(buf.freeze(), payload);
913 }
914
915 #[test]
918 fn budget_returns_reservations() {
919 let budget = Budget::new(100);
920 let a = budget.reserve(60).unwrap();
921 assert!(budget.reserve(41).is_none());
922 let b = budget.reserve(40).unwrap();
923 assert!(budget.reserve(1).is_none());
924
925 drop(a);
926 drop(b);
927 assert!(budget.reserve(100).is_some());
928 }
929}