Simplifies in-memory transactions

pull/46/head
Tpt 4 years ago
parent 0a6a09bcb4
commit 79fcd9bc00
  1. 127
      lib/src/store/memory.rs

@ -1,7 +1,7 @@
//! In-memory store. //! In-memory store.
use crate::error::UnwrapInfallible; use crate::error::{invalid_input_error, UnwrapInfallible};
use crate::io::{DatasetFormat, GraphFormat}; use crate::io::{DatasetFormat, DatasetParser, GraphFormat, GraphParser};
use crate::model::*; use crate::model::*;
use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::store::numeric_encoder::{ use crate::store::numeric_encoder::{
@ -240,17 +240,26 @@ impl MemoryStore {
/// assert!(store.contains(&quad)); /// assert!(store.contains(&quad));
/// # Result::<_,Box<dyn std::error::Error>>::Ok(()) /// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ``` /// ```
pub fn transaction<'a, E>( pub fn transaction<E>(
&'a self, &self,
f: impl FnOnce(&mut MemoryTransaction<'a>) -> Result<(), E>, f: impl FnOnce(&mut MemoryTransaction) -> Result<(), E>,
) -> Result<(), E> { ) -> Result<(), E> {
let mut transaction = MemoryTransaction { let mut transaction = MemoryTransaction { ops: Vec::new() };
store: self,
ops: Vec::new(),
strings: TrivialHashMap::default(),
};
f(&mut transaction)?; f(&mut transaction)?;
transaction.commit();
let mut indexes = self.indexes_mut();
for op in transaction.ops {
match op {
TransactionOp::Insert(quad) => {
let quad = indexes.encode_quad(&quad).unwrap_infallible();
indexes.insert_encoded(&quad).unwrap_infallible()
}
TransactionOp::Delete(quad) => {
let quad = indexes.encode_quad(&quad).unwrap_infallible();
indexes.remove_encoded(&quad).unwrap_infallible()
}
}
}
Ok(()) Ok(())
} }
@ -959,18 +968,16 @@ impl MemoryPreparedQuery {
} }
/// Allows to insert and delete quads during a transaction with the `MemoryStore`. /// Allows to insert and delete quads during a transaction with the `MemoryStore`.
pub struct MemoryTransaction<'a> { pub struct MemoryTransaction {
store: &'a MemoryStore,
ops: Vec<TransactionOp>, ops: Vec<TransactionOp>,
strings: TrivialHashMap<StrHash, String>,
} }
enum TransactionOp { enum TransactionOp {
Insert(EncodedQuad), Insert(Quad),
Delete(EncodedQuad), Delete(Quad),
} }
impl<'a> MemoryTransaction<'a> { impl MemoryTransaction {
/// Loads a graph file (i.e. triples) into the store during the transaction. /// Loads a graph file (i.e. triples) into the store during the transaction.
/// ///
/// Usage example: /// Usage example:
@ -1000,7 +1007,17 @@ impl<'a> MemoryTransaction<'a> {
to_graph_name: &GraphName, to_graph_name: &GraphName,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<(), io::Error> { ) -> Result<(), io::Error> {
load_graph(self, reader, format, to_graph_name, base_iri)?; let mut parser = GraphParser::from_format(format);
if let Some(base_iri) = base_iri {
parser = parser
.with_base_iri(base_iri)
.map_err(invalid_input_error)?;
}
for triple in parser.read_triples(reader)? {
self.ops.push(TransactionOp::Insert(
triple?.in_graph(to_graph_name.clone()),
));
}
Ok(()) Ok(())
} }
@ -1030,77 +1047,27 @@ impl<'a> MemoryTransaction<'a> {
format: DatasetFormat, format: DatasetFormat,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<(), io::Error> { ) -> Result<(), io::Error> {
load_dataset(self, reader, format, base_iri)?; let mut parser = DatasetParser::from_format(format);
if let Some(base_iri) = base_iri {
parser = parser
.with_base_iri(base_iri)
.map_err(invalid_input_error)?;
}
for quad in parser.read_quads(reader)? {
self.ops.push(TransactionOp::Insert(quad?));
}
Ok(()) Ok(())
} }
/// Adds a quad to this store during the transaction. /// Adds a quad to this store during the transaction.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub fn insert(&mut self, quad: Quad) { pub fn insert(&mut self, quad: Quad) {
let quad = self.encode_quad(&quad).unwrap_infallible(); self.ops.push(TransactionOp::Insert(quad))
self.insert_encoded(&quad).unwrap_infallible();
} }
/// Removes a quad from this store during the transaction. /// Removes a quad from this store during the transaction.
pub fn remove(&mut self, quad: &Quad) { pub fn remove(&mut self, quad: Quad) {
if let Some(quad) = self.get_encoded_quad(quad).unwrap_infallible() { self.ops.push(TransactionOp::Delete(quad))
self.remove_encoded(&quad).unwrap_infallible();
}
}
fn commit(self) {
let mut indexes = self.store.indexes_mut();
indexes.id2str.extend(self.strings);
for op in self.ops {
match op {
TransactionOp::Insert(quad) => indexes.insert_encoded(&quad).unwrap_infallible(),
TransactionOp::Delete(quad) => indexes.remove_encoded(&quad).unwrap_infallible(),
}
}
}
}
impl StrLookup for MemoryTransaction<'_> {
fn get_str(&self, id: StrHash) -> Result<Option<String>, Infallible> {
if let Some(str) = self.strings.get(&id) {
Ok(Some(str.clone()))
} else {
self.store.get_str(id)
}
}
fn get_str_id(&self, value: &str) -> Result<Option<StrHash>, Infallible> {
let id = StrHash::new(value);
if self.strings.contains_key(&id) {
Ok(Some(id))
} else {
self.store.get_str_id(value)
}
}
}
impl WithStoreError for MemoryTransaction<'_> {
type Error = Infallible;
type StrId = StrHash;
}
impl StrContainer for MemoryTransaction<'_> {
fn insert_str(&mut self, value: &str) -> Result<StrHash, Infallible> {
let key = StrHash::new(value);
self.strings.insert(key, value.to_owned());
Ok(key)
}
}
impl WritableEncodedStore for MemoryTransaction<'_> {
fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<(), Infallible> {
self.ops.push(TransactionOp::Insert(*quad));
Ok(())
}
fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<(), Infallible> {
self.ops.push(TransactionOp::Delete(*quad));
Ok(())
} }
} }

Loading…
Cancel
Save