Skip to content

Commit 99ca004

Browse files
committed
fix: buffer vector payload writes
1 parent 12e823c commit 99ca004

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

‎src/vector/storage.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ impl MmapVectorStorage {
213213
self.write_header(&mut file)?;
214214
}
215215

216+
// Buffer the payload instead of issuing one system call per float.
217+
let mut file = io::BufWriter::new(file);
218+
216219
// Write vectors
217220
for (id, vector) in vectors {
218221
// Write vector ID

‎tests/vector_storage_batch.rs‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use codanna::vector::{MmapVectorStorage, SegmentOrdinal, VectorDimension, VectorId};
2+
use std::time::Instant;
3+
4+
fn check_batches(count: u32) {
5+
let dir = tempfile::tempdir().unwrap();
6+
let segment = SegmentOrdinal::new(0);
7+
let mut storage =
8+
MmapVectorStorage::new(dir.path(), segment, VectorDimension::dimension_384()).unwrap();
9+
let vectors: Vec<_> = (1..=count)
10+
.map(|id| (VectorId::new(id).unwrap(), vec![id as f32; 384]))
11+
.collect();
12+
let batch: Vec<_> = vectors.iter().map(|(id, v)| (*id, v.as_slice())).collect();
13+
let middle = batch.len() / 2;
14+
15+
let start = Instant::now();
16+
storage.write_batch(&batch[..middle]).unwrap();
17+
let first_write = start.elapsed();
18+
assert_eq!(storage.read_all_vectors().unwrap(), vectors[..middle]);
19+
let start = Instant::now();
20+
storage.write_batch(&batch[middle..]).unwrap();
21+
println!(
22+
"{count} vectors, 384 dimensions: {:?} writing",
23+
first_write + start.elapsed()
24+
);
25+
26+
let mut reopened = MmapVectorStorage::open(dir.path(), segment).unwrap();
27+
assert_eq!(reopened.vector_count(), count as usize);
28+
assert_eq!(reopened.read_all_vectors().unwrap(), vectors);
29+
assert_eq!(
30+
std::fs::metadata(dir.path().join("segment_0.vec"))
31+
.unwrap()
32+
.len(),
33+
16 + u64::from(count) * (4 + 384 * 4)
34+
);
35+
}
36+
37+
#[test]
38+
fn appended_batches_are_readable_after_reopen() {
39+
check_batches(32);
40+
}
41+
42+
#[test]
43+
#[ignore = "measures a large synthetic embedding batch; run explicitly for write throughput"]
44+
fn large_embedding_batch_roundtrips() {
45+
check_batches(10_000);
46+
}

0 commit comments

Comments
 (0)