use crate::store::numeric_encoder::*; use crate::store::*; use crate::{Repository, Result}; use failure::{Backtrace, Fail}; use std::collections::{BTreeMap, BTreeSet}; use std::iter::{empty, once}; use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}; /// Memory based implementation of the `Repository` trait. /// They are cheap to build using the `MemoryRepository::default()` method. /// /// Usage example: /// ``` /// use oxigraph::model::*; /// use oxigraph::{Repository, RepositoryConnection, MemoryRepository, Result}; /// use crate::oxigraph::sparql::PreparedQuery; /// use oxigraph::sparql::{QueryResult, QueryOptions}; /// /// let repository = MemoryRepository::default(); /// let mut connection = repository.connection().unwrap(); /// /// // insertion /// let ex = NamedNode::parse("http://example.com").unwrap(); /// let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None); /// connection.insert(&quad); /// /// // quad filter /// let results: Result> = connection.quads_for_pattern(None, None, None, None).collect(); /// assert_eq!(vec![quad], results.unwrap()); /// /// // SPARQL query /// let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default()).unwrap(); /// let results = prepared_query.exec().unwrap(); /// if let QueryResult::Bindings(results) = results { /// assert_eq!(results.into_values_iter().next().unwrap().unwrap()[0], Some(ex.into())); /// } /// ``` #[derive(Default)] pub struct MemoryRepository { inner: MemoryStore, } pub type MemoryRepositoryConnection<'a> = StoreRepositoryConnection<&'a MemoryStore>; type TripleMap = BTreeMap>>; type QuadMap = BTreeMap>; #[derive(Default)] pub struct MemoryStore { indexes: RwLock, } #[derive(Default)] struct MemoryStoreIndexes { spog: QuadMap, posg: QuadMap, ospg: QuadMap, gspo: QuadMap, gpos: QuadMap, gosp: QuadMap, str_store: MemoryStrStore, } impl<'a> Repository for &'a MemoryRepository { type Connection = MemoryRepositoryConnection<'a>; fn connection(self) -> Result> { Ok(self.inner.connection()?.into()) } } impl<'a> Store for &'a MemoryStore { type Connection = &'a MemoryStore; fn connection(self) -> Result { Ok(self) } } impl<'a> StrLookup for &'a MemoryStore { fn get_str(&self, id: u128) -> Result> { self.indexes()?.str_store.get_str(id) } } impl<'a> StrContainer for &'a MemoryStore { fn insert_str(&mut self, key: u128, value: &str) -> Result<()> { self.indexes_mut()?.str_store.insert_str(key, value) } } impl<'a> StoreConnection for &'a MemoryStore { type Transaction = &'a MemoryStore; fn transaction(&self) -> Result<&'a MemoryStore> { Ok(self) } fn contains(&self, quad: &EncodedQuad) -> Result { Ok(self .indexes()? .spog .get(&quad.subject) .map_or(false, |pog| { pog.get(&quad.predicate).map_or(false, |og| { og.get(&quad.object) .map_or(false, |g| g.contains(&quad.graph_name)) }) })) } fn quads_for_pattern<'b>( &'b self, subject: Option, predicate: Option, object: Option, graph_name: Option, ) -> Box> + 'b> { match subject { Some(subject) => match predicate { Some(predicate) => match object { Some(object) => match graph_name { Some(graph_name) => { let quad = EncodedQuad::new(subject, predicate, object, graph_name); match self.contains(&quad) { Ok(true) => Box::new(once(Ok(quad))), Ok(false) => Box::new(empty()), Err(error) => Box::new(once(Err(error))), } } None => wrap_error( self.quads_for_subject_predicate_object(subject, predicate, object), ), }, None => match graph_name { Some(graph_name) => wrap_error( self.quads_for_subject_predicate_graph(subject, predicate, graph_name), ), None => wrap_error(self.quads_for_subject_predicate(subject, predicate)), }, }, None => match object { Some(object) => match graph_name { Some(graph_name) => wrap_error( self.quads_for_subject_object_graph(subject, object, graph_name), ), None => wrap_error(self.quads_for_subject_object(subject, object)), }, None => match graph_name { Some(graph_name) => { wrap_error(self.quads_for_subject_graph(subject, graph_name)) } None => wrap_error(self.quads_for_subject(subject)), }, }, }, None => match predicate { Some(predicate) => match object { Some(object) => match graph_name { Some(graph_name) => wrap_error( self.quads_for_predicate_object_graph(predicate, object, graph_name), ), None => wrap_error(self.quads_for_predicate_object(predicate, object)), }, None => match graph_name { Some(graph_name) => { wrap_error(self.quads_for_predicate_graph(predicate, graph_name)) } None => wrap_error(self.quads_for_predicate(predicate)), }, }, None => match object { Some(object) => match graph_name { Some(graph_name) => { wrap_error(self.quads_for_object_graph(object, graph_name)) } None => wrap_error(self.quads_for_object(object)), }, None => match graph_name { Some(graph_name) => wrap_error(self.quads_for_graph(graph_name)), None => wrap_error(self.quads()), }, }, }, } } } /// TODO: implement properly impl<'a> StoreTransaction for &'a MemoryStore { fn insert(&mut self, quad: &EncodedQuad) -> Result<()> { let mut quad_indexes = self.indexes_mut()?; insert_into_quad_map( &mut quad_indexes.gosp, quad.graph_name, quad.object, quad.subject, quad.predicate, ); insert_into_quad_map( &mut quad_indexes.gpos, quad.graph_name, quad.predicate, quad.object, quad.subject, ); insert_into_quad_map( &mut quad_indexes.gspo, quad.graph_name, quad.subject, quad.predicate, quad.object, ); insert_into_quad_map( &mut quad_indexes.ospg, quad.object, quad.subject, quad.predicate, quad.graph_name, ); insert_into_quad_map( &mut quad_indexes.posg, quad.predicate, quad.object, quad.subject, quad.graph_name, ); insert_into_quad_map( &mut quad_indexes.spog, quad.subject, quad.predicate, quad.object, quad.graph_name, ); Ok(()) } fn remove(&mut self, quad: &EncodedQuad) -> Result<()> { let mut quad_indexes = self.indexes_mut()?; remove_from_quad_map( &mut quad_indexes.gosp, &quad.graph_name, &quad.object, &quad.subject, &quad.predicate, ); remove_from_quad_map( &mut quad_indexes.gpos, &quad.graph_name, &quad.predicate, &quad.object, &quad.subject, ); remove_from_quad_map( &mut quad_indexes.gspo, &quad.graph_name, &quad.subject, &quad.predicate, &quad.object, ); remove_from_quad_map( &mut quad_indexes.ospg, &quad.object, &quad.subject, &quad.predicate, &quad.graph_name, ); remove_from_quad_map( &mut quad_indexes.posg, &quad.predicate, &quad.object, &quad.subject, &quad.graph_name, ); remove_from_quad_map( &mut quad_indexes.spog, &quad.subject, &quad.predicate, &quad.object, &quad.graph_name, ); Ok(()) } fn commit(self) -> Result<()> { Ok(()) } } impl MemoryStore { fn indexes(&self) -> Result> { Ok(self.indexes.read().map_err(MutexPoisonError::from)?) } fn indexes_mut(&self) -> Result> { Ok(self.indexes.write().map_err(MutexPoisonError::from)?) } fn quads<'a>(&'a self) -> Result> + 'a> { Ok(quad_map_flatten(&self.indexes()?.gspo) .map(|(g, s, p, o)| Ok(EncodedQuad::new(s, p, o, g))) .collect::>() .into_iter()) } fn quads_for_subject( &self, subject: EncodedTerm, ) -> Result>> { Ok( option_triple_map_flatten(self.indexes()?.spog.get(&subject)) .map(|(p, o, g)| Ok(EncodedQuad::new(subject, p, o, g))) .collect::>() .into_iter(), ) } fn quads_for_subject_predicate( &self, subject: EncodedTerm, predicate: EncodedTerm, ) -> Result>> { Ok(option_pair_map_flatten( self.indexes()? .spog .get(&subject) .and_then(|pog| pog.get(&predicate)), ) .map(|(o, g)| Ok(EncodedQuad::new(subject, predicate, o, g))) .collect::>() .into_iter()) } fn quads_for_subject_predicate_object( &self, subject: EncodedTerm, predicate: EncodedTerm, object: EncodedTerm, ) -> Result>> { Ok(option_set_flatten( self.indexes()? .spog .get(&subject) .and_then(|pog| pog.get(&predicate)) .and_then(|og| og.get(&object)), ) .map(|g| Ok(EncodedQuad::new(subject, predicate, object, g))) .collect::>() .into_iter()) } fn quads_for_subject_object( &self, subject: EncodedTerm, object: EncodedTerm, ) -> Result>> { Ok(option_pair_map_flatten( self.indexes()? .ospg .get(&object) .and_then(|spg| spg.get(&subject)), ) .map(|(p, g)| Ok(EncodedQuad::new(subject, p, object, g))) .collect::>() .into_iter()) } fn quads_for_predicate( &self, predicate: EncodedTerm, ) -> Result>> { Ok( option_triple_map_flatten(self.indexes()?.posg.get(&predicate)) .map(|(o, s, g)| Ok(EncodedQuad::new(s, predicate, o, g))) .collect::>() .into_iter(), ) } fn quads_for_predicate_object( &self, predicate: EncodedTerm, object: EncodedTerm, ) -> Result>> { Ok(option_pair_map_flatten( self.indexes()? .posg .get(&predicate) .and_then(|osg| osg.get(&object)), ) .map(|(s, g)| Ok(EncodedQuad::new(s, predicate, object, g))) .collect::>() .into_iter()) } fn quads_for_object( &self, object: EncodedTerm, ) -> Result>> { Ok(option_triple_map_flatten(self.indexes()?.ospg.get(&object)) .map(|(s, p, g)| Ok(EncodedQuad::new(s, p, object, g))) .collect::>() .into_iter()) } fn quads_for_graph( &self, graph_name: EncodedTerm, ) -> Result>> { Ok( option_triple_map_flatten(self.indexes()?.gspo.get(&graph_name)) .map(|(s, p, o)| Ok(EncodedQuad::new(s, p, o, graph_name))) .collect::>() .into_iter(), ) } fn quads_for_subject_graph( &self, subject: EncodedTerm, graph_name: EncodedTerm, ) -> Result>> { Ok(option_pair_map_flatten( self.indexes()? .gspo .get(&graph_name) .and_then(|spo| spo.get(&subject)), ) .map(|(p, o)| Ok(EncodedQuad::new(subject, p, o, graph_name))) .collect::>() .into_iter()) } fn quads_for_subject_predicate_graph( &self, subject: EncodedTerm, predicate: EncodedTerm, graph_name: EncodedTerm, ) -> Result>> { Ok(option_set_flatten( self.indexes()? .gspo .get(&graph_name) .and_then(|spo| spo.get(&subject)) .and_then(|po| po.get(&predicate)), ) .map(|o| Ok(EncodedQuad::new(subject, predicate, o, graph_name))) .collect::>() .into_iter()) } fn quads_for_subject_object_graph( &self, subject: EncodedTerm, object: EncodedTerm, graph_name: EncodedTerm, ) -> Result>> { Ok(option_set_flatten( self.indexes()? .gosp .get(&graph_name) .and_then(|osp| osp.get(&object)) .and_then(|sp| sp.get(&subject)), ) .map(|p| Ok(EncodedQuad::new(subject, p, object, graph_name))) .collect::>() .into_iter()) } fn quads_for_predicate_graph( &self, predicate: EncodedTerm, graph_name: EncodedTerm, ) -> Result>> { Ok(option_pair_map_flatten( self.indexes()? .gpos .get(&graph_name) .and_then(|pos| pos.get(&predicate)), ) .map(|(o, s)| Ok(EncodedQuad::new(s, predicate, o, graph_name))) .collect::>() .into_iter()) } fn quads_for_predicate_object_graph( &self, predicate: EncodedTerm, object: EncodedTerm, graph_name: EncodedTerm, ) -> Result>> { Ok(option_set_flatten( self.indexes()? .gpos .get(&graph_name) .and_then(|pos| pos.get(&predicate)) .and_then(|os| os.get(&object)), ) .map(|s| Ok(EncodedQuad::new(s, predicate, object, graph_name))) .collect::>() .into_iter()) } fn quads_for_object_graph( &self, object: EncodedTerm, graph_name: EncodedTerm, ) -> Result>> { Ok(option_pair_map_flatten( self.indexes()? .gosp .get(&graph_name) .and_then(|osp| osp.get(&object)), ) .map(|(s, p)| Ok(EncodedQuad::new(s, p, object, graph_name))) .collect::>() .into_iter()) } } fn wrap_error<'a, E: 'static, I: Iterator> + 'a>( iter: Result, ) -> Box> + 'a> { match iter { Ok(iter) => Box::new(iter), Err(error) => Box::new(once(Err(error))), } } fn insert_into_quad_map(map: &mut QuadMap, e1: T, e2: T, e3: T, e4: T) { map.entry(e1) .or_default() .entry(e2) .or_default() .entry(e3) .or_default() .insert(e4); } fn remove_from_quad_map(map1: &mut QuadMap, e1: &T, e2: &T, e3: &T, e4: &T) { let mut map2empty = false; if let Some(map2) = map1.get_mut(e1) { let mut map3empty = false; if let Some(map3) = map2.get_mut(e2) { let mut set4empty = false; if let Some(set4) = map3.get_mut(e3) { set4.remove(e4); set4empty = set4.is_empty(); } if set4empty { map3.remove(e3); } map3empty = map3.is_empty(); } if map3empty { map2.remove(e2); } map2empty = map2.is_empty(); } if map2empty { map1.remove(e1); } } fn option_set_flatten<'a, T: Clone>(i: Option<&'a BTreeSet>) -> impl Iterator + 'a { i.into_iter().flat_map(|s| s.iter().cloned()) } fn option_pair_map_flatten<'a, T: Copy>( i: Option<&'a BTreeMap>>, ) -> impl Iterator + 'a { i.into_iter().flat_map(|kv| { kv.iter().flat_map(|(k, vs)| { let k = *k; vs.iter().map(move |v| (k, *v)) }) }) } fn option_triple_map_flatten<'a, T: Copy>( i: Option<&'a TripleMap>, ) -> impl Iterator + 'a { i.into_iter().flat_map(|spo| { spo.iter().flat_map(|(s, po)| { let s = *s; po.iter().flat_map(move |(p, os)| { let p = *p; os.iter().map(move |o| (s, p, *o)) }) }) }) } fn quad_map_flatten<'a, T: Copy>(gspo: &'a QuadMap) -> impl Iterator + 'a { gspo.iter().flat_map(|(g, spo)| { let g = *g; spo.iter().flat_map(move |(s, po)| { let s = *s; po.iter().flat_map(move |(p, os)| { let p = *p; os.iter().map(move |o| (g, s, p, *o)) }) }) }) } #[derive(Debug, Fail)] #[fail(display = "Mutex Mutex was poisoned")] pub struct MutexPoisonError { backtrace: Backtrace, } impl From> for MutexPoisonError { fn from(_: PoisonError) -> Self { Self { backtrace: Backtrace::new(), } } }