pub struct NeighborLists { /* private fields */ }Expand description
Storage for neighbor lists (lock-free reads, thread-safe writes)
Neighbors are stored separately from nodes to improve cache utilization. Only fetch neighbors when traversing the graph.
Thread-safety:
- Reads: Lock-free via
ArcSwap(just atomic load) - Writes: Mutex-protected copy-on-write for thread-safety
Performance: Search is read-heavy, construction is write-heavy. Lock-free reads give ~40% speedup on high-dimension searches.
Implementations§
Source§impl NeighborLists
impl NeighborLists
Sourcepub fn with_capacity(num_nodes: usize, max_levels: usize, m: usize) -> Self
pub fn with_capacity(num_nodes: usize, max_levels: usize, m: usize) -> Self
Create with pre-allocated capacity and M parameter
Sourcepub fn get_neighbors(&self, node_id: u32, level: u8) -> Vec<u32>
pub fn get_neighbors(&self, node_id: u32, level: u8) -> Vec<u32>
Get neighbors for a node at a specific level (lock-free)
Returns a cloned Vec. For iteration without allocation, use with_neighbors.
Sourcepub fn with_neighbors<F, R>(&self, node_id: u32, level: u8, f: F) -> R
pub fn with_neighbors<F, R>(&self, node_id: u32, level: u8, f: F) -> R
Execute a closure with read access to neighbors (LOCK-FREE, zero-copy)
This is the hot path for search - just an atomic load, no locking.
~40% faster than RwLock at high dimensions (1536D+).
Sourcepub fn prefetch(&self, node_id: u32, level: u8)
pub fn prefetch(&self, node_id: u32, level: u8)
Prefetch neighbor list into CPU cache
Hints to CPU that we’ll need the neighbor data soon. This hides memory latency by overlapping data fetch with computation. Only beneficial on x86/ARM servers - Apple Silicon’s DMP handles this automatically.
Sourcepub fn set_neighbors(
&mut self,
node_id: u32,
level: u8,
neighbors_list: Vec<u32>,
)
pub fn set_neighbors( &mut self, node_id: u32, level: u8, neighbors_list: Vec<u32>, )
Set neighbors for a node at a specific level
Sourcepub fn add_bidirectional_link(&mut self, node_a: u32, node_b: u32, level: u8)
pub fn add_bidirectional_link(&mut self, node_a: u32, node_b: u32, level: u8)
Add a bidirectional link between two nodes at a level
Thread-safe with deadlock prevention via ordered locking. Uses copy-on-write for lock-free reads during search.
Sourcepub fn add_bidirectional_link_parallel(
&self,
node_a: u32,
node_b: u32,
level: u8,
)
pub fn add_bidirectional_link_parallel( &self, node_a: u32, node_b: u32, level: u8, )
Add bidirectional link (thread-safe version for parallel construction)
Assumes nodes are already allocated. Uses mutex + copy-on-write. Only for use during parallel graph construction where all nodes pre-exist.
Sourcepub fn remove_link_parallel(&self, node_a: u32, node_b: u32, level: u8)
pub fn remove_link_parallel(&self, node_a: u32, node_b: u32, level: u8)
Remove unidirectional link (thread-safe version for parallel construction)
Removes link from node_a to node_b (NOT bidirectional).
Uses mutex + copy-on-write for thread-safety.
Sourcepub fn set_neighbors_parallel(
&self,
node_id: u32,
level: u8,
neighbors_list: Vec<u32>,
)
pub fn set_neighbors_parallel( &self, node_id: u32, level: u8, neighbors_list: Vec<u32>, )
Set neighbors (thread-safe version for parallel construction)
Assumes node is already allocated. Uses mutex for thread-safety.
Sourcepub fn total_neighbors(&self) -> usize
pub fn total_neighbors(&self) -> usize
Get total number of neighbor entries
Sourcepub fn memory_usage(&self) -> usize
pub fn memory_usage(&self) -> usize
Get memory usage in bytes (approximate)
Sourcepub fn reorder_bfs(&mut self, entry_point: u32, start_level: u8) -> Vec<u32>
pub fn reorder_bfs(&mut self, entry_point: u32, start_level: u8) -> Vec<u32>
Reorder nodes using BFS for cache locality
This improves cache performance by placing frequently-accessed neighbors close together in memory. Uses BFS from the entry point to determine ordering.
Returns a mapping from old_id -> new_id
Trait Implementations§
Source§impl Debug for NeighborLists
impl Debug for NeighborLists
Source§impl<'de> Deserialize<'de> for NeighborLists
impl<'de> Deserialize<'de> for NeighborLists
Source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for NeighborLists
impl !RefUnwindSafe for NeighborLists
impl Send for NeighborLists
impl Sync for NeighborLists
impl Unpin for NeighborLists
impl UnwindSafe for NeighborLists
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more