mod handle;
mod ops;
mod shard_read;
use std::sync::Arc;
use rayon::prelude::*;
use rayon::{ThreadPool, ThreadPoolBuilder};
use crate::segment::common::operation_error::{OperationError, OperationResult};
pub use self::handle::ReadSegmentHandle;
pub use self::ops::{Group, SearchMatrixResponse, ShardInfo};
pub use self::shard_read::EdgeShardRead;
pub(crate) use self::shard_read::ReadViewProvider;
use crate::edge::EdgeConfig;
pub struct EdgeReadView<H: ReadSegmentHandle> {
pub(crate) segments: Vec<H>,
pub(crate) config: Arc<EdgeConfig>,
pub(crate) pool: Arc<ThreadPool>,
}
impl<H: ReadSegmentHandle> EdgeReadView<H> {
pub(crate) fn new(segments: Vec<H>, config: Arc<EdgeConfig>, pool: Arc<ThreadPool>) -> Self {
Self {
segments,
config,
pool,
}
}
pub(crate) fn segment_arcs(&self) -> Vec<Arc<parking_lot::RwLock<H::Segment>>> {
self.segments
.iter()
.map(ReadSegmentHandle::segment_arc)
.collect()
}
pub(crate) fn par_map_segments<R, F>(&self, f: F) -> OperationResult<Vec<R>>
where
F: Fn(&H) -> OperationResult<R> + Send + Sync,
R: Send,
{
self.pool
.install(|| self.segments.par_iter().map(f).collect())
}
}
pub(crate) fn build_segment_pool(
thread_name_prefix: &'static str,
num_threads: usize,
pin_core: Option<usize>,
) -> OperationResult<Arc<ThreadPool>> {
let pin_core = pin_core.filter(|core| {
let available =
core_affinity::get_core_ids().is_some_and(|ids| ids.iter().any(|c| c.id == *core));
if !available {
log::warn!(
"{thread_name_prefix} pool core {core} is not available; leaving threads unpinned"
);
}
available
});
let mut builder = ThreadPoolBuilder::new()
.num_threads(num_threads)
.thread_name(move |idx| format!("{thread_name_prefix}-{idx}"));
if let Some(core) = pin_core {
builder = builder.start_handler(move |idx| {
if !core_affinity::set_for_current(core_affinity::CoreId { id: core }) {
log::warn!("failed to pin edge {thread_name_prefix} thread {idx} to core {core}");
}
});
}
let pool = builder.build().map_err(|err| {
OperationError::service_error(format!(
"failed to build edge {thread_name_prefix} thread pool: {err}"
))
})?;
Ok(Arc::new(pool))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pinned_pool_builds_and_runs() {
let pool = build_segment_pool("edge-search", 2, Some(0)).unwrap();
let sum: i32 = pool.install(|| (0..4).sum());
assert_eq!(sum, 6);
let pool = build_segment_pool("edge-search", 1, Some(usize::MAX)).unwrap();
assert_eq!(pool.install(|| 1 + 1), 2);
}
}