Expand description
§win-durable-ioring
A ring for Windows file I/O with durability scheduled into its work: the Windows driver for
durable-ioring, built on
windows-ioring-sys’s IoRing. A consumer submits reads and
writes as it would to the ring, tags each write with an epoch, asks for durability with
make_durable_through(n), and learns – in the same completion stream as its operations – when
everything through n has become durable, or that it has failed and which writes are suspect as a
result.
§What is here, and what is not
Here (DI-D-50): Dioring, the threaded driver
that implements the contract over the Windows backend; the backend and its file target
(windows_backend), the thread-pool and pumped and signalled delivery of its completions, the
readiness Event and the harness check of it (readiness), the interrupt-time clock the driver
stamps with, and a way to read an HRESULT out of an io::Error (error_code_of). It forbids
unsafe code: a Win32 call no lower crate wraps safely is added to that crate.
Not here: the contract, the core that decides when writes are durable, the target and backend traits, the in-memory backend and the conformance oracle. Those are durable-ioring, which has no Windows dependency, so another platform’s driver can be built on it as this one is. The specification is that crate’s CONTRACT.md; its spelling as Rust types is API.md. This crate re-exports the portable crate’s API, so a consumer needs only this one.
A blocking push is not an API of either crate: a refused push names its cause, and the loop that waits it out is a maintained example, examples/blocking_push/, to use as it stands or adapt (DI-D-56).
DeliveryMode::Pool, DeliveryMode::Signalled and EntryDelivery::new take
windows-threadpool-sys’s CallbackEnviron, so that crate’s types are part of this crate’s public
API. A minor release of windows-threadpool-sys that changes those types is a minor release of this
crate too, in the 0.x series: 0.3 of this crate pairs with 0.3 of windows-threadpool-sys.
§Opening a file
A file target is made from a file this crate opened, and from nothing else
(DI-D-60). How a handle was opened decides what its
target can claim, and the only call that reports it is one this repository does not make, so the
open mode is recorded by the type that opens the file instead of asked of a handle afterwards.
OpenedFile<Cached> is a file opened for cached I/O: it claims BestEffort and needs no alignment.
OpenedFile<Unbuffered> is opened with no intermediate buffering: it claims SharedDevice, needs
a sector’s alignment (4096 unless told less with with_sector_size), and offers per-write
write-through. A consumer that needs the stronger warranty asks for OpenedFile<Unbuffered> in its
own signature, and a cached file cannot be passed. A handle opened elsewhere cannot be given to a
target in this version.
use win_durable_ioring::windows_backend::{
Cached, FileOptions, OpenedFile, Unbuffered, Win32FileTarget,
};
use win_durable_ioring::{IoTarget, WarrantyClass};
let path = std::env::temp_dir().join(format!("durable-ioring-open-{}", std::process::id()));
std::fs::write(&path, [0u8; 8192])?;
let options = FileOptions::new().read(true).write(true);
let cached = Win32FileTarget::new(OpenedFile::<Cached>::open(&path, options)?);
assert_eq!(cached.warranty(), WarrantyClass::BestEffort);
let unbuffered = Win32FileTarget::new(OpenedFile::<Unbuffered>::open(&path, options)?);
assert_eq!(unbuffered.warranty(), WarrantyClass::SharedDevice);
assert!(unbuffered.capabilities().write_through());An unbuffered file is refused on a remote device, where the claim cannot hold.
§A raw volume
A raw volume is a target too (DI-D-61): one handle, one
commit per volume, and regions are offsets the consumer allocates inside it, not targets of their
own. OpenedVolume opens it by a path that can only name a volume, a drive letter or a volume GUID,
and finds what the backing must know for itself with documented device controls
(win-volume-sys): the disks it sits on, which become its flush
domains (disk_flush_domain names a disk, so a consumer can declare the same domain for a file on
it), and the sector it is addressed in, which is the alignment of its operations. A volume that is
remote, or not a volume, is refused. It claims SharedDevice when opened unbuffered and BestEffort when opened cached, and never
Complete: a lock keeps other handles off the volume, not other writers off its disks. Opening one for writing needs an
administrator, and VolumeOptions::lock takes the volume lock, which a write to a volume with a
file system on it needs and which fails if anything else has the volume open.
use win_durable_ioring::windows_backend::{
OpenedVolume, Unbuffered, VolumeOptions, VolumePath, Win32FileTarget,
};
let path = VolumePath::drive('E')?;
let volume = OpenedVolume::<Unbuffered>::open(&path, VolumeOptions::new().lock(true))?;
let target = Win32FileTarget::from_volume(volume);§A whole disk
OpenedDisk opens a physical disk by its number, \\.\PhysicalDriveN, rather than a volume on it
(DI-D-62). The disk is its own flush domain, named by
disk_flush_domain as a volume on it would name it, and its operations are aligned to its sector,
which a device control reports. It claims SharedDevice when opened unbuffered and BestEffort when opened cached, never
Complete, for the reason a volume does not. Windows documents that it blocks a direct write to a sector a mounted volume covers, so a
disk with volumes on it is written through them, or has them locked or is taken offline first; the
tests here use a disk with no partition. Opening one for writing needs an administrator.
use win_durable_ioring::windows_backend::{DiskPath, OpenedDisk, Unbuffered, Win32FileTarget};
let disk = OpenedDisk::<Unbuffered>::open(DiskPath::number(3))?;
let target = Win32FileTarget::from_disk(disk);§Worked examples
Each example is dioring running the trace in its comments, compiled and run as a test, so a change
that breaks one breaks the build. In the comments, -> is a call the consumer makes and <- an
entry it pops. Every write is in the default lineage, so the lineage is not shown; construction
returns a handle to it, and tag(n) is its epoch n as a write or a seal takes it, epoch(n) as a
query or an entry names it. A commit failure cannot be provoked on a healthy machine through a Win32
file, so each example arms one with dioring’s fault seam, fail_next_flush, which makes the next
flush of a file report the error given whatever the device answered. Setting up the instance, and a
pop_until that pops until an entry it is looking for, are hidden.
§Healing a failure
let tag = |n: u64| lineage.at(n); // what a write or a seal takes
let epoch = |n: u64| Epoch::new(lineage.lineage(), n); // what a query or an entry names
// -> write(tag 41, A) ; write(tag 41, B) ; write(tag 41, C)
for offset in [0, 8, 16] {
ring.write(FILE, offset, vec![1; 8], tag(41), ()).expect("a write");
}
ring.fail_next_flush(FILE, 1117); // ERROR_IO_DEVICE, for the flush the seal issues
// -> make_durable_through(41) // seals everything <= 41
ring.make_durable_through(tag(41)).expect("a seal");
// <- WriteDone(A) ; WriteDone(B) ; WriteDone(C)
// <- Failed { failure: F1, cause: Commit, suspect: [A@41, B@41, C@41] }
let Entry::Failed(f1) = pop_until(&mut ring, |e| matches!(e, Entry::Failed(_))) else {
unreachable!()
};
assert!(matches!(f1.cause, FailureCause::Commit { .. }));
assert_eq!(f1.suspect.writes().len(), 3);
assert_eq!(ring.durable_through(lineage.lineage()), Ok(None)); // nothing is durable yet
// -> write(tag 41, A') // refused: 41 is sealed (guarantee 6)
let refused = ring.write(FILE, 0, vec![2; 8], tag(41), ()).expect_err("41 is sealed");
assert!(matches!(refused.reason, PushRefusal::Sealed { .. }));
// -> write(tag 42, A') ; write(tag 42, B') ; write(tag 42, C')
for offset in [0, 8, 16] {
ring.write(FILE, offset, vec![2; 8], tag(42), ()).expect("a write");
}
// -> heal(F1) // "I have re-issued what I need"
ring.resolve(vec![(f1.token, Resolution::Heal)]).expect("heal");
// -> make_durable_through(42) // the first after the heal reaching the re-issue
ring.make_durable_through(tag(42)).expect("a seal");
// <- WriteDone(A') ; WriteDone(B') ; WriteDone(C')
// <- Durable { through: 42 } // F1 healed; 41 and 42 durable
pop_until(&mut ring, |e| matches!(e, Entry::Durable { through } if *through == epoch(42)));
assert_eq!(ring.epoch_state(epoch(41)), Ok(EpochState::Durable));
assert!(ring.failures().is_empty());Without the heal, the last entry is Blocked { through: 42, by: F1 }: 42’s own commit succeeded, but
the high-water mark cannot pass the unresolved failure at 41.
§Failures and epochs are many-to-many
P is pushed before the seal, rather than after it as a consumer might, so that it is certainly
pushed before the failure is observed: the seal’s commit is issued as soon as A completes.
let tag = |n: u64| lineage.at(n); // what a write or a seal takes
let epoch = |n: u64| Epoch::new(lineage.lineage(), n); // what a query or an entry names
let ops = |set: &SuspectSet<WindowsIds<u64>>| set.writes().iter().map(|w| w.op).collect::<Vec<_>>();
// -> write(tag 41, A) ; write(tag 43, P) // 43 is open
let a = ring.write(FILE, 0, vec![1; 8], tag(41), ()).expect("a write");
let p = ring.write(FILE, 8, vec![1; 8], tag(43), ()).expect("a write");
ring.fail_next_flush(FILE, 1117);
// -> make_durable_through(41) // seals 41
ring.make_durable_through(tag(41)).expect("a seal");
// <- WriteDone(A) ; WriteDone(P)
// <- Failed { failure: F1, cause: Commit, suspect: [A@41, P@43] }
let Entry::Failed(f1) = pop_until(&mut ring, |e| matches!(e, Entry::Failed(_))) else {
unreachable!()
};
assert_eq!(ops(&f1.suspect), [a, p]); // one failure, two epochs: sealed 41 and open 43
// -> write(tag 43, R) // still allowed: 43 is open
let r = ring.write(FILE, 16, vec![1; 8], tag(43), ()).expect("a write");
// <- WriteDone(R)
pop_until(&mut ring, |e| matches!(e, Entry::Op(done) if done.id == r));
// -> import_failure() // the consumer learned of an outside failure
let f2_id = ring.import_failure(ImportScope::All).expect("the whole instance").failure;
// <- Failed { failure: F2, cause: Imported, suspect: [A@41, P@43, R@43] }
let Entry::Failed(f2) = pop_until(&mut ring, |e| matches!(e, Entry::Failed(_))) else {
unreachable!()
};
assert_eq!(f2.id, f2_id);
assert_eq!(ops(&f2.suspect), [a, p, r]); // epoch 43 now sits in F1 and F2
// The first ending: heal both. Re-issue A, P and R under tag 44, resolve both in one atomic
// call, and seal 44.
for offset in [0, 8, 16] {
ring.write(FILE, offset, vec![2; 8], tag(44), ()).expect("a write");
}
ring.resolve(vec![(f1.token, Resolution::Heal), (f2.token, Resolution::Heal)])
.expect("heal both");
ring.make_durable_through(tag(44)).expect("a seal");
// <- Durable { through: 44 } // 41 and 43 passed once both failures were resolved
pop_until(&mut ring, |e| matches!(e, Entry::Durable { through } if *through == epoch(44)));
assert_eq!(ring.epoch_state(epoch(41)), Ok(EpochState::Durable));
assert_eq!(ring.epoch_state(epoch(43)), Ok(EpochState::Durable));The second ending: heal F1, abandon F2. Epochs 41 and 43 both sit in F2, so both become abandoned – one abandonment is enough – even though F1 was healed. The high-water mark moves past them once every failure containing them is resolved: F2 at once, and F1 when its heal takes effect, at the first seal made after it that reaches the re-issue. Any operation gated on 41 or 43 fails as never issued.
// The trace above, to F2's arrival, is hidden. Then:
ring.resolve(vec![(f1.token, Resolution::Heal), (f2.token, Resolution::Abandon)])
.expect("heal F1, abandon F2");
// <- Abandoned { failure: F2, suspect: [A@41, P@43, R@43] }
pop_until(&mut ring, |e| matches!(e, Entry::Abandoned { .. }));
assert_eq!(ring.epoch_state(epoch(41)), Ok(EpochState::Abandoned));
assert_eq!(ring.epoch_state(epoch(43)), Ok(EpochState::Abandoned));
// -> make_durable_through(44) // F1's heal takes effect here
ring.make_durable_through(tag(44)).expect("a seal");
// <- Durable { through: 44 } // "durable through 44" means durable or abandoned
pop_until(&mut ring, |e| matches!(e, Entry::Durable { through } if *through == epoch(44)));
assert_eq!(ring.durable_through(lineage.lineage()), Ok(Some(44)));
assert_eq!(ring.epoch_state(epoch(43)), Ok(EpochState::Abandoned));Re-exports§
pub use readiness::ReadinessFailure;pub use readiness::check_readiness;
Modules§
- backend
- The backend beneath the core: what runs targets’ I/O (DI-D-50 P10, DI-D-52).
- driver
- What a driver builds on: the engine that joins a core to its backend under one lock, the pump a consumer’s own thread drains, and the few helpers the core’s own bookkeeping shares with a driver (DI-D-50, DI-D-53).
- memory
- An in-memory backend and target (DI-D-50 P13, DI-D-52): a deterministic backend, holding each target’s bytes in memory, for testing the core and driving it without a device.
- oracle
- The conformance oracle (DI-D-24): the contract’s rules over the event stream, as one executable definition every implementation’s tests bind to – dioring’s own, the fault-injecting implementation’s, and those of layers above. A hand-written second copy of a rule in some other test is a check of the copy, not of the contract.
- readiness
- The readiness signal’s harness check (DI-D-28), for a signal that is a Windows
Event: push into an empty queue and require the signal set, drain, and again. The portable oracle sees entries, not wakes, so this runs beside it. - windows_
backend - The Windows backend (DI-D-50 P10, DI-D-52):
WindowsBackend, anIoBackendoverwindows-ioring-sys’IoRing, andWin32FileTarget, a target backed by a Win32 file.
Structs§
- AddTarget
Error - A refused
add_target: a target is already present underkey. The target, of the implementation’s type, is handed back. - Capabilities
- What a target offers beyond the contract’s obligations. Built with setters from
Capabilities::NONE; the fields are private, so a capability added later is not a breaking change. - Core
Actions - What the driver does after a call into the core.
- Delivery
Handle - The operations of an instance whose delivery an
EntryDeliveryowns, through&selffrom any thread. The handler is given one; the owner derefs to its own, so both offer the same operations from one definition. - Delivery
Setup Error - A failed
EntryDelivery::new, handing back what it took. - Dioring
- dioring:
Bis the owned buffer type,Ethe epoch-id type,Cthe consumer’s per-operation context,Rthe registered-buffer type, andKthe clock it stamps failures with (aTimeBase;InterruptStampsunless built withDioring::with_clock). - Dioring
Ids - dioring’s identities, with the consumer’s epoch-id type
Eand the time typeIits stamps are read in (DI-D-50): the clock the core was given decides it, and each driver names its own (win-durable-ioring’s isWindowsIds). Zero-sized; it exists only to name them, so its comparison and hashing traits hold for everyEandI. - Domain
Completion - Answers one domain of one request, once, from any thread at any time – inside
make_durableincluded. Success warrants that every write named for the domain is durable (the contract). Dropped unanswered, it is a failure of the domain,FailureCause::ProviderAbandoned. Answering records the outcome, and sets the readiness signal if that makes an entry poppable; it never runs delivery. Once the instance has ended, an answer does nothing; ending waits for every completion to be answered or dropped. - Domain
Request - One flush domain’s part of a request, and the handle that answers it.
- Duplicate
Domain - A provider named a domain twice: the domain.
- Durable
IoCore - dioring’s core: every lineage’s durability, the targets it decides for, the operations in
flight or held for their gates, and the queue of entries for the consumer (DI-D-49).
Eis the epoch-id type,Bthe backend’s owned buffer,Cthe consumer’s per-operation context, andKthe clock failures are stamped with. - EndLineage
Error - A refused
end_lineage, handing the handle back. - Entry
Delivery - The Model A front end: owns an instance and hands its entries, one at a time and in queue
order, to a handler on thread-pool threads. Derefs to the
DeliveryHandlethrough which the instance’s operations are reached. For an instance whose readiness signal is anEvent, which it waits on through the thread pool. - Epoch
- An epoch: an epoch id within a lineage, by the lineage’s plain name. What the API reports, and
what names or asks about an epoch – a gate, a query – takes; what acts on a lineage takes a
Taginstead (DI-D-40). Plain data, so a consumer can keep it in its own records. - Error
Code - A fault’s code, as the layer that reported it numbers it: its meaning is the
IoFault’s source’s (DI-D-50). The Windows backend’s areHRESULTs, the form the I/O ring reports every failure in. A Win32 code is wrapped into one, and read back out of one, bywin-durable-ioring, which owns that rule; this type carries the number and does not interpret it. - Event
- An owned event object.
- Failed
- The payload of a
Failedentry: the one place a token is dispensed besides the inventory. - Failure
Id - dioring’s failure identity:
Copy, never reused within an instance. It cannot resolve anything. - Failure
Info - One unresolved failure, as the inventory reports it. Owned, so holding it borrows nothing.
- Failure
Token - dioring’s failure token: the one thing that resolves its failure. At most one is live per
failure (DI-D-12). Resolving consumes it; dropping it is
close. - FanOut
Diagnostics - A sink that hands each event to every sink it holds that wants its kind, in order.
- Flush
Domain - A flush domain: a unit whose volatile cache a flush commits and whose failure everything behind it shares – a disk, a controller cache, a virtual disk, a remote share (DI-D-21). Named by the consumer’s exact identifier bytes, so two instances or processes name one domain alike. dioring interns each distinct domain into a word-sized value of its own, so comparisons after declaration are cheap, and reports return the bytes.
- Flush
Request - One seal’s work for the consumer’s provider.
- From
Clock - A
win-time-sysclock on interrupt time, given to dioring as the clock it stamps with: the clock must keepSteady’s promise that its readings never decrease, which it states by implementing it. Awin-time-sysclock cannot be aStampClockitself, because the trait is another crate’s. - Geometry
- The alignment a target’s offsets, lengths and buffer addresses need, each a power of two, one
meaning none. Built through
Geometry::neworGeometry::uniform, which refuse any other value, so aGeometryalways holds powers of two. - Geometry
Error - A geometry was asked for with an alignment that is not a power of two (zero included).
- Held
Operation - An operation held for its gate and never issued, handed back by
close()(DI-2.7). - Imported
- What
import_failurerecorded. - Interrupt
Stamps - Interrupt time, read through
win-time-sys’InterruptClock: the default clock aDioringstamps with (DI-D-37). Its readings never decrease, which isStampClock’s promise. - IoFault
- A fault, as the layer that observed it reported it (DI-D-50): what failed an operation or a commit, relayed with where it came from.
- IoTarget
Busy - Everything still holding a file that
remove_targetrefused, and what clears each hold. Every field is reported, not only the first that applies, so one refusal says all a consumer has to do. - IoTarget
Description - What a target states about itself, taken once when it is given to an instance: what the core decides with, while the backend holds the target.
- IoTarget
Key - The consumer’s identity for a file, supplied when the file is given to dioring and used in every report, so a report stays meaningful after the file’s handle is gone (DI-D-11).
- IoTarget
Writes - A target in one domain’s part, and the writes to it named for that domain: identities, never extents. Every one has completed. The provider reaches what backs the target by its own means; the request lends it nothing (DI-D-50 P6).
- Leftovers
- What
close()hands back once the instance has ended (DI-2.7). Dropping the instance discards the same things. - Lineage
- dioring’s lineage: minted at any time, never reused, including after retirement. Carries its instance, so another instance’s lineage is refused.
- Lineage
Busy - Everything still holding a lineage that
retire_lineagerefused, and what clears each hold. - Lineage
Handle - dioring’s handle to a live lineage (DI-D-40): what pushing into the lineage and sealing it take. Cloning it is cheap, and every copy names the same lineage.
- Lineage
Info - One lineage, as the enumeration reports it. Owned, so holding it borrows nothing.
- Marking
- What happened to one of a failure’s suspect writes after the failure was observed (DI-D-36): an append-only record, so the history can be reconciled after the fact. A marking reports; it never changes the high-water mark, what holds it, or what resolving the failure needs.
- NoDiagnostics
- A sink that wants nothing: the core’s default.
- OpCompletion
- A consumer operation’s completion, passed through the instance’s queue.
bufferisNonefor an operation on a registered span: the bytes belong to the registration, not to the operation. - OpId
- dioring’s identity for one pushed operation. Ordered by push order within an instance;
identities from two instances are incomparable (
partial_cmpisNone). - Provider
Part - One flush domain’s part of a
ProviderRequest. - Provider
Request - One seal’s request for the consumer’s provider, as
DurableIoCoremakes it: the driver hands it to the provider and returns each domain’s answer to the core withDurableIoCore::provided, naming this lineage and seal. - Push
Error - A refused push hands back what it was given: the buffer (
Nonefor a registered-span operation, which has none) and the consumer’s context – a backend’s refusal included, which hands its submission back whole (DI-D-52). - Read
Options - The advanced parameters of a read. Reads take no part in durability, so a gate is their only option.
- Registered
Span - Which bytes of one registered buffer an operation reads or writes: bundled into one value so a registered read or write stays under a sane argument count.
- Resolve
Error - A refused resolution hands every token back.
- Retire
Lineage Error - A refused
retire_lineage, handing the handle back. - Setup
- What a dioring instance is built with. Both registrations are the ring’s only ones (one of each per ring), so they are made here or never.
- Setup
Error - A failed construction hands back what it was given.
buffersisNoneonly once the buffers have been handed to the kernel and could not be shown to have come back: when the kernel’s registration completion itself failed (windows-ioring-sysdrops them then), when no completion arrived (the ring crate leaks them rather than free memory the kernel may hold), or when the registration succeeded and wiring the ring’s delivery then failed (the registration holds them, and has no way to give them back). - Shared
Handle - A shared owner of a Windows handle: an
OwnedHandlebehind a reference count. - Stderr
Diagnostics - A sink that writes every event as a line on standard error, prefixed
dioring:. - Suspect
Set - A failure’s suspect set: frozen when the failure is observed, shared rather than copied. It never
gains a write; what happens to its writes afterwards is recorded as
Markings (DI-D-36). - Suspect
Write - One write a failure put at risk.
- Tag
- What acts on an epoch of a live lineage: an epoch id, with the lineage’s handle (DI-D-40). A write is tagged with one, and a seal names one, so neither can name a lineage that is not live. Borrows the handle, never the instance.
- Target
Setup - One target given at construction.
- Time
Point - A point on timeline
T: a tick count since the timeline’s zero. - Unknown
Lineage - A plain lineage, or an epoch of one, that the instance cannot answer for: another instance’s, or one ended or retired (DI-D-40). The instance keeps no memory of a lineage once it is gone, as it keeps none of a resolved failure.
- Write
Options - The advanced parameters of a write. Passed by value and built with setters, like
windows-ioring-sys’PushOptions; the fields are private, so adding one later is not a breaking change. A gate may name an epoch in any lineage of this instance, including another lineage than the write’s own.
Enums§
- Delivery
Event - What the deliverer hands its handler: an entry, or why it could not pop one.
- Delivery
Mode - How an instance’s completions are drained: by the thread pool, or by the consumer’s own thread, which the pool may tell. Chosen once, as the instance is built, and not changed after.
- Diagnostic
- One event dioring reports. Open to further kinds, so match it with a wildcard arm.
- Diagnostic
Kind - What a
Diagnosticis about: what a sink answersDiagnosticSink::wantsfor, before the event is built. Open to further kinds – the delay events ofDI-12.1among them. - Domain
Outcome - How a provider answered one domain of one request.
- Durability
Request - The immediate answer to
make_durable_through. - EndLineage
Refusal - Why
end_lineagewas refused. - Entry
- One entry of the instance’s completion queue (DI-D-13).
- Epoch
State - An epoch’s state as the instance sees it.
- Failure
Cause - Why a failure exists, citing where it came from (DI-D-47, DI-D-50). A failed write is never a cause (DI-D-12 (a)). The lineages a failure belongs to are those of the writes in its suspect set.
- Import
Scope - Where an imported failure lands (DI-2.10 point 5).
- Interrupt
Time - Interrupt time: 100 ns ticks since this boot began, including time asleep or hibernating.
- Marking
Kind - What a
Markingrecords. Open to further kinds, so match it with a wildcard arm. - OpKind
- What a consumer operation was.
- Outcome
- How a consumer operation ended.
- Push
Refusal - Why a push was refused before anything was reserved.
- Remove
Target Error - Why
remove_targetwas refused. - Resolution
- How a failure is resolved.
- Resolve
Refusal - Why a resolution call was refused as a whole.
- Retire
Lineage Refusal - Why
retire_lineagewas refused. - Seal
Error - Why
make_durable_throughwas refused. Nothing was sealed. - Setup
Refusal - Why construction failed.
- Warranty
Class - How far a target honours the contract’s obligations (DI-D-50 P3). Information only: dioring
behaves identically for every class and does not label a
Durablewith it. - Write
Caching - Whether a write may rest in the system cache (DI-2.6). The contract’s own type, so an implementation needs nothing from the ring crate for it; dioring passes it through as the write’s flag. It does not change durability: a write-through write is still durable only when its epoch is sealed, because device-level write-through (FUA) is not relied on.
Traits§
- Diagnostic
Sink - Where an instance’s diagnostics go (DI-D-51). Called from whatever thread observed the event, with dioring’s lock held, so a sink returns promptly and never calls back into the instance.
- Durability
Provider - A consumer-supplied durability provider. It makes writes the instance has seen complete durable, by any means, and answers per flush domain. An instance holds at most one; several are composed by a router that is itself a provider. Every other domain, and every file declared with none, is the built-in default’s.
- Durable
Ring - The contract: an instance that takes tagged writes and reports durability by epoch.
- EpochId
- What dioring requires of an epoch id, the ordered value within a lineage that names an epoch.
The consumer chooses the type – a
u64(the default), anLsnnewtype, a(segment, offset)pair – and dioring only ever compares and stores it. “Id” rather than “number” because it need not be one. - Identities
- The identity types an implementation mints, and the consumer’s epoch-id type (DI-D-24). Each
identity carries its implementation’s private provenance, so only that implementation can
make one, and another instance’s is refused. A zero-sized marker implements this; the shared
types are generic over it, so a consumer names one parameter,
D::Ids, not five. - Instant
- What a stamp is: a reading of a
StampClock, ordered, and cheap to copy and share. - IoBuf
- An owned buffer an operation reads bytes from (a write).
- IoBuf
Mut - An owned buffer an operation writes bytes into (a read).
- IoTarget
- A target: what a write or a read addresses and a commit makes durable, defined by the contract’s obligations and by what it reports here (DI-D-50).
- Registered
Buffer Ring - The registered-buffer extension (DI-D-24): operations on spans of buffers registered with the instance’s ring when it was built. An extension because an implementation without a wioring may have none.
- Stamp
Clock - A clock whose readings never decrease, read once per stamped transition.
- Time
Base - A clock dioring can stamp with: a
StampClockwhose readings are interrupt time, its one time base (DI-D-37), and never decrease, and that can be held under the lock pool threads take (DI-D-38).InterruptStampsis the default; a test may give an instance its own mock, which takes onStampClock’s promise by implementing it, and awin-time-sysclock on interrupt time is given asFromClock. Implemented for every type that meets those bounds. - Waitable
- A backend notification a thread can wait on.
Functions§
- error_
code_ from_ win32 - The code a Win32 error names, wrapped as
HRESULT_FROM_WIN32wraps it: a value that is already anHRESULT– zero, or one with the severity bit set – is taken as it is, and any other keeps only its low sixteen bits. The rule iswin-error-codes’s (HResult::from_win32); the number space is this crate’s, since the codes this driver reports areHRESULTs. - error_
code_ of - The code
errorcarries, if it carries one. - win32_
code_ of - The Win32 code
codewraps, if it is one wrapped byHRESULT_FROM_WIN32: severity set,FACILITY_WIN32, and no other bit above the code.NoneforS_OK, a success wrapping no error, and for anHRESULTof any other facility. The inverse oferror_code_from_win32for the codes from 1 to 65535.
Type Aliases§
- EntryOf
- An implementation’s queue entry.
- Epoch
IdOf - An implementation’s epoch-id type.
- Failure
IdOf - An implementation’s failure identity.
- Handle
Of - An implementation’s lineage handle.
- Lin
- An implementation’s lineage type.
- OpIdOf
- An implementation’s operation identity.
- Push
Result - What an implementation’s push returns.
- TokenOf
- An implementation’s failure token.
- WinInstant
- The time type the Windows driver’s stamps are read in: interrupt time, its one time base (DI-D-37).
- Windows
Ids - dioring’s identities over the Windows driver’s stamps (DI-D-50): what a consumer names its
Dioring’s identities by.