pub struct Batch<'ring> { /* private fields */ }Expand description
A scoped, exclusive submission window over one IoRing (D-5).
Holding &mut IoRing for its lifetime is what turns Win32’s own
“you must serialize submission” footnote into a compiler-enforced
guarantee: two batches over the same ring cannot coexist. Every push
queues its SQE the instant it succeeds – there is no rewind – so
Batch submits on Drop rather than leaving queued SQEs for some
later, unrelated submit to discover (D-5).
Implementations§
Source§impl<'ring> Batch<'ring>
impl<'ring> Batch<'ring>
Sourcepub unsafe fn read_raw<B: IoBufMut>(
&mut self,
file: impl Into<FileRef>,
buffer: B,
offset: u64,
options: PushOptions,
) -> Result<Token<B>>
pub unsafe fn read_raw<B: IoBufMut>( &mut self, file: impl Into<FileRef>, buffer: B, offset: u64, options: PushOptions, ) -> Result<Token<B>>
Queue a read of buffer.bytes_len() bytes from file at offset.
Prefer Batch::read unless file needs to address a raw
FileRef directly, without SharedFile’s Arc bookkeeping.
§Safety
If file is FileRef::Raw, the handle must be valid, opened with
read access, and must remain valid – not closed, not reused for a
different object – until this operation’s completion is observed
(via a popped Completion or Token::claim_if) or until the
ring runs down (M8, PR #20 review response). A FileRef::Registered
target needs none of this.
§Errors
io::ErrorKind::Unsupported if the ring was not probed as
supporting Op::Read; io::ErrorKind::InvalidInput if the
buffer is longer than u32::MAX; an crate::IoRingError wrapping
IORING_E_SUBMISSION_QUEUE_FULL if the queue has no room (M3.3, not
auto-flushed – see Batch’s own docs); or any other error from
BuildIoRingReadFile. On any error the buffer is dropped normally,
not leaked or handed back.
Sourcepub fn read<B: IoBufMut, F: FileTarget>(
&mut self,
file: &F,
buffer: B,
offset: u64,
options: PushOptions,
) -> Result<Token<(B, F::Guard)>>
pub fn read<B: IoBufMut, F: FileTarget>( &mut self, file: &F, buffer: B, offset: u64, options: PushOptions, ) -> Result<Token<(B, F::Guard)>>
As Batch::read_raw, but safe: file is a SharedFile rather
than a bare FileRef, so the pushed operation keeps its own clone
of the handle alive regardless of what the caller does with its
copy. The returned token yields (buffer, file) once claimed.
§Errors
As Batch::read_raw, plus io::ErrorKind::InvalidInput if file
is a RegisteredFile from a different ring.
Sourcepub unsafe fn write_raw<B: IoBuf>(
&mut self,
file: impl Into<FileRef>,
buffer: B,
offset: u64,
options: PushOptions,
caching: WriteCaching,
) -> Result<Token<B>>
pub unsafe fn write_raw<B: IoBuf>( &mut self, file: impl Into<FileRef>, buffer: B, offset: u64, options: PushOptions, caching: WriteCaching, ) -> Result<Token<B>>
Queue a write of buffer.bytes_len() bytes to file at offset.
caching is FILE_WRITE_FLAGS; see WriteCaching, and note that
write-through is a cache directive rather than a durability guarantee.
Durability comes from Batch::flush with
FlushCoverage::CoversPrecedingOperations, never from a write flag.
Prefer Batch::write unless file needs to address a raw
FileRef directly, without SharedFile’s Arc bookkeeping.
§Safety
As Batch::read_raw’s, for a write-access handle.
§Errors
As Batch::read_raw, plus any error from BuildIoRingWriteFile.
Sourcepub fn write<B: IoBuf, F: FileTarget>(
&mut self,
file: &F,
buffer: B,
offset: u64,
options: PushOptions,
caching: WriteCaching,
) -> Result<Token<(B, F::Guard)>>
pub fn write<B: IoBuf, F: FileTarget>( &mut self, file: &F, buffer: B, offset: u64, options: PushOptions, caching: WriteCaching, ) -> Result<Token<(B, F::Guard)>>
As Batch::write_raw, but safe: file is a SharedFile rather
than a bare FileRef. The returned token yields (buffer, file)
once claimed.
§Errors
As Batch::write_raw, plus io::ErrorKind::InvalidInput if file
is a RegisteredFile from a different ring.
Sourcepub unsafe fn flush_raw(
&mut self,
file: impl Into<FileRef>,
coverage: FlushCoverage,
mode: FlushMode,
) -> Result<usize>
pub unsafe fn flush_raw( &mut self, file: impl Into<FileRef>, coverage: FlushCoverage, mode: FlushMode, ) -> Result<usize>
Queue a flush of file’s buffered data.
coverage decides whether this flush covers the operations queued
before it. It is required rather than defaulted because there is no
safe default – see FlushCoverage and the measured contract below.
mode is FILE_FLUSH_MODE; FlushMode::Default is the durability
barrier. Note that FlushMode::NoSync issues no device sync and so
makes nothing durable, whatever coverage says.
There is no buffer, so this returns the raw UserData identity
rather than a Token: nothing owns a buffer for a completion to
hand back. Prefer Batch::flush unless file needs to address a
raw FileRef directly.
§A flush is the ring’s only durability primitive
The ring has no FUA. BuildIoRingWriteFile’s entire flag set is
{FILE_WRITE_FLAGS_NONE, FILE_WRITE_FLAGS_WRITE_THROUGH}, and
write-through is a cache-bypass directive to the OS rather than a
device-level durability guarantee – whether it becomes a Force Unit
Access bit depends on the driver, the volume, and whether the device’s
write cache is enabled (see WriteCaching). So this operation is the
only way the ring makes anything durable, and only with
FlushCoverage::CoversPrecedingOperations and a syncing
FlushMode.
§The measured contract (D-23 in DESIGN-NOTES.md)
An unflagged flush does not cover preceding writes. It is an ordinary operation competing with them, and it frequently wins: a flush pushed after a batch of writes with no barrier was observed completing while 17, and on another run 23, of 32 of those writes were still outstanding. A caller that reads such a completion as “the writes before it are now durable” has lost data it believes it has committed, and nothing reports the loss until power fails.
Which direction the reordering shows in is device-dependent, and a machine where the flush happens to land last anyway proves nothing: that is incidental behavior of one device stack, not a guarantee. Only the barrier makes it one.
Durability on this ring is therefore a property of an epoch, never
of an individual write, because there is no per-write primitive to
make it one: stream the writes unflagged, close the epoch with one
covering flush, and wait on that flush rather than on the writes.
“Durability on the ring” in DESIGN-NOTES.md has the full
construction, and the three ways to pay for the barrier’s ring-wide
stall.
§Safety
As Batch::read_raw’s, for a FileRef::Raw target.
§Errors
io::ErrorKind::Unsupported if the ring was not probed as
supporting Op::Flush; an crate::IoRingError wrapping
IORING_E_SUBMISSION_QUEUE_FULL if the queue has no room; or any
other error from BuildIoRingFlushFile.
Sourcepub fn flush<F: FileTarget>(
&mut self,
file: &F,
coverage: FlushCoverage,
mode: FlushMode,
) -> Result<Token<F::Guard>>
pub fn flush<F: FileTarget>( &mut self, file: &F, coverage: FlushCoverage, mode: FlushMode, ) -> Result<Token<F::Guard>>
As Batch::flush_raw, but safe: file is a FileTarget – a
SharedFile or a RegisteredFile – and the returned Token
(rather than a bare UserData) holds its guard until this
operation’s completion is observed.
coverage is required for the reason FlushCoverage documents: an
unflagged flush does not cover preceding writes (D-23), so there is no
default spelling of this call that is safe to inherit. mode selects
how much is flushed and whether the device is synced at all; see
FlushMode.
§Errors
As Batch::flush_raw, plus io::ErrorKind::InvalidInput if
file is a RegisteredFile from a different ring.
Sourcepub unsafe fn cancel_raw(
&mut self,
file: impl Into<FileRef>,
target: usize,
) -> Result<usize>
pub unsafe fn cancel_raw( &mut self, file: impl Into<FileRef>, target: usize, ) -> Result<usize>
Queue cancellation of the operation identified by target (the
usize a prior push returned), against file.
A cancel is itself an operation: it completes on its own UserData,
returned here, independently of whether target was actually
outstanding. Cancelling a target that has already completed – or
was never outstanding – reports ERROR_NOT_FOUND through this
completion rather than failing to build (M3.6). Prefer
Batch::cancel unless file needs to address a raw FileRef
directly.
§Safety
As Batch::read_raw’s, for a FileRef::Raw target.
§Errors
io::ErrorKind::Unsupported if the ring was not probed as
supporting Op::Cancel; an crate::IoRingError wrapping
IORING_E_SUBMISSION_QUEUE_FULL if the queue has no room; or any
other error from BuildIoRingCancelRequest.
Sourcepub fn cancel<F: FileTarget>(
&mut self,
file: &F,
target: usize,
) -> Result<Token<F::Guard>>
pub fn cancel<F: FileTarget>( &mut self, file: &F, target: usize, ) -> Result<Token<F::Guard>>
As Batch::cancel_raw, but safe: file is a SharedFile, and
the returned Token keeps file’s clone alive until this
operation’s completion is observed.
A cancel is a request, not a guarantee (M10.2): target may complete
normally regardless, and this push produces its own completion in
addition to the target’s, so a cancelled operation yields two. A
result of ERROR_NOT_FOUND on this push’s own completion means
target was no longer outstanding – a normal race, not a caller
error.
§Errors
Sourcepub unsafe fn register_files(
&mut self,
handles: &[HANDLE],
) -> Result<PendingFileRegistration>
pub unsafe fn register_files( &mut self, handles: &[HANDLE], ) -> Result<PendingFileRegistration>
Queue registration of handles as a ring’s file-handle table (M5.1).
BuildIoRingRegisterFileHandles replaces the ring’s entire
file-handle table rather than appending to it (Win32 docs: “If a
previous registration exists, this replaces the previous
registration completely”), which would silently invalidate every
RegisteredFile index a prior registration handed out. Rather than
track and resubmit that whole prior table transparently, this method
refuses a second registration outright: a ring accepts at most one
file-handle registration that assigned an index in its lifetime.
Two consequences of that rule being enforced against
crate::IoRing::registered_file_count rather than a flag (M10.1):
a zero-length handles does not spend the ring’s one registration,
since it hands out no index for a later replacement to invalidate;
and the count advances when this call queues, not when its
completion succeeds (D-14), so a registration whose completion
reports failure has still spent it. There is no retry – a consumer
whose registration fails must build the registration on a new ring.
handles only needs to stay valid for this call, unlike a data
buffer referenced through an IORING_HANDLE_REF/IORING_BUFFER_REF:
BuildIoRingRegisterFileHandles has no such ref, it takes the array
directly and reads it synchronously – confirmed by measurement, not
assumed (D-32). The handles themselves must still stay open for as
long as the registration is used – this crate does not take
ownership of them, only of their assigned indices’ bookkeeping.
Do not generalize this to Batch::register_buffers:
BuildIoRingRegisterBuffers reads its array when the op runs, and
assuming otherwise was a live use-after-free in 0.1.2.
§Safety
Every handle in handles must be valid, and must remain valid for
as long as the resulting registration is used – for the ring’s
remaining life, since Win32 has no unregister call (M8, PR #20
review response). There is no safe counterpart: a single-push
Token cannot express a lifetime spanning arbitrarily many later
reads and writes against every registered index, unlike a Token
tied to one push’s own completion.
§Errors
io::ErrorKind::AlreadyExists if this ring already has a
file-handle registration (see above); io::ErrorKind::Unsupported
if the ring was not probed as
supporting Op::RegisterFiles;
io::ErrorKind::InvalidInput if handles has more than
u32::MAX entries; an crate::IoRingError wrapping
IORING_E_SUBMISSION_QUEUE_FULL if the queue has no room; or any
other error from BuildIoRingRegisterFileHandles.
Sourcepub fn register_buffers<B: IoBufMut>(
&mut self,
buffers: Vec<B>,
) -> Result<PendingBufferRegistration<B>>
pub fn register_buffers<B: IoBufMut>( &mut self, buffers: Vec<B>, ) -> Result<PendingBufferRegistration<B>>
Queue registration of buffers as a ring’s registered-buffer table
(M5.2).
As Batch::register_files: BuildIoRingRegisterBuffers replaces
the ring’s entire buffer table rather than appending to it, so this
method refuses a second registration outright – a ring accepts at
most one buffer registration that assigned an index in its
lifetime, with the same zero-length and failed-registration
consequences Batch::register_files spells out (M10.1).
Unlike Batch::register_files, two things must outlive this
call, and the asymmetry is measured rather than assumed (D-32):
- the bytes each entry points at – the registration case
IoBuf’s contract was extended to cover (D-11), sobuffersis taken by value and kept inside the returnedRegisteredBuffersonce claimed; - the
IORING_BUFFER_INFOarray itself.BuildIoRingRegisterBuffersdoes not read it synchronously the wayBuildIoRingRegisterFileHandlesreads itshandlesarray; the kernel reads it when the registration op runs, during a laterSubmitIoRing. This crate builds that array and hands it to the ring, which holds it for its remaining life, so a caller has nothing to do – but the distinction is whycrate::IoRing::push_rawcallers building this op themselves must not pass a temporary.
§Errors
As Batch::register_files, for Op::RegisterBuffers
and BuildIoRingRegisterBuffers.
Sourcepub unsafe fn read_registered_raw<B: IoBufMut>(
&mut self,
file: impl Into<FileRef>,
registration: &RegisteredBuffers<B>,
span: RegisteredSpan,
file_offset: u64,
options: PushOptions,
) -> Result<Token<RegisteredUse>>
pub unsafe fn read_registered_raw<B: IoBufMut>( &mut self, file: impl Into<FileRef>, registration: &RegisteredBuffers<B>, span: RegisteredSpan, file_offset: u64, options: PushOptions, ) -> Result<Token<RegisteredUse>>
Queue a read of span.len bytes from file at file_offset, into
span’s byte offset of registration’s buffer at span.buffer_index,
instead of handing over a fresh owned buffer (M5.2).
The returned Token must be claimed once its completion is
observed, exactly like Batch::read’s – but claiming it recovers
no buffer, only releases this use against registration’s own drop
check (M5.3). Read the transferred bytes back from registration
itself afterward, for example via a caller-side accessor into the
buffer it was constructed from. Prefer Batch::read_registered
unless file needs to address a raw FileRef directly.
§Safety
As Batch::read_raw’s.
§Errors
As Batch::read_raw, plus io::ErrorKind::InvalidInput if
span.buffer_index is out of range for registration.
Sourcepub fn read_registered<B: IoBufMut, F: FileTarget>(
&mut self,
file: &F,
registration: &RegisteredBuffers<B>,
span: RegisteredSpan,
file_offset: u64,
options: PushOptions,
) -> Result<Token<(RegisteredUse, F::Guard)>>
pub fn read_registered<B: IoBufMut, F: FileTarget>( &mut self, file: &F, registration: &RegisteredBuffers<B>, span: RegisteredSpan, file_offset: u64, options: PushOptions, ) -> Result<Token<(RegisteredUse, F::Guard)>>
As Batch::read_registered_raw, but safe: file is a
FileTarget rather than a bare FileRef. The returned token
yields (RegisteredUse, guard) once claimed.
Passing a RegisteredFile here is the fully-registered form –
registered file and registered buffer, neither costing a handle
lookup nor a buffer pin per operation – which before M10.4 the safe
API could not express at all.
§Errors
As Batch::read_registered_raw, plus
io::ErrorKind::InvalidInput if file is a RegisteredFile from
a different ring.
Sourcepub unsafe fn write_registered_raw<B: IoBufMut>(
&mut self,
file: impl Into<FileRef>,
registration: &RegisteredBuffers<B>,
span: RegisteredSpan,
file_offset: u64,
options: PushOptions,
caching: WriteCaching,
) -> Result<Token<RegisteredUse>>
pub unsafe fn write_registered_raw<B: IoBufMut>( &mut self, file: impl Into<FileRef>, registration: &RegisteredBuffers<B>, span: RegisteredSpan, file_offset: u64, options: PushOptions, caching: WriteCaching, ) -> Result<Token<RegisteredUse>>
Queue a write of span.len bytes to file at file_offset, from
span’s byte offset of registration’s buffer at span.buffer_index
(M5.2).
As Batch::read_registered_raw, but for BuildIoRingWriteFile.
Prefer Batch::write_registered unless file needs to address a
raw FileRef directly.
§Safety
As Batch::read_registered_raw’s.
§Errors
Sourcepub fn write_registered<B: IoBufMut, F: FileTarget>(
&mut self,
file: &F,
registration: &RegisteredBuffers<B>,
span: RegisteredSpan,
file_offset: u64,
options: PushOptions,
caching: WriteCaching,
) -> Result<Token<(RegisteredUse, F::Guard)>>
pub fn write_registered<B: IoBufMut, F: FileTarget>( &mut self, file: &F, registration: &RegisteredBuffers<B>, span: RegisteredSpan, file_offset: u64, options: PushOptions, caching: WriteCaching, ) -> Result<Token<(RegisteredUse, F::Guard)>>
As Batch::write_registered_raw, but safe: file is a
FileTarget rather than a bare FileRef. The returned token
yields (RegisteredUse, guard) once claimed.
Passing a RegisteredFile here is the fully-registered form, as
for Batch::read_registered.
§Errors
As Batch::write_registered_raw, plus
io::ErrorKind::InvalidInput if file is a RegisteredFile from
a different ring.
Sourcepub fn submit(self) -> Result<u32>
pub fn submit(self) -> Result<u32>
Submit everything queued so far, returning the number of entries the kernel accepted.
That count is entries submitted, never entries completed (M10.2):
draining is crate::IoRing::try_pop’s job and stays the caller’s.
§Errors
Returns any error from SubmitIoRing.
Sourcepub fn submit_and_wait(
self,
wait_operations: u32,
timeout_ms: u32,
) -> Result<u32>
pub fn submit_and_wait( self, wait_operations: u32, timeout_ms: u32, ) -> Result<u32>
Submit everything queued so far, then block until at least
wait_operations of them have completed or timeout_ms elapses
(D-3’s Model B primitive: the fused submit-and-wait is the event
loop for a pinned-thread consumer).
Returning does not mean wait_operations completions are poppable:
the timeout can expire first, and the returned count is entries
submitted rather than completed (M10.2). Drain with
crate::IoRing::try_pop and count for yourself.
§Errors
Returns any error from SubmitIoRing.