From 12f80fc622cc21f7024f5a04cb89b440ad6cf3eb Mon Sep 17 00:00:00 2001 From: Tpt Date: Wed, 7 Nov 2018 15:21:53 +0100 Subject: [PATCH] Migrates to failure from error_chain --- lib/Cargo.toml | 2 +- lib/src/errors.rs | 45 ------------------ lib/src/lib.rs | 9 ++-- lib/src/rio/ntriples/mod.rs | 2 - lib/src/rio/turtle/mod.rs | 3 +- lib/src/rio/xml.rs | 16 +++++-- lib/src/sparql/algebra.rs | 2 +- lib/src/sparql/parser.rs | 3 +- lib/src/sparql/plan.rs | 7 ++- lib/src/sparql/xml_results.rs | 72 ++++++++++++++--------------- lib/src/store/encoded.rs | 20 ++++---- lib/src/store/memory.rs | 79 +++++++++++++++++++++++--------- lib/src/store/numeric_encoder.rs | 45 ++++++++++-------- lib/src/store/rocksdb.rs | 24 +++++++++- lib/tests/rdf_test_cases.rs | 25 +++++----- lib/tests/sparql_test_cases.rs | 36 ++++++++------- python/src/lib.rs | 6 +-- 17 files changed, 214 insertions(+), 182 deletions(-) delete mode 100644 lib/src/errors.rs diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 819ff24b..59f4c773 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -15,7 +15,6 @@ build = "build.rs" travis-ci = { repository = "Tpt/rudf" } [dependencies] -error-chain = "0.12" lazy_static = "1" rocksdb = "0.10" url = "1" @@ -28,6 +27,7 @@ num-traits = "0.2" rust_decimal = "0.10" chrono = "0.4" language-tags = "0.2" +failure = "0.1" [build-dependencies] peg = "0.5" diff --git a/lib/src/errors.rs b/lib/src/errors.rs deleted file mode 100644 index 397b6b86..00000000 --- a/lib/src/errors.rs +++ /dev/null @@ -1,45 +0,0 @@ -use quick_xml::Error as Xml_Error; -use std::fmt; -use std::sync::PoisonError; - -error_chain! { - foreign_links { - Url(::url::ParseError); - RocksDB(::rocksdb::Error); - Utf8(::std::str::Utf8Error); - Io(::std::io::Error); - NTriples(::rio::ntriples::ParseError); - Turtle(::rio::turtle::ParseError); - SparqlParser(::sparql::parser::ParseError); - } - - errors { - Xml(error: Xml_Error) { - description("XML parsing error") - display("XML parsing error: {:?}", error) - } - } -} - -impl From> for Error { - fn from(_: PoisonError) -> Self { - //TODO: improve conversion - "Unexpected lock error".into() - } -} - -impl From for Error { - fn from(error: Xml_Error) -> Self { - match error { - Xml_Error::Io(error) => error.into(), - Xml_Error::Utf8(error) => error.into(), - error => ErrorKind::Xml(error).into(), - } - } -} - -impl From for fmt::Error { - fn from(_: Error) -> Self { - fmt::Error - } -} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 62f8f4a7..2254161d 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -33,8 +33,6 @@ extern crate byteorder; #[macro_use] -extern crate error_chain; -#[macro_use] extern crate lazy_static; extern crate chrono; extern crate language_tags; @@ -45,13 +43,14 @@ extern crate rocksdb; extern crate rust_decimal; extern crate url; extern crate uuid; +#[macro_use] +extern crate failure; -mod errors; pub mod model; pub mod rio; pub mod sparql; pub mod store; mod utils; -pub use errors::Error; -pub use errors::Result; +pub use failure::Error; +pub type Result = ::std::result::Result; diff --git a/lib/src/rio/ntriples/mod.rs b/lib/src/rio/ntriples/mod.rs index eaf53cf8..2953c104 100644 --- a/lib/src/rio/ntriples/mod.rs +++ b/lib/src/rio/ntriples/mod.rs @@ -41,8 +41,6 @@ use std::io::BufReader; use std::io::Read; use Result; -pub(crate) type ParseError = self::grammar::ParseError; - struct NTriplesIterator { buffer: String, reader: BufReader, diff --git a/lib/src/rio/turtle/mod.rs b/lib/src/rio/turtle/mod.rs index f53b11db..596013b7 100644 --- a/lib/src/rio/turtle/mod.rs +++ b/lib/src/rio/turtle/mod.rs @@ -45,7 +45,7 @@ mod grammar { pub fn read_turtle<'a, R: Read + 'a>( source: R, base_uri: impl Into>, - ) -> super::super::super::errors::Result> { + ) -> super::super::super::Result> { let mut state = ParserState { base_uri: base_uri.into(), namespaces: HashMap::default(), @@ -78,5 +78,4 @@ mod grammar { } } -pub(crate) type ParseError = self::grammar::ParseError; pub use self::grammar::read_turtle; diff --git a/lib/src/rio/xml.rs b/lib/src/rio/xml.rs index 4d4324ff..4439dfec 100644 --- a/lib/src/rio/xml.rs +++ b/lib/src/rio/xml.rs @@ -283,7 +283,11 @@ impl RdfXmlIterator { Some(RdfXmlState::ParseTypeCollectionPropertyElt { .. }) => { RdfXmlNextProduction::NodeElt {} } - None => return Err("No state in the stack: the XML is not balanced".into()), + None => { + return Err(format_err!( + "No state in the stack: the XML is not balanced" + )) + } }; let new_state = match next_production { @@ -356,7 +360,9 @@ impl RdfXmlIterator { } } RdfXmlParseType::Literal => { - return Err("rdf:parseType=\"Literal\" is not supported yet".into()); + return Err(format_err!( + "rdf:parseType=\"Literal\" is not supported yet" + )); } RdfXmlParseType::Resource => self.build_parse_type_resource_property_elt( NamedNode::from(uri), @@ -366,10 +372,12 @@ impl RdfXmlIterator { id_attr, ), RdfXmlParseType::Collection => { - return Err("rdf:parseType=\"Collection\" is not supported yet".into()); + return Err(format_err!( + "rdf:parseType=\"Collection\" is not supported yet" + )); } RdfXmlParseType::Other => { - return Err("Arbitrary rdf:parseType are not supported yet".into()); + return Err(format_err!("Arbitrary rdf:parseType are not supported yet")); } }, }; diff --git a/lib/src/sparql/algebra.rs b/lib/src/sparql/algebra.rs index 874a7a61..6ba5f20a 100644 --- a/lib/src/sparql/algebra.rs +++ b/lib/src/sparql/algebra.rs @@ -30,7 +30,7 @@ impl Variable { pub fn name(&self) -> Result<&str> { match self { Variable::Variable { name } => Ok(name), - _ => Err(format!("The variable {} has no name", self).into()), + _ => Err(format_err!("The variable {} has no name", self)), } } } diff --git a/lib/src/sparql/parser.rs b/lib/src/sparql/parser.rs index 7566caa4..f098f947 100644 --- a/lib/src/sparql/parser.rs +++ b/lib/src/sparql/parser.rs @@ -334,7 +334,7 @@ mod grammar { pub fn read_sparql_query<'a, R: Read + 'a>( source: R, base_uri: impl Into>, - ) -> super::super::super::errors::Result { + ) -> super::super::super::Result { let mut state = ParserState { base_uri: base_uri.into(), namespaces: HashMap::default(), @@ -352,5 +352,4 @@ mod grammar { } } -pub(crate) type ParseError = self::grammar::ParseError; pub use self::grammar::read_sparql_query; diff --git a/lib/src/sparql/plan.rs b/lib/src/sparql/plan.rs index 17a71c1c..273945de 100644 --- a/lib/src/sparql/plan.rs +++ b/lib/src/sparql/plan.rs @@ -629,7 +629,7 @@ impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> { } else if *name == *xsd::STRING { self.build_cast(parameters, PlanExpression::StringCast, variables, "string")? } else { - Err(format!("Not supported custom function {}", expression))? + Err(format_err!("Not supported custom function {}", expression))? }, _ => unimplemented!(), }) @@ -647,7 +647,10 @@ impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> { self.build_for_expression(¶meters[0], variables)?, ))) } else { - Err(format!("The xsd:{} casting takes only one parameter", name).into()) + Err(format_err!( + "The xsd:{} casting takes only one parameter", + name + )) } } diff --git a/lib/src/sparql/xml_results.rs b/lib/src/sparql/xml_results.rs index cf9fffc9..70040029 100644 --- a/lib/src/sparql/xml_results.rs +++ b/lib/src/sparql/xml_results.rs @@ -33,10 +33,10 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result Result tag, found {}", reader.decode(event.name())).into()); + return Err(format_err!("Expecting tag, found {}", reader.decode(event.name()))); } } State::Sparql => { if event.name() == b"head" { state = State::Head; } else { - return Err(format!("Expecting tag, found {}", reader.decode(event.name())).into()); + return Err(format_err!("Expecting tag, found {}", reader.decode(event.name()))); } } State::Head => if event.name() == b"variable" || event.name() == b"link" { - return Err(" and tag should be autoclosing".into()); + return Err(format_err!(" and tag should be autoclosing")); } else { - return Err(format!("Expecting or tag, found {}", reader.decode(event.name())).into()); - }, + return Err(format_err!("Expecting or tag, found {}", reader.decode(event.name()))); + } State::AfterHead => { if event.name() == b"boolean" { state = State::Boolean @@ -81,10 +81,10 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result return Err(format!("Unexpected tag inside of tag: {}", reader.decode(event.name())).into()) + State::Boolean => return Err(format_err!("Unexpected tag inside of tag: {}", reader.decode(event.name()))) }, Event::Empty(event) => match state { State::Head => { @@ -92,12 +92,12 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result tag"); + .ok_or(format_err!("No name attribute found for the tag")); variables.push(name?.unescape_and_decode_value(&reader)?); } else if event.name() == b"link" { // no op } else { - return Err(format!("Expecting or tag, found {}", reader.decode(event.name())).into()); + return Err(format_err!("Expecting or tag, found {}", reader.decode(event.name()))); } }, State::AfterHead => { @@ -107,10 +107,10 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result", reader.decode(event.name())).into()) + return Err(format_err!("Unexpected autoclosing tag <{}>", reader.decode(event.name()))) } } - _ => return Err(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name())).into()) + _ => return Err(format_err!("Unexpected autoclosing tag <{}>", reader.decode(event.name()))) }, Event::Text(event) => { let value = event.unescaped()?; @@ -121,18 +121,18 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result Err(format!("Unexpected textual value found: {}", reader.decode(&value)).into()) + _ => Err(format_err!("Unexpected textual value found: {}", reader.decode(&value))) }; }, Event::End(_) => if let State::Head = state { state = State::AfterHead; } else { - return Err("Unexpected early file end. All results file should have a and a or tag".into()); + return Err(format_err!("Unexpected early file end. All results file should have a and a or tag")); }, - Event::Eof => return Err("Unexpected early file end. All results file should have a and a or tag".into()), + Event::Eof => return Err(format_err!("Unexpected early file end. All results file should have a and a or tag")), _ => (), } } @@ -178,10 +178,10 @@ impl Iterator for ResultsIterator { }; if let Some(ns) = ns { if ns != b"http://www.w3.org/2005/sparql-results#".as_ref() { - return Some(Err(format!( + return Some(Err(format_err!( "Unexpected namespace found in RDF/XML query result: {}", self.reader.decode(ns) - ).into())); + ))); } } match event { @@ -189,10 +189,10 @@ impl Iterator for ResultsIterator { State::Start => if event.name() == b"result" { state = State::Result; } else { - return Some(Err(format!( + return Some(Err(format_err!( "Expecting , found {}", self.reader.decode(event.name()) - ).into())); + ))); }, State::Result => if event.name() == b"binding" { match event @@ -205,23 +205,23 @@ impl Iterator for ResultsIterator { Err(error) => return Some(Err(error.into())), }, None => { - return Some(Err( - "No name attribute found for the tag".into() - )) + return Some(Err(format_err!( + "No name attribute found for the tag" + ))) } } state = State::Binding; } else { - return Some(Err(format!( + return Some(Err(format_err!( "Expecting , found {}", self.reader.decode(event.name()) - ).into())); + ))); }, State::Binding => { if term.is_some() { - return Some(Err( - "There is already a value for the current binding".into() - )); + return Some(Err(format_err!( + "There is already a value for the current binding" + ))); } if event.name() == b"uri" { state = State::Uri; @@ -251,10 +251,10 @@ impl Iterator for ResultsIterator { } state = State::Literal; } else { - return Some(Err(format!( + return Some(Err(format_err!( "Expecting , or found {}", self.reader.decode(event.name()) - ).into())); + ))); } } _ => (), @@ -279,10 +279,10 @@ impl Iterator for ResultsIterator { term = Some(build_literal(value, &lang, &datatype).into()); } _ => { - return Some(Err(format!( + return Some(Err(format_err!( "Unexpected textual value found: {}", self.reader.decode(&data) - ).into())) + ))) } }, Err(error) => return Some(Err(error.into())), @@ -296,12 +296,12 @@ impl Iterator for ResultsIterator { new_bindings[self.mapping[var]] = Some(term.clone()) } (Some(var), None) => { - return Some(Err(format!( + return Some(Err(format_err!( "No variable found for variable {}", self.reader.decode(&var) - ).into())) + ))) } - _ => return Some(Err("No name found for tag".into())), + _ => return Some(Err(format_err!("No name found for tag"))), } term = None; state = State::Result; diff --git a/lib/src/store/encoded.rs b/lib/src/store/encoded.rs index 33f3373d..667b2bc4 100644 --- a/lib/src/store/encoded.rs +++ b/lib/src/store/encoded.rs @@ -353,8 +353,8 @@ impl Dataset for StoreDataset { impl fmt::Display for StoreDataset { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - for quad in self.iter()? { - writeln!(fmt, "{}", quad?)?; + for quad in self.iter().map_err(|_| fmt::Error)? { + writeln!(fmt, "{}", quad.map_err(|_| fmt::Error)?)?; } Ok(()) } @@ -539,8 +539,8 @@ impl NamedGraph for StoreNamedGraph { impl fmt::Display for StoreNamedGraph { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - for triple in self.iter()? { - writeln!(fmt, "{}", triple?)?; + for triple in self.iter().map_err(|_| fmt::Error)? { + writeln!(fmt, "{}", triple.map_err(|_| fmt::Error)?)?; } Ok(()) } @@ -694,8 +694,8 @@ impl Graph for StoreDefaultGraph { impl fmt::Display for StoreDefaultGraph { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - for triple in self.iter()? { - writeln!(fmt, "{}", triple?)?; + for triple in self.iter().map_err(|_| fmt::Error)? { + writeln!(fmt, "{}", triple.map_err(|_| fmt::Error)?)?; } Ok(()) } @@ -840,11 +840,11 @@ impl Graph for StoreUnionGraph { } fn insert(&self, _triple: &Triple) -> Result<()> { - Err("Union graph is not writable".into()) + Err(format_err!("Union graph is not writable")) } fn remove(&self, _triple: &Triple) -> Result<()> { - Err("Union graph is not writable".into()) + Err(format_err!("Union graph is not writable")) } fn len(&self) -> Result { @@ -858,8 +858,8 @@ impl Graph for StoreUnionGraph { impl fmt::Display for StoreUnionGraph { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - for triple in self.iter()? { - writeln!(fmt, "{}", triple?)?; + for triple in self.iter().map_err(|_| fmt::Error)? { + writeln!(fmt, "{}", triple.map_err(|_| fmt::Error)?)?; } Ok(()) } diff --git a/lib/src/store/memory.rs b/lib/src/store/memory.rs index 65e67292..3211baaf 100644 --- a/lib/src/store/memory.rs +++ b/lib/src/store/memory.rs @@ -1,6 +1,10 @@ +use failure::Backtrace; use std::collections::BTreeMap; use std::collections::BTreeSet; +use std::sync::PoisonError; use std::sync::RwLock; +use std::sync::RwLockReadGuard; +use std::sync::RwLockWriteGuard; use store::encoded::*; use store::numeric_encoder::*; use Result; @@ -71,8 +75,8 @@ impl BytesStore for MemoryStore { type BytesOutput = Vec; fn insert_bytes(&self, value: &[u8]) -> Result { - let mut id2str = self.id2str.write()?; - let mut str2id = self.str2id.write()?; + let mut id2str = self.id2str.write().map_err(MemoryStorePoisonError::from)?; + let mut str2id = self.str2id.write().map_err(MemoryStorePoisonError::from)?; let id = str2id.entry(value.to_vec()).or_insert_with(|| { let id = id2str.len() as u64; id2str.push(value.to_vec()); @@ -83,7 +87,7 @@ impl BytesStore for MemoryStore { fn get_bytes(&self, id: u64) -> Result>> { //TODO: use try_from when stable - let id2str = self.id2str.read()?; + let id2str = self.id2str.read().map_err(MemoryStorePoisonError::from)?; Ok(if id2str.len() as u64 <= id { None } else { @@ -114,7 +118,7 @@ impl EncodedQuadsStore for MemoryStore { fn quads(&self) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - for (graph_name, graph) in self.graph_indexes.read()?.iter() { + for (graph_name, graph) in self.graph_indexes()?.iter() { for (s, pos) in &graph.spo { for (p, os) in pos.iter() { for o in os.iter() { @@ -131,7 +135,7 @@ impl EncodedQuadsStore for MemoryStore { subject: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - for (graph_name, graph) in self.graph_indexes.read()?.iter() { + for (graph_name, graph) in self.graph_indexes()?.iter() { if let Some(pos) = graph.spo.get(&subject) { for (p, os) in pos.iter() { for o in os.iter() { @@ -149,7 +153,7 @@ impl EncodedQuadsStore for MemoryStore { predicate: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - for (graph_name, graph) in self.graph_indexes.read()?.iter() { + for (graph_name, graph) in self.graph_indexes()?.iter() { if let Some(pos) = graph.spo.get(&subject) { if let Some(os) = pos.get(&predicate) { for o in os.iter() { @@ -168,7 +172,7 @@ impl EncodedQuadsStore for MemoryStore { object: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - for (graph_name, graph) in self.graph_indexes.read()?.iter() { + for (graph_name, graph) in self.graph_indexes()?.iter() { if let Some(pos) = graph.spo.get(&subject) { if let Some(os) = pos.get(&predicate) { if os.contains(&object) { @@ -191,7 +195,7 @@ impl EncodedQuadsStore for MemoryStore { object: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - for (graph_name, graph) in self.graph_indexes.read()?.iter() { + for (graph_name, graph) in self.graph_indexes()?.iter() { if let Some(sps) = graph.osp.get(&object) { if let Some(ps) = sps.get(&subject) { for p in ps.iter() { @@ -208,7 +212,7 @@ impl EncodedQuadsStore for MemoryStore { predicate: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - for (graph_name, graph) in self.graph_indexes.read()?.iter() { + for (graph_name, graph) in self.graph_indexes()?.iter() { if let Some(oss) = graph.pos.get(&predicate) { for (o, ss) in oss.iter() { for s in ss.iter() { @@ -226,7 +230,7 @@ impl EncodedQuadsStore for MemoryStore { object: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - for (graph_name, graph) in self.graph_indexes.read()?.iter() { + for (graph_name, graph) in self.graph_indexes()?.iter() { if let Some(oss) = graph.pos.get(&predicate) { if let Some(ss) = oss.get(&object) { for s in ss.iter() { @@ -243,7 +247,7 @@ impl EncodedQuadsStore for MemoryStore { object: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - for (graph_name, graph) in self.graph_indexes.read()?.iter() { + for (graph_name, graph) in self.graph_indexes()?.iter() { if let Some(sps) = graph.osp.get(&object) { for (s, ps) in sps.iter() { for p in ps.iter() { @@ -260,7 +264,7 @@ impl EncodedQuadsStore for MemoryStore { graph_name: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - if let Some(graph) = self.graph_indexes.read()?.get(&graph_name) { + if let Some(graph) = self.graph_indexes()?.get(&graph_name) { for (s, pos) in &graph.spo { for (p, os) in pos.iter() { for o in os.iter() { @@ -278,7 +282,7 @@ impl EncodedQuadsStore for MemoryStore { graph_name: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - if let Some(graph) = self.graph_indexes.read()?.get(&graph_name) { + if let Some(graph) = self.graph_indexes()?.get(&graph_name) { if let Some(pos) = graph.spo.get(&subject) { for (p, os) in pos.iter() { for o in os.iter() { @@ -297,7 +301,7 @@ impl EncodedQuadsStore for MemoryStore { graph_name: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - if let Some(graph) = self.graph_indexes.read()?.get(&graph_name) { + if let Some(graph) = self.graph_indexes()?.get(&graph_name) { if let Some(pos) = graph.spo.get(&subject) { if let Some(os) = pos.get(&predicate) { for o in os.iter() { @@ -316,7 +320,7 @@ impl EncodedQuadsStore for MemoryStore { graph_name: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - if let Some(graph) = self.graph_indexes.read()?.get(&graph_name) { + if let Some(graph) = self.graph_indexes()?.get(&graph_name) { if let Some(sps) = graph.osp.get(&object) { if let Some(ps) = sps.get(&subject) { for p in ps.iter() { @@ -334,7 +338,7 @@ impl EncodedQuadsStore for MemoryStore { graph_name: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - if let Some(graph) = self.graph_indexes.read()?.get(&graph_name) { + if let Some(graph) = self.graph_indexes()?.get(&graph_name) { if let Some(oss) = graph.pos.get(&predicate) { for (o, ss) in oss.iter() { for s in ss.iter() { @@ -353,7 +357,7 @@ impl EncodedQuadsStore for MemoryStore { graph_name: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - if let Some(graph) = self.graph_indexes.read()?.get(&graph_name) { + if let Some(graph) = self.graph_indexes()?.get(&graph_name) { if let Some(oss) = graph.pos.get(&predicate) { if let Some(ss) = oss.get(&object) { for s in ss.iter() { @@ -371,7 +375,7 @@ impl EncodedQuadsStore for MemoryStore { graph_name: EncodedTerm, ) -> Result<> as IntoIterator>::IntoIter> { let mut result = Vec::default(); - if let Some(graph) = self.graph_indexes.read()?.get(&graph_name) { + if let Some(graph) = self.graph_indexes()?.get(&graph_name) { if let Some(sps) = graph.osp.get(&object) { for (s, ps) in sps.iter() { for p in ps.iter() { @@ -385,8 +389,7 @@ impl EncodedQuadsStore for MemoryStore { fn contains(&self, quad: &EncodedQuad) -> Result { Ok(self - .graph_indexes - .read()? + .graph_indexes()? .get(&quad.graph_name) .map_or(false, |graph| { graph.spo.get(&quad.subject).map_or(false, |po| { @@ -397,7 +400,7 @@ impl EncodedQuadsStore for MemoryStore { } fn insert(&self, quad: &EncodedQuad) -> Result<()> { - let mut graph_indexes = self.graph_indexes.write()?; + let mut graph_indexes = self.graph_indexes_mut()?; let graph = graph_indexes .entry(quad.graph_name) .or_insert_with(MemoryGraphIndexes::default); @@ -426,7 +429,7 @@ impl EncodedQuadsStore for MemoryStore { } fn remove(&self, quad: &EncodedQuad) -> Result<()> { - let mut graph_indexes = self.graph_indexes.write()?; + let mut graph_indexes = self.graph_indexes_mut()?; let mut empty_graph = false; if let Some(graph) = graph_indexes.get_mut(&quad.graph_name) { { @@ -491,3 +494,35 @@ impl EncodedQuadsStore for MemoryStore { Ok(()) } } + +impl MemoryStore { + fn graph_indexes(&self) -> Result>> { + Ok(self + .graph_indexes + .read() + .map_err(MemoryStorePoisonError::from)?) + } + + fn graph_indexes_mut( + &self, + ) -> Result>> { + Ok(self + .graph_indexes + .write() + .map_err(MemoryStorePoisonError::from)?) + } +} + +#[derive(Debug, Fail)] +#[fail(display = "MemoryStore Mutex was poisoned")] +pub struct MemoryStorePoisonError { + backtrace: Backtrace, +} + +impl From> for MemoryStorePoisonError { + fn from(_: PoisonError) -> Self { + Self { + backtrace: Backtrace::new(), + } + } +} diff --git a/lib/src/store/numeric_encoder.rs b/lib/src/store/numeric_encoder.rs index f1df294c..b9861a0b 100644 --- a/lib/src/store/numeric_encoder.rs +++ b/lib/src/store/numeric_encoder.rs @@ -14,7 +14,6 @@ use std::str; use std::str::FromStr; use url::Url; use uuid::Uuid; -use Error; use Result; const EMPTY_STRING_ID: u64 = 0; @@ -47,7 +46,9 @@ pub trait BytesStore { { Ok(()) } else { - Err("Failed to properly setup the basic string ids in the dictionnary".into()) + Err(format_err!( + "Failed to properly setup the basic string ids in the dictionnary" + )) } } } @@ -317,17 +318,17 @@ impl TermReader for R { NaiveDateTime::from_timestamp_opt( self.read_i64::()?, self.read_u32::()?, - ).ok_or("Invalid date time serialization")?, + ).ok_or_else(|| format_err!("Invalid date time serialization"))?, FixedOffset::east_opt(self.read_i32::()?) - .ok_or("Invalid timezone offset")?, + .ok_or_else(|| format_err!("Invalid timezone offset"))?, ))), TYPE_NAIVE_DATE_TIME_LITERAL => Ok(EncodedTerm::NaiveDateTime( NaiveDateTime::from_timestamp_opt( self.read_i64::()?, self.read_u32::()?, - ).ok_or("Invalid date time serialization")?, + ).ok_or_else(|| format_err!("Invalid date time serialization"))?, )), - _ => Err("the term buffer has an invalid type id".into()), + _ => Err(format_err!("the term buffer has an invalid type id")), } } @@ -483,37 +484,37 @@ impl Encoder { } else if literal.is_boolean() { literal .to_bool() - .ok_or_else(|| Error::from("boolean literal without boolean value"))? + .ok_or_else(|| format_err!("boolean literal without boolean value"))? .into() } else if literal.is_float() { literal .to_float() - .ok_or_else(|| Error::from("float literal without float value"))? + .ok_or_else(|| format_err!("float literal without float value"))? .into() } else if literal.is_double() { literal .to_double() - .ok_or_else(|| Error::from("double literal without double value"))? + .ok_or_else(|| format_err!("double literal without double value"))? .into() } else if literal.is_integer() { literal .to_integer() - .ok_or_else(|| Error::from("integer literal without integer value"))? + .ok_or_else(|| format_err!("integer literal without integer value"))? .into() } else if literal.is_decimal() { literal .to_decimal() - .ok_or_else(|| Error::from("decimal literal without decimal value"))? + .ok_or_else(|| format_err!("decimal literal without decimal value"))? .into() } else if literal.is_date_time_stamp() { literal .to_date_time_stamp() - .ok_or_else(|| Error::from("dateTimeStamp literal without dateTimeStamp value"))? + .ok_or_else(|| format_err!("dateTimeStamp literal without dateTimeStamp value"))? .into() } else if literal.is_decimal() { literal .to_date_time() - .ok_or_else(|| Error::from("dateTime literal without dateTime value"))? + .ok_or_else(|| format_err!("dateTime literal without dateTime value"))? .into() } else { EncodedTerm::TypedLiteral { @@ -565,7 +566,9 @@ impl Encoder { pub fn decode_term(&self, encoded: EncodedTerm) -> Result { match encoded { - EncodedTerm::DefaultGraph {} => Err("The default graph tag is not a valid term".into()), + EncodedTerm::DefaultGraph {} => { + Err(format_err!("The default graph tag is not a valid term")) + } EncodedTerm::NamedNode { iri_id } => { Ok(NamedNode::from(self.decode_url_value(iri_id)?).into()) } @@ -604,15 +607,21 @@ impl Encoder { match self.decode_term(encoded)? { Term::NamedNode(named_node) => Ok(named_node.into()), Term::BlankNode(blank_node) => Ok(blank_node.into()), - Term::Literal(_) => Err("A literal has ben found instead of a named node".into()), + Term::Literal(_) => Err(format_err!( + "A literal has ben found instead of a named node" + )), } } pub fn decode_named_node(&self, encoded: EncodedTerm) -> Result { match self.decode_term(encoded)? { Term::NamedNode(named_node) => Ok(named_node), - Term::BlankNode(_) => Err("A blank node has been found instead of a named node".into()), - Term::Literal(_) => Err("A literal has ben found instead of a named node".into()), + Term::BlankNode(_) => Err(format_err!( + "A blank node has been found instead of a named node" + )), + Term::Literal(_) => Err(format_err!( + "A literal has ben found instead of a named node" + )), } } @@ -653,7 +662,7 @@ impl Encoder { fn decode_value(&self, id: u64) -> Result { self.string_store .get_bytes(id)? - .ok_or_else(|| "value not found in the dictionary".into()) + .ok_or_else(|| format_err!("value not found in the dictionary")) } } diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index 69cf6d20..e895eb66 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -1,5 +1,6 @@ use byteorder::ByteOrder; use byteorder::LittleEndian; +use failure::Backtrace; use rocksdb::ColumnFamily; use rocksdb::DBRawIterator; use rocksdb::DBVector; @@ -10,6 +11,7 @@ use std::io::Cursor; use std::path::Path; use std::str; use std::sync::Mutex; +use std::sync::PoisonError; use store::encoded::EncodedQuadsStore; use store::encoded::StoreDataset; use store::numeric_encoder::*; @@ -86,7 +88,11 @@ impl BytesStore for RocksDbStore { Ok(if let Some(id) = self.db.get_cf(self.str2id_cf, value)? { LittleEndian::read_u64(&id) } else { - let id = self.str_id_counter.lock()?.get_and_increment(&self.db)? as u64; + let id = self + .str_id_counter + .lock() + .map_err(RocksDBCounterMutexPoisonError::from)? + .get_and_increment(&self.db)? as u64; let id_bytes = to_bytes(id); let mut batch = WriteBatch::default(); batch.put_cf(self.id2str_cf, &id_bytes, value)?; @@ -326,7 +332,7 @@ impl EncodedQuadsStore for RocksDbStore { pub fn get_cf(db: &DB, name: &str) -> Result { db.cf_handle(name) - .ok_or_else(|| "column family not found".into()) + .ok_or_else(|| format_err!("column family not found")) } struct RocksDBCounter { @@ -516,3 +522,17 @@ fn to_bytes(int: u64) -> [u8; 8] { LittleEndian::write_u64(&mut buf, int); buf } + +#[derive(Debug, Fail)] +#[fail(display = "RocksDBStore Mutex was poisoned")] +pub struct RocksDBCounterMutexPoisonError { + backtrace: Backtrace, +} + +impl From> for RocksDBCounterMutexPoisonError { + fn from(_: PoisonError) -> Self { + Self { + backtrace: Backtrace::new(), + } + } +} diff --git a/lib/tests/rdf_test_cases.rs b/lib/tests/rdf_test_cases.rs index 62498d61..0efa1732 100644 --- a/lib/tests/rdf_test_cases.rs +++ b/lib/tests/rdf_test_cases.rs @@ -5,6 +5,8 @@ extern crate lazy_static; extern crate reqwest; extern crate rudf; extern crate url; +#[macro_use] +extern crate failure; use reqwest::Client; use reqwest::Response; @@ -212,7 +214,7 @@ impl RDFClient { { self.get(url) } else { - Err(format!("HTTP request error: {}", error.description()).into()) + Err(format_err!("HTTP request error: {}", error.description())) }, } } @@ -296,9 +298,9 @@ impl<'a> Iterator for TestManifest<'a> { { Some(Term::NamedNode(c)) => match c.as_str().split("#").last() { Some(k) => k.to_string(), - None => return Some(Err("no type".into())), + None => return Some(Err(format_err!("no type"))), }, - _ => return Some(Err("no type".into())), + _ => return Some(Err(format_err!("no type"))), }; let name = match self .graph @@ -322,8 +324,8 @@ impl<'a> Iterator for TestManifest<'a> { .unwrap() { Some(Term::NamedNode(n)) => n.as_url().clone(), - Some(_) => return Some(Err("invalid action".into())), - None => return Some(Err("action not found".into())), + Some(_) => return Some(Err(format_err!("invalid action"))), + None => return Some(Err(format_err!("action not found"))), }; let result = match self .graph @@ -331,7 +333,7 @@ impl<'a> Iterator for TestManifest<'a> { .unwrap() { Some(Term::NamedNode(n)) => Some(n.as_url().clone()), - Some(_) => return Some(Err("invalid result".into())), + Some(_) => return Some(Err(format_err!("invalid result"))), None => None, }; Some(Ok(Test { @@ -343,7 +345,7 @@ impl<'a> Iterator for TestManifest<'a> { result, })) } - Some(_) => Some(Err("invalid test list".into())), + Some(_) => Some(Err(format_err!("invalid test list"))), None => { match self.manifests_to_do.pop() { Some(url) => { @@ -371,7 +373,7 @@ impl<'a> Iterator for TestManifest<'a> { }), ); } - Some(_) => return Some(Err("invalid tests list".into())), + Some(_) => return Some(Err(format_err!("invalid tests list"))), None => (), } @@ -388,9 +390,10 @@ impl<'a> Iterator for TestManifest<'a> { )); } Some(term) => { - return Some(Err( - format!("Invalid tests list. Got term {}", term).into() - )) + return Some(Err(format_err!( + "Invalid tests list. Got term {}", + term + ))) } None => (), } diff --git a/lib/tests/sparql_test_cases.rs b/lib/tests/sparql_test_cases.rs index 8539d425..2626d6f2 100644 --- a/lib/tests/sparql_test_cases.rs +++ b/lib/tests/sparql_test_cases.rs @@ -4,6 +4,8 @@ extern crate lazy_static; extern crate reqwest; extern crate rudf; extern crate url; +#[macro_use] +extern crate failure; use reqwest::Client; use reqwest::Response; @@ -276,7 +278,7 @@ impl RDFClient { } else if url.as_str().ends_with(".rdf") { read_rdf_xml(BufReader::new(self.get(&url)?), Some(url)).collect() } else { - Err(format!("Serialization type not found for {}", url).into()) + Err(format_err!("Serialization type not found for {}", url)) } } @@ -299,7 +301,7 @@ impl RDFClient { { self.get(url) } else { - Err(format!("HTTP request error: {}", error.description()).into()) + Err(format_err!("HTTP request error: {}", error.description())) }, } } @@ -518,9 +520,9 @@ impl<'a> Iterator for TestManifest<'a> { { Some(Term::NamedNode(c)) => match c.as_str().split("#").last() { Some(k) => k.to_string(), - None => return Some(Err("no type".into())), + None => return Some(Err(format_err!("no type"))), }, - _ => return Some(Err("no type".into())), + _ => return Some(Err(format_err!("no type"))), }; let name = match self .graph @@ -552,8 +554,8 @@ impl<'a> Iterator for TestManifest<'a> { .unwrap() { Some(Term::NamedNode(q)) => q.into(), - Some(_) => return Some(Err("invalid query".into())), - None => return Some(Err("query not found".into())), + Some(_) => return Some(Err(format_err!("invalid query"))), + None => return Some(Err(format_err!("query not found"))), }; let data = match self .graph @@ -573,11 +575,12 @@ impl<'a> Iterator for TestManifest<'a> { }).collect(); (query, data, graph_data) } - Some(_) => return Some(Err("invalid action".into())), + Some(_) => return Some(Err(format_err!("invalid action"))), None => { - return Some(Err( - format!("action not found for test {}", test_subject).into() - )) + return Some(Err(format_err!( + "action not found for test {}", + test_subject + ))) } }; let result = match self @@ -586,7 +589,7 @@ impl<'a> Iterator for TestManifest<'a> { .unwrap() { Some(Term::NamedNode(n)) => Some(n.into()), - Some(_) => return Some(Err("invalid result".into())), + Some(_) => return Some(Err(format_err!("invalid result"))), None => None, }; Some(Ok(Test { @@ -600,7 +603,7 @@ impl<'a> Iterator for TestManifest<'a> { result, })) } - Some(_) => Some(Err("invalid test list".into())), + Some(_) => Some(Err(format_err!("invalid test list"))), None => { match self.manifests_to_do.pop() { Some(url) => { @@ -628,7 +631,7 @@ impl<'a> Iterator for TestManifest<'a> { }), ); } - Some(_) => return Some(Err("invalid tests list".into())), + Some(_) => return Some(Err(format_err!("invalid tests list"))), None => (), } @@ -645,9 +648,10 @@ impl<'a> Iterator for TestManifest<'a> { )); } Some(term) => { - return Some(Err( - format!("Invalid tests list. Got term {}", term).into() - )); + return Some(Err(format_err!( + "Invalid tests list. Got term {}", + term + ))); } None => (), } diff --git a/python/src/lib.rs b/python/src/lib.rs index df20de06..44b8fe1d 100644 --- a/python/src/lib.rs +++ b/python/src/lib.rs @@ -15,8 +15,8 @@ use cpython::Python; use cpython::PythonObject; use cpython::ToPyObject; use rudf::model; +use rudf::Error; use std::collections::hash_map::DefaultHasher; -use std::error::Error; use std::hash::Hash; use std::hash::Hasher; use std::str::FromStr; @@ -29,8 +29,8 @@ py_module_initializer!(rudf, initrudf, PyInit_rudf, |py, m| { Ok(()) }); -fn new_value_error(py: Python, error: &impl Error) -> PyErr { - PyErr::new::(py, error.description()) +fn new_value_error(py: Python, error: &Error) -> PyErr { + PyErr::new::(py, error.to_string()) } fn eq_compare(a: &T, b: &T, op: &CompareOp) -> bool {