|
| 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