Skip to main content

Crate win_durable_ioring

Crate win_durable_ioring 

Source
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, an IoBackend over windows-ioring-sys’ IoRing, and Win32FileTarget, a target backed by a Win32 file.

Structs§

AddTargetError
A refused add_target: a target is already present under key. 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.
CoreActions
What the driver does after a call into the core.
DeliveryHandle
The operations of an instance whose delivery an EntryDelivery owns, through &self from any thread. The handler is given one; the owner derefs to its own, so both offer the same operations from one definition.
DeliverySetupError
A failed EntryDelivery::new, handing back what it took.
Dioring
dioring: B is the owned buffer type, E the epoch-id type, C the consumer’s per-operation context, R the registered-buffer type, and K the clock it stamps failures with (a TimeBase; InterruptStamps unless built with Dioring::with_clock).
DioringIds
dioring’s identities, with the consumer’s epoch-id type E and the time type I its 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 is WindowsIds). Zero-sized; it exists only to name them, so its comparison and hashing traits hold for every E and I.
DomainCompletion
Answers one domain of one request, once, from any thread at any time – inside make_durable included. 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.
DomainRequest
One flush domain’s part of a request, and the handle that answers it.
DuplicateDomain
A provider named a domain twice: the domain.
DurableIoCore
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). E is the epoch-id type, B the backend’s owned buffer, C the consumer’s per-operation context, and K the clock failures are stamped with.
EndLineageError
A refused end_lineage, handing the handle back.
EntryDelivery
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 DeliveryHandle through which the instance’s operations are reached. For an instance whose readiness signal is an Event, 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 Tag instead (DI-D-40). Plain data, so a consumer can keep it in its own records.
ErrorCode
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 are HRESULTs, the form the I/O ring reports every failure in. A Win32 code is wrapped into one, and read back out of one, by win-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 Failed entry: the one place a token is dispensed besides the inventory.
FailureId
dioring’s failure identity: Copy, never reused within an instance. It cannot resolve anything.
FailureInfo
One unresolved failure, as the inventory reports it. Owned, so holding it borrows nothing.
FailureToken
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.
FanOutDiagnostics
A sink that hands each event to every sink it holds that wants its kind, in order.
FlushDomain
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.
FlushRequest
One seal’s work for the consumer’s provider.
FromClock
A win-time-sys clock on interrupt time, given to dioring as the clock it stamps with: the clock must keep Steady’s promise that its readings never decrease, which it states by implementing it. A win-time-sys clock cannot be a StampClock itself, 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::new or Geometry::uniform, which refuse any other value, so a Geometry always holds powers of two.
GeometryError
A geometry was asked for with an alignment that is not a power of two (zero included).
HeldOperation
An operation held for its gate and never issued, handed back by close() (DI-2.7).
Imported
What import_failure recorded.
InterruptStamps
Interrupt time, read through win-time-sys’ InterruptClock: the default clock a Dioring stamps with (DI-D-37). Its readings never decrease, which is StampClock’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.
IoTargetBusy
Everything still holding a file that remove_target refused, 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.
IoTargetDescription
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.
IoTargetKey
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).
IoTargetWrites
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.
LineageBusy
Everything still holding a lineage that retire_lineage refused, and what clears each hold.
LineageHandle
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.
LineageInfo
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. buffer is None for 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_cmp is None).
ProviderPart
One flush domain’s part of a ProviderRequest.
ProviderRequest
One seal’s request for the consumer’s provider, as DurableIoCore makes it: the driver hands it to the provider and returns each domain’s answer to the core with DurableIoCore::provided, naming this lineage and seal.
PushError
A refused push hands back what it was given: the buffer (None for 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).
ReadOptions
The advanced parameters of a read. Reads take no part in durability, so a gate is their only option.
RegisteredSpan
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.
ResolveError
A refused resolution hands every token back.
RetireLineageError
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.
SetupError
A failed construction hands back what it was given. buffers is None only 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-sys drops 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).
SharedHandle
A shared owner of a Windows handle: an OwnedHandle behind a reference count.
StderrDiagnostics
A sink that writes every event as a line on standard error, prefixed dioring:.
SuspectSet
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).
SuspectWrite
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.
TargetSetup
One target given at construction.
TimePoint
A point on timeline T: a tick count since the timeline’s zero.
UnknownLineage
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.
WriteOptions
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§

DeliveryEvent
What the deliverer hands its handler: an entry, or why it could not pop one.
DeliveryMode
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.
DiagnosticKind
What a Diagnostic is about: what a sink answers DiagnosticSink::wants for, before the event is built. Open to further kinds – the delay events of DI-12.1 among them.
DomainOutcome
How a provider answered one domain of one request.
DurabilityRequest
The immediate answer to make_durable_through.
EndLineageRefusal
Why end_lineage was refused.
Entry
One entry of the instance’s completion queue (DI-D-13).
EpochState
An epoch’s state as the instance sees it.
FailureCause
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.
ImportScope
Where an imported failure lands (DI-2.10 point 5).
InterruptTime
Interrupt time: 100 ns ticks since this boot began, including time asleep or hibernating.
MarkingKind
What a Marking records. Open to further kinds, so match it with a wildcard arm.
OpKind
What a consumer operation was.
Outcome
How a consumer operation ended.
PushRefusal
Why a push was refused before anything was reserved.
RemoveTargetError
Why remove_target was refused.
Resolution
How a failure is resolved.
ResolveRefusal
Why a resolution call was refused as a whole.
RetireLineageRefusal
Why retire_lineage was refused.
SealError
Why make_durable_through was refused. Nothing was sealed.
SetupRefusal
Why construction failed.
WarrantyClass
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 Durable with it.
WriteCaching
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§

DiagnosticSink
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.
DurabilityProvider
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.
DurableRing
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), an Lsn newtype, 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).
IoBufMut
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).
RegisteredBufferRing
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.
StampClock
A clock whose readings never decrease, read once per stamped transition.
TimeBase
A clock dioring can stamp with: a StampClock whose 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). InterruptStamps is the default; a test may give an instance its own mock, which takes on StampClock’s promise by implementing it, and a win-time-sys clock on interrupt time is given as FromClock. 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_WIN32 wraps it: a value that is already an HRESULT – zero, or one with the severity bit set – is taken as it is, and any other keeps only its low sixteen bits. The rule is win-error-codes’s (HResult::from_win32); the number space is this crate’s, since the codes this driver reports are HRESULTs.
error_code_of
The code error carries, if it carries one.
win32_code_of
The Win32 code code wraps, if it is one wrapped by HRESULT_FROM_WIN32: severity set, FACILITY_WIN32, and no other bit above the code. None for S_OK, a success wrapping no error, and for an HRESULT of any other facility. The inverse of error_code_from_win32 for the codes from 1 to 65535.

Type Aliases§

EntryOf
An implementation’s queue entry.
EpochIdOf
An implementation’s epoch-id type.
FailureIdOf
An implementation’s failure identity.
HandleOf
An implementation’s lineage handle.
Lin
An implementation’s lineage type.
OpIdOf
An implementation’s operation identity.
PushResult
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).
WindowsIds
dioring’s identities over the Windows driver’s stamps (DI-D-50): what a consumer names its Dioring’s identities by.