Skip to main content

NarCodec

Enum NarCodec 

Source
pub enum NarCodec {
    Zstd,
    Xz,
}
Expand description

How a NAR is packed for the cache.

── ★ ONE VALUE — THE BYTES, THE SUFFIX AND THE NARINFO ALL DERIVE ────── The codec used to be stated in THREE disconnected places in push_path: the call to compress_xz, the literal .nar.xz in the URL, and compression: "xz".to_string() in the narinfo. Three declarations of one fact, free to disagree — and disagreement is not a cosmetic bug: a narinfo that says xz over zstd bytes makes EVERY client fail to decompress, so the cache would serve corruption while reporting success. That is the failure mode this type removes, by leaving no way to state the codec twice.

── WHY zstd IS THE DEFAULT — MEASURED, NOT ASSUMED ───────────────────── Benchmarked on a real 48 MB NAR (git 2.51.2), 10 cores, 2026-08-05:

  codec              ms     size   %orig
  xz -6  (previous)  8368   8 MB    17%
  xz -6 -T0          7615   8 MB    17%     <- multithreading xz buys 9%
  zstd -19 -T0      11298   8 MB    17%     <- SLOWER than xz for the ratio
  zstd -12 -T0        440  10 MB    21%     <- 19x faster than xz -6
  zstd -9  -T0        243  10 MB    22%     <- 34x faster

Two beliefs died there. “Just add -T0 to xz” gains 9%, not the order of magnitude it promises — liblzma’s block splitting barely engages at this size. And zstd is only faster at lower levels; at -19 it loses to xz on both axes. The knee is -12: 19x the speed for four percentage points of ratio.

That trade is obviously right HERE and the reason is architectural: this cache is a LOCAL origin serving a handful of fleet nodes over tailscale. Bandwidth is cheap; CPU-hours on the fleet’s only x86_64-linux builder are not. MEASURED cost of the old default on rio 2026-08-05: a 2483-path closure spent FOUR HOURS in single-threaded xz, and because nix runs the post-build hook synchronously it blocked every build on that node — which is a different bug (fixed by detaching the hook) that this default made unsurvivable.

A mixed cache is fine and needs no migration: each narinfo declares its own codec, so paths already stored as .nar.xz keep resolving while new pushes land as .nar.zst.

Variants§

§

Zstd

zstd at [ZSTD_LEVEL], multithreaded. The default.

§

Xz

xz level 6 — what this cache used before 2026-08-05. Kept selectable rather than deleted (★★ MODULARIZE, DON’T DELETE): it is still the right choice for an origin that is bandwidth-bound rather than CPU-bound, and it is what every already-stored path is packed with.

Implementations§

Source§

impl NarCodec

Source

pub fn narinfo_name(self) -> &'static str

The Compression: field value. nix’s wire vocabulary, not ours — verified 2026-08-05 by having nix write a zstd cache itself (nix copy --to 'file://…?compression=zstd') and reading back what it emitted.

Source

pub fn url_suffix(self) -> &'static str

The NAR URL suffix.

.nar.zst, NOT .nar.zstd — taken from nix’s own output in the same experiment above. Guessing here would have produced a cache whose URLs no client resolves, and nothing in our own types would have objected.

Source

pub fn compress(self, data: &[u8]) -> Result<Vec<u8>, CacheError>

Compress a NAR under this codec.

zstd runs multithreaded across the machine’s cores; workers(0) asks the library for one worker per core. A failure to enable threading is deliberately NOT fatal — it costs speed, never correctness, and a cache push that refuses to run is worse than a slow one.

Trait Implementations§

Source§

impl Clone for NarCodec

Source§

fn clone(&self) -> NarCodec

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for NarCodec

Source§

impl Debug for NarCodec

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for NarCodec

Source§

fn default() -> NarCodec

Returns the “default value” for a type. Read more
Source§

impl Eq for NarCodec

Source§

impl PartialEq for NarCodec

Source§

fn eq(&self, other: &NarCodec) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for NarCodec

Auto Trait Implementations§

Blanket Implementations§

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more