use super::*;
use std::sync::atomic::Ordering;
#[path = "edge_query_support/io_support.rs"]
mod io_support;
#[path = "edge_query_support/weighted_support.rs"]
mod weighted_support;
impl V3EdgeStore {
pub fn btree_lock(&self) -> &Arc<parking_lot::RwLock<BTreeManager>> {
&self.btree
}
pub fn cache_lock(&self) -> &Arc<RwLock<HashMap<(i64, Direction), Arc<[i64]>>>> {
&self.cache
}
pub fn cache_weighted_lock(
&self,
) -> &Arc<RwLock<HashMap<(i64, Direction), Arc<[(i64, f32)]>>>> {
&self.cache_weighted
}
pub fn edge_types_lock(&self) -> &Arc<RwLock<HashMap<(i64, i64, Direction), String>>> {
&self.edge_types
}
pub fn page_size(&self) -> u64 {
self.page_size as u64
}
pub fn set_file_coordinator(&mut self, coordinator: Arc<FileCoordinator>) {
self.btree.write().set_file_coordinator(coordinator.clone());
self.file_coordinator = Some(coordinator);
}
pub fn neighbors(&self, src: i64, dir: Direction) -> NativeResult<Arc<[i64]>> {
let key = (src, dir);
#[cfg(feature = "v3-forensics")]
FORENSIC_COUNTERS
.logical_neighbors_calls
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
{
let cache = self.cache.read();
if let Some(neighbors) = cache.get(&key) {
self.cache_hits.fetch_add(1, Ordering::Relaxed);
#[cfg(feature = "v3-forensics")]
FORENSIC_COUNTERS
.edge_cache_hit_count
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
return Ok(neighbors.clone()); }
}
self.cache_misses.fetch_add(1, Ordering::Relaxed);
#[cfg(feature = "v3-forensics")]
FORENSIC_COUNTERS
.edge_cache_miss_count
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
if let Some(ref db_path) = self.db_path
&& let Ok(neighbors) = self.load_neighbors_from_disk(src, dir, db_path)
{
#[cfg(feature = "v3-forensics")]
if !neighbors.is_empty() {
FORENSIC_COUNTERS
.edge_page_read_count
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}
if !neighbors.is_empty() {
let mut cache = self.cache.write();
cache.insert(key, neighbors.clone());
return Ok(neighbors);
}
}
Ok(Arc::from([])) }
pub(crate) fn load_neighbors_from_disk(
&self,
src: i64,
dir: Direction,
db_path: &Path,
) -> NativeResult<Arc<[i64]>> {
let key = edge_key(src, dir);
let btree = self.btree.read();
let page_id = match btree.lookup(key) {
Ok(Some(pid)) => pid,
Ok(None) => {
return Ok(Arc::from([]));
}
Err(_) => {
return Ok(Arc::from([]));
}
};
drop(btree);
match self.load_cluster_from_disk(page_id, src, dir, db_path) {
Ok(cluster) => {
let edges_with_types = cluster.edges_with_types();
let mut edge_types = self.edge_types.write();
for (dst, edge_type) in edges_with_types {
if let Some(et) = edge_type {
edge_types.insert((src, dst, dir), et);
}
}
let neighbors: Vec<i64> = cluster.dsts();
Ok(Arc::from(neighbors.into_boxed_slice()))
}
Err(_) => Ok(Arc::from([])),
}
}
pub fn outgoing(&self, src: i64) -> NativeResult<Arc<[i64]>> {
self.neighbors(src, Direction::Outgoing)
}
pub fn incoming(&self, src: i64) -> NativeResult<Arc<[i64]>> {
self.neighbors(src, Direction::Incoming)
}
pub fn neighbors_filtered(
&self,
src: i64,
dir: Direction,
edge_type: &str,
) -> NativeResult<Arc<[i64]>> {
let all_neighbors = self.neighbors(src, dir)?;
let edge_types = self.edge_types.read();
let filtered: Vec<i64> = all_neighbors
.iter()
.filter(|&&dst| {
edge_types
.get(&(src, dst, dir))
.map(|stored_type| stored_type == edge_type)
.unwrap_or(false)
})
.copied()
.collect();
Ok(Arc::from(filtered.into_boxed_slice()))
}
pub fn get_edge_type(&self, src: i64, dst: i64, dir: Direction) -> Option<String> {
let edge_types = self.edge_types.read();
edge_types.get(&(src, dst, dir)).cloned()
}
}