Skip to content

Commit a9b602a

Browse files
authored
document reproducible writes (#5280)
Signed-off-by: Onur Satici <[email protected]>
1 parent 32d0834 commit a9b602a

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

docs/specs/file-format.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,26 @@ The plan is that at write-time, a minimum supported reader version is declared.
117117
reader version can then be embedded into the file with WebAssembly decompression logic. Old readers are able to decompress new
118118
data (slower than native code, but still with SIMD acceleration) and read the file. New readers are able to make the best use of
119119
these encodings with native decompression logic and additional push-down compute functions (which also provides an incentive to upgrade).
120+
121+
## File Determinism and Reproducibility
122+
123+
### Encoding Order Indeterminism
124+
125+
When writing Vortex files, each array segment references its encoding via an integer index into the footer's `array_specs`
126+
list. During serialization, encodings are registered in the order they are first encountered via calls to
127+
`ArrayContext::encoding_idx()`. With concurrent writes, this encounter order depends on thread scheduling and lock
128+
acquisition timing, making the ordering in the footer non-deterministic between runs.
129+
130+
This affects the `encoding` field in each serialized array segment. The same encoding might receive index 0 in one run and
131+
index 1 in another, changing the integer value stored in each array segment that uses that encoding. FlatBuffers optimize
132+
storage by omitting fields with default values (such as 0), so when an encoding index is 0, the field may be omitted from
133+
the serialized representation. This saves approximately 2 bytes per affected array segment, and with alignment adjustments,
134+
can result in up to 4 bytes difference per array segment between runs.
135+
136+
:::{note}
137+
Despite this non-determinism, the practical impact is minimal:
138+
139+
- File size may vary by up to 4 bytes per affected array segment
140+
- All file contents remain semantically identical and fully readable
141+
- Segment ordering (the actual data layout) remains deterministic and consistent across writes
142+
:::

vortex-array/src/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ impl<T: Clone + Eq> VTableContext<T> {
7070
}
7171

7272
/// Returns the index of the encoding in the context, or adds it if it doesn't exist.
73+
///
74+
/// At write time the order encodings are registered by this method can change.
75+
/// See [File Format specification](https://docs.vortex.rs/specs/file-format#file-determinism-and-reproducibility)
76+
/// for more details.
7377
pub fn encoding_idx(&self, encoding: &T) -> u16 {
7478
let mut write = self.0.write();
7579
if let Some(idx) = write.iter().position(|e| e == encoding) {

0 commit comments

Comments
 (0)