mirror of
https://github.com/qdrant/qdrant.git
synced 2026-09-21 13:37:46 -05:00
Standardize map index (#9305)
* rename to OnDiskMapIndex * rename module * remove `is_on_disk` field from `OnDiskMapIndex` * add separate Immutable and OnDisk ReadOnlyMapIndex * rename StoredPointToValues to OnDiskPointToValues * rename module to `on_disk_point_to_values` * rename to `build_from_iter` and add `populate` arg * fix test
This commit is contained in:
@@ -28,7 +28,7 @@ use super::{
|
||||
use crate::common::Flusher;
|
||||
use crate::common::operation_error::{OperationError, OperationResult};
|
||||
use crate::index::field_index::geo_hash::{GeoHash, GeoHashRaw};
|
||||
use crate::index::field_index::stored_point_to_values::StoredPointToValues;
|
||||
use crate::index::field_index::on_disk_point_to_values::OnDiskPointToValues;
|
||||
use crate::types::GeoPoint;
|
||||
|
||||
impl<S: UniversalRead> StoredGeoMapIndex<S> {
|
||||
@@ -48,7 +48,7 @@ impl<S: UniversalRead> StoredGeoMapIndex<S> {
|
||||
let points_map_ids_path = path.join(POINTS_MAP_IDS);
|
||||
|
||||
// Create the point-to-value mapping and persist in the file
|
||||
StoredPointToValues::<GeoPoint, MmapFile>::from_iter(
|
||||
OnDiskPointToValues::<GeoPoint, MmapFile>::build_from_iter(
|
||||
&MmapFs,
|
||||
path,
|
||||
dynamic_index
|
||||
@@ -56,6 +56,7 @@ impl<S: UniversalRead> StoredGeoMapIndex<S> {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, values)| (idx as PointOffsetType, values.iter())),
|
||||
!is_on_disk,
|
||||
)?;
|
||||
|
||||
{
|
||||
@@ -195,7 +196,7 @@ impl<S: UniversalRead> StoredGeoMapIndex<S> {
|
||||
TypedStorage::open(fs, &points_map_path, open_options, Default::default())?;
|
||||
let points_map_ids =
|
||||
TypedStorage::open(fs, &points_map_ids_path, open_options, Default::default())?;
|
||||
let point_to_values = StoredPointToValues::open(fs, path, true)?;
|
||||
let point_to_values = OnDiskPointToValues::open(fs, path, true)?;
|
||||
|
||||
let mut deleted = deleted_points.to_owned();
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use common::universal_io::{MmapFile, TypedStorage, UniversalRead};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::index::field_index::geo_hash::GeoHashRaw;
|
||||
use crate::index::field_index::stored_point_to_values::StoredPointToValues;
|
||||
use crate::index::field_index::on_disk_point_to_values::OnDiskPointToValues;
|
||||
use crate::types::GeoPoint;
|
||||
|
||||
mod lifecycle;
|
||||
@@ -79,7 +79,7 @@ pub(in super::super) struct Storage<S: UniversalRead = MmapFile> {
|
||||
/// A storage of associations between geo-hashes and point ids. (See the diagram above)
|
||||
pub(in super::super) points_map_ids: TypedStorage<S, PointOffsetType>,
|
||||
/// One-to-many mapping of the PointOffsetType to the GeoPoint.
|
||||
pub(in super::super) point_to_values: StoredPointToValues<GeoPoint, S>,
|
||||
pub(in super::super) point_to_values: OnDiskPointToValues<GeoPoint, S>,
|
||||
/// In-memory deletion bitmap. Reconstructed at load time as the union of
|
||||
/// the build-time empty-payload bits read from `deleted.bin` and the
|
||||
/// segment-level deleted bitslice supplied by the id-tracker. Not persisted.
|
||||
|
||||
@@ -12,7 +12,7 @@ use super::null_index::{ImmutableNullIndex, NullIndex};
|
||||
use super::numeric_index::{
|
||||
Encodable, NumericIndexGridstoreBuilder, NumericIndexIntoInnerValue, NumericIndexMmapBuilder,
|
||||
};
|
||||
use super::stored_point_to_values::StoredValue;
|
||||
use super::on_disk_point_to_values::StoredValue;
|
||||
use super::{FieldIndexBuilder, ValueIndexer};
|
||||
use crate::common::operation_error::{OperationError, OperationResult};
|
||||
use crate::data_types::index::TextIndexParams;
|
||||
@@ -294,10 +294,10 @@ impl IndexSelector<'_> {
|
||||
{
|
||||
Ok(match self {
|
||||
IndexSelector::NonAppendable { dir, is_on_disk } => {
|
||||
MapIndex::new_mmap(&map_dir(dir, field), *is_on_disk, deleted_points)?
|
||||
MapIndex::new_immutable(&map_dir(dir, field), *is_on_disk, deleted_points)?
|
||||
}
|
||||
IndexSelector::Appendable { dir } => {
|
||||
MapIndex::new_gridstore(map_dir(dir, field), create_if_missing)?
|
||||
MapIndex::new_mutable(map_dir(dir, field), create_if_missing)?
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -313,13 +313,11 @@ impl IndexSelector<'_> {
|
||||
Vec<<N as MapIndexKey>::Owned>: Blob + Send + Sync,
|
||||
{
|
||||
match self {
|
||||
IndexSelector::NonAppendable { dir, is_on_disk } => make_mmap(MapIndex::builder_mmap(
|
||||
&map_dir(dir, field),
|
||||
*is_on_disk,
|
||||
deleted_points,
|
||||
)),
|
||||
IndexSelector::NonAppendable { dir, is_on_disk } => make_mmap(
|
||||
MapIndex::builder_immutable(&map_dir(dir, field), *is_on_disk, deleted_points),
|
||||
),
|
||||
IndexSelector::Appendable { dir } => {
|
||||
make_gridstore(MapIndex::builder_gridstore(map_dir(dir, field)))
|
||||
make_gridstore(MapIndex::builder_mutable(map_dir(dir, field)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,9 @@ use serde_json::Value;
|
||||
|
||||
use super::MapIndex;
|
||||
use super::key::MapIndexKey;
|
||||
use super::universal_map_index::UniversalMapIndex;
|
||||
use super::on_disk_map_index::OnDiskMapIndex;
|
||||
use crate::common::operation_error::{OperationError, OperationResult};
|
||||
use crate::index::field_index::map_index::immutable_map_index::ImmutableMapIndex;
|
||||
use crate::index::field_index::{FieldIndexBuilderTrait, PayloadFieldIndex, ValueIndexer};
|
||||
|
||||
pub struct MapIndexBuilder<N: MapIndexKey + ?Sized>(pub(super) MapIndex<N>)
|
||||
@@ -110,14 +111,23 @@ where
|
||||
}
|
||||
|
||||
fn finalize(self) -> OperationResult<Self::FieldIndexType> {
|
||||
Ok(MapIndex::OnDisk(Box::new(UniversalMapIndex::build(
|
||||
let populate = !self.is_on_disk;
|
||||
let on_disk_index = OnDiskMapIndex::build(
|
||||
&MmapFs,
|
||||
&self.path,
|
||||
self.point_to_values,
|
||||
self.values_to_points,
|
||||
self.is_on_disk,
|
||||
populate,
|
||||
&self.deleted_points,
|
||||
)?)))
|
||||
)?;
|
||||
|
||||
let index = if self.is_on_disk {
|
||||
MapIndex::OnDisk(on_disk_index)
|
||||
} else {
|
||||
MapIndex::Immutable(ImmutableMapIndex::load_from_on_disk(on_disk_index)?)
|
||||
};
|
||||
|
||||
Ok(index)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +162,7 @@ where
|
||||
"index must be initialized exactly once",
|
||||
);
|
||||
self.index.replace(
|
||||
MapIndex::new_gridstore(self.dir.clone(), true)?.ok_or_else(|| {
|
||||
MapIndex::new_mutable(self.dir.clone(), true)?.ok_or_else(|| {
|
||||
OperationError::service_error("Failed to create mutable map index")
|
||||
})?,
|
||||
);
|
||||
|
||||
@@ -101,6 +101,12 @@ where
|
||||
Ok(())
|
||||
}
|
||||
ReadOnlyMapIndex::Immutable(index) => {
|
||||
index.for_points_values(points, |idx, slice| {
|
||||
f(idx, &mut slice.iter().map(|v| v.borrow().into()));
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
ReadOnlyMapIndex::OnDisk(index) => {
|
||||
index.for_points_values(points, hw_counter, |idx, vals| {
|
||||
f(idx, &mut vals.map(|v| v.into()));
|
||||
})
|
||||
|
||||
@@ -5,23 +5,27 @@ use std::path::PathBuf;
|
||||
use bitvec::vec::BitVec;
|
||||
use common::counter::hardware_counter::HardwareCounterCell;
|
||||
use common::types::PointOffsetType;
|
||||
use common::universal_io::{UniversalRead, UniversalWrite};
|
||||
use gridstore::Blob;
|
||||
|
||||
use super::super::MapIndexKey;
|
||||
use super::super::on_disk_map_index::OnDiskMapIndex;
|
||||
use super::super::read_ops::MapIndexRead;
|
||||
use super::super::universal_map_index::UniversalMapIndex;
|
||||
use super::{ContainerSegment, ImmutableMapIndex, Storage};
|
||||
use super::{ContainerSegment, ImmutableMapIndex};
|
||||
use crate::common::Flusher;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::immutable_point_to_values::ImmutablePointToValues;
|
||||
|
||||
impl<N: MapIndexKey + ?Sized> ImmutableMapIndex<N>
|
||||
impl<N, S> ImmutableMapIndex<N, S>
|
||||
where
|
||||
Vec<<N as MapIndexKey>::Owned>: Blob + Send + Sync,
|
||||
N: MapIndexKey + ?Sized,
|
||||
S: UniversalRead,
|
||||
{
|
||||
/// Open and load the immutable map index from mmap storage.
|
||||
pub(in super::super) fn open_mmap(index: UniversalMapIndex<N>) -> OperationResult<Self> {
|
||||
let index = Box::new(index);
|
||||
pub(in super::super) fn load_from_on_disk(
|
||||
index: OnDiskMapIndex<N, S>,
|
||||
) -> OperationResult<Self> {
|
||||
let hw_counter = HardwareCounterCell::disposable(); // Internal operation
|
||||
|
||||
let mut indexed_points = 0;
|
||||
@@ -87,7 +91,7 @@ where
|
||||
|
||||
// Index is now loaded into memory, clear cache of backing mmap storage
|
||||
if let Err(err) = index.clear_cache() {
|
||||
log::warn!("Failed to clear mmap cache of ram mmap map index: {err}");
|
||||
log::warn!("Failed to clear mmap cache of immutable map index: {err}");
|
||||
}
|
||||
|
||||
let mut result = Self {
|
||||
@@ -97,7 +101,7 @@ where
|
||||
point_to_values,
|
||||
indexed_points,
|
||||
values_count,
|
||||
storage: Storage::Mmap(index),
|
||||
storage: index,
|
||||
cached_ram_usage_bytes: 0,
|
||||
};
|
||||
result.cached_ram_usage_bytes = result.compute_ram_usage_bytes();
|
||||
@@ -137,7 +141,14 @@ where
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, S> ImmutableMapIndex<N, S>
|
||||
where
|
||||
Vec<<N as MapIndexKey>::Owned>: Blob + Send + Sync,
|
||||
N: MapIndexKey + ?Sized,
|
||||
S: UniversalWrite,
|
||||
{
|
||||
/// Removes `idx` from values-to-points-container.
|
||||
/// It is implemented by shrinking the range of values-to-points by one and moving the removed element
|
||||
/// out of the range.
|
||||
@@ -209,12 +220,8 @@ where
|
||||
idx,
|
||||
);
|
||||
|
||||
// Update persisted storage
|
||||
match self.storage {
|
||||
Storage::Mmap(ref mut index) => {
|
||||
index.remove_point(idx);
|
||||
}
|
||||
}
|
||||
// Update storage
|
||||
self.storage.remove_point(idx);
|
||||
removed_values_count += 1;
|
||||
}
|
||||
|
||||
@@ -229,9 +236,7 @@ where
|
||||
|
||||
#[inline]
|
||||
pub(in super::super) fn wipe(self) -> OperationResult<()> {
|
||||
match self.storage {
|
||||
Storage::Mmap(index) => index.wipe(),
|
||||
}
|
||||
self.storage.wipe()
|
||||
}
|
||||
|
||||
/// Clear cache
|
||||
@@ -239,29 +244,21 @@ where
|
||||
/// Only clears cache of mmap storage if used. Does not clear in-memory representation of
|
||||
/// index.
|
||||
pub fn clear_cache(&self) -> OperationResult<()> {
|
||||
match self.storage {
|
||||
Storage::Mmap(ref index) => index.clear_cache(),
|
||||
}
|
||||
self.storage.clear_cache()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(in super::super) fn files(&self) -> Vec<PathBuf> {
|
||||
match self.storage {
|
||||
Storage::Mmap(ref index) => index.files(),
|
||||
}
|
||||
self.storage.files()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(in super::super) fn immutable_files(&self) -> Vec<PathBuf> {
|
||||
match &self.storage {
|
||||
Storage::Mmap(index) => index.immutable_files(),
|
||||
}
|
||||
self.storage.immutable_files()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(in super::super) fn flusher(&self) -> Flusher {
|
||||
match self.storage {
|
||||
Storage::Mmap(ref index) => index.flusher(),
|
||||
}
|
||||
self.storage.flusher()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,20 @@ use std::ops::Range;
|
||||
use bitvec::vec::BitVec;
|
||||
use common::persisted_hashmap::Key;
|
||||
use common::types::PointOffsetType;
|
||||
use common::universal_io::{MmapFile, UniversalRead};
|
||||
|
||||
use super::MapIndexKey;
|
||||
use super::universal_map_index::UniversalMapIndex;
|
||||
use super::on_disk_map_index::OnDiskMapIndex;
|
||||
use crate::index::field_index::immutable_point_to_values::ImmutablePointToValues;
|
||||
|
||||
mod lifecycle;
|
||||
mod read_ops;
|
||||
|
||||
pub struct ImmutableMapIndex<N: MapIndexKey + Key + ?Sized> {
|
||||
pub struct ImmutableMapIndex<N, S = MmapFile>
|
||||
where
|
||||
N: MapIndexKey + Key + ?Sized,
|
||||
S: UniversalRead,
|
||||
{
|
||||
pub(super) value_to_points: HashMap<<N as MapIndexKey>::Owned, ContainerSegment>,
|
||||
/// Container holding a slice of point IDs per value. `value_to_point` holds the range per value.
|
||||
/// Each slice MUST be sorted so that we can binary search over it.
|
||||
@@ -23,16 +28,12 @@ pub struct ImmutableMapIndex<N: MapIndexKey + Key + ?Sized> {
|
||||
pub(super) indexed_points: usize,
|
||||
pub(super) values_count: usize,
|
||||
// Backing storage, source of state, persists deletions
|
||||
pub(super) storage: Storage<N>,
|
||||
pub(super) storage: OnDiskMapIndex<N, S>,
|
||||
/// Snapshot of approximate RAM usage at construction time.
|
||||
/// Not refreshed on `remove_point`.
|
||||
pub(super) cached_ram_usage_bytes: usize,
|
||||
}
|
||||
|
||||
pub(super) enum Storage<N: MapIndexKey + Key + ?Sized> {
|
||||
Mmap(Box<UniversalMapIndex<N>>),
|
||||
}
|
||||
|
||||
pub(super) struct ContainerSegment {
|
||||
/// Range in the container which holds point IDs for the value.
|
||||
range: Range<u32>,
|
||||
|
||||
@@ -3,17 +3,20 @@ use std::iter;
|
||||
|
||||
use common::counter::hardware_counter::HardwareCounterCell;
|
||||
use common::types::PointOffsetType;
|
||||
use common::universal_io::UniversalRead;
|
||||
use gridstore::Blob;
|
||||
|
||||
use super::super::read_ops::MapIndexRead;
|
||||
use super::super::{IdIter, MapIndexKey};
|
||||
use super::{ContainerSegment, ImmutableMapIndex, Storage};
|
||||
use super::{ContainerSegment, ImmutableMapIndex};
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::payload_config::StorageType;
|
||||
|
||||
impl<N: MapIndexKey + ?Sized> MapIndexRead<N> for ImmutableMapIndex<N>
|
||||
impl<N, S> MapIndexRead<N> for ImmutableMapIndex<N, S>
|
||||
where
|
||||
Vec<<N as MapIndexKey>::Owned>: Blob + Send + Sync,
|
||||
N: MapIndexKey + ?Sized,
|
||||
S: UniversalRead,
|
||||
{
|
||||
fn check_values_any(
|
||||
&self,
|
||||
@@ -99,11 +102,7 @@ where
|
||||
}
|
||||
|
||||
fn storage_type(&self) -> StorageType {
|
||||
match &self.storage {
|
||||
Storage::Mmap(index) => StorageType::Mmap {
|
||||
is_on_disk: index.is_on_disk(),
|
||||
},
|
||||
}
|
||||
StorageType::Mmap { is_on_disk: false }
|
||||
}
|
||||
|
||||
/// Approximate RAM usage in bytes (cached at construction).
|
||||
@@ -116,9 +115,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: MapIndexKey + ?Sized> ImmutableMapIndex<N>
|
||||
impl<N, S> ImmutableMapIndex<N, S>
|
||||
where
|
||||
Vec<<N as MapIndexKey>::Owned>: Blob + Send + Sync,
|
||||
N: MapIndexKey + ?Sized,
|
||||
S: UniversalRead,
|
||||
{
|
||||
pub fn for_points_values(
|
||||
&self,
|
||||
|
||||
@@ -7,7 +7,7 @@ use common::persisted_hashmap::Key;
|
||||
use ecow::EcoString;
|
||||
|
||||
use super::BLOCK_SIZE_KEYWORD;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::types::{IntPayloadType, UuidIntType};
|
||||
|
||||
pub trait MapIndexKey: Key + StoredValue + Eq + Display + Debug {
|
||||
|
||||
@@ -10,7 +10,7 @@ use super::builders::MapIndexMmapBuilder;
|
||||
use super::immutable_map_index::ImmutableMapIndex;
|
||||
use super::key::MapIndexKey;
|
||||
use super::mutable_map_index::MutableMapIndex;
|
||||
use super::universal_map_index::UniversalMapIndex;
|
||||
use super::on_disk_map_index::OnDiskMapIndex;
|
||||
use crate::common::Flusher;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
|
||||
@@ -19,7 +19,7 @@ where
|
||||
Vec<<N as MapIndexKey>::Owned>: Blob + Send + Sync,
|
||||
{
|
||||
/// Load immutable mmap based index, either in RAM or on disk
|
||||
pub fn new_mmap(
|
||||
pub fn new_immutable(
|
||||
path: &Path,
|
||||
is_on_disk: bool,
|
||||
deleted_points: &BitSlice,
|
||||
@@ -31,27 +31,27 @@ where
|
||||
let effective_is_on_disk =
|
||||
is_on_disk || common::low_memory::low_memory_mode().prefer_disk();
|
||||
|
||||
let Some(universal_index) =
|
||||
UniversalMapIndex::open(&MmapFs, path, effective_is_on_disk, deleted_points)?
|
||||
let Some(on_disk_index) =
|
||||
OnDiskMapIndex::open(&MmapFs, path, !effective_is_on_disk, deleted_points)?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let index = if effective_is_on_disk {
|
||||
MapIndex::OnDisk(Box::new(universal_index))
|
||||
MapIndex::OnDisk(on_disk_index)
|
||||
} else {
|
||||
// Load into RAM, use mmap as backing storage
|
||||
MapIndex::Immutable(ImmutableMapIndex::open_mmap(universal_index)?)
|
||||
MapIndex::Immutable(ImmutableMapIndex::load_from_on_disk(on_disk_index)?)
|
||||
};
|
||||
Ok(Some(index))
|
||||
}
|
||||
|
||||
pub fn new_gridstore(dir: PathBuf, create_if_missing: bool) -> OperationResult<Option<Self>> {
|
||||
pub fn new_mutable(dir: PathBuf, create_if_missing: bool) -> OperationResult<Option<Self>> {
|
||||
let index = MutableMapIndex::open_gridstore(dir, create_if_missing)?;
|
||||
Ok(index.map(MapIndex::Mutable))
|
||||
}
|
||||
|
||||
pub fn builder_mmap(
|
||||
pub fn builder_immutable(
|
||||
path: &Path,
|
||||
is_on_disk: bool,
|
||||
deleted_points: &BitSlice,
|
||||
@@ -65,7 +65,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn builder_gridstore(dir: PathBuf) -> super::builders::MapIndexGridstoreBuilder<N> {
|
||||
pub fn builder_mutable(dir: PathBuf) -> super::builders::MapIndexGridstoreBuilder<N> {
|
||||
super::builders::MapIndexGridstoreBuilder::new(dir)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ pub use self::builders::{MapIndexBuilder, MapIndexGridstoreBuilder, MapIndexMmap
|
||||
use self::immutable_map_index::ImmutableMapIndex;
|
||||
pub use self::key::MapIndexKey;
|
||||
use self::mutable_map_index::MutableMapIndex;
|
||||
use self::universal_map_index::UniversalMapIndex;
|
||||
use self::on_disk_map_index::OnDiskMapIndex;
|
||||
|
||||
mod builders;
|
||||
mod facet_index_impl;
|
||||
@@ -13,11 +13,11 @@ pub mod immutable_map_index;
|
||||
pub mod key;
|
||||
mod lifecycle;
|
||||
pub mod mutable_map_index;
|
||||
pub mod on_disk_map_index;
|
||||
mod payload_index_impl;
|
||||
pub mod read_ops;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
pub mod universal_map_index;
|
||||
mod value_indexer_impl;
|
||||
|
||||
pub mod read_only;
|
||||
@@ -40,5 +40,5 @@ where
|
||||
/// Loaded in RAM, use immutable storage format
|
||||
Immutable(ImmutableMapIndex<N>),
|
||||
/// Served directly from storage (via mmap), use immutable format
|
||||
OnDisk(Box<UniversalMapIndex<N>>),
|
||||
OnDisk(OnDiskMapIndex<N>),
|
||||
}
|
||||
|
||||
+107
-110
@@ -17,13 +17,13 @@ use fs_err as fs;
|
||||
|
||||
use super::super::MapIndexKey;
|
||||
use super::{
|
||||
CONFIG_PATH, DELETED_PATH, HASHMAP_PATH, Storage, UniversalMapIndex, UniversalMapIndexConfig,
|
||||
CONFIG_PATH, DELETED_PATH, HASHMAP_PATH, OnDiskMapIndex, Storage, UniversalMapIndexConfig,
|
||||
};
|
||||
use crate::common::Flusher;
|
||||
use crate::common::operation_error::{OperationError, OperationResult};
|
||||
use crate::index::field_index::stored_point_to_values::StoredPointToValues;
|
||||
use crate::index::field_index::on_disk_point_to_values::OnDiskPointToValues;
|
||||
|
||||
impl<N, S> UniversalMapIndex<N, S>
|
||||
impl<N, S> OnDiskMapIndex<N, S>
|
||||
where
|
||||
N: MapIndexKey + Key + ?Sized,
|
||||
S: UniversalRead,
|
||||
@@ -32,7 +32,7 @@ where
|
||||
pub fn open(
|
||||
fs: &S::Fs,
|
||||
path: &Path,
|
||||
is_on_disk: bool,
|
||||
populate: bool,
|
||||
deleted_points: &BitSlice,
|
||||
) -> OperationResult<Option<Self>> {
|
||||
let hashmap_path = path.join(HASHMAP_PATH);
|
||||
@@ -46,20 +46,18 @@ where
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let do_populate = !is_on_disk;
|
||||
|
||||
let value_to_points = UniversalHashMap::open(
|
||||
fs,
|
||||
&hashmap_path,
|
||||
OpenOptions {
|
||||
writeable: false,
|
||||
need_sequential: false,
|
||||
populate: Populate::from(do_populate),
|
||||
populate: Populate::from(populate),
|
||||
advice: AdviceSetting::Global,
|
||||
},
|
||||
Default::default(),
|
||||
)?;
|
||||
let point_to_values = StoredPointToValues::open(fs, path, do_populate)?;
|
||||
let point_to_values = OnDiskPointToValues::open(fs, path, populate)?;
|
||||
|
||||
let mut deleted = deleted_points.to_owned();
|
||||
|
||||
@@ -69,7 +67,7 @@ where
|
||||
OpenOptions {
|
||||
writeable: true,
|
||||
need_sequential: false,
|
||||
populate: Populate::from(do_populate),
|
||||
populate: Populate::from(populate),
|
||||
advice: AdviceSetting::Global,
|
||||
},
|
||||
Default::default(),
|
||||
@@ -96,7 +94,6 @@ where
|
||||
},
|
||||
deleted_count,
|
||||
total_key_value_pairs: config.total_key_value_pairs,
|
||||
is_on_disk,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -111,105 +108,6 @@ where
|
||||
self.deleted_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, S> UniversalMapIndex<N, S>
|
||||
where
|
||||
N: MapIndexKey + Key + ?Sized,
|
||||
S: UniversalWrite,
|
||||
{
|
||||
/// TODO: Use Fs to create config and hashmap files?
|
||||
pub fn build(
|
||||
fs: &S::Fs,
|
||||
path: &Path,
|
||||
point_to_values: Vec<Vec<<N as MapIndexKey>::Owned>>,
|
||||
values_to_points: HashMap<<N as MapIndexKey>::Owned, Vec<PointOffsetType>>,
|
||||
is_on_disk: bool,
|
||||
deleted_points: &BitSlice,
|
||||
) -> OperationResult<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
let hashmap_path = path.join(HASHMAP_PATH);
|
||||
let deleted_path = path.join(DELETED_PATH);
|
||||
let config_path = path.join(CONFIG_PATH);
|
||||
|
||||
atomic_save_json(
|
||||
&config_path,
|
||||
&UniversalMapIndexConfig {
|
||||
total_key_value_pairs: point_to_values.iter().map(|v| v.len()).sum(),
|
||||
},
|
||||
)?;
|
||||
|
||||
serialize_hashmap(
|
||||
&hashmap_path,
|
||||
values_to_points
|
||||
.iter()
|
||||
.map(|(value, ids)| (value.borrow(), ids.iter().copied())),
|
||||
)?;
|
||||
|
||||
StoredPointToValues::<N, MmapFile>::from_iter(
|
||||
&MmapFs,
|
||||
path,
|
||||
point_to_values.iter().enumerate().map(|(idx, values)| {
|
||||
(
|
||||
idx as PointOffsetType,
|
||||
values.iter().map(|value| value.borrow()),
|
||||
)
|
||||
}),
|
||||
)?;
|
||||
|
||||
{
|
||||
let deleted_flags_count = point_to_values.len();
|
||||
let _ = create_and_ensure_length(
|
||||
&deleted_path,
|
||||
deleted_flags_count
|
||||
.div_ceil(u8::BITS as usize)
|
||||
.next_multiple_of(size_of::<u64>()),
|
||||
)?;
|
||||
|
||||
let mut deleted = StoredBitSlice::<S>::open(
|
||||
fs,
|
||||
&deleted_path,
|
||||
OpenOptions {
|
||||
writeable: true,
|
||||
need_sequential: false,
|
||||
populate: Populate::Auto,
|
||||
advice: AdviceSetting::Global,
|
||||
},
|
||||
Default::default(),
|
||||
)?;
|
||||
deleted.set_ascending_bits_batch(
|
||||
point_to_values
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, values)| values.is_empty())
|
||||
.map(|(idx, _)| (idx as u64, true)),
|
||||
)?;
|
||||
deleted.flusher()()?;
|
||||
}
|
||||
|
||||
Self::open(fs, path, is_on_disk, deleted_points)?.ok_or_else(|| {
|
||||
OperationError::service_error("Failed to open UniversalMapIndex after building it")
|
||||
})
|
||||
}
|
||||
|
||||
/// No-op flusher: the on-disk state is build-time only. See the type-level
|
||||
/// docs on [`UniversalMapIndex`] for the deletion durability contract.
|
||||
pub fn flusher(&self) -> Flusher {
|
||||
Box::new(|| Ok(()))
|
||||
}
|
||||
|
||||
pub fn wipe(self) -> OperationResult<()> {
|
||||
let files = self.files();
|
||||
let path = self.path.clone();
|
||||
// drop mmap handles before deleting files
|
||||
drop(self);
|
||||
for file in files {
|
||||
fs::remove_file(file)?;
|
||||
}
|
||||
let _ = fs::remove_dir(path);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn files(&self) -> Vec<PathBuf> {
|
||||
let mut files = vec![
|
||||
@@ -246,7 +144,6 @@ where
|
||||
storage,
|
||||
deleted_count: _,
|
||||
total_key_value_pairs: _,
|
||||
is_on_disk: _,
|
||||
} = self;
|
||||
let Storage {
|
||||
value_to_points,
|
||||
@@ -263,3 +160,103 @@ where
|
||||
self.storage.ram_usage_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, S> OnDiskMapIndex<N, S>
|
||||
where
|
||||
N: MapIndexKey + Key + ?Sized,
|
||||
S: UniversalWrite,
|
||||
{
|
||||
/// TODO: Use Fs to create config and hashmap files?
|
||||
pub fn build(
|
||||
fs: &S::Fs,
|
||||
path: &Path,
|
||||
point_to_values: Vec<Vec<<N as MapIndexKey>::Owned>>,
|
||||
values_to_points: HashMap<<N as MapIndexKey>::Owned, Vec<PointOffsetType>>,
|
||||
populate: bool,
|
||||
deleted_points: &BitSlice,
|
||||
) -> OperationResult<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
let hashmap_path = path.join(HASHMAP_PATH);
|
||||
let deleted_path = path.join(DELETED_PATH);
|
||||
let config_path = path.join(CONFIG_PATH);
|
||||
|
||||
atomic_save_json(
|
||||
&config_path,
|
||||
&UniversalMapIndexConfig {
|
||||
total_key_value_pairs: point_to_values.iter().map(|v| v.len()).sum(),
|
||||
},
|
||||
)?;
|
||||
|
||||
serialize_hashmap(
|
||||
&hashmap_path,
|
||||
values_to_points
|
||||
.iter()
|
||||
.map(|(value, ids)| (value.borrow(), ids.iter().copied())),
|
||||
)?;
|
||||
|
||||
OnDiskPointToValues::<N, MmapFile>::build_from_iter(
|
||||
&MmapFs,
|
||||
path,
|
||||
point_to_values.iter().enumerate().map(|(idx, values)| {
|
||||
(
|
||||
idx as PointOffsetType,
|
||||
values.iter().map(|value| value.borrow()),
|
||||
)
|
||||
}),
|
||||
populate,
|
||||
)?;
|
||||
|
||||
{
|
||||
let deleted_flags_count = point_to_values.len();
|
||||
let _ = create_and_ensure_length(
|
||||
&deleted_path,
|
||||
deleted_flags_count
|
||||
.div_ceil(u8::BITS as usize)
|
||||
.next_multiple_of(size_of::<u64>()),
|
||||
)?;
|
||||
|
||||
let mut deleted = StoredBitSlice::<S>::open(
|
||||
fs,
|
||||
&deleted_path,
|
||||
OpenOptions {
|
||||
writeable: true,
|
||||
need_sequential: false,
|
||||
populate: Populate::Auto,
|
||||
advice: AdviceSetting::Global,
|
||||
},
|
||||
Default::default(),
|
||||
)?;
|
||||
deleted.set_ascending_bits_batch(
|
||||
point_to_values
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, values)| values.is_empty())
|
||||
.map(|(idx, _)| (idx as u64, true)),
|
||||
)?;
|
||||
deleted.flusher()()?;
|
||||
}
|
||||
|
||||
Self::open(fs, path, populate, deleted_points)?.ok_or_else(|| {
|
||||
OperationError::service_error("Failed to open UniversalMapIndex after building it")
|
||||
})
|
||||
}
|
||||
|
||||
/// No-op flusher: the on-disk state is build-time only. See the type-level
|
||||
/// docs on [`OnDiskMapIndex`] for the deletion durability contract.
|
||||
pub fn flusher(&self) -> Flusher {
|
||||
Box::new(|| Ok(()))
|
||||
}
|
||||
|
||||
pub fn wipe(self) -> OperationResult<()> {
|
||||
let files = self.files();
|
||||
let path = self.path.clone();
|
||||
// drop mmap handles before deleting files
|
||||
drop(self);
|
||||
for file in files {
|
||||
fs::remove_file(file)?;
|
||||
}
|
||||
let _ = fs::remove_dir(path);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,9 +5,9 @@ use common::universal_io::UniversalRead;
|
||||
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::map_index::MapIndexKey;
|
||||
use crate::index::field_index::map_index::universal_map_index::UniversalMapIndex;
|
||||
use crate::index::field_index::map_index::on_disk_map_index::OnDiskMapIndex;
|
||||
|
||||
impl<N, S> UniversalMapIndex<N, S>
|
||||
impl<N, S> OnDiskMapIndex<N, S>
|
||||
where
|
||||
N: MapIndexKey + Key + ?Sized,
|
||||
S: UniversalRead,
|
||||
+3
-7
@@ -7,7 +7,7 @@ use common::universal_io::{MmapFile, UniversalRead};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::MapIndexKey;
|
||||
use crate::index::field_index::stored_point_to_values::StoredPointToValues;
|
||||
use crate::index::field_index::on_disk_point_to_values::OnDiskPointToValues;
|
||||
|
||||
mod lifecycle;
|
||||
mod live_reload;
|
||||
@@ -19,9 +19,6 @@ pub(super) const CONFIG_PATH: &str = "mmap_field_index_config.json";
|
||||
|
||||
/// Immutable map index served directly from a [`UniversalRead`] storage backend.
|
||||
///
|
||||
/// The storage parameter `S` defaults to [`MmapFile`], but any `UniversalRead`
|
||||
/// implementation works — e.g. io_uring or disk-cache wrappers.
|
||||
///
|
||||
/// On-disk state (`values_to_points.bin`, `deleted.bin`, `point_to_values.*`,
|
||||
/// `mmap_field_index_config.json`) is written once during [`Self::build`] and
|
||||
/// not mutated afterwards: `deleted.bin` records only the points whose payload
|
||||
@@ -32,17 +29,16 @@ pub(super) const CONFIG_PATH: &str = "mmap_field_index_config.json";
|
||||
/// only updates the in-memory bitvec. Callers must re-supply the authoritative
|
||||
/// deletion set (typically `id_tracker.deleted_point_bitslice()`) via the
|
||||
/// `deleted_points` argument to [`Self::open`] on reload.
|
||||
pub struct UniversalMapIndex<N: MapIndexKey + Key + ?Sized, S: UniversalRead = MmapFile> {
|
||||
pub struct OnDiskMapIndex<N: MapIndexKey + Key + ?Sized, S: UniversalRead = MmapFile> {
|
||||
pub(super) path: PathBuf,
|
||||
pub(super) storage: Storage<N, S>,
|
||||
pub(super) deleted_count: usize,
|
||||
pub(super) total_key_value_pairs: usize,
|
||||
pub(super) is_on_disk: bool,
|
||||
}
|
||||
|
||||
pub(super) struct Storage<N: MapIndexKey + Key + ?Sized, S: UniversalRead = MmapFile> {
|
||||
pub(super) value_to_points: UniversalHashMap<N, PointOffsetType, S>,
|
||||
pub(super) point_to_values: StoredPointToValues<N, S>,
|
||||
pub(super) point_to_values: OnDiskPointToValues<N, S>,
|
||||
/// In-memory deletion bitmap. Reconstructed at load time as the union of
|
||||
/// the build-time empty-payload bits read from `deleted.bin` and the
|
||||
/// segment-level deleted bitslice supplied by the id-tracker. Not persisted.
|
||||
+13
-21
@@ -12,19 +12,19 @@ use itertools::Itertools;
|
||||
|
||||
use super::super::read_ops::MapIndexRead;
|
||||
use super::super::{IdIter, MapIndexKey};
|
||||
use super::UniversalMapIndex;
|
||||
use super::OnDiskMapIndex;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::stored_point_to_values::ValuesIter;
|
||||
use crate::index::field_index::on_disk_point_to_values::ValuesIter;
|
||||
use crate::index::payload_config::StorageType;
|
||||
|
||||
impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> MapIndexRead<N> for UniversalMapIndex<N, S> {
|
||||
impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> MapIndexRead<N> for OnDiskMapIndex<N, S> {
|
||||
fn check_values_any(
|
||||
&self,
|
||||
idx: PointOffsetType,
|
||||
hw_counter: &HardwareCounterCell,
|
||||
check_fn: impl Fn(&N) -> bool,
|
||||
) -> bool {
|
||||
let hw_counter = self.make_conditioned_counter(hw_counter);
|
||||
let hw_counter = ConditionedCounter::always(hw_counter);
|
||||
|
||||
// Measure self.deleted access.
|
||||
hw_counter
|
||||
@@ -56,7 +56,7 @@ impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> MapIndexRead<N> for Univer
|
||||
where
|
||||
N: 'a,
|
||||
{
|
||||
let hw_counter = self.make_conditioned_counter(hw_counter);
|
||||
let hw_counter = ConditionedCounter::always(hw_counter);
|
||||
|
||||
// We can account cost of reading `bool`, but it will likely be more expensive, than
|
||||
// actually reading bool itself.
|
||||
@@ -98,7 +98,7 @@ impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> MapIndexRead<N> for Univer
|
||||
}
|
||||
|
||||
fn get_count_for_value(&self, value: &N, hw_counter: &HardwareCounterCell) -> Option<usize> {
|
||||
let hw_counter = self.make_conditioned_counter(hw_counter);
|
||||
let hw_counter = ConditionedCounter::always(hw_counter);
|
||||
|
||||
// Since `value_to_points.get` doesn't actually force read from disk for all values
|
||||
// we need to only account for the overhead of hashmap lookup
|
||||
@@ -125,7 +125,7 @@ impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> MapIndexRead<N> for Univer
|
||||
}
|
||||
|
||||
fn get_iterator(&self, value: &N, hw_counter: &HardwareCounterCell) -> IdIter<'_> {
|
||||
let hw_counter = self.make_conditioned_counter(hw_counter);
|
||||
let hw_counter = ConditionedCounter::always(hw_counter);
|
||||
|
||||
match self.storage.value_to_points.unbatched_get(value) {
|
||||
Ok(Some(values)) => {
|
||||
@@ -188,7 +188,8 @@ impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> MapIndexRead<N> for Univer
|
||||
hw_counter: &HardwareCounterCell,
|
||||
mut f: impl FnMut(&N, &mut dyn Iterator<Item = PointOffsetType>) -> OperationResult<()>,
|
||||
) -> OperationResult<()> {
|
||||
let hw_counter = self.make_conditioned_counter(hw_counter);
|
||||
let hw_counter = ConditionedCounter::always(hw_counter);
|
||||
|
||||
let deleted = &self.storage.deleted;
|
||||
|
||||
self.storage.value_to_points.for_each_entry(|k, v| {
|
||||
@@ -211,9 +212,7 @@ impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> MapIndexRead<N> for Univer
|
||||
}
|
||||
|
||||
fn storage_type(&self) -> StorageType {
|
||||
StorageType::Mmap {
|
||||
is_on_disk: self.is_on_disk,
|
||||
}
|
||||
StorageType::Mmap { is_on_disk: true }
|
||||
}
|
||||
|
||||
fn ram_usage_bytes(&self) -> usize {
|
||||
@@ -225,14 +224,14 @@ impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> MapIndexRead<N> for Univer
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> UniversalMapIndex<N, S> {
|
||||
impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> OnDiskMapIndex<N, S> {
|
||||
pub fn for_points_values(
|
||||
&self,
|
||||
mut points: impl Iterator<Item = PointOffsetType>,
|
||||
hw_counter: &HardwareCounterCell,
|
||||
mut f: impl FnMut(PointOffsetType, ValuesIter<'_, N>),
|
||||
) -> OperationResult<()> {
|
||||
let hw_counter = self.make_conditioned_counter(hw_counter);
|
||||
let hw_counter = ConditionedCounter::always(hw_counter);
|
||||
|
||||
points.try_for_each(|idx| {
|
||||
if self.storage.deleted.get_bit(idx as usize) != Some(false) {
|
||||
@@ -245,14 +244,7 @@ impl<N: MapIndexKey + Key + ?Sized, S: UniversalRead> UniversalMapIndex<N, S> {
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn make_conditioned_counter<'a>(
|
||||
&self,
|
||||
hw_counter: &'a HardwareCounterCell,
|
||||
) -> ConditionedCounter<'a> {
|
||||
ConditionedCounter::new(self.is_on_disk, hw_counter)
|
||||
}
|
||||
|
||||
pub fn is_on_disk(&self) -> bool {
|
||||
self.is_on_disk
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,10 @@ use gridstore::Blob;
|
||||
|
||||
use super::super::MapIndexKey;
|
||||
use super::super::mutable_map_index::read_only::ReadOnlyAppendableMapIndex;
|
||||
use super::super::universal_map_index::UniversalMapIndex;
|
||||
use super::super::on_disk_map_index::OnDiskMapIndex;
|
||||
use super::ReadOnlyMapIndex;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::map_index::immutable_map_index::ImmutableMapIndex;
|
||||
use crate::index::payload_config::IndexMutability;
|
||||
|
||||
impl<N: MapIndexKey + ?Sized, S: UniversalRead> ReadOnlyMapIndex<N, S>
|
||||
@@ -51,10 +52,19 @@ where
|
||||
let effective_is_on_disk =
|
||||
is_on_disk || common::low_memory::low_memory_mode().prefer_disk();
|
||||
|
||||
Ok(
|
||||
UniversalMapIndex::open(fs, path, effective_is_on_disk, deleted_points)?
|
||||
.map(Self::Immutable),
|
||||
)
|
||||
let Some(on_disk_index) =
|
||||
OnDiskMapIndex::open(fs, path, !effective_is_on_disk, deleted_points)?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
if effective_is_on_disk {
|
||||
Ok(Some(Self::OnDisk(on_disk_index)))
|
||||
} else {
|
||||
Ok(Some(Self::Immutable(ImmutableMapIndex::load_from_on_disk(
|
||||
on_disk_index,
|
||||
)?)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reports the on-disk format's mutability, mirroring
|
||||
@@ -72,6 +82,7 @@ where
|
||||
match self {
|
||||
Self::Appendable(_) => IndexMutability::Mutable,
|
||||
Self::Immutable(_) => IndexMutability::Immutable,
|
||||
Self::OnDisk(_) => IndexMutability::Immutable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ use common::universal_io::UniversalRead;
|
||||
use gridstore::Blob;
|
||||
|
||||
use crate::index::field_index::map_index::MapIndexKey;
|
||||
use crate::index::field_index::map_index::immutable_map_index::ImmutableMapIndex;
|
||||
use crate::index::field_index::map_index::mutable_map_index::read_only::ReadOnlyAppendableMapIndex;
|
||||
use crate::index::field_index::map_index::universal_map_index::UniversalMapIndex;
|
||||
use crate::index::field_index::map_index::on_disk_map_index::OnDiskMapIndex;
|
||||
|
||||
mod lifecycle;
|
||||
mod read_ops;
|
||||
@@ -32,8 +33,9 @@ where
|
||||
{
|
||||
/// Loads into RAM from appendable storage format
|
||||
Appendable(ReadOnlyAppendableMapIndex<N, S>),
|
||||
Immutable(ImmutableMapIndex<N, S>),
|
||||
/// Directly reads from storage in immutable format
|
||||
Immutable(UniversalMapIndex<N, S>),
|
||||
OnDisk(OnDiskMapIndex<N, S>),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -64,7 +66,7 @@ mod tests {
|
||||
// Build via the writable gridstore builder (matches the existing map
|
||||
// tests' `IndexType::MutableGridstore` path).
|
||||
{
|
||||
let mut builder = MapIndex::<str>::builder_gridstore(dir.path().to_path_buf());
|
||||
let mut builder = MapIndex::<str>::builder_mutable(dir.path().to_path_buf());
|
||||
builder.init().unwrap();
|
||||
let entries: &[(PointOffsetType, &[&str])] = &[
|
||||
(0, &["red", "green"]),
|
||||
|
||||
@@ -32,6 +32,7 @@ where
|
||||
index.check_values_any(idx, hw_counter, check_fn)
|
||||
}
|
||||
ReadOnlyMapIndex::Immutable(index) => index.check_values_any(idx, hw_counter, check_fn),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.check_values_any(idx, hw_counter, check_fn),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +47,7 @@ where
|
||||
let boxed: Box<dyn Iterator<Item = Cow<'a, N>> + 'a> = match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => Box::new(index.get_values(idx, hw_counter)?),
|
||||
ReadOnlyMapIndex::Immutable(index) => Box::new(index.get_values(idx, hw_counter)?),
|
||||
ReadOnlyMapIndex::OnDisk(index) => Box::new(index.get_values(idx, hw_counter)?),
|
||||
};
|
||||
Some(boxed)
|
||||
}
|
||||
@@ -54,6 +56,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.values_count(idx),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.values_count(idx),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.values_count(idx),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +64,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.get_indexed_points(),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.get_indexed_points(),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.get_indexed_points(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +72,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.get_values_count(),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.get_values_count(),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.get_values_count(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +80,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.get_unique_values_count(),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.get_unique_values_count(),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.get_unique_values_count(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +88,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.get_count_for_value(value, hw_counter),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.get_count_for_value(value, hw_counter),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.get_count_for_value(value, hw_counter),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +96,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.get_iterator(value, hw_counter),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.get_iterator(value, hw_counter),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.get_iterator(value, hw_counter),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +104,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.for_each_value(f),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.for_each_value(f),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.for_each_value(f),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +120,9 @@ where
|
||||
ReadOnlyMapIndex::Immutable(index) => {
|
||||
index.for_each_count_per_value(deferred_internal_id, f)
|
||||
}
|
||||
ReadOnlyMapIndex::OnDisk(index) => {
|
||||
index.for_each_count_per_value(deferred_internal_id, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +134,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.for_each_value_map(hw_counter, f),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.for_each_value_map(hw_counter, f),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.for_each_value_map(hw_counter, f),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +142,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.storage_type(),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.storage_type(),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.storage_type(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,6 +150,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.ram_usage_bytes(),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.ram_usage_bytes(),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.ram_usage_bytes(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +158,7 @@ where
|
||||
match self {
|
||||
ReadOnlyMapIndex::Appendable(index) => index.telemetry_index_type(),
|
||||
ReadOnlyMapIndex::Immutable(index) => index.telemetry_index_type(),
|
||||
ReadOnlyMapIndex::OnDisk(index) => index.telemetry_index_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ fn save_map_index<N>(
|
||||
|
||||
match index_type {
|
||||
IndexType::MutableGridstore => {
|
||||
let mut builder = MapIndex::<N>::builder_gridstore(path.to_path_buf());
|
||||
let mut builder = MapIndex::<N>::builder_mutable(path.to_path_buf());
|
||||
builder.init().unwrap();
|
||||
for (idx, values) in data.iter().enumerate() {
|
||||
let values: Vec<Value> = values.iter().map(&into_value).collect();
|
||||
@@ -76,7 +76,7 @@ fn save_map_index<N>(
|
||||
builder.finalize().unwrap();
|
||||
}
|
||||
IndexType::Mmap | IndexType::RamMmap => {
|
||||
let mut builder = MapIndex::<N>::builder_mmap(path, false, &empty_deleted());
|
||||
let mut builder = MapIndex::<N>::builder_immutable(path, false, &empty_deleted());
|
||||
builder.init().unwrap();
|
||||
for (idx, values) in data.iter().enumerate() {
|
||||
let values: Vec<Value> = values.iter().map(&into_value).collect();
|
||||
@@ -99,13 +99,13 @@ where
|
||||
Vec<<N as MapIndexKey>::Owned>: Blob + Send + Sync,
|
||||
{
|
||||
let index = match index_type {
|
||||
IndexType::MutableGridstore => MapIndex::<N>::new_gridstore(path.to_path_buf(), true)
|
||||
IndexType::MutableGridstore => MapIndex::<N>::new_mutable(path.to_path_buf(), true)
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
IndexType::Mmap => MapIndex::<N>::new_mmap(path, true, &empty_deleted())
|
||||
IndexType::Mmap => MapIndex::<N>::new_immutable(path, true, &empty_deleted())
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
IndexType::RamMmap => MapIndex::<N>::new_mmap(path, false, &empty_deleted())
|
||||
IndexType::RamMmap => MapIndex::<N>::new_immutable(path, false, &empty_deleted())
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
};
|
||||
@@ -128,7 +128,7 @@ where
|
||||
fn test_uuid_payload_index() {
|
||||
let temp_dir = Builder::new().prefix("store_dir").tempdir().unwrap();
|
||||
let mut builder =
|
||||
MapIndex::<UuidIntType>::builder_mmap(temp_dir.path(), false, &empty_deleted());
|
||||
MapIndex::<UuidIntType>::builder_immutable(temp_dir.path(), false, &empty_deleted());
|
||||
|
||||
builder.init().unwrap();
|
||||
|
||||
@@ -152,11 +152,13 @@ fn test_uuid_payload_index() {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_index_non_ascending_insertion() {
|
||||
#[rstest]
|
||||
#[case(false)]
|
||||
#[case(true)]
|
||||
fn test_index_non_ascending_insertion(#[case] on_disk: bool) {
|
||||
let temp_dir = Builder::new().prefix("store_dir").tempdir().unwrap();
|
||||
let mut builder =
|
||||
MapIndex::<IntPayloadType>::builder_mmap(temp_dir.path(), false, &empty_deleted());
|
||||
MapIndex::<IntPayloadType>::builder_immutable(temp_dir.path(), on_disk, &empty_deleted());
|
||||
builder.init().unwrap();
|
||||
|
||||
let data = [vec![1, 2, 3, 4, 5, 6], vec![25], vec![10, 11]];
|
||||
@@ -173,13 +175,16 @@ fn test_index_non_ascending_insertion() {
|
||||
|
||||
let index = builder.finalize().unwrap();
|
||||
let hw_counter = HardwareCounterCell::new();
|
||||
for (idx, values) in data.iter().enumerate().rev() {
|
||||
let res: Vec<_> = index
|
||||
for (idx, values) in data.into_iter().enumerate().rev() {
|
||||
// values themselves don't promise any particular order
|
||||
// so we only compare the set of values.
|
||||
let values = HashSet::from_iter(values);
|
||||
let res: HashSet<_> = index
|
||||
.get_values(idx as u32, &hw_counter)
|
||||
.unwrap()
|
||||
.map(|i| *i as i32)
|
||||
.collect();
|
||||
assert_eq!(res, *values);
|
||||
assert_eq!(res, values);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,15 +352,17 @@ fn test_map_index_reload(#[case] index_type: IndexType) {
|
||||
let deleted = deleted_with(&[1, 2, 5]);
|
||||
let new_index = match index_type {
|
||||
IndexType::MutableGridstore => {
|
||||
MapIndex::<IntPayloadType>::new_gridstore(temp_dir.path().to_path_buf(), true)
|
||||
MapIndex::<IntPayloadType>::new_mutable(temp_dir.path().to_path_buf(), true)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
}
|
||||
IndexType::Mmap => {
|
||||
MapIndex::<IntPayloadType>::new_immutable(temp_dir.path(), true, &deleted)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
}
|
||||
IndexType::Mmap => MapIndex::<IntPayloadType>::new_mmap(temp_dir.path(), true, &deleted)
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
IndexType::RamMmap => {
|
||||
MapIndex::<IntPayloadType>::new_mmap(temp_dir.path(), false, &deleted)
|
||||
MapIndex::<IntPayloadType>::new_immutable(temp_dir.path(), false, &deleted)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
}
|
||||
@@ -417,12 +424,12 @@ fn test_map_index_reload_short_deleted_bitslice(#[case] index_type: IndexType) {
|
||||
|
||||
let new_index = match index_type {
|
||||
IndexType::Mmap => {
|
||||
MapIndex::<IntPayloadType>::new_mmap(temp_dir.path(), true, &short_deleted)
|
||||
MapIndex::<IntPayloadType>::new_immutable(temp_dir.path(), true, &short_deleted)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
}
|
||||
IndexType::RamMmap => {
|
||||
MapIndex::<IntPayloadType>::new_mmap(temp_dir.path(), false, &short_deleted)
|
||||
MapIndex::<IntPayloadType>::new_immutable(temp_dir.path(), false, &short_deleted)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ mod memory_reporter;
|
||||
pub mod null_index;
|
||||
pub mod numeric_index;
|
||||
mod numeric_point;
|
||||
mod on_disk_point_to_values;
|
||||
pub mod schema_transition;
|
||||
mod stat_tools;
|
||||
mod stored_point_to_values;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod utils;
|
||||
|
||||
@@ -15,7 +15,7 @@ use super::{Encodable, NumericIndex, NumericIndexIntoInnerValue};
|
||||
use crate::common::operation_error::{OperationError, OperationResult};
|
||||
use crate::index::field_index::numeric_index::immutable_numeric_index::ImmutableNumericIndex;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::field_index::{FieldIndexBuilderTrait, ValueIndexer};
|
||||
|
||||
pub struct NumericIndexBuilder<T: Encodable + Numericable + StoredValue + Send + Sync + Default, P>(
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::immutable_point_to_values::ImmutablePointToValues;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
|
||||
impl<T, S> ImmutableNumericIndex<T, S>
|
||||
where
|
||||
|
||||
@@ -8,7 +8,7 @@ use super::on_disk_numeric_index::OnDiskNumericIndex;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::immutable_point_to_values::ImmutablePointToValues;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
|
||||
mod lifecycle;
|
||||
mod read_ops;
|
||||
|
||||
@@ -11,7 +11,7 @@ use super::ImmutableNumericIndex;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::payload_config::StorageType;
|
||||
|
||||
impl<T, S> ImmutableNumericIndex<T, S>
|
||||
|
||||
@@ -17,7 +17,7 @@ use super::{
|
||||
};
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::field_index::{PayloadFieldIndex, ValueIndexer};
|
||||
use crate::index::payload_config::{IndexMutability, StorageType};
|
||||
use crate::telemetry::PayloadIndexTelemetry;
|
||||
|
||||
@@ -27,7 +27,7 @@ pub use storage::NumericIndexInner;
|
||||
pub use storage::read_only::ReadOnlyNumericIndexInner;
|
||||
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::common::Flusher;
|
||||
use crate::common::operation_error::{OperationError, OperationResult};
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
|
||||
impl<T: Encodable + Numericable> Default for InMemoryNumericIndex<T> {
|
||||
fn default() -> Self {
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ use super::ReadOnlyAppendableNumericIndex;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::payload_config::StorageType;
|
||||
|
||||
impl<T: Encodable + Numericable + Send + Sync + Default + StoredValue, S: UniversalRead>
|
||||
|
||||
@@ -10,7 +10,7 @@ use super::{InMemoryNumericIndex, MutableNumericIndex};
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::payload_config::StorageType;
|
||||
|
||||
impl<T: Encodable + Numericable + Default> InMemoryNumericIndex<T> {
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::Encodable;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::payload_config::StorageType;
|
||||
use crate::telemetry::PayloadIndexTelemetry;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ use crate::common::Flusher;
|
||||
use crate::common::operation_error::{OperationError, OperationResult};
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::{StoredPointToValues, StoredValue};
|
||||
use crate::index::field_index::on_disk_point_to_values::{OnDiskPointToValues, StoredValue};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct UniversalNumericIndexConfig {
|
||||
@@ -56,7 +56,7 @@ where
|
||||
|
||||
in_memory_index.histogram.save(path)?;
|
||||
|
||||
StoredPointToValues::<T, S>::from_iter(
|
||||
OnDiskPointToValues::<T, S>::build_from_iter(
|
||||
fs,
|
||||
path,
|
||||
in_memory_index
|
||||
@@ -64,6 +64,7 @@ where
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, values)| (idx as PointOffsetType, values.iter().map(|v| v.borrow()))),
|
||||
populate,
|
||||
)?;
|
||||
|
||||
{
|
||||
@@ -142,7 +143,7 @@ where
|
||||
};
|
||||
let pairs = TypedStorage::open(fs, pairs_path, pairs_options, Default::default())?;
|
||||
|
||||
let point_to_values = StoredPointToValues::open(fs, path, populate)?;
|
||||
let point_to_values = OnDiskPointToValues::open(fs, path, populate)?;
|
||||
let mut deleted = deleted_points.to_owned();
|
||||
|
||||
let deleted_payload_mmap = StoredBitSlice::<S>::open(
|
||||
|
||||
@@ -6,7 +6,7 @@ use common::universal_io::{MmapFile, TypedStorage, UniversalRead};
|
||||
use super::Encodable;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::{StoredPointToValues, StoredValue};
|
||||
use crate::index::field_index::on_disk_point_to_values::{OnDiskPointToValues, StoredValue};
|
||||
|
||||
mod lifecycle;
|
||||
mod read_ops;
|
||||
@@ -45,7 +45,7 @@ pub(in super::super) struct Storage<
|
||||
pub(super) deleted: BitVec,
|
||||
// sorted pairs (id + value), sorted by value (by id if values are equal)
|
||||
pub(super) pairs: TypedStorage<S, Point<T>>,
|
||||
pub(in super::super) point_to_values: StoredPointToValues<T, S>,
|
||||
pub(in super::super) point_to_values: OnDiskPointToValues<T, S>,
|
||||
}
|
||||
|
||||
impl<T: Encodable + Numericable + Default + StoredValue + 'static, S: UniversalRead> Storage<T, S> {
|
||||
|
||||
@@ -16,7 +16,7 @@ use super::OnDiskNumericIndex;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::payload_config::StorageType;
|
||||
|
||||
impl<T: Encodable + Numericable + Default + StoredValue + 'static, S: UniversalRead>
|
||||
|
||||
@@ -23,8 +23,8 @@ use super::Encodable;
|
||||
use super::numeric_index_read::NumericIndexRead;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::field_index::stat_tools::estimate_multi_value_selection_cardinality;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::utils::check_boundaries;
|
||||
use crate::index::field_index::{CardinalityEstimation, PayloadBlockCondition, PrimaryCondition};
|
||||
use crate::index::query_optimization::optimized_filter::ConditionCheckerFn;
|
||||
|
||||
@@ -10,7 +10,7 @@ use super::super::storage::read_only::ReadOnlyNumericIndexInner;
|
||||
use super::ReadOnlyNumericIndex;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::payload_config::IndexMutability;
|
||||
|
||||
impl<T: Encodable + Numericable + StoredValue + Send + Sync + Default, P, S: UniversalRead>
|
||||
|
||||
@@ -6,7 +6,7 @@ use gridstore::Blob;
|
||||
use super::Encodable;
|
||||
use super::storage::read_only::ReadOnlyNumericIndexInner;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
|
||||
mod lifecycle;
|
||||
mod read_ops;
|
||||
|
||||
@@ -15,7 +15,7 @@ use super::ReadOnlyNumericIndex;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::field_index::{
|
||||
CardinalityEstimation, PayloadBlockCondition, PayloadFieldIndexRead,
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@ use super::super::numeric_index_read::NumericIndexRead;
|
||||
use super::ReadOnlyNumericIndex;
|
||||
use crate::common::utils::MultiValue;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::query_optimization::rescore_formula::value_retriever::VariableRetrieverFn;
|
||||
use crate::types::{
|
||||
DateTimePayloadType, FloatPayloadType, IntPayloadType, UuidIntType, UuidPayloadType,
|
||||
|
||||
@@ -14,7 +14,7 @@ use serde_json::Value;
|
||||
use super::{Encodable, NumericIndex};
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::field_index::{
|
||||
CardinalityEstimation, PayloadBlockCondition, PayloadFieldIndexRead,
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ use super::NumericIndexInner;
|
||||
use crate::common::Flusher;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
|
||||
impl<T: Encodable + Numericable + StoredValue + Send + Sync + Default> NumericIndexInner<T>
|
||||
where
|
||||
|
||||
@@ -33,7 +33,7 @@ use super::immutable_numeric_index::ImmutableNumericIndex;
|
||||
use super::mutable_numeric_index::MutableNumericIndex;
|
||||
use super::on_disk_numeric_index::OnDiskNumericIndex;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
|
||||
pub enum NumericIndexInner<T: Encodable + Numericable + StoredValue + Send + Sync + Default>
|
||||
where
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::numeric_index::immutable_numeric_index::ImmutableNumericIndex;
|
||||
use crate::index::field_index::numeric_index::on_disk_numeric_index::OnDiskNumericIndex;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::payload_config::IndexMutability;
|
||||
|
||||
impl<T: Encodable + Numericable + StoredValue + Send + Sync + Default, S: UniversalRead>
|
||||
|
||||
@@ -6,7 +6,7 @@ use super::super::mutable_numeric_index::read_only::ReadOnlyAppendableNumericInd
|
||||
use super::super::on_disk_numeric_index::OnDiskNumericIndex;
|
||||
use crate::index::field_index::numeric_index::immutable_numeric_index::ImmutableNumericIndex;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
|
||||
mod lifecycle;
|
||||
mod read_ops;
|
||||
|
||||
@@ -18,7 +18,7 @@ use super::ReadOnlyNumericIndexInner;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::payload_config::StorageType;
|
||||
use crate::types::RangeInterface;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ use super::super::super::{Encodable, query};
|
||||
use super::ReadOnlyNumericIndexInner;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::field_index::{
|
||||
CardinalityEstimation, PayloadBlockCondition, PayloadFieldIndexRead,
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ use super::NumericIndexInner;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::histogram::Histogram;
|
||||
use crate::index::field_index::numeric_point::{Numericable, Point};
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::payload_config::StorageType;
|
||||
|
||||
impl<T: Encodable + Numericable + StoredValue + Send + Sync + Default> NumericIndexRead<T>
|
||||
|
||||
@@ -24,7 +24,7 @@ use super::NumericIndexInner;
|
||||
use crate::common::Flusher;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::field_index::{
|
||||
CardinalityEstimation, PayloadBlockCondition, PayloadFieldIndex, PayloadFieldIndexRead,
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ use tempfile::{Builder, TempDir};
|
||||
use super::*;
|
||||
use crate::common::operation_error::OperationResult;
|
||||
use crate::index::field_index::numeric_point::Numericable;
|
||||
use crate::index::field_index::stored_point_to_values::StoredValue;
|
||||
use crate::index::field_index::on_disk_point_to_values::StoredValue;
|
||||
use crate::index::field_index::{
|
||||
CardinalityEstimation, FieldIndexBuilderTrait, PayloadFieldIndexRead, ValueIndexer,
|
||||
};
|
||||
|
||||
+11
-8
@@ -68,7 +68,7 @@ impl StoredValue for str {
|
||||
/// This structure is immutable.
|
||||
/// It's used in mmap field indices like `UniversalMapIndex`, `UniversalNumericIndex`, etc to store points-to-values map.
|
||||
/// This structure is not generic to avoid boxing lifetimes for `&str` values.
|
||||
pub struct StoredPointToValues<T: StoredValue + ?Sized, S: UniversalRead> {
|
||||
pub struct OnDiskPointToValues<T: StoredValue + ?Sized, S: UniversalRead> {
|
||||
file_name: PathBuf,
|
||||
store: ReadOnly<S>,
|
||||
header: Header,
|
||||
@@ -92,15 +92,16 @@ struct Header {
|
||||
points_count: u64,
|
||||
}
|
||||
|
||||
impl<T, S> StoredPointToValues<T, S>
|
||||
impl<T, S> OnDiskPointToValues<T, S>
|
||||
where
|
||||
T: StoredValue + ?Sized,
|
||||
S: UniversalRead,
|
||||
{
|
||||
pub fn from_iter<'a>(
|
||||
pub fn build_from_iter<'a>(
|
||||
fs: &S::Fs,
|
||||
path: &Path,
|
||||
iter: impl Iterator<Item = (PointOffsetType, impl Iterator<Item = &'a T>)> + Clone,
|
||||
populate: bool,
|
||||
) -> OperationResult<Self>
|
||||
where
|
||||
T: 'a,
|
||||
@@ -160,7 +161,7 @@ where
|
||||
mmap.flush()?;
|
||||
drop(mmap);
|
||||
|
||||
Self::open(fs, path, true)
|
||||
Self::open(fs, path, populate)
|
||||
}
|
||||
|
||||
pub fn open(fs: &S::Fs, path: &Path, populate: bool) -> OperationResult<Self> {
|
||||
@@ -432,17 +433,18 @@ mod tests {
|
||||
.prefix("mmap_point_to_values")
|
||||
.tempdir()
|
||||
.unwrap();
|
||||
StoredPointToValues::<str, MmapFile>::from_iter(
|
||||
OnDiskPointToValues::<str, MmapFile>::build_from_iter(
|
||||
&MmapFs,
|
||||
dir.path(),
|
||||
values
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(id, values)| (id as PointOffsetType, values.iter().map(|s| s.as_str()))),
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
let point_to_values =
|
||||
StoredPointToValues::<str, MmapFile>::open(&MmapFs, dir.path(), false).unwrap();
|
||||
OnDiskPointToValues::<str, MmapFile>::open(&MmapFs, dir.path(), false).unwrap();
|
||||
|
||||
for (idx, values) in values.iter().enumerate() {
|
||||
let v = point_to_values
|
||||
@@ -493,17 +495,18 @@ mod tests {
|
||||
.prefix("mmap_point_to_values")
|
||||
.tempdir()
|
||||
.unwrap();
|
||||
StoredPointToValues::<GeoPoint, MmapFile>::from_iter(
|
||||
OnDiskPointToValues::<GeoPoint, MmapFile>::build_from_iter(
|
||||
&MmapFs,
|
||||
dir.path(),
|
||||
values
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(id, values)| (id as PointOffsetType, values.iter())),
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
let point_to_values =
|
||||
StoredPointToValues::<GeoPoint, MmapFile>::open(&MmapFs, dir.path(), false).unwrap();
|
||||
OnDiskPointToValues::<GeoPoint, MmapFile>::open(&MmapFs, dir.path(), false).unwrap();
|
||||
|
||||
for (idx, values) in values.iter().enumerate() {
|
||||
let iter = point_to_values
|
||||
Reference in New Issue
Block a user