vnfs 0.0.10

Vectorized NFSv4 client and compatibility facade for VFSI
Documentation

vnfs

A vectorized NFSv4.1 client library written in Rust.

NFSv4 supports COMPOUND requests: one RPC can carry an ordered sequence of file operations. A conventional POSIX-style loop hides that capability behind one-file-at-a-time calls, so latency grows with the number of files. vnfs instead exposes a vectorized VecFs API (the idea from the FAST'17 paper vNFS: Maximizing NFS Performance with Compounds and Vectorized I/O) as a Rust crate. The NFS backend packs each vector into compounds up to the server's negotiated operation and message-size limits, then returns results in input order.

Package boundary

The vnfs crate is the NFS-focused Rust compatibility package in the wider VFSI project. It provides NfsVecFs, the shared VecFs interfaces and types, and DummyVecFs for local testing. New protocol backends are published as separate vfsi-* crates so each backend has an independent dependency and release boundary.

NFS, the dummy backend, and NFSv4.2 server-side COPY are enabled by default. Applications that only need interface types can disable default features:

vnfs = { version = "0.0.10", default-features = false }

Example

Read the first 4 KiB of 32 independent files as one vectorized operation:

use vnfs::{NfsVecFs, ReadOp, VecFs, VfOffset};

fn main() -> vnfs::VfResult<()> {
    let mut fs = NfsVecFs::connect("nfs.example.com")?;
    let paths: Vec<String> = (0..32)
        .map(|shard| format!("/dataset/shard-{shard:02}.json"))
        .collect();
    let reads: Vec<ReadOp> = paths
        .iter()
        .map(|path| ReadOp::from_path(path, VfOffset::At(0), 4096))
        .collect();

    // One API call gives the backend the whole batch. NfsVecFs emits as few
    // NFSv4 COMPOUND RPCs as the negotiated server limits allow.
    let results = fs.readv(&reads)?;

    for (path, result) in paths.iter().zip(results) {
        println!("{path}: {} bytes (eof={})", result.data.len(), result.eof);
    }
    Ok(())
}

With scalar calls, reading 32 paths requires a succession of path lookup, open, read, and close exchanges for each file. readv exposes all 32 reads at once, allowing NfsVecFs to place many independent operation chains into each NFSv4 COMPOUND. The number of latency-bearing RPC round trips therefore scales with the number of compound chunks instead of directly with the number of files. The exact packing depends on the server's ca_maxoperations, request size, and response-size limits; oversized vectors are split automatically.

The same model applies to openv, writev, getattrsv, listdirv, renamev, removev, and the other vector methods. This is especially useful for metadata-heavy workloads and for many small, independent I/O operations, where network latency dominates transfer time.

License

Licensed under either of

  • Apache License, Version 2.0
  • MIT license

at your option.