Skip to main content

FailureStore

Trait FailureStore 

Source
pub trait FailureStore {
    type Factory: StreamFactory<Stream: StreamMemory>;

    // Required methods
    fn split(&mut self) -> (&mut StreamPool<Self::Factory>, &mut Failures);
    fn parts(&self) -> (&StreamPool<Self::Factory>, &Failures);

    // Provided methods
    fn ensure_written<'a>(
        &self,
        handles: impl Iterator<Item = &'a BufferBinding>,
    ) -> Result<(), ServerError> { ... }
    fn read_failure<'a>(
        &self,
        reads: impl Iterator<Item = &'a BufferBinding>,
    ) -> Option<ReadFailure> { ... }
    fn taint<'a>(
        &mut self,
        error: ServerError,
        written: impl Iterator<Item = &'a BufferBinding>,
    ) { ... }
    fn written<'a>(&mut self, written: impl Iterator<Item = &'a BufferBinding>) { ... }
    fn propagate(
        &mut self,
        found: &ReadFailure,
        kernel: KernelId,
        written: Vec<BufferBinding>,
    ) { ... }
    fn write_set(&mut self) -> Vec<BufferBinding> { ... }
    fn enter_write(&mut self, written: &[BufferBinding]) -> Option<FailureId> { ... }
    fn exit_write(
        &mut self,
        provisional: Option<FailureId>,
        written: Vec<BufferBinding>,
        error: Option<&ServerError>,
    ) { ... }
}
Expand description

A multi-stream driver that owns a device’s Failures.

Implementing split and parts buys the whole taint surface below, and the write scope’s hooks with it. Whether a buffer can be trusted lives on its allocation, so every operation here is the same two steps: resolve each binding to the stream that allocated it, and tell that stream’s memory what happened.

Required Associated Types§

Source

type Factory: StreamFactory<Stream: StreamMemory>

The factory the driver’s StreamPool was built from. Its streams expose the memory the taint is recorded on.

Required Methods§

Source

fn split(&mut self) -> (&mut StreamPool<Self::Factory>, &mut Failures)

The pool and the store, split-borrowed: nearly every operation here reaches the allocations through the pool while mutating the store.

Source

fn parts(&self) -> (&StreamPool<Self::Factory>, &Failures)

split for the read-only questions.

Provided Methods§

Source

fn ensure_written<'a>( &self, handles: impl Iterator<Item = &'a BufferBinding>, ) -> Result<(), ServerError>

Fails when the buffers handles name carry a failure, with the errors of the work that was supposed to write them.

A read is only as good as the work that wrote the buffer: a launch that failed never wrote it, so copying its bytes out hands back whatever was in memory before. Whether that happened is a field on the allocation, so the question is answered by the slice each binding resolves to — a lookup the read was going to do anyway — and by nobody’s queue.

§Errors

ServerError::Several naming every failure one of these buffers carries, each failure once however many buffers carry it, and every buffer that was never allocated. The caller has nothing to retry — the bytes are gone — so the error is the answer to the read, not a hint to try again.

Source

fn read_failure<'a>( &self, reads: impl Iterator<Item = &'a BufferBinding>, ) -> Option<ReadFailure>

The failure claiming bytes any of reads names, with its error — the check a launch makes before it runs.

A launch whose input cannot be trusted does not run: a buffer holding garbage can be read as a dynamic cube count or as indices in a gather, so running would risk dispatching an absurd grid or scattering into memory that carried no failure at all. Skipping costs the same lookup, because the inputs have to be read either way to decide anything.

Source

fn taint<'a>( &mut self, error: ServerError, written: impl Iterator<Item = &'a BufferBinding>, )

Taint every allocation in written with error: the work that was going to write those buffers did not run, so a read of any of them fails on this failure until something writes them again.

Each binding is resolved to the manager of the stream it was created on, which may not be the stream that failed — that is the point: the fact lands on the memory, wherever it lives.

Source

fn written<'a>(&mut self, written: impl Iterator<Item = &'a BufferBinding>)

Release the failure on every allocation in written: work that writes them has been enqueued, so a read of one is no longer reading bytes nothing wrote.

Source

fn propagate( &mut self, found: &ReadFailure, kernel: KernelId, written: Vec<BufferBinding>, )

A skipped launch’s outputs take the failure that stopped it: nothing wrote them, exactly as if the launch had failed, and the claim names the root cause rather than minting a new one. The skip is recorded on the failure, so a read of anything downstream can name the path back to the root.

Takes the write set by value and hands it back to the pool, the same contract exit_write has, because a skip is the other way a scope ends: a loop carrying a tainted buffer forward skips on every iteration — the most frequent event in this whole design — and a set the skip path dropped would allocate a fresh one every time.

Source

fn write_set(&mut self) -> Vec<BufferBinding>

An empty write set, pooled here so a launch allocates nothing for it. exit_write hands it back.

Source

fn enter_write(&mut self, written: &[BufferBinding]) -> Option<FailureId>

Enter a write scope over written: taint every buffer the work is going to write with a provisional failure, minted here because the real one does not exist yet.

The default this sets is tainted unless proven written — the opposite of clearing on success and hoping every failure path remembered to taint. A body that returns early, or panics before exit_write runs, leaves the write set carrying this failure, so a read of one of its buffers fails loudly instead of returning bytes nothing wrote.

An empty write set — a dry run, a launch writing nothing — claims nothing and mints nothing.

Source

fn exit_write( &mut self, provisional: Option<FailureId>, written: Vec<BufferBinding>, error: Option<&ServerError>, )

Settle the scope entered over written: release the provisional failure when the work was enqueued, and swap the real error in for it when the work was not. The taint is the whole answer — a read of one of these buffers fails on it, whoever asks — and the error is logged here, the backstop for the failure nobody ever reads. The staged vector goes back to the pool either way.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§