1use std::sync::Arc;
9use std::sync::OnceLock;
10use std::sync::atomic::{AtomicUsize, Ordering};
11use std::task::{Poll, ready};
12
13use bytes::Bytes;
14
15use crate::group::{self, GroupState};
16use crate::{Error, IntoBytes, Result, Timestamp, stats};
17
18#[derive(Clone, Copy, Debug)]
23pub struct Info {
24 pub size: u64,
26 pub timestamp: Timestamp,
32}
33
34#[derive(Clone, Debug)]
39pub struct Frame {
40 pub timestamp: Timestamp,
42 pub payload: Bytes,
44}
45
46#[derive(Clone)]
55pub(crate) struct FrameBuf(Arc<FrameBufInner>);
56
57struct FrameBufInner {
58 capacity: usize,
59 written: AtomicUsize,
60 storage: OnceLock<FrameStorage>,
61}
62
63enum FrameStorage {
64 Shared(Bytes),
65 Mutable(MutableFrameBuf),
66}
67
68struct MutableFrameBuf {
69 data: *mut u8,
71 capacity: usize,
72}
73
74unsafe impl Send for MutableFrameBuf {}
77unsafe impl Sync for MutableFrameBuf {}
78
79impl Drop for MutableFrameBuf {
80 fn drop(&mut self) {
81 unsafe {
84 let slice = std::ptr::slice_from_raw_parts_mut(self.data, self.capacity);
85 drop(Box::from_raw(slice));
86 }
87 }
88}
89
90impl MutableFrameBuf {
91 fn new(size: usize) -> Self {
92 let boxed: Box<[u8]> = vec![0u8; size].into_boxed_slice();
93 let capacity = boxed.len();
94 let data = Box::into_raw(boxed) as *mut u8;
95 Self { data, capacity }
96 }
97}
98
99impl FrameBuf {
100 pub(crate) fn new(size: usize) -> Self {
105 Self(Arc::new(FrameBufInner {
106 capacity: size,
107 written: AtomicUsize::new(0),
108 storage: OnceLock::new(),
109 }))
110 }
111
112 pub(crate) fn capacity(&self) -> usize {
113 self.0.capacity
114 }
115
116 pub(crate) fn written(&self, ord: Ordering) -> usize {
117 self.0.written.load(ord)
118 }
119
120 fn try_set_bytes(&self, bytes: Bytes) -> std::result::Result<(), Bytes> {
121 if bytes.len() != self.capacity() || self.written(Ordering::Acquire) != 0 {
122 return Err(bytes);
123 }
124 self.0
125 .storage
126 .set(FrameStorage::Shared(bytes))
127 .map_err(|storage| match storage {
128 FrameStorage::Shared(bytes) => bytes,
129 FrameStorage::Mutable(_) => unreachable!("try_set_bytes only installs shared storage"),
130 })
131 }
132
133 fn mutable(&self) -> Option<&MutableFrameBuf> {
137 match self
138 .0
139 .storage
140 .get_or_init(|| FrameStorage::Mutable(MutableFrameBuf::new(self.capacity())))
141 {
142 FrameStorage::Shared(_) => None,
143 FrameStorage::Mutable(buf) => Some(buf),
144 }
145 }
146
147 unsafe fn store_written(&self, new_written: usize) {
149 self.0.written.store(new_written, Ordering::Release);
151 }
152
153 fn append(&self, src: &[u8]) {
159 if src.is_empty() {
160 return;
161 }
162 let prev = self.written(Ordering::Relaxed);
163 let Some(buf) = self.mutable() else {
164 return;
167 };
168 unsafe {
171 std::ptr::copy_nonoverlapping(src.as_ptr(), buf.data.add(prev), src.len());
172 self.store_written(prev + src.len());
173 }
174 }
175
176 fn freeze(&self, size: usize) -> Bytes {
181 match self.0.storage.get() {
182 Some(FrameStorage::Shared(bytes)) => bytes.clone(),
183 _ => self.slice(0, size),
184 }
185 }
186
187 fn slice(&self, start: usize, end: usize) -> Bytes {
189 Bytes::from_owner(self.clone()).slice(start..end)
190 }
191}
192
193impl AsRef<[u8]> for FrameBuf {
194 fn as_ref(&self) -> &[u8] {
195 let written = self.0.written.load(Ordering::Acquire);
198 match self.0.storage.get() {
199 Some(FrameStorage::Shared(bytes)) => &bytes[..written],
200 Some(FrameStorage::Mutable(buf)) => {
201 unsafe { std::slice::from_raw_parts(buf.data, written) }
205 }
206 None => &[],
207 }
208 }
209}
210
211pub struct Producer<'a> {
222 group: &'a mut group::Producer,
223 buf: FrameBuf,
224 info: Info,
225 done: bool,
227 stats: stats::Meter,
230}
231
232impl std::ops::Deref for Producer<'_> {
233 type Target = Info;
234
235 fn deref(&self) -> &Self::Target {
236 &self.info
237 }
238}
239
240impl<'a> Producer<'a> {
241 pub(crate) fn new(group: &'a mut group::Producer, buf: FrameBuf, info: Info) -> Self {
242 Self {
243 group,
244 buf,
245 info,
246 done: false,
247 stats: stats::Meter::default(),
248 }
249 }
250
251 pub(crate) fn with_meter(mut self, meter: stats::Meter) -> Self {
253 self.stats = meter;
254 self
255 }
256
257 pub fn group(&self) -> group::Info {
259 self.group.info()
260 }
261
262 pub fn remaining(&self) -> usize {
264 self.buf.capacity() - self.buf.written(Ordering::Acquire)
265 }
266
267 pub fn write<B: IntoBytes>(&mut self, chunk: B) -> Result<()> {
271 let len = chunk.as_ref().len();
272 if len > self.remaining() {
273 return Err(Error::WrongSize);
274 }
275 self.stats.bytes(len as u64);
277 if len == self.buf.capacity() && self.buf.written(Ordering::Acquire) == 0 {
279 match self.buf.try_set_bytes(chunk.into_bytes()) {
280 Ok(()) => {
281 let cap = self.buf.capacity();
282 unsafe { self.buf.store_written(cap) };
285 }
286 Err(chunk) => self.buf.append(&chunk),
287 }
288 } else {
289 self.buf.append(chunk.as_ref());
290 }
291 self.group.frame_notify();
292 Ok(())
293 }
294
295 pub fn finish(mut self) -> Result<()> {
299 if self.buf.written(Ordering::Acquire) != self.buf.capacity() {
300 return Err(Error::WrongSize);
301 }
302 let payload = self.buf.freeze(self.buf.capacity());
303 self.group.frame_commit(Frame {
304 timestamp: self.info.timestamp,
305 payload,
306 })?;
307 self.done = true;
308 Ok(())
309 }
310
311 pub fn abort(mut self, err: Error) -> Result<()> {
313 self.group.frame_abort(err);
314 self.done = true;
315 Ok(())
316 }
317}
318
319impl Drop for Producer<'_> {
320 fn drop(&mut self) {
321 if !self.done {
322 tracing::warn!(
325 group = self.group.info().sequence,
326 "frame::Producer dropped before writing all bytes"
327 );
328 self.group.frame_abort(Error::Dropped);
329 }
330 }
331}
332
333#[derive(Clone)]
336pub(crate) enum Source {
337 Complete(Bytes),
338 Partial(FrameBuf),
339}
340
341#[derive(Clone)]
347pub struct Consumer {
348 state: kio::Consumer<GroupState>,
350 info: Info,
351 source: Source,
352 read_idx: usize,
354 stats: stats::Meter,
358}
359
360impl std::ops::Deref for Consumer {
361 type Target = Info;
362
363 fn deref(&self) -> &Self::Target {
364 &self.info
365 }
366}
367
368impl Consumer {
369 pub(crate) fn new(state: kio::Consumer<GroupState>, info: Info, source: Source) -> Self {
370 Self {
371 state,
372 info,
373 source,
374 read_idx: 0,
375 stats: stats::Meter::default(),
376 }
377 }
378
379 pub(crate) fn with_meter(mut self, meter: stats::Meter) -> Self {
382 self.stats = meter;
383 self
384 }
385
386 pub fn poll_read_chunk(&mut self, waiter: &kio::Waiter) -> Poll<Result<Option<Bytes>>> {
390 match &self.source {
391 Source::Complete(bytes) => {
392 if self.read_idx >= bytes.len() {
393 return Poll::Ready(Ok(None));
394 }
395 let out = bytes.slice(self.read_idx..);
396 self.read_idx = bytes.len();
397 self.stats.bytes(out.len() as u64);
398 Poll::Ready(Ok(Some(out)))
399 }
400 Source::Partial(buf) => {
401 let buf = buf.clone();
402 let size = self.info.size as usize;
403 loop {
404 let written = buf.written(Ordering::Acquire);
405 if written > self.read_idx {
406 let out = buf.slice(self.read_idx, written);
407 self.read_idx = written;
408 self.stats.bytes(out.len() as u64);
409 return Poll::Ready(Ok(Some(out)));
410 }
411 if written >= size {
412 return Poll::Ready(Ok(None));
413 }
414 let read_idx = self.read_idx;
415 ready!(poll_state(&self.state, waiter, |state| {
418 if let Some(err) = &state.abort {
419 return Poll::Ready(Err(err.clone()));
420 }
421 let w = buf.written(Ordering::Acquire);
422 if w > read_idx || w >= size {
423 Poll::Ready(Ok(()))
424 } else {
425 Poll::Pending
426 }
427 })?);
428 }
429 }
430 }
431 }
432
433 pub async fn read_chunk(&mut self) -> Result<Option<Bytes>> {
435 kio::wait(|waiter| self.poll_read_chunk(waiter)).await
436 }
437
438 pub fn poll_read_all(&mut self, waiter: &kio::Waiter) -> Poll<Result<Bytes>> {
440 match &self.source {
441 Source::Complete(bytes) => {
442 let out = bytes.slice(self.read_idx..);
443 self.read_idx = bytes.len();
444 self.stats.bytes(out.len() as u64);
445 Poll::Ready(Ok(out))
446 }
447 Source::Partial(buf) => {
448 let buf = buf.clone();
449 let size = self.info.size as usize;
450 let read_idx = self.read_idx;
451 ready!(poll_state(&self.state, waiter, |state| {
452 if let Some(err) = &state.abort {
453 return Poll::Ready(Err(err.clone()));
454 }
455 if buf.written(Ordering::Acquire) >= size {
456 Poll::Ready(Ok(()))
457 } else {
458 Poll::Pending
459 }
460 })?);
461 let out = buf.slice(read_idx, size);
462 self.read_idx = size;
463 self.stats.bytes(out.len() as u64);
464 Poll::Ready(Ok(out))
465 }
466 }
467 }
468
469 pub async fn read_all(&mut self) -> Result<Bytes> {
471 kio::wait(|waiter| self.poll_read_all(waiter)).await
472 }
473}
474
475fn poll_state<F, R>(state: &kio::Consumer<GroupState>, waiter: &kio::Waiter, f: F) -> Poll<Result<R>>
478where
479 F: Fn(&kio::Ref<'_, GroupState>) -> Poll<Result<R>>,
480{
481 Poll::Ready(match ready!(state.poll(waiter, f)) {
482 Ok(res) => res,
483 Err(state) => Err(state.abort.clone().unwrap_or(Error::Dropped)),
484 })
485}