Skip to main content

win_durable_ioring/
delivery.rs

1// Copyright (c) 2026 Mike Grier
2//! The Model A front end ([DI-D-31](../DESIGN-NOTES.md#di-d-31),
3//! [DI-D-32](../DESIGN-NOTES.md#di-d-32)): an instance whose entries are handed, one at a time and
4//! in queue order, to a handler on thread-pool threads, and whose operations are reachable from any
5//! thread through `&self`.
6//!
7//! Written once over the trait, so it serves every implementation whose readiness signal is an
8//! `Event` (DI-D-52 Q6). It waits on that signal through a thread-pool wait, and on each wake pops
9//! to `None` before waiting again (DI-D-28). The handler is called with the instance's lock
10//! released, so it may call back in through the [`DeliveryHandle`] it is given; it runs under a
11//! lock of its own, which only the single deliverer takes.
12
13use std::fmt;
14use std::io;
15use std::ops::Deref;
16use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
17
18use win_sync_sys::Event;
19use windows_ioring_sys::{IoBuf, IoBufMut, RegisteredSpan};
20use windows_threadpool_sys::callback_env::CallbackEnviron;
21use windows_threadpool_sys::wait::{ThreadpoolWait, WaitActivation};
22
23use durable_ioring::{
24    AddTargetError, DurabilityRequest, EndLineageError, Epoch, EpochState, FailureInfo,
25    ImportScope, Imported, IoTargetKey, Leftovers, LineageInfo, ReadOptions, RemoveTargetError,
26    Resolution, ResolveError, RetireLineageError, SealError, Tag, UnknownLineage, WriteOptions,
27};
28use durable_ioring::{
29    DurableRing, EntryOf, EpochIdOf, FailureIdOf, HandleOf, Lin, PushResult, RegisteredBufferRing,
30    TokenOf,
31};
32use durable_ioring::{ReadKey, TargetKey, WriteKey};
33
34#[cfg(test)]
35mod tests;
36
37/// What the deliverer hands its handler: an entry, or why it could not pop one.
38///
39/// A failure is the instance's own pop failing -- a submission its doorbell could not issue, or a
40/// ring it could not read ([DI-D-58](../../durable-ioring/DESIGN-NOTES.md#di-d-58)). It is reported
41/// once per wake, and the delivery goes on: the next wake delivers what can be, and a cause that
42/// stays is reported again. The handler's remedy for one that stays is to stop and drop the
43/// delivery, which hands the instance back (into_inner) or closes it (close).
44#[derive(Debug)]
45pub enum DeliveryEvent<E> {
46    /// The next entry, in queue order.
47    Entry(E),
48    /// The instance's `pop` failed. The error says why, and downcasts to the cause the instance
49    /// reported, as an instance's own `pop` error does.
50    Failure(io::Error),
51}
52
53/// The handler, as the deliverer holds it.
54type Handler<D> = dyn FnMut(DeliveryEvent<EntryOf<D>>, &DeliveryHandle<D>) + Send;
55
56/// What the deliverer and the owner share. The handler is last, so a front end built with one
57/// handler type can be held as the trait object.
58struct Inner<D, H: ?Sized> {
59    handle: DeliveryHandle<D>,
60    handler: Mutex<H>,
61}
62
63/// The operations of an instance whose delivery an [`EntryDelivery`] owns, through `&self` from
64/// any thread. The handler is given one; the owner derefs to its own, so both offer the same
65/// operations from one definition.
66///
67/// Each call takes the front end's lock on the instance for its duration -- dioring's lock in
68/// DI-D-18's order, taken before the ring's -- and the handler is called with that lock released.
69///
70/// # What it withholds
71///
72/// - **`pop` and `readiness`**: the delivery is the single deliverer and the signal's one waiter
73///   (DI-D-28). A second popper would take entries out of order; a second waiter would steal wakes.
74/// - **Any `&mut` to the instance**, including through a closure. Safe code could then replace the
75///   instance while the wait stayed armed on the old one's signal, and delivery would stop without
76///   an error -- the ring crate's measured defect
77///   ([D-43](../../windows-ioring-sys/DESIGN-NOTES.md#d-43)), which a closure does not close.
78///   Registered bytes are therefore reached through closures over the bytes alone.
79///
80/// Not constructible, and not `Clone`: a handler holds one only for the length of a call, so it
81/// cannot keep the front end alive.
82pub struct DeliveryHandle<D> {
83    /// `None` only after [`EntryDelivery::into_inner`] has quiesced the delivery and taken it.
84    ring: Mutex<Option<D>>,
85}
86
87impl<D> DeliveryHandle<D> {
88    /// Run `f` on the instance under the front end's lock.
89    fn with<R>(&self, f: impl FnOnce(&mut D) -> R) -> R {
90        let mut ring = self.ring.lock().unwrap_or_else(PoisonError::into_inner);
91        f(ring
92            .as_mut()
93            .expect("the instance is taken only once nothing can reach this handle"))
94    }
95
96    fn take(&self) -> D {
97        self.ring
98            .lock()
99            .unwrap_or_else(PoisonError::into_inner)
100            .take()
101            .expect("the instance is taken once")
102    }
103}
104
105impl<D: DurableRing> DeliveryHandle<D> {
106    /// [`DurableRing::add_target`].
107    ///
108    /// # Errors
109    ///
110    /// As [`DurableRing::add_target`].
111    pub fn add_target<K: TargetKey>(
112        &self,
113        key: K,
114        target: D::Target,
115    ) -> Result<(), AddTargetError<D::Target>> {
116        self.with(|ring| ring.add_target(key, target))
117    }
118
119    /// [`DurableRing::remove_target`].
120    ///
121    /// # Errors
122    ///
123    /// As [`DurableRing::remove_target`].
124    pub fn remove_target(&self, key: IoTargetKey) -> Result<D::Target, RemoveTargetError<D::Ids>> {
125        self.with(|ring| ring.remove_target(key))
126    }
127
128    /// [`DurableRing::default_lineage`].
129    pub fn default_lineage(&self) -> HandleOf<D> {
130        self.with(|ring| ring.default_lineage())
131    }
132
133    /// [`DurableRing::mint_lineage`].
134    pub fn mint_lineage(&self, description: Option<String>) -> HandleOf<D> {
135        self.with(|ring| ring.mint_lineage(description))
136    }
137
138    /// [`DurableRing::lineages`].
139    pub fn lineages(&self) -> Vec<LineageInfo<D::Ids>> {
140        self.with(|ring| ring.lineages())
141    }
142
143    /// [`DurableRing::end_lineage`].
144    ///
145    /// # Errors
146    ///
147    /// As [`DurableRing::end_lineage`].
148    pub fn end_lineage(&self, handle: HandleOf<D>) -> Result<(), EndLineageError<D::Ids>> {
149        self.with(|ring| ring.end_lineage(handle))
150    }
151
152    /// [`DurableRing::retire_lineage`].
153    ///
154    /// # Errors
155    ///
156    /// As [`DurableRing::retire_lineage`].
157    pub fn retire_lineage(&self, handle: HandleOf<D>) -> Result<(), RetireLineageError<D::Ids>> {
158        self.with(|ring| ring.retire_lineage(handle))
159    }
160
161    /// [`DurableRing::write`].
162    ///
163    /// # Errors
164    ///
165    /// As [`DurableRing::write`].
166    pub fn write<K: WriteKey>(
167        &self,
168        file: K,
169        offset: u64,
170        buffer: D::Buffer,
171        tag: Tag<'_, D::Ids>,
172        context: D::Context,
173    ) -> PushResult<D>
174    where
175        D::Buffer: IoBuf,
176    {
177        self.with(|ring| ring.write(file, offset, buffer, tag, context))
178    }
179
180    /// [`DurableRing::write_with`].
181    ///
182    /// # Errors
183    ///
184    /// As [`DurableRing::write_with`].
185    pub fn write_with<K: WriteKey>(
186        &self,
187        file: K,
188        offset: u64,
189        buffer: D::Buffer,
190        tag: Tag<'_, D::Ids>,
191        context: D::Context,
192        options: WriteOptions<D::Ids>,
193    ) -> PushResult<D>
194    where
195        D::Buffer: IoBuf,
196    {
197        self.with(|ring| ring.write_with(file, offset, buffer, tag, context, options))
198    }
199
200    /// [`DurableRing::read`].
201    ///
202    /// # Errors
203    ///
204    /// As [`DurableRing::read`].
205    pub fn read<K: ReadKey>(
206        &self,
207        file: K,
208        offset: u64,
209        buffer: D::Buffer,
210        context: D::Context,
211    ) -> PushResult<D>
212    where
213        D::Buffer: IoBufMut,
214    {
215        self.with(|ring| ring.read(file, offset, buffer, context))
216    }
217
218    /// [`DurableRing::read_with`].
219    ///
220    /// # Errors
221    ///
222    /// As [`DurableRing::read_with`].
223    pub fn read_with<K: ReadKey>(
224        &self,
225        file: K,
226        offset: u64,
227        buffer: D::Buffer,
228        context: D::Context,
229        options: ReadOptions<D::Ids>,
230    ) -> PushResult<D>
231    where
232        D::Buffer: IoBufMut,
233    {
234        self.with(|ring| ring.read_with(file, offset, buffer, context, options))
235    }
236
237    /// [`DurableRing::make_durable_through`].
238    ///
239    /// # Errors
240    ///
241    /// As [`DurableRing::make_durable_through`].
242    pub fn make_durable_through(
243        &self,
244        through: Tag<'_, D::Ids>,
245    ) -> Result<DurabilityRequest<D::Ids>, SealError<D::Ids>> {
246        self.with(|ring| ring.make_durable_through(through))
247    }
248
249    /// [`DurableRing::durable_through`].
250    ///
251    /// # Errors
252    ///
253    /// As [`DurableRing::durable_through`].
254    pub fn durable_through(
255        &self,
256        lineage: Lin<D>,
257    ) -> Result<Option<EpochIdOf<D>>, UnknownLineage<D::Ids>> {
258        self.with(|ring| ring.durable_through(lineage))
259    }
260
261    /// [`DurableRing::sealed_through`].
262    ///
263    /// # Errors
264    ///
265    /// As [`DurableRing::sealed_through`].
266    pub fn sealed_through(
267        &self,
268        lineage: Lin<D>,
269    ) -> Result<Option<EpochIdOf<D>>, UnknownLineage<D::Ids>> {
270        self.with(|ring| ring.sealed_through(lineage))
271    }
272
273    /// [`DurableRing::epoch_state`].
274    ///
275    /// # Errors
276    ///
277    /// As [`DurableRing::epoch_state`].
278    pub fn epoch_state(
279        &self,
280        epoch: Epoch<D::Ids>,
281    ) -> Result<EpochState<D::Ids>, UnknownLineage<D::Ids>> {
282        self.with(|ring| ring.epoch_state(epoch))
283    }
284
285    /// [`DurableRing::resolve`].
286    ///
287    /// # Errors
288    ///
289    /// As [`DurableRing::resolve`].
290    pub fn resolve(
291        &self,
292        items: Vec<(TokenOf<D>, Resolution)>,
293    ) -> Result<(), ResolveError<D::Ids>> {
294        self.with(|ring| ring.resolve(items))
295    }
296
297    /// [`DurableRing::import_failure`].
298    ///
299    /// # Errors
300    ///
301    /// As [`DurableRing::import_failure`].
302    pub fn import_failure(
303        &self,
304        scope: ImportScope<D::Ids>,
305    ) -> Result<Imported<D::Ids>, UnknownLineage<D::Ids>> {
306        self.with(|ring| ring.import_failure(scope))
307    }
308
309    /// [`DurableRing::failures`].
310    pub fn failures(&self) -> Vec<FailureInfo<D::Ids>> {
311        self.with(|ring| ring.failures())
312    }
313
314    /// [`DurableRing::take_token`].
315    pub fn take_token(&self, failure: FailureIdOf<D>) -> Option<TokenOf<D>> {
316        self.with(|ring| ring.take_token(failure))
317    }
318}
319
320impl<D: RegisteredBufferRing> DeliveryHandle<D> {
321    /// Run `f` on the bytes of registered buffer `i`, under the front end's lock.
322    ///
323    /// # Errors
324    ///
325    /// As [`RegisteredBufferRing::with_registered_buffer`].
326    pub fn with_registered_buffer<R>(&self, i: u32, f: impl FnOnce(&[u8]) -> R) -> io::Result<R> {
327        self.with(|ring| ring.with_registered_buffer(i, f))
328    }
329
330    /// Run `f` on the bytes of registered buffer `i`, mutably, under the front end's lock.
331    ///
332    /// # Errors
333    ///
334    /// As [`RegisteredBufferRing::with_registered_buffer_mut`].
335    pub fn with_registered_buffer_mut<R>(
336        &self,
337        i: u32,
338        f: impl FnOnce(&mut [u8]) -> R,
339    ) -> io::Result<R> {
340        self.with(|ring| ring.with_registered_buffer_mut(i, f))
341    }
342
343    /// [`RegisteredBufferRing::write_registered`].
344    ///
345    /// # Errors
346    ///
347    /// As [`RegisteredBufferRing::write_registered`].
348    pub fn write_registered<K: WriteKey>(
349        &self,
350        file: K,
351        offset: u64,
352        span: RegisteredSpan,
353        tag: Tag<'_, D::Ids>,
354        context: D::Context,
355    ) -> PushResult<D> {
356        self.with(|ring| ring.write_registered(file, offset, span, tag, context))
357    }
358
359    /// [`RegisteredBufferRing::write_registered_with`].
360    ///
361    /// # Errors
362    ///
363    /// As [`RegisteredBufferRing::write_registered_with`].
364    pub fn write_registered_with<K: WriteKey>(
365        &self,
366        file: K,
367        offset: u64,
368        span: RegisteredSpan,
369        tag: Tag<'_, D::Ids>,
370        context: D::Context,
371        options: WriteOptions<D::Ids>,
372    ) -> PushResult<D> {
373        self.with(|ring| ring.write_registered_with(file, offset, span, tag, context, options))
374    }
375
376    /// [`RegisteredBufferRing::read_registered`].
377    ///
378    /// # Errors
379    ///
380    /// As [`RegisteredBufferRing::read_registered`].
381    pub fn read_registered<K: ReadKey>(
382        &self,
383        file: K,
384        offset: u64,
385        span: RegisteredSpan,
386        context: D::Context,
387    ) -> PushResult<D> {
388        self.with(|ring| ring.read_registered(file, offset, span, context))
389    }
390
391    /// [`RegisteredBufferRing::read_registered_with`].
392    ///
393    /// # Errors
394    ///
395    /// As [`RegisteredBufferRing::read_registered_with`].
396    pub fn read_registered_with<K: ReadKey>(
397        &self,
398        file: K,
399        offset: u64,
400        span: RegisteredSpan,
401        context: D::Context,
402        options: ReadOptions<D::Ids>,
403    ) -> PushResult<D> {
404        self.with(|ring| ring.read_registered_with(file, offset, span, context, options))
405    }
406}
407
408/// A failed [`EntryDelivery::new`], handing back what it took.
409pub struct DeliverySetupError<D, F> {
410    /// Why it failed.
411    pub error: io::Error,
412    /// The instance.
413    pub ring: D,
414    /// The handler.
415    pub on_entry: F,
416}
417
418impl<D, F> fmt::Debug for DeliverySetupError<D, F> {
419    // By hand, so neither the instance nor the handler need be `Debug`.
420    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421        f.debug_struct("DeliverySetupError")
422            .field("error", &self.error)
423            .finish_non_exhaustive()
424    }
425}
426
427/// The Model A front end: owns an instance and hands its entries, one at a time and in queue
428/// order, to a handler on thread-pool threads. Derefs to the [`DeliveryHandle`] through which the
429/// instance's operations are reached. For an instance whose readiness signal is an [`Event`],
430/// which it waits on through the thread pool.
431///
432/// # The handler
433///
434/// Called with a [`DeliveryEvent`]: each entry, in queue order, and a failure of the instance's
435/// `pop` when it has one to report, which a handler that ignores is a delivery that stalls
436/// without saying so. Called on a pool thread, never twice at once, with the instance's lock released. It must not
437/// panic -- a panic unwinds into the thread pool's callback and aborts the process -- and while it
438/// runs no further entry is delivered, so a handler that blocks holds up delivery, and holds up
439/// [`into_inner`](Self::into_inner) and drop, which wait for it.
440///
441/// # Ending
442///
443/// Drop, [`close`](Self::close) and [`into_inner`](Self::into_inner) all quiesce the delivery
444/// first: no handler call is running or will start (DI-2.7 point 5), so none runs once they have
445/// returned. Drop then drops the instance, and `close` closes it, each discarding any entry not yet
446/// delivered; `into_inner` hands the instance back with those entries still queued, so it can be
447/// popped directly or closed.
448pub struct EntryDelivery<D: DurableRing<Readiness = Event> + Send + 'static> {
449    /// `None` once the delivery has been quiesced.
450    wait: Option<ThreadpoolWait>,
451    inner: Arc<Inner<D, Handler<D>>>,
452}
453
454impl<D: DurableRing<Readiness = Event> + Send + 'static> EntryDelivery<D> {
455    /// Take `ring` and deliver its entries to `on_entry`, on the default thread pool, or on the
456    /// pool and priority `env` selects.
457    ///
458    /// Entries already queued when the ring is handed over are delivered: the readiness signal may
459    /// already have been consumed, so this arms the wait and then sets the signal itself.
460    ///
461    /// # Errors
462    ///
463    /// A [`DeliverySetupError`] handing back the instance and the handler, when taking the
464    /// readiness signal from the instance, creating the thread-pool wait, or setting the signal
465    /// fails. Only the first is reached by a test: the others fail when the thread pool cannot
466    /// create a wait.
467    pub fn new<F>(
468        mut ring: D,
469        on_entry: F,
470        env: Option<&mut CallbackEnviron<'_>>,
471    ) -> Result<Self, DeliverySetupError<D, F>>
472    where
473        F: FnMut(DeliveryEvent<EntryOf<D>>, &DeliveryHandle<D>) + Send + 'static,
474    {
475        let clones = ring.readiness().map(|signal| (signal.clone(), signal));
476        let (signal, kick) = match clones {
477            Ok(clones) => clones,
478            Err(error) => {
479                return Err(DeliverySetupError {
480                    error,
481                    ring,
482                    on_entry,
483                });
484            }
485        };
486        let inner: Arc<Inner<D, F>> = Arc::new(Inner {
487            handle: DeliveryHandle {
488                ring: Mutex::new(Some(ring)),
489            },
490            handler: Mutex::new(on_entry),
491        });
492
493        let deliverer: Arc<Inner<D, Handler<D>>> = inner.clone();
494        let wait = match ThreadpoolWait::new(
495            signal.into(),
496            move |activation| deliver(&deliverer, activation),
497            env,
498        ) {
499            Ok(wait) => wait,
500            // The refused wait dropped its callback, and the deliverer's reference with it.
501            Err(error) => return Err(recover(inner, error)),
502        };
503        wait.arm(None);
504        if let Err(error) = kick.set() {
505            wait.stop_and_drain();
506            drop(wait);
507            return Err(recover(inner, error));
508        }
509        Ok(Self {
510            wait: Some(wait),
511            inner,
512        })
513    }
514
515    /// Quiesce the delivery and hand back the instance, with any entry not yet delivered still in
516    /// its queue.
517    #[must_use]
518    pub fn into_inner(mut self) -> D {
519        self.quiesce();
520        self.inner.handle.take()
521    }
522
523    /// Quiesce the delivery and end the instance with [`DurableRing::close`], handing back what is
524    /// left. Entries not yet delivered are discarded with it.
525    pub fn close(self) -> Leftovers<D::Ids, D::Buffer, D::Context> {
526        self.into_inner().close()
527    }
528
529    /// Disarm the wait, wait for a delivery in progress to finish, and release the wait and the
530    /// deliverer's reference to the instance.
531    fn quiesce(&mut self) {
532        if let Some(wait) = self.wait.take() {
533            wait.stop_and_drain();
534        }
535    }
536}
537
538impl<D: DurableRing<Readiness = Event> + Send + 'static> Deref for EntryDelivery<D> {
539    type Target = DeliveryHandle<D>;
540
541    fn deref(&self) -> &DeliveryHandle<D> {
542        &self.inner.handle
543    }
544}
545
546impl<D: DurableRing<Readiness = Event> + Send + 'static> Drop for EntryDelivery<D> {
547    fn drop(&mut self) {
548        // Before the instance is released, which the field drop that follows does (DI-2.7 point
549        // 5): no handler call can still be reaching it.
550        self.quiesce();
551    }
552}
553
554/// One wake: pop to `None`, handing each entry to the handler with the instance's lock released,
555/// then re-arm (DI-D-28). Re-arming last is what serialises delivery: a wake that arrives while
556/// this one drains finds the signal set once it is re-armed, and starts only after this one has
557/// made its last handler call.
558///
559/// A failed `pop` is the handler's to be told, once, and ends the wake: dioring's is a submission
560/// its doorbell could not issue, or a ring it could not read, with nothing to pop, and the readiness
561/// edge this wake took is the only thing that told the consumer (DI-D-58). Looping again would
562/// repeat a cause that stays, with nothing to stop it.
563fn deliver<D: DurableRing>(inner: &Inner<D, Handler<D>>, activation: &WaitActivation<'_>) {
564    loop {
565        let event = match inner.handle.with(|ring| ring.pop()) {
566            Ok(Some(entry)) => DeliveryEvent::Entry(entry),
567            Ok(None) => break,
568            Err(error) => {
569                let mut handler = lock(&inner.handler);
570                (*handler)(DeliveryEvent::Failure(error), &inner.handle);
571                break;
572            }
573        };
574        let mut handler = lock(&inner.handler);
575        (*handler)(event, &inner.handle);
576    }
577    activation.rearm(None);
578}
579
580fn lock<T: ?Sized>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
581    // The handler aborts the process rather than unwinding, so a poisoned handler lock means a
582    // panic elsewhere, which leaves the handler as it was.
583    mutex.lock().unwrap_or_else(PoisonError::into_inner)
584}
585
586/// Take back the instance and the handler from a front end that never started delivering.
587fn recover<D, F>(inner: Arc<Inner<D, F>>, error: io::Error) -> DeliverySetupError<D, F> {
588    let Inner { handle, handler } = Arc::into_inner(inner)
589        .expect("no wait holds the deliverer's reference once construction has failed");
590    DeliverySetupError {
591        error,
592        ring: handle
593            .ring
594            .into_inner()
595            .unwrap_or_else(PoisonError::into_inner)
596            .expect("the instance is still in place"),
597        on_entry: handler.into_inner().unwrap_or_else(PoisonError::into_inner),
598    }
599}