use crate::common::bitvec::{BitSlice, BitSliceExt as _};
use crate::common::types::PointOffsetType;
use crate::common::universal_io::UniversalRead;
use super::reader::{self, DiskMappingReader};
use crate::segment::common::operation_error::OperationResult;
use crate::segment::types::PointIdType;
pub trait DiskMappingsSource {
type Backend: UniversalRead;
fn mapping_reader(&self) -> &DiskMappingReader<Self::Backend>;
fn point_deleted(&self, offset: PointOffsetType) -> OperationResult<bool>;
fn deleted_bitslice(&self) -> OperationResult<&BitSlice>;
fn mappings_ref(&self) -> OperationResult<DiskMappingsRef<'_, Self::Backend>> {
Ok(DiskMappingsRef::new(
self.mapping_reader(),
self.deleted_bitslice()?,
))
}
fn mappings_ref_lossy(&self) -> DiskMappingsRef<'_, Self::Backend> {
self.mappings_ref().unwrap_or_else(|err| {
log::error!("disk id tracker deleted set load failed: {err}");
DiskMappingsRef::new(self.mapping_reader(), BitSlice::empty())
})
}
fn resolve_internal(
&self,
external_id: PointIdType,
) -> OperationResult<Option<PointOffsetType>> {
let Some(offset) = self.mapping_reader().lookup(external_id)? else {
return Ok(None);
};
Ok((!self.point_deleted(offset)?).then_some(offset))
}
fn resolve_external(&self, offset: PointOffsetType) -> OperationResult<Option<PointIdType>> {
if self.point_deleted(offset)? {
Ok(None)
} else {
self.mapping_reader().external_id(offset)
}
}
fn resolve_internal_batch(
&self,
external_ids: impl IntoIterator<Item = PointIdType>,
on_live: impl FnMut(PointIdType, PointOffsetType),
) -> OperationResult<()>;
}
pub struct DiskMappingsRef<'a, S: UniversalRead> {
reader: &'a DiskMappingReader<S>,
deleted: &'a BitSlice,
}
impl<S: UniversalRead> Clone for DiskMappingsRef<'_, S> {
fn clone(&self) -> Self {
*self
}
}
impl<S: UniversalRead> Copy for DiskMappingsRef<'_, S> {}
impl<'a, S: UniversalRead> DiskMappingsRef<'a, S> {
pub fn new(reader: &'a DiskMappingReader<S>, deleted: &'a BitSlice) -> Self {
Self { reader, deleted }
}
pub fn deleted(self) -> &'a BitSlice {
self.deleted
}
pub fn iter_external(self) -> impl Iterator<Item = PointIdType> + 'a {
self.reader
.iter_from(None)
.filter(live_filter(self.deleted))
.map(|(external_id, _)| external_id)
}
pub fn iter_internal(self) -> impl Iterator<Item = PointOffsetType> + 'a {
let deleted = self.deleted;
let total = self.reader.total_point_count() as PointOffsetType;
(0..total).filter(move |&offset| !deleted.get_bit(offset as usize).unwrap_or(false))
}
pub fn iter_from(
self,
external_id: Option<PointIdType>,
) -> impl Iterator<Item = (PointIdType, PointOffsetType)> + 'a {
self.reader
.iter_from(external_id)
.filter(live_filter(self.deleted))
}
pub fn iter_random(self) -> impl Iterator<Item = (PointIdType, PointOffsetType)> + 'a {
reader::iter_random(self.reader, self.deleted)
}
}
fn live_filter(deleted: &BitSlice) -> impl Fn(&(PointIdType, PointOffsetType)) -> bool + '_ {
move |&(_, offset)| !deleted.get_bit(offset as usize).unwrap_or(false)
}
pub fn log_lookup_err<T>(result: OperationResult<Option<T>>) -> Option<T> {
result.unwrap_or_else(|err| {
log::error!("disk id tracker lookup failed: {err}");
None
})
}