spark_storage/weight_peer/
manifest.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2//
3// Weight-staging manifest types + address math (un-gated, CUDA-free, verbs-free).
4//
5// This half is exactly what the RDMA clients import: `WeightManifest`,
6// `WeightTensorRecord`, `rail_for_tensor`, `tensor_remote_addr`. Keeping it free
7// of any back-edge into the server (`serve`/`shard`) is what makes the LoRA
8// carve-out (`weight_lora_rdma`) a clean lift.
9
10use serde::{Deserialize, Serialize};
11
12/// One tensor's placement inside a staged model, mirroring the safetensors
13/// header exactly: `offset_in_shard` is the ABSOLUTE file offset (8-byte size
14/// prefix + header + the tensor's data-section start), `len` is the raw
15/// contiguous byte count (`data_offsets[1] - data_offsets[0]`). The client
16/// RDMA-READs exactly `[shard_base + offset_in_shard .. + len)`.
17#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
18pub struct WeightTensorRecord {
19    /// HuggingFace tensor name — the `WeightStore` key, verbatim.
20    pub name: String,
21    /// Raw safetensors dtype string (`"BF16"`, `"F8_E4M3"`, `"I8"`, …). The
22    /// client maps it via `WeightDtype::from_safetensors_str` — the same closed
23    /// mapping the disk loaders use.
24    pub dtype: String,
25    pub shape: Vec<u64>,
26    /// Absolute byte offset of the tensor's first byte within its shard file.
27    pub offset_in_shard: u64,
28    /// Tensor byte length (authoritative — do NOT recompute from shape; packed
29    /// NVFP4 lengths differ from `numel * byte_size`).
30    pub len: u64,
31    /// Index into [`WeightManifest::shard_files`].
32    pub shard_index: u32,
33    /// True for tensors from `extra_weights.safetensors` (grafted MTP etc.):
34    /// loaded with NO expert-skip filter, exactly like the disk loaders.
35    pub extra: bool,
36}
37
38/// A staged model's manifest: the geometry the client needs to reconstruct a
39/// byte-identical `WeightStore`. Published as length-prefixed JSON right after
40/// the client's model request. The per-shard `(base, rkey)` MR handles ride the
41/// verbs handshake separately (see the module doc).
42#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
43pub struct WeightManifest {
44    pub version: u32,
45    /// The resolved model id/path the peer staged (echo for the client's log).
46    pub model_id: String,
47    /// Shard file names, shard-indexed. `shard_index` in each tensor record
48    /// indexes this list; the verbs `layers` vector is per-shard in this order.
49    pub shard_files: Vec<String>,
50    /// Byte length of each shard file, shard-indexed (parallels `shard_files`).
51    pub shard_lens: Vec<u64>,
52    pub tensors: Vec<WeightTensorRecord>,
53}
54
55impl WeightManifest {
56    pub const VERSION: u32 = 1;
57
58    /// Number of shard files (== the per-rail `layers` MR count the peer
59    /// publishes and the client validates against).
60    pub fn num_shards(&self) -> usize {
61        self.shard_files.len()
62    }
63
64    /// Total registered bytes across all shards (the whole-file MRs) — the
65    /// figure charged against the blade `CommitLedger` once per staged model.
66    pub fn total_shard_bytes(&self) -> u64 {
67        self.shard_lens.iter().sum()
68    }
69}
70
71/// Rail selection for a tensor under dual-rail striping: tensor `N` is served
72/// over rail `N % n_rails`. Factored out (un-gated) so the striping is unit-
73/// testable off the RDMA path — the client's read loop calls this so the tested
74/// logic and the shipped logic are the same. `n_rails` is clamped to `>= 1`.
75pub fn rail_for_tensor(tensor_index: usize, n_rails: usize) -> usize {
76    tensor_index % n_rails.max(1)
77}
78
79/// Absolute peer virtual address of a tensor's first byte: the shard's whole-
80/// file REMOTE_READ MR base plus the tensor's ABSOLUTE in-shard offset (the
81/// safetensors data-section offset, which already includes the 8-byte size
82/// prefix + header). The client RDMA-READs `[addr .. addr + len)`. Factored out
83/// (un-gated) so the address math is unit-testable off the RDMA path.
84pub fn tensor_remote_addr(shard_base: u64, offset_in_shard: u64) -> u64 {
85    shard_base + offset_in_shard
86}
87
88#[cfg(test)]
89#[path = "manifest_tests.rs"]
90mod tests;