diff --git a/lib/src/sparql/dataset.rs b/lib/src/sparql/dataset.rs index 77871ee3..6c5e45e7 100644 --- a/lib/src/sparql/dataset.rs +++ b/lib/src/sparql/dataset.rs @@ -199,7 +199,7 @@ impl ReadableEncodedStore for DatasetView } impl<'a, S: ReadableEncodedStore> StrContainer for &'a DatasetView { - fn insert_str(&mut self, value: &str) -> Result { + fn insert_str(&self, value: &str) -> Result { if let Some(hash) = self.store.get_str_id(value).map_err(|e| e.into())? { Ok(hash) } else { diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index 05946a27..4a41553c 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -1377,7 +1377,7 @@ where } else { None }?; - let mut encoder = self.dataset.as_ref(); + let encoder = self.dataset.as_ref(); encoder .encode_literal(LiteralRef::new_typed_literal( &value, @@ -1823,7 +1823,7 @@ where ) -> EncodedTuplesIterator { let eval = self.clone(); Box::new(iter.map(move |solution| { - let mut encoder = eval.dataset.as_ref(); + let encoder = eval.dataset.as_ref(); let mut encoded_terms = EncodedTuple::with_capacity(variables.len()); for (variable, term) in solution?.iter() { put_variable_value( diff --git a/lib/src/store/binary_encoder.rs b/lib/src/store/binary_encoder.rs index d989c39a..3b5abfe1 100644 --- a/lib/src/store/binary_encoder.rs +++ b/lib/src/store/binary_encoder.rs @@ -630,17 +630,11 @@ mod tests { use crate::store::numeric_encoder::*; use std::collections::HashMap; use std::convert::Infallible; + use std::sync::RwLock; + #[derive(Default)] struct MemoryStrStore { - id2str: HashMap, - } - - impl Default for MemoryStrStore { - fn default() -> Self { - Self { - id2str: HashMap::default(), - } - } + id2str: RwLock>, } impl StrEncodingAware for MemoryStrStore { @@ -649,12 +643,12 @@ mod tests { impl StrLookup for MemoryStrStore { fn get_str(&self, id: StrHash) -> Result, Infallible> { - Ok(self.id2str.get(&id).cloned()) + Ok(self.id2str.read().unwrap().get(&id).cloned()) } fn get_str_id(&self, value: &str) -> Result, Infallible> { let id = StrHash::new(value); - Ok(if self.id2str.contains_key(&id) { + Ok(if self.id2str.read().unwrap().contains_key(&id) { Some(id) } else { None @@ -663,9 +657,13 @@ mod tests { } impl StrContainer for MemoryStrStore { - fn insert_str(&mut self, value: &str) -> Result { + fn insert_str(&self, value: &str) -> Result { let key = StrHash::new(value); - self.id2str.entry(key).or_insert_with(|| value.to_owned()); + self.id2str + .write() + .unwrap() + .entry(key) + .or_insert_with(|| value.to_owned()); Ok(key) } } @@ -675,7 +673,7 @@ mod tests { use crate::model::vocab::xsd; use crate::model::*; - let mut store = MemoryStrStore::default(); + let store = MemoryStrStore::default(); let terms: Vec = vec![ NamedNode::new_unchecked("http://foo.com").into(), NamedNode::new_unchecked("http://bar.com").into(), diff --git a/lib/src/store/numeric_encoder.rs b/lib/src/store/numeric_encoder.rs index 73b6ca1d..0216d5a3 100644 --- a/lib/src/store/numeric_encoder.rs +++ b/lib/src/store/numeric_encoder.rs @@ -502,7 +502,7 @@ pub(crate) trait StrLookup: StrEncodingAware { } pub(crate) trait StrContainer: StrEncodingAware { - fn insert_str(&mut self, value: &str) -> Result; + fn insert_str(&self, value: &str) -> Result; } /// Tries to encode a term based on the existing strings (does not insert anything) @@ -744,17 +744,11 @@ impl ReadEncoder for S { /// Encodes a term and insert strings if needed pub(crate) trait WriteEncoder: StrEncodingAware { - fn encode_named_node( - &mut self, - named_node: NamedNodeRef<'_>, - ) -> Result { + fn encode_named_node(&self, named_node: NamedNodeRef<'_>) -> Result { self.encode_rio_named_node(named_node.into()) } - fn encode_blank_node( - &mut self, - blank_node: BlankNodeRef<'_>, - ) -> Result { + fn encode_blank_node(&self, blank_node: BlankNodeRef<'_>) -> Result { Ok(if let Some(id) = blank_node.id() { EncodedTerm::NumericalBlankNode { id } } else { @@ -769,12 +763,12 @@ pub(crate) trait WriteEncoder: StrEncodingAware { }) } - fn encode_literal(&mut self, literal: LiteralRef<'_>) -> Result { + fn encode_literal(&self, literal: LiteralRef<'_>) -> Result { self.encode_rio_literal(literal.into()) } fn encode_named_or_blank_node( - &mut self, + &self, term: NamedOrBlankNodeRef<'_>, ) -> Result { match term { @@ -783,7 +777,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } } - fn encode_term(&mut self, term: TermRef<'_>) -> Result { + fn encode_term(&self, term: TermRef<'_>) -> Result { match term { TermRef::NamedNode(named_node) => self.encode_named_node(named_node), TermRef::BlankNode(blank_node) => self.encode_blank_node(blank_node), @@ -791,7 +785,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } } - fn encode_graph_name(&mut self, name: GraphNameRef<'_>) -> Result { + fn encode_graph_name(&self, name: GraphNameRef<'_>) -> Result { match name { GraphNameRef::NamedNode(named_node) => self.encode_named_node(named_node), GraphNameRef::BlankNode(blank_node) => self.encode_blank_node(blank_node), @@ -799,7 +793,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } } - fn encode_quad(&mut self, quad: QuadRef<'_>) -> Result { + fn encode_quad(&self, quad: QuadRef<'_>) -> Result { Ok(EncodedQuad { subject: self.encode_named_or_blank_node(quad.subject)?, predicate: self.encode_named_node(quad.predicate)?, @@ -809,7 +803,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } fn encode_triple_in_graph( - &mut self, + &self, triple: TripleRef<'_>, graph_name: EncodedTerm, ) -> Result { @@ -822,7 +816,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } fn encode_rio_named_node( - &mut self, + &self, named_node: rio::NamedNode<'_>, ) -> Result { Ok(EncodedTerm::NamedNode { @@ -831,7 +825,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } fn encode_rio_blank_node( - &mut self, + &self, blank_node: rio::BlankNode<'_>, bnodes_map: &mut HashMap, ) -> Result { @@ -843,10 +837,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { EncodedTerm::NumericalBlankNode { id } }) } - fn encode_rio_literal( - &mut self, - literal: rio::Literal<'_>, - ) -> Result { + fn encode_rio_literal(&self, literal: rio::Literal<'_>) -> Result { Ok(match literal { rio::Literal::Simple { value } => { if let Ok(value) = SmallString::try_from(value) { @@ -949,7 +940,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } fn encode_rio_named_or_blank_node( - &mut self, + &self, term: rio::NamedOrBlankNode<'_>, bnodes_map: &mut HashMap, ) -> Result { @@ -962,7 +953,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } fn encode_rio_term( - &mut self, + &self, term: rio::Term<'_>, bnodes_map: &mut HashMap, ) -> Result { @@ -974,7 +965,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } fn encode_rio_quad( - &mut self, + &self, quad: rio::Quad<'_>, bnodes_map: &mut HashMap, ) -> Result { @@ -990,7 +981,7 @@ pub(crate) trait WriteEncoder: StrEncodingAware { } fn encode_rio_triple_in_graph( - &mut self, + &self, triple: rio::Triple<'_>, graph_name: EncodedTerm, bnodes_map: &mut HashMap, @@ -1003,11 +994,11 @@ pub(crate) trait WriteEncoder: StrEncodingAware { }) } - fn encode_str(&mut self, value: &str) -> Result; + fn encode_str(&self, value: &str) -> Result; } impl WriteEncoder for S { - fn encode_str(&mut self, value: &str) -> Result { + fn encode_str(&self, value: &str) -> Result { self.insert_str(value) } } diff --git a/lib/src/store/sled.rs b/lib/src/store/sled.rs index b29a0964..52098f7b 100644 --- a/lib/src/store/sled.rs +++ b/lib/src/store/sled.rs @@ -336,26 +336,28 @@ impl SledStore { /// Adds a quad to this store. /// + /// Returns `true` if the quad was not already in the store. + /// /// This method is optimized for performances and is not atomic. /// It might leave the store in a bad state if a crash happens during the insertion. /// Use a (memory greedy) [transaction](SledStore::transaction()) if you do not want that. - pub fn insert<'a>(&self, quad: impl Into>) -> Result<(), io::Error> { - let mut this = self; - let quad = this.encode_quad(quad.into())?; - this.insert_encoded(&quad) + pub fn insert<'a>(&self, quad: impl Into>) -> Result { + let quad = self.encode_quad(quad.into())?; + self.storage.insert(&quad) } /// Removes a quad from this store. /// + /// Returns `true` if the quad was in the store and has been removed. + /// /// This method is optimized for performances and is not atomic. /// It might leave the store in a bad state if a crash happens during the removal. /// Use a (memory greedy) [transaction](SledStore::transaction()) if you do not want that. - pub fn remove<'a>(&self, quad: impl Into>) -> Result<(), io::Error> { + pub fn remove<'a>(&self, quad: impl Into>) -> Result { if let Some(quad) = self.get_encoded_quad(quad.into())? { - let mut this = self; - this.remove_encoded(&quad) + self.storage.remove(&quad) } else { - Ok(()) + Ok(false) } } @@ -458,6 +460,8 @@ impl SledStore { /// Inserts a graph into this store /// + /// Returns `true` if the graph was not already in the store. + /// /// Usage example: /// ``` /// use oxigraph::SledStore; @@ -472,10 +476,9 @@ impl SledStore { pub fn insert_named_graph<'a>( &self, graph_name: impl Into>, - ) -> Result<(), io::Error> { - let mut this = self; - let graph_name = this.encode_named_or_blank_node(graph_name.into())?; - this.insert_encoded_named_graph(graph_name) + ) -> Result { + let graph_name = self.encode_named_or_blank_node(graph_name.into())?; + self.storage.insert_named_graph(graph_name) } /// Clears a graph from this store. @@ -510,6 +513,8 @@ impl SledStore { /// Removes a graph from this store. /// + /// Returns `true` if the graph was in the store and has been removed. + /// /// Usage example: /// ``` /// use oxigraph::SledStore; @@ -529,12 +534,11 @@ impl SledStore { pub fn remove_named_graph<'a>( &self, graph_name: impl Into>, - ) -> Result<(), io::Error> { + ) -> Result { if let Some(graph_name) = self.get_encoded_named_or_blank_node(graph_name.into())? { - let mut this = self; - this.remove_encoded_named_graph(graph_name) + self.storage.remove_named_graph(graph_name) } else { - Ok(()) + Ok(false) } } @@ -580,12 +584,7 @@ impl StrLookup for SledStore { } fn get_str_id(&self, value: &str) -> Result, io::Error> { - let key = StrHash::new(value); - Ok(if self.storage.contains_str(key)? { - Some(key) - } else { - None - }) + self.storage.get_str_id(value) } } @@ -614,7 +613,7 @@ impl ReadableEncodedStore for SledStore { } impl<'a> StrContainer for &'a SledStore { - fn insert_str(&mut self, value: &str) -> Result { + fn insert_str(&self, value: &str) -> Result { let key = StrHash::new(value); self.storage.insert_str(key, value)?; Ok(key) @@ -623,15 +622,18 @@ impl<'a> StrContainer for &'a SledStore { impl<'a> WritableEncodedStore for &'a SledStore { fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<(), io::Error> { - self.storage.insert(quad) + self.storage.insert(quad)?; + Ok(()) } fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<(), io::Error> { - self.storage.remove(quad) + self.storage.remove(quad)?; + Ok(()) } fn insert_encoded_named_graph(&mut self, graph_name: EncodedTerm) -> Result<(), io::Error> { - self.storage.insert_named_graph(graph_name) + self.storage.insert_named_graph(graph_name)?; + Ok(()) } fn clear_encoded_graph(&mut self, graph_name: EncodedTerm) -> Result<(), io::Error> { @@ -639,7 +641,8 @@ impl<'a> WritableEncodedStore for &'a SledStore { } fn remove_encoded_named_graph(&mut self, graph_name: EncodedTerm) -> Result<(), io::Error> { - self.storage.remove_named_graph(graph_name) + self.storage.remove_named_graph(graph_name)?; + Ok(()) } fn clear(&mut self) -> Result<(), io::Error> { @@ -747,25 +750,27 @@ impl SledTransaction<'_> { } /// Adds a quad to this store during the transaction. + /// + /// Returns `true` if the quad was not already in the store. pub fn insert<'a>( &self, quad: impl Into>, - ) -> Result<(), SledUnabortableTransactionError> { - let mut this = self; - let quad = this.encode_quad(quad.into())?; - this.insert_encoded(&quad) + ) -> Result { + let quad = self.encode_quad(quad.into())?; + self.storage.insert(&quad) } /// Removes a quad from this store during the transaction. + /// + /// Returns `true` if the quad was in the store and has been removed. pub fn remove<'a>( &self, quad: impl Into>, - ) -> Result<(), SledUnabortableTransactionError> { - let mut this = self; - if let Some(quad) = this.get_encoded_quad(quad.into())? { - this.remove_encoded(&quad) + ) -> Result { + if let Some(quad) = self.get_encoded_quad(quad.into())? { + self.storage.remove(&quad) } else { - Ok(()) + Ok(false) } } } @@ -780,17 +785,12 @@ impl<'a> StrLookup for &'a SledTransaction<'a> { } fn get_str_id(&self, value: &str) -> Result, SledUnabortableTransactionError> { - let key = StrHash::new(value); - Ok(if self.storage.contains_str(key)? { - Some(key) - } else { - None - }) + self.storage.get_str_id(value) } } impl<'a> StrContainer for &'a SledTransaction<'a> { - fn insert_str(&mut self, value: &str) -> Result { + fn insert_str(&self, value: &str) -> Result { let key = StrHash::new(value); self.storage.insert_str(key, value)?; Ok(key) @@ -802,21 +802,24 @@ impl<'a> WritableEncodedStore for &'a SledTransaction<'a> { &mut self, quad: &EncodedQuad, ) -> Result<(), SledUnabortableTransactionError> { - self.storage.insert(quad) + self.storage.insert(quad)?; + Ok(()) } fn remove_encoded( &mut self, quad: &EncodedQuad, ) -> Result<(), SledUnabortableTransactionError> { - self.storage.remove(quad) + self.storage.remove(quad)?; + Ok(()) } fn insert_encoded_named_graph( &mut self, graph_name: EncodedTerm, ) -> Result<(), SledUnabortableTransactionError> { - self.storage.insert_named_graph(graph_name) + self.storage.insert_named_graph(graph_name)?; + Ok(()) } fn clear_encoded_graph( @@ -938,16 +941,20 @@ fn store() -> Result<(), io::Error> { let store = SledStore::new()?; for t in &default_quads { - store.insert(t)?; + assert!(store.insert(t)?); } let result: Result<_, SledTransactionError> = store.transaction(|t| { - t.remove(&default_quad)?; - t.insert(&named_quad)?; - t.insert(&default_quad)?; + assert!(t.remove(&default_quad)?); + assert_eq!(t.remove(&default_quad)?, false); + assert!(t.insert(&named_quad)?); + assert_eq!(t.insert(&named_quad)?, false); + assert!(t.insert(&default_quad)?); + assert_eq!(t.insert(&default_quad)?, false); Ok(()) }); result?; + assert_eq!(store.insert(&default_quad)?, false); assert_eq!(store.len(), 4); assert_eq!(store.iter().collect::, _>>()?, all_quads); diff --git a/lib/src/store/storage.rs b/lib/src/store/storage.rs index b0343c2f..25010db7 100644 --- a/lib/src/store/storage.rs +++ b/lib/src/store/storage.rs @@ -444,101 +444,115 @@ impl Storage { } } - pub fn insert(&self, quad: &EncodedQuad) -> Result<(), io::Error> { + pub fn insert(&self, quad: &EncodedQuad) -> Result { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE + 1); if quad.graph_name.is_default_graph() { write_spo_quad(&mut buffer, quad); - self.dspo.insert(buffer.as_slice(), &[])?; - buffer.clear(); + let is_new = self.dspo.insert(buffer.as_slice(), &[])?.is_none(); - write_pos_quad(&mut buffer, quad); - self.dpos.insert(buffer.as_slice(), &[])?; - buffer.clear(); + if is_new { + buffer.clear(); - write_osp_quad(&mut buffer, quad); - self.dosp.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_pos_quad(&mut buffer, quad); + self.dpos.insert(buffer.as_slice(), &[])?; + buffer.clear(); + + write_osp_quad(&mut buffer, quad); + self.dosp.insert(buffer.as_slice(), &[])?; + buffer.clear(); + } + + Ok(is_new) } else { write_spog_quad(&mut buffer, quad); - self.spog.insert(buffer.as_slice(), &[])?; - buffer.clear(); + let is_new = self.spog.insert(buffer.as_slice(), &[])?.is_none(); + if is_new { + buffer.clear(); - write_posg_quad(&mut buffer, quad); - self.posg.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_posg_quad(&mut buffer, quad); + self.posg.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_ospg_quad(&mut buffer, quad); - self.ospg.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_ospg_quad(&mut buffer, quad); + self.ospg.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gspo_quad(&mut buffer, quad); - self.gspo.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_gspo_quad(&mut buffer, quad); + self.gspo.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gpos_quad(&mut buffer, quad); - self.gpos.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_gpos_quad(&mut buffer, quad); + self.gpos.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gosp_quad(&mut buffer, quad); - self.gosp.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_gosp_quad(&mut buffer, quad); + self.gosp.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_term(&mut buffer, quad.graph_name); - self.graphs.insert(&buffer, &[])?; - buffer.clear(); - } + write_term(&mut buffer, quad.graph_name); + self.graphs.insert(&buffer, &[])?; + buffer.clear(); + } - Ok(()) + Ok(is_new) + } } - pub fn remove(&self, quad: &EncodedQuad) -> Result<(), io::Error> { + pub fn remove(&self, quad: &EncodedQuad) -> Result { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE + 1); if quad.graph_name.is_default_graph() { write_spo_quad(&mut buffer, quad); - self.dspo.remove(buffer.as_slice())?; - buffer.clear(); + let is_present = self.dspo.remove(buffer.as_slice())?.is_some(); + + if is_present { + buffer.clear(); - write_pos_quad(&mut buffer, quad); - self.dpos.remove(buffer.as_slice())?; - buffer.clear(); + write_pos_quad(&mut buffer, quad); + self.dpos.remove(buffer.as_slice())?; + buffer.clear(); - write_osp_quad(&mut buffer, quad); - self.dosp.remove(buffer.as_slice())?; - buffer.clear(); + write_osp_quad(&mut buffer, quad); + self.dosp.remove(buffer.as_slice())?; + buffer.clear(); + } + + Ok(is_present) } else { write_spog_quad(&mut buffer, quad); - self.spog.remove(buffer.as_slice())?; - buffer.clear(); + let is_present = self.spog.remove(buffer.as_slice())?.is_some(); - write_posg_quad(&mut buffer, quad); - self.posg.remove(buffer.as_slice())?; - buffer.clear(); + if is_present { + buffer.clear(); - write_ospg_quad(&mut buffer, quad); - self.ospg.remove(buffer.as_slice())?; - buffer.clear(); + write_posg_quad(&mut buffer, quad); + self.posg.remove(buffer.as_slice())?; + buffer.clear(); - write_gspo_quad(&mut buffer, quad); - self.gspo.remove(buffer.as_slice())?; - buffer.clear(); + write_ospg_quad(&mut buffer, quad); + self.ospg.remove(buffer.as_slice())?; + buffer.clear(); - write_gpos_quad(&mut buffer, quad); - self.gpos.remove(buffer.as_slice())?; - buffer.clear(); + write_gspo_quad(&mut buffer, quad); + self.gspo.remove(buffer.as_slice())?; + buffer.clear(); - write_gosp_quad(&mut buffer, quad); - self.gosp.remove(buffer.as_slice())?; - buffer.clear(); - } + write_gpos_quad(&mut buffer, quad); + self.gpos.remove(buffer.as_slice())?; + buffer.clear(); - Ok(()) + write_gosp_quad(&mut buffer, quad); + self.gosp.remove(buffer.as_slice())?; + buffer.clear(); + } + + Ok(is_present) + } } - pub fn insert_named_graph(&self, graph_name: EncodedTerm) -> Result<(), io::Error> { - self.graphs.insert(&encode_term(graph_name), &[])?; - Ok(()) + pub fn insert_named_graph(&self, graph_name: EncodedTerm) -> Result { + Ok(self.graphs.insert(&encode_term(graph_name), &[])?.is_none()) } pub fn clear_graph(&self, graph_name: EncodedTerm) -> Result<(), io::Error> { @@ -554,12 +568,11 @@ impl Storage { Ok(()) } - pub fn remove_named_graph(&self, graph_name: EncodedTerm) -> Result<(), io::Error> { + pub fn remove_named_graph(&self, graph_name: EncodedTerm) -> Result { for quad in self.quads_for_graph(graph_name) { self.remove(&quad?)?; } - self.graphs.remove(&encode_term(graph_name))?; - Ok(()) + Ok(self.graphs.remove(&encode_term(graph_name))?.is_some()) } pub fn clear(&self) -> Result<(), io::Error> { @@ -589,9 +602,8 @@ impl Storage { Ok(self.id2str.contains_key(key.to_be_bytes())?) } - pub fn insert_str(&self, key: StrHash, value: &str) -> Result<(), io::Error> { - self.id2str.insert(key.to_be_bytes(), value)?; - Ok(()) + pub fn insert_str(&self, key: StrHash, value: &str) -> Result { + Ok(self.id2str.insert(key.to_be_bytes(), value)?.is_none()) } } @@ -676,104 +688,119 @@ pub struct StorageTransaction<'a> { } impl<'a> StorageTransaction<'a> { - pub fn insert(&self, quad: &EncodedQuad) -> Result<(), SledUnabortableTransactionError> { + pub fn insert(&self, quad: &EncodedQuad) -> Result { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE + 1); if quad.graph_name.is_default_graph() { write_spo_quad(&mut buffer, quad); - self.dspo.insert(buffer.as_slice(), &[])?; - buffer.clear(); + let is_new = self.dspo.insert(buffer.as_slice(), &[])?.is_none(); + + if is_new { + buffer.clear(); - write_pos_quad(&mut buffer, quad); - self.dpos.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_pos_quad(&mut buffer, quad); + self.dpos.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_osp_quad(&mut buffer, quad); - self.dosp.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_osp_quad(&mut buffer, quad); + self.dosp.insert(buffer.as_slice(), &[])?; + buffer.clear(); + } + + Ok(is_new) } else { write_spog_quad(&mut buffer, quad); - self.spog.insert(buffer.as_slice(), &[])?; - buffer.clear(); + let is_new = self.spog.insert(buffer.as_slice(), &[])?.is_none(); - write_posg_quad(&mut buffer, quad); - self.posg.insert(buffer.as_slice(), &[])?; - buffer.clear(); + if is_new { + buffer.clear(); - write_ospg_quad(&mut buffer, quad); - self.ospg.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_posg_quad(&mut buffer, quad); + self.posg.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gspo_quad(&mut buffer, quad); - self.gspo.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_ospg_quad(&mut buffer, quad); + self.ospg.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gpos_quad(&mut buffer, quad); - self.gpos.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_gspo_quad(&mut buffer, quad); + self.gspo.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gosp_quad(&mut buffer, quad); - self.gosp.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_gpos_quad(&mut buffer, quad); + self.gpos.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_term(&mut buffer, quad.graph_name); - self.graphs.insert(buffer.as_slice(), &[])?; - buffer.clear(); - } + write_gosp_quad(&mut buffer, quad); + self.gosp.insert(buffer.as_slice(), &[])?; + buffer.clear(); - Ok(()) + write_term(&mut buffer, quad.graph_name); + self.graphs.insert(buffer.as_slice(), &[])?; + buffer.clear(); + } + + Ok(is_new) + } } - pub fn remove(&self, quad: &EncodedQuad) -> Result<(), SledUnabortableTransactionError> { + pub fn remove(&self, quad: &EncodedQuad) -> Result { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE + 1); if quad.graph_name.is_default_graph() { write_spo_quad(&mut buffer, quad); - self.dspo.remove(buffer.as_slice())?; - buffer.clear(); + let is_present = self.dspo.remove(buffer.as_slice())?.is_some(); - write_pos_quad(&mut buffer, quad); - self.dpos.remove(buffer.as_slice())?; - buffer.clear(); + if is_present { + buffer.clear(); - write_osp_quad(&mut buffer, quad); - self.dosp.remove(buffer.as_slice())?; - buffer.clear(); + write_pos_quad(&mut buffer, quad); + self.dpos.remove(buffer.as_slice())?; + buffer.clear(); + + write_osp_quad(&mut buffer, quad); + self.dosp.remove(buffer.as_slice())?; + buffer.clear(); + } + + Ok(is_present) } else { write_spog_quad(&mut buffer, quad); - self.spog.remove(buffer.as_slice())?; - buffer.clear(); + let is_present = self.spog.remove(buffer.as_slice())?.is_some(); - write_posg_quad(&mut buffer, quad); - self.posg.remove(buffer.as_slice())?; - buffer.clear(); + if is_present { + buffer.clear(); - write_ospg_quad(&mut buffer, quad); - self.ospg.remove(buffer.as_slice())?; - buffer.clear(); + write_posg_quad(&mut buffer, quad); + self.posg.remove(buffer.as_slice())?; + buffer.clear(); - write_gspo_quad(&mut buffer, quad); - self.gspo.remove(buffer.as_slice())?; - buffer.clear(); + write_ospg_quad(&mut buffer, quad); + self.ospg.remove(buffer.as_slice())?; + buffer.clear(); - write_gpos_quad(&mut buffer, quad); - self.gpos.remove(buffer.as_slice())?; - buffer.clear(); + write_gspo_quad(&mut buffer, quad); + self.gspo.remove(buffer.as_slice())?; + buffer.clear(); - write_gosp_quad(&mut buffer, quad); - self.gosp.remove(buffer.as_slice())?; - buffer.clear(); - } + write_gpos_quad(&mut buffer, quad); + self.gpos.remove(buffer.as_slice())?; + buffer.clear(); - Ok(()) + write_gosp_quad(&mut buffer, quad); + self.gosp.remove(buffer.as_slice())?; + buffer.clear(); + } + + Ok(is_present) + } } pub fn insert_named_graph( &self, graph_name: EncodedTerm, - ) -> Result<(), SledUnabortableTransactionError> { - self.graphs.insert(encode_term(graph_name), &[])?; - Ok(()) + ) -> Result { + Ok(self.graphs.insert(encode_term(graph_name), &[])?.is_none()) } pub fn get_str(&self, key: StrHash) -> Result, SledUnabortableTransactionError> { @@ -792,9 +819,8 @@ impl<'a> StorageTransaction<'a> { &self, key: StrHash, value: &str, - ) -> Result<(), SledUnabortableTransactionError> { - self.id2str.insert(&key.to_be_bytes(), value)?; - Ok(()) + ) -> Result { + Ok(self.id2str.insert(&key.to_be_bytes(), value)?.is_none()) } } @@ -949,3 +975,57 @@ impl From> for ConflictableTransactionErr } } } + +impl StrEncodingAware for Storage { + type Error = io::Error; +} + +impl StrLookup for Storage { + fn get_str(&self, id: StrHash) -> Result, io::Error> { + self.get_str(id) + } + + fn get_str_id(&self, value: &str) -> Result, io::Error> { + let key = StrHash::new(value); + Ok(if self.contains_str(key)? { + Some(key) + } else { + None + }) + } +} + +impl StrContainer for Storage { + fn insert_str(&self, value: &str) -> Result { + let key = StrHash::new(value); + self.insert_str(key, value)?; + Ok(key) + } +} + +impl<'a> StrEncodingAware for StorageTransaction<'a> { + type Error = SledUnabortableTransactionError; +} + +impl<'a> StrLookup for StorageTransaction<'a> { + fn get_str(&self, id: StrHash) -> Result, SledUnabortableTransactionError> { + self.get_str(id) + } + + fn get_str_id(&self, value: &str) -> Result, SledUnabortableTransactionError> { + let key = StrHash::new(value); + Ok(if self.contains_str(key)? { + Some(key) + } else { + None + }) + } +} + +impl<'a> StrContainer for StorageTransaction<'a> { + fn insert_str(&self, value: &str) -> Result { + let key = StrHash::new(value); + self.insert_str(key, value)?; + Ok(key) + } +} diff --git a/python/src/store.rs b/python/src/store.rs index 0adc2cdc..ead1d66c 100644 --- a/python/src/store.rs +++ b/python/src/store.rs @@ -60,7 +60,8 @@ impl PyStore { /// [ predicate= object=> graph_name=>] #[text_signature = "($self, quad)"] fn add(&self, quad: &PyQuad) -> PyResult<()> { - self.inner.insert(quad).map_err(map_io_err) + self.inner.insert(quad).map_err(map_io_err)?; + Ok(()) } /// Removes a quad from the store @@ -77,7 +78,8 @@ impl PyStore { /// [] #[text_signature = "($self, quad)"] fn remove(&self, quad: &PyQuad) -> PyResult<()> { - self.inner.remove(quad).map_err(map_io_err) + self.inner.remove(quad).map_err(map_io_err)?; + Ok(()) } /// Looks for the quads matching a given pattern @@ -383,10 +385,12 @@ impl PyStore { PyGraphNameRef::DefaultGraph => Ok(()), PyGraphNameRef::NamedNode(graph_name) => self .inner - .insert_named_graph(&PyNamedOrBlankNodeRef::NamedNode(graph_name)), + .insert_named_graph(&PyNamedOrBlankNodeRef::NamedNode(graph_name)) + .map(|_| ()), PyGraphNameRef::BlankNode(graph_name) => self .inner - .insert_named_graph(&PyNamedOrBlankNodeRef::BlankNode(graph_name)), + .insert_named_graph(&PyNamedOrBlankNodeRef::BlankNode(graph_name)) + .map(|_| ()), } .map_err(map_io_err) } @@ -410,12 +414,15 @@ impl PyStore { PyGraphNameRef::DefaultGraph => self.inner.clear_graph(GraphNameRef::DefaultGraph), PyGraphNameRef::NamedNode(graph_name) => self .inner - .remove_named_graph(&PyNamedOrBlankNodeRef::NamedNode(graph_name)), + .remove_named_graph(&PyNamedOrBlankNodeRef::NamedNode(graph_name)) + .map(|_| ()), PyGraphNameRef::BlankNode(graph_name) => self .inner - .remove_named_graph(&PyNamedOrBlankNodeRef::BlankNode(graph_name)), + .remove_named_graph(&PyNamedOrBlankNodeRef::BlankNode(graph_name)) + .map(|_| ()), } - .map_err(map_io_err) + .map_err(map_io_err)?; + Ok(()) } }