Skip to main content

FastWriter

Struct FastWriter 

Source
pub struct FastWriter { /* private fields */ }
Expand description

The cheating arm. Returns before the bytes are on disk.

§What it does NOT guarantee

append returns as soon as one pwrite(2) has handed the bytes to the kernel’s page cache. There is no fsync, no journal row, and no barrier of any kind. Concretely:

  • A crash (power loss, kernel panic, SIGKILL of the box) after append returns loses the data. Not “may lose” — the bytes exist only in volatile page cache and nothing has told the device about them.
  • Nothing on disk references the extent, so even bytes that did reach the platter are unreachable after a restart until something scans for them.
  • A process crash alone (not a machine crash) does keep them: page cache survives exit. That is the only crash it survives.

It is here to bound SafeWriter and [UringWriter]: it is the ceiling the price of durability is measured against — at 8 KiB it acks in 3.9 µs against SafeWriter’s 132 µs (examples/push_path_bench.rs, oden 2026-08-07).

§Selecting it

It is a first-class arm of crate::arms::WriterArm and GitStore will be built on it if it is asked for. Nothing refuses it, because “durable before ack” is git’s contract and not every store on this code is serving git pushes: a mirror that can be re-cloned, an import that is re-run on failure and a benchmark all have a weaker requirement, and for them the four bullets above are a price they are not obliged to pay. A store that is serving pushes and picks this one loses acked data on a machine crash, and that is the whole of what the choice means.

There is one consequence beyond durability, because it follows from the same absence: with no journal there is no durable record that a pack was ever acked, so a reopened store re-queues nothing and pack ordinals restart at 0 (indexer::packs_already_acked).

§Zero-copy

The caller’s bytes are handed to pwrite at their own address. There is no to_vec, no staging buffer and no BufWriter — one userspace→kernel copy, which is the syscall itself and cannot be removed without io_uring registered buffers (see [UringWriter]).

Implementations§

Source§

impl FastWriter

Source

pub fn create(archive: &Path) -> Result<Self>

Open archive for verbatim appends.

Source

pub fn blobs(&self) -> &File

The blob file, for a reader that wants to pread an extent back.

Trait Implementations§

Source§

impl ArchiveWrite for FastWriter

Source§

fn append(&self, bytes: &[u8]) -> Result<Extent>

Append these bytes and return when this implementation’s durability contract is met. Returns the byte extent written. Read more
Source§

fn name(&self) -> &'static str

Name it on a bench row.
Source§

fn durability(&self) -> &'static str

One-line statement of what a crash immediately after append returns does to the bytes. On the bench table next to the throughput, because a throughput without this is not a comparison.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Allocation for T
where T: RefUnwindSafe + Send + Sync,

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.