Skip to content

Commit

Permalink
feat(cognitarium): make delete msg rely on triple iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
amimart committed Nov 2, 2023
1 parent 292ef7d commit 1fdc691
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 93 deletions.
20 changes: 11 additions & 9 deletions contracts/okp4-cognitarium/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,23 @@ pub mod execute {
} else {
delete
};
let variables = util::as_select_veriables(&patterns);

let prefix_map = <PrefixMap>::from(prefixes).into_inner();
let mut plan_builder = PlanBuilder::new(deps.storage, &prefix_map, None);
let plan = plan_builder.build_plan(&r#where)?;

let response = QueryEngine::new(deps.storage).select(
plan,
variables,
plan_builder.cached_namespaces().into(),
)?;
let results = response.results;
let atoms = util::as_atoms_result(results, patterns, &prefix_map)?;
let triples = QueryEngine::new(deps.storage)
.select(plan, util::as_select_variables(&patterns))?
.solutions
.resolve_triples(
deps.storage,
&prefix_map,
patterns,
plan_builder.cached_namespaces(),
)?;

let mut store = StoreEngine::new(deps.storage)?;
let count = store.delete_all(&atoms)?;
let count = store.delete_all(&triples)?;

Ok(Response::new()
.add_attribute("action", "delete")
Expand Down
59 changes: 28 additions & 31 deletions contracts/okp4-cognitarium/src/state/namespaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,16 @@ impl NamespaceBatchService {
})
}

/// Resolve a [Namespace] from its internal key, returning it from cache in priority before accessing
/// the state.
pub fn resolve_from_key(
&mut self,
storage: &dyn Storage,
key: u128,
) -> StdResult<Option<Namespace>> {
self.ns_resolver.resolve_from_key(storage, key)
}

/// Resolve a namespace by its value, or allocate a new one if not existing. This is applied to
/// the in-memory cache only, [Self::flush] must be called to write the changes to the state.
pub fn resolve_or_allocate(
Expand Down Expand Up @@ -228,21 +238,26 @@ impl NamespaceBatchService {
/// Decrement the count of references to this namespace, deleting it if not used anymore.
/// This is applied to the in-memory cache only, [Self::flush] must be called to write the changes
/// to the state.
pub fn free_ref_by_key(&mut self, storage: &dyn Storage, key: u128) -> StdResult<Namespace> {
pub fn free_ref(&mut self, storage: &dyn Storage, key: u128) -> StdResult<Namespace> {
self.ns_resolver
.resolve_cell_from_key(storage, key)
.and_then(|maybe_cell| self.free_ref(maybe_cell))
}

/// Same as [Self::free_ref_by_key] but identifying a namespace by value.
pub fn free_ref_by_val(
&mut self,
storage: &dyn Storage,
value: String,
) -> StdResult<Namespace> {
self.ns_resolver
.resolve_cell_from_val(storage, value)
.and_then(|maybe_cell| self.free_ref(maybe_cell))
.and_then(|maybe_cell| {
let cell = match maybe_cell.filter(|c| c.borrow().counter > 0) {
Some(c) => c,
None => Err(StdError::generic_err(
"Trying to delete a non existing namespace",
))?,
};

let mut ns = cell.borrow_mut();
ns.counter -= 1;
if ns.counter == 0 {
self.ns_count_diff -= 1;
}

let tmp = ns.clone();
Ok(tmp)
})
}

/// Writes all the cached changes to the state, returning the namespace count diff.
Expand All @@ -268,24 +283,6 @@ impl NamespaceBatchService {
Ok(count_diff)
}

fn free_ref(&mut self, maybe_ns_cell: Option<Rc<RefCell<Namespace>>>) -> StdResult<Namespace> {
let cell = match maybe_ns_cell.filter(|c| c.borrow().counter > 0) {
Some(c) => c,
None => Err(StdError::generic_err(
"Trying to delete a non existing namespace",
))?,
};

let mut ns = cell.borrow_mut();
ns.counter -= 1;
if ns.counter == 0 {
self.ns_count_diff -= 1;
}

let tmp = ns.clone();
Ok(tmp)
}

fn allocate(&mut self, value: String) -> Namespace {
let ns = Namespace {
value,
Expand Down
117 changes: 64 additions & 53 deletions contracts/okp4-cognitarium/src/storer/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::state::{
triples, Literal, NamespaceBatchService, Node, Object, Store, Subject, Triple, STORE,
};
use crate::{rdf, ContractError};
use blake3::Hash;
use cosmwasm_std::{StdError, StdResult, Storage, Uint128};
use rio_api::model;
use rio_api::model::Term;
Expand Down Expand Up @@ -53,7 +52,12 @@ impl<'a> StoreEngine<'a> {
))?;
}

let t_size = Uint128::from(Self::triple_size(t) as u128);
let triple = Self::rio_to_triple(t, &mut |ns_str| {
self.ns_batch_svc
.resolve_or_allocate(self.storage, ns_str)
.map(|ns| ns.key)
})?;
let t_size = Uint128::from(self.triple_size(&triple).map_err(ContractError::Std)? as u128);
if t_size > self.store.limits.max_triple_byte_size {
Err(StoreError::TripleByteSize(
t_size,
Expand All @@ -73,19 +77,12 @@ impl<'a> StoreEngine<'a> {
))?;
}

let triple = Self::rio_to_triple(t, &mut |ns_str| {
self.ns_batch_svc
.resolve_or_allocate(self.storage, ns_str)
.map(|ns| ns.key)
})?;
let object_hash: Hash = triple.object.as_hash();

let mut new_ns_refs = Vec::new();
triples()
.update(
self.storage,
(
object_hash.as_bytes(),
triple.object.as_hash().as_bytes(),
triple.predicate.key(),
triple.subject.key(),
),
Expand All @@ -108,35 +105,47 @@ impl<'a> StoreEngine<'a> {
Ok(())
}

pub fn delete_all(&mut self, atoms: &[rdf::Atom]) -> Result<Uint128, ContractError> {
for atom in atoms {
self.delete_triple(atom)?;
pub fn delete_all(&mut self, triples: &[Triple]) -> Result<Uint128, ContractError> {
for triple in triples {
self.delete_triple(triple)?;
}
self.finish()
}

fn delete_triple(&mut self, atom: &rdf::Atom) -> Result<(), ContractError> {
let triple_model = atom.into();
let triple = Self::rio_to_triple(triple_model, &mut |ns_str| {
self.ns_batch_svc
.free_ref_by_val(self.storage, ns_str)
.map(|ns| ns.key)
})?;
let object_hash: Hash = triple.object.as_hash();

self.store.stat.triple_count -= Uint128::one();
self.store.stat.byte_size -= Uint128::from(Self::triple_size(triple_model) as u128);

triples()
.remove(
fn delete_triple(&mut self, triple: &Triple) -> Result<(), ContractError> {
let old = triples()
.may_load(
self.storage,
(
object_hash.as_bytes(),
triple.object.as_hash().as_bytes(),
triple.predicate.key(),
triple.subject.key(),
),
)
.map_err(ContractError::Std)
.map_err(ContractError::Std)?;

if let Some(_) = old {
triples().replace(
self.storage,
(
triple.object.as_hash().as_bytes(),
triple.predicate.key(),
triple.subject.key(),
),
None,
old.as_ref(),
)?;
self.store.stat.triple_count -= Uint128::one();
let triple_size = self.triple_size(triple).map_err(ContractError::Std)?;
self.store.stat.byte_size -= Uint128::from(triple_size as u128);

for ns_key in triple.namespaces() {
self.ns_batch_svc
.free_ref(self.storage, ns_key)
.map_err(ContractError::Std)?;
}
}
Ok(())
}

/// Flushes the store to the storage.
Expand Down Expand Up @@ -229,38 +238,40 @@ impl<'a> StoreEngine<'a> {
}
}

fn triple_size(triple: model::Triple<'_>) -> usize {
Self::subject_size(triple.subject)
+ Self::node_size(triple.predicate)
+ Self::object_size(triple.object)
fn triple_size(&mut self, triple: &Triple) -> StdResult<usize> {
Ok(self.subject_size(&triple.subject)?
+ self.node_size(&triple.predicate)?
+ self.object_size(&triple.object)?)
}

fn subject_size(subject: model::Subject<'_>) -> usize {
fn subject_size(&mut self, subject: &Subject) -> StdResult<usize> {
match subject {
model::Subject::NamedNode(n) => Self::node_size(n),
model::Subject::BlankNode(n) => n.id.len(),
model::Subject::Triple(_) => 0,
Subject::Named(n) => self.node_size(&n),
Subject::Blank(n) => Ok(n.len()),
}
}

fn node_size(node: model::NamedNode<'_>) -> usize {
node.iri.len()
fn node_size(&mut self, node: &Node) -> StdResult<usize> {
if let Some(ns) = self
.ns_batch_svc
.resolve_from_key(self.storage, node.namespace)?
{
return Ok(ns.value.len() + node.value.len());
}

// Should never happen as in its use the namespace should be already cached.
Err(StdError::not_found("Namespace"))
}

fn object_size(term: Term<'_>) -> usize {
match term {
Term::NamedNode(n) => Self::node_size(n),
Term::BlankNode(n) => n.id.len(),
Term::Literal(l) => match l {
model::Literal::Simple { value } => value.len(),
model::Literal::LanguageTaggedString { value, language } => {
value.len() + language.len()
}
model::Literal::Typed { value, datatype } => {
value.len() + Self::node_size(datatype)
}
fn object_size(&mut self, object: &Object) -> StdResult<usize> {
Ok(match object {
Object::Blank(n) => n.len(),
Object::Named(n) => self.node_size(n)?,
Object::Literal(l) => match l {
Literal::Simple { value } => value.len(),
Literal::I18NString { value, language } => value.len() + language.len(),
Literal::Typed { value, datatype } => value.len() + self.node_size(datatype)?,
},
Term::Triple(_) => 0,
}
})
}
}

0 comments on commit 1fdc691

Please sign in to comment.