1use std::io;
4use std::mem::size_of;
5
6use serde::{Deserialize, Serialize};
7
8use crate::directories::{FileHandle, OwnedBytes};
9use crate::dsl::DenseVectorQuantization;
10use crate::segment::format::{DOC_ID_ENTRY_SIZE, FLAT_BINARY_HEADER_SIZE, FLAT_BINARY_MAGIC};
11use crate::structures::simd::{batch_f32_to_f16, batch_f32_to_u8, f16_to_f32, u8_to_f32};
12
13#[inline]
19pub fn dequantize_raw(
20 raw: &[u8],
21 quant: DenseVectorQuantization,
22 num_floats: usize,
23 out: &mut [f32],
24) {
25 debug_assert!(out.len() >= num_floats);
26 match quant {
27 DenseVectorQuantization::F32 => {
28 debug_assert!(
29 (raw.as_ptr() as usize).is_multiple_of(std::mem::align_of::<f32>()),
30 "f32 vector data not 4-byte aligned"
31 );
32 out[..num_floats].copy_from_slice(unsafe {
33 std::slice::from_raw_parts(raw.as_ptr() as *const f32, num_floats)
34 });
35 }
36 DenseVectorQuantization::F16 => {
37 debug_assert!(
38 (raw.as_ptr() as usize).is_multiple_of(std::mem::align_of::<u16>()),
39 "f16 vector data not 2-byte aligned"
40 );
41 let f16_slice =
42 unsafe { std::slice::from_raw_parts(raw.as_ptr() as *const u16, num_floats) };
43 for (i, &h) in f16_slice.iter().enumerate() {
44 out[i] = f16_to_f32(h);
45 }
46 }
47 DenseVectorQuantization::UInt8 => {
48 for (i, &b) in raw.iter().enumerate().take(num_floats) {
49 out[i] = u8_to_f32(b);
50 }
51 }
52 DenseVectorQuantization::Binary => {
53 unreachable!("Binary vectors use raw bytes, not f32 dequantization");
54 }
55 }
56}
57
58pub struct FlatVectorData;
71
72impl FlatVectorData {
73 pub fn write_binary_header(
75 dim: usize,
76 num_vectors: usize,
77 quant: DenseVectorQuantization,
78 writer: &mut dyn std::io::Write,
79 ) -> std::io::Result<()> {
80 writer.write_all(&FLAT_BINARY_MAGIC.to_le_bytes())?;
81 writer.write_all(&(dim as u32).to_le_bytes())?;
82 writer.write_all(&(num_vectors as u32).to_le_bytes())?;
83 writer.write_all(&[quant.tag(), 0, 0, 0])?; Ok(())
85 }
86
87 pub fn serialized_binary_size(
89 dim: usize,
90 num_vectors: usize,
91 quant: DenseVectorQuantization,
92 ) -> usize {
93 let bytes_per_vector = match quant {
94 DenseVectorQuantization::Binary => dim.div_ceil(8),
95 _ => dim * quant.element_size(),
96 };
97 FLAT_BINARY_HEADER_SIZE + num_vectors * bytes_per_vector + num_vectors * DOC_ID_ENTRY_SIZE
98 }
99
100 pub fn serialize_binary_from_flat_streaming(
105 dim: usize,
106 flat_vectors: &[f32],
107 doc_ids: &[(u32, u16)],
108 quant: DenseVectorQuantization,
109 writer: &mut dyn std::io::Write,
110 ) -> std::io::Result<()> {
111 let num_vectors = doc_ids.len();
112 Self::write_binary_header(dim, num_vectors, quant, writer)?;
113
114 match quant {
115 DenseVectorQuantization::F32 => {
116 let bytes: &[u8] = unsafe {
117 std::slice::from_raw_parts(
118 flat_vectors.as_ptr() as *const u8,
119 std::mem::size_of_val(flat_vectors),
120 )
121 };
122 writer.write_all(bytes)?;
123 }
124 DenseVectorQuantization::F16 => {
125 let mut buf = vec![0u16; dim];
126 for v in flat_vectors.chunks_exact(dim) {
127 batch_f32_to_f16(v, &mut buf);
128 let bytes: &[u8] =
129 unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const u8, dim * 2) };
130 writer.write_all(bytes)?;
131 }
132 }
133 DenseVectorQuantization::UInt8 => {
134 let mut buf = vec![0u8; dim];
135 for v in flat_vectors.chunks_exact(dim) {
136 batch_f32_to_u8(v, &mut buf);
137 writer.write_all(&buf)?;
138 }
139 }
140 DenseVectorQuantization::Binary => {
141 unreachable!("Binary quantization should use serialize_binary_from_bits_streaming");
143 }
144 }
145
146 for &(doc_id, ordinal) in doc_ids {
147 writer.write_all(&doc_id.to_le_bytes())?;
148 writer.write_all(&ordinal.to_le_bytes())?;
149 }
150
151 Ok(())
152 }
153
154 pub fn serialize_binary_from_bits_streaming(
159 dim_bits: usize,
160 packed_vectors: &[u8],
161 doc_ids: &[(u32, u16)],
162 writer: &mut dyn std::io::Write,
163 ) -> std::io::Result<()> {
164 let num_vectors = doc_ids.len();
165 let byte_len = dim_bits.div_ceil(8);
166 debug_assert_eq!(packed_vectors.len(), num_vectors * byte_len);
167
168 Self::write_binary_header(
169 dim_bits,
170 num_vectors,
171 DenseVectorQuantization::Binary,
172 writer,
173 )?;
174 writer.write_all(packed_vectors)?;
175
176 for &(doc_id, ordinal) in doc_ids {
177 writer.write_all(&doc_id.to_le_bytes())?;
178 writer.write_all(&ordinal.to_le_bytes())?;
179 }
180
181 Ok(())
182 }
183
184 pub fn write_raw_vector_bytes(
188 raw_bytes: &[u8],
189 writer: &mut dyn std::io::Write,
190 ) -> std::io::Result<()> {
191 writer.write_all(raw_bytes)
192 }
193}
194
195#[derive(Debug, Clone)]
207pub struct LazyFlatVectorData {
208 pub dim: usize,
210 pub num_vectors: usize,
212 pub quantization: DenseVectorQuantization,
214 doc_ids_bytes: OwnedBytes,
216 handle: FileHandle,
218 vectors_offset: u64,
220 vbs: usize,
222}
223
224impl LazyFlatVectorData {
225 pub async fn open(handle: FileHandle) -> io::Result<Self> {
230 let header = handle
232 .read_bytes_range(0..FLAT_BINARY_HEADER_SIZE as u64)
233 .await?;
234 let hdr = header.as_slice();
235
236 let magic = u32::from_le_bytes([hdr[0], hdr[1], hdr[2], hdr[3]]);
237 if magic != FLAT_BINARY_MAGIC {
238 return Err(io::Error::new(
239 io::ErrorKind::InvalidData,
240 "Invalid FlatVectorData binary magic",
241 ));
242 }
243
244 let dim = u32::from_le_bytes([hdr[4], hdr[5], hdr[6], hdr[7]]) as usize;
245 let num_vectors = u32::from_le_bytes([hdr[8], hdr[9], hdr[10], hdr[11]]) as usize;
246 let quantization = DenseVectorQuantization::from_tag(hdr[12]).ok_or_else(|| {
247 io::Error::new(
248 io::ErrorKind::InvalidData,
249 format!("Unknown quantization tag: {}", hdr[12]),
250 )
251 })?;
252 let vbs = if quantization == DenseVectorQuantization::Binary {
254 dim.div_ceil(8)
255 } else {
256 dim * quantization.element_size()
257 };
258 let vectors_byte_len = num_vectors * vbs;
259 let doc_ids_start = (FLAT_BINARY_HEADER_SIZE + vectors_byte_len) as u64;
260 let doc_ids_byte_len = (num_vectors * DOC_ID_ENTRY_SIZE) as u64;
261
262 let doc_ids_bytes = handle
263 .read_bytes_range(doc_ids_start..doc_ids_start + doc_ids_byte_len)
264 .await?;
265
266 Ok(Self {
267 dim,
268 num_vectors,
269 quantization,
270 doc_ids_bytes,
271 handle,
272 vectors_offset: FLAT_BINARY_HEADER_SIZE as u64,
273 vbs,
274 })
275 }
276
277 #[cfg(feature = "native")]
280 pub(crate) fn pin_doc_ids(
281 &mut self,
282 mode: crate::segment::pin::PinMode,
283 remaining: &mut u64,
284 report: &mut crate::segment::pin::PinReport,
285 ) {
286 crate::segment::pin::pin_section(
287 &mut self.doc_ids_bytes,
288 "flat doc_ids",
289 mode,
290 remaining,
291 report,
292 );
293 }
294
295 #[cfg(feature = "native")]
302 pub fn advise_random_access(&self) {
303 let data_len = (self.num_vectors * self.vbs) as u64;
304 self.handle.madvise_range(
305 self.vectors_offset..self.vectors_offset + data_len,
306 libc::MADV_RANDOM,
307 );
308 }
309
310 #[cfg(feature = "native")]
317 pub fn prefetch_vectors(&self, sorted_flat_indexes: impl IntoIterator<Item = usize>) {
318 const COALESCE_GAP: u64 = 64 * 1024;
320 let vbs = self.vbs as u64;
321 let mut iter = sorted_flat_indexes.into_iter();
322 let Some(first) = iter.next() else {
323 return;
324 };
325 let mut run_start = self.vectors_offset + first as u64 * vbs;
326 let mut run_end = run_start + vbs;
327 for idx in iter {
328 let start = self.vectors_offset + idx as u64 * vbs;
329 if start <= run_end + COALESCE_GAP {
330 run_end = start + vbs;
331 } else {
332 self.handle
333 .madvise_range(run_start..run_end, libc::MADV_WILLNEED);
334 run_start = start;
335 run_end = start + vbs;
336 }
337 }
338 self.handle
339 .madvise_range(run_start..run_end, libc::MADV_WILLNEED);
340 }
341
342 pub async fn read_vector_into(&self, idx: usize, out: &mut [f32]) -> io::Result<()> {
347 debug_assert!(out.len() >= self.dim);
348 let vbs = self.vector_byte_size();
349 let byte_offset = self.vectors_offset + (idx * vbs) as u64;
350 let bytes = self
351 .handle
352 .read_bytes_range(byte_offset..byte_offset + vbs as u64)
353 .await?;
354 let raw = bytes.as_slice();
355
356 dequantize_raw(raw, self.quantization, self.dim, out);
357 Ok(())
358 }
359
360 pub async fn get_vector(&self, idx: usize) -> io::Result<Vec<f32>> {
362 let mut vector = vec![0f32; self.dim];
363 self.read_vector_into(idx, &mut vector).await?;
364 Ok(vector)
365 }
366
367 pub async fn read_vector_raw_into(&self, idx: usize, out: &mut [u8]) -> io::Result<()> {
372 let vbs = self.vector_byte_size();
373 debug_assert!(out.len() >= vbs);
374 let byte_offset = self.vectors_offset + (idx * vbs) as u64;
375 let bytes = self
376 .handle
377 .read_bytes_range(byte_offset..byte_offset + vbs as u64)
378 .await?;
379 out[..vbs].copy_from_slice(bytes.as_slice());
380 Ok(())
381 }
382
383 pub async fn read_vectors_batch(
389 &self,
390 start_idx: usize,
391 count: usize,
392 ) -> io::Result<OwnedBytes> {
393 debug_assert!(start_idx + count <= self.num_vectors);
394 let vbs = self.vector_byte_size();
395 let byte_offset = self.vectors_offset + (start_idx * vbs) as u64;
396 let byte_len = (count * vbs) as u64;
397 self.handle
398 .read_bytes_range(byte_offset..byte_offset + byte_len)
399 .await
400 }
401
402 #[cfg(feature = "sync")]
404 pub fn read_vector_raw_into_sync(&self, idx: usize, out: &mut [u8]) -> io::Result<()> {
405 let vbs = self.vector_byte_size();
406 debug_assert!(out.len() >= vbs);
407 let byte_offset = self.vectors_offset + (idx * vbs) as u64;
408 let bytes = self
409 .handle
410 .read_bytes_range_sync(byte_offset..byte_offset + vbs as u64)?;
411 out[..vbs].copy_from_slice(bytes.as_slice());
412 Ok(())
413 }
414
415 #[cfg(feature = "sync")]
417 pub fn read_vectors_batch_sync(
418 &self,
419 start_idx: usize,
420 count: usize,
421 ) -> io::Result<OwnedBytes> {
422 debug_assert!(start_idx + count <= self.num_vectors);
423 let vbs = self.vector_byte_size();
424 let byte_offset = self.vectors_offset + (start_idx * vbs) as u64;
425 let byte_len = (count * vbs) as u64;
426 self.handle
427 .read_bytes_range_sync(byte_offset..byte_offset + byte_len)
428 }
429
430 pub fn flat_indexes_for_doc_range(&self, doc_id: u32) -> (usize, usize) {
436 let n = self.num_vectors;
437 let start = {
438 let mut lo = 0usize;
439 let mut hi = n;
440 while lo < hi {
441 let mid = lo + (hi - lo) / 2;
442 if self.doc_id_at(mid) < doc_id {
443 lo = mid + 1;
444 } else {
445 hi = mid;
446 }
447 }
448 lo
449 };
450 let mut count = 0;
451 let mut i = start;
452 while i < n && self.doc_id_at(i) == doc_id {
453 count += 1;
454 i += 1;
455 }
456 (start, count)
457 }
458
459 pub fn flat_indexes_for_doc(&self, doc_id: u32) -> (usize, Vec<(u32, u16)>) {
466 let n = self.num_vectors;
467 let start = {
469 let mut lo = 0usize;
470 let mut hi = n;
471 while lo < hi {
472 let mid = lo + (hi - lo) / 2;
473 if self.doc_id_at(mid) < doc_id {
474 lo = mid + 1;
475 } else {
476 hi = mid;
477 }
478 }
479 lo
480 };
481 let mut entries = Vec::new();
483 let mut i = start;
484 while i < n {
485 let (did, ord) = self.get_doc_id(i);
486 if did != doc_id {
487 break;
488 }
489 entries.push((did, ord));
490 i += 1;
491 }
492 (start, entries)
493 }
494
495 #[inline]
497 fn doc_id_at(&self, idx: usize) -> u32 {
498 let off = idx * DOC_ID_ENTRY_SIZE;
499 let d = &self.doc_ids_bytes[off..];
500 u32::from_le_bytes([d[0], d[1], d[2], d[3]])
501 }
502
503 #[inline]
505 pub fn get_doc_id(&self, idx: usize) -> (u32, u16) {
506 let off = idx * DOC_ID_ENTRY_SIZE;
507 let d = &self.doc_ids_bytes[off..];
508 let doc_id = u32::from_le_bytes([d[0], d[1], d[2], d[3]]);
509 let ordinal = u16::from_le_bytes([d[4], d[5]]);
510 (doc_id, ordinal)
511 }
512
513 #[inline]
515 pub fn vector_byte_size(&self) -> usize {
516 self.vbs
517 }
518
519 pub fn vector_bytes_len(&self) -> u64 {
521 (self.num_vectors as u64) * (self.vector_byte_size() as u64)
522 }
523
524 pub fn vectors_byte_offset(&self) -> u64 {
526 self.vectors_offset
527 }
528
529 pub fn handle(&self) -> &FileHandle {
531 &self.handle
532 }
533
534 pub fn estimated_memory_bytes(&self) -> usize {
536 size_of::<Self>() + size_of::<OwnedBytes>()
537 }
538}
539
540#[derive(Debug, Clone, Serialize, Deserialize)]
545pub struct IVFRaBitQIndexData {
546 pub index: crate::structures::IVFRaBitQIndex,
547 pub codebook: crate::structures::RaBitQCodebook,
548}
549
550impl IVFRaBitQIndexData {
551 pub fn to_bytes(&self) -> std::io::Result<Vec<u8>> {
552 bincode::serde::encode_to_vec(self, bincode::config::standard())
553 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
554 }
555
556 pub fn from_bytes(data: &[u8]) -> std::io::Result<Self> {
557 bincode::serde::decode_from_slice(data, bincode::config::standard())
558 .map(|(v, _)| v)
559 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
560 }
561}
562
563#[derive(Debug, Clone, Serialize, Deserialize)]
568pub struct ScaNNIndexData {
569 pub index: crate::structures::IVFPQIndex,
570 pub codebook: crate::structures::PQCodebook,
571}
572
573impl ScaNNIndexData {
574 pub fn to_bytes(&self) -> std::io::Result<Vec<u8>> {
575 bincode::serde::encode_to_vec(self, bincode::config::standard())
576 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
577 }
578
579 pub fn from_bytes(data: &[u8]) -> std::io::Result<Self> {
580 bincode::serde::decode_from_slice(data, bincode::config::standard())
581 .map(|(v, _)| v)
582 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
583 }
584}