use std::path::PathBuf;
use crate::common::types::PointOffsetType;
use crate::common::universal_io::{UniversalRead, UniversalWrite};
use roaring::RoaringBitmap;
use super::buffered_dynamic_flags::BufferedDynamicFlags;
use super::dynamic_stored_flags::DynamicStoredFlags;
use crate::segment::common::Flusher;
use crate::segment::common::operation_error::OperationResult;
pub trait RoaringFlagsRead {
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn get_bitmap(&self) -> &RoaringBitmap;
fn get(&self, index: PointOffsetType) -> bool {
self.get_bitmap().contains(index)
}
fn iter_trues(&self) -> roaring::bitmap::Iter<'_> {
self.get_bitmap().iter()
}
fn iter_falses(&self) -> Box<dyn Iterator<Item = PointOffsetType> + '_> {
let len = self.len() as PointOffsetType;
let bitmap = self.get_bitmap();
Box::new((0..len).filter(move |i| !bitmap.contains(*i)))
}
fn count_trues(&self) -> usize {
self.get_bitmap().len() as usize
}
fn count_falses(&self) -> usize {
self.len().saturating_sub(self.count_trues())
}
fn populate(&self) -> OperationResult<()> {
Ok(())
}
fn clear_cache(&self) -> OperationResult<()> {
Ok(())
}
fn files(&self) -> Vec<PathBuf>;
}
pub struct RoaringFlags<S: UniversalRead> {
storage: BufferedDynamicFlags<S>,
bitmap: RoaringBitmap,
len: usize,
}
impl<S> RoaringFlagsRead for RoaringFlags<S>
where
S: UniversalWrite + Send + 'static,
S::Fs: Send + Sync + 'static,
{
fn len(&self) -> usize {
self.len
}
fn get_bitmap(&self) -> &RoaringBitmap {
&self.bitmap
}
fn clear_cache(&self) -> OperationResult<()> {
let Self {
storage,
bitmap: _,
len: _,
} = self;
storage.clear_cache()?;
Ok(())
}
fn files(&self) -> Vec<PathBuf> {
self.storage.files()
}
}
impl<S> RoaringFlags<S>
where
S: UniversalWrite + Send + 'static,
S::Fs: Send + Sync + 'static,
{
pub fn new(fs: S::Fs, dynamic_flags: DynamicStoredFlags<S>) -> OperationResult<Self> {
let bitmap = RoaringBitmap::from_sorted_iter(dynamic_flags.iter_trues()?)
.expect("iter_trues iterates in sorted order");
if let Err(err) = dynamic_flags.clear_cache() {
log::warn!("Failed to clear bitslice cache: {err}");
}
Ok(Self {
len: dynamic_flags.len(),
storage: BufferedDynamicFlags::new(fs, dynamic_flags),
bitmap,
})
}
pub fn set(&mut self, index: PointOffsetType, value: bool) -> bool {
self.storage.buffer_set(index, value);
let index_usize = index as usize;
if index_usize >= self.len {
self.len = index_usize + 1;
}
if value {
!self.bitmap.insert(index)
} else {
self.bitmap.remove(index)
}
}
pub fn set_immutable(&mut self, index: PointOffsetType, value: bool) -> bool {
let index_usize = index as usize;
if index_usize >= self.len {
self.len = index_usize + 1;
}
if value {
!self.bitmap.insert(index)
} else {
self.bitmap.remove(index)
}
}
pub fn flusher(&self) -> Flusher {
self.storage.flusher()
}
}
#[allow(clippy::default_constructed_unit_structs)]
#[duplicate::duplicate_item(
tests_mod S Fs cfg_predicate;
[tests_mmap] [MmapFile] [MmapFs] [cfg(all())];
[tests_uring] [IoUringFile] [IoUringFs] [cfg(target_os = "linux")];
)]
#[cfg_predicate]
#[cfg(test)]
mod tests_mod {
use crate::common::types::PointOffsetType;
#[cfg_predicate]
use crate::common::universal_io::{Fs, S};
use crate::segment::common::flags::dynamic_stored_flags::DynamicStoredFlags;
use crate::segment::common::flags::roaring_flags::{RoaringFlags, RoaringFlagsRead};
#[test]
fn test_roaring_flags_consistency_after_persistence() {
let dir = tempfile::Builder::new()
.prefix("roaring_flags_consistency")
.tempdir()
.unwrap();
{
let dynamic_flags =
DynamicStoredFlags::<S>::open(&Fs::default(), dir.path(), false).unwrap();
let mut roaring_flags = RoaringFlags::new(Fs::default(), dynamic_flags).unwrap();
for i in 16..20 {
roaring_flags.set(i, false); }
roaring_flags.set(0, true);
roaring_flags.set(5, true);
roaring_flags.set(10, true);
roaring_flags.set(15, true);
roaring_flags.set(7, false);
let flusher = roaring_flags.flusher();
flusher().unwrap();
}
{
let mmap_flags =
DynamicStoredFlags::<S>::open(&Fs::default(), dir.path(), true).unwrap();
let roaring_flags = RoaringFlags::new(Fs::default(), mmap_flags).unwrap();
let iter_trues: Vec<_> = roaring_flags.iter_trues().collect();
assert_eq!(iter_trues, vec![0, 5, 10, 15]);
assert_eq!(roaring_flags.count_trues(), 4);
assert_eq!(
roaring_flags.count_falses(),
roaring_flags.len() - roaring_flags.count_trues()
);
let all_trues: Vec<_> = roaring_flags.iter_trues().collect();
let all_falses: Vec<_> = roaring_flags.iter_falses().collect();
let mut all_indices = all_trues;
all_indices.extend(all_falses);
all_indices.sort();
let expected_all: Vec<_> = (0..roaring_flags.len() as PointOffsetType).collect();
assert_eq!(all_indices, expected_all);
}
}
}