encode, decode, compare
parent
6c5ac6faa9
commit
dd7a59d258
@ -0,0 +1,159 @@
|
|||||||
|
use crate::data::encode::{
|
||||||
|
decode_ae_key, decode_attr_key_by_id, decode_attr_key_by_kw, decode_ea_key,
|
||||||
|
decode_unique_attr_val, decode_vae_key, decode_value_from_key, StorageTag,
|
||||||
|
};
|
||||||
|
use crate::data::id::{EntityId, TxId};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn rusty_cmp(a: &cozorocks::Slice, b: &cozorocks::Slice) -> cozorocks::c_int {
|
||||||
|
let a = cozorocks::convert_slice_back(a);
|
||||||
|
let b = cozorocks::convert_slice_back(b);
|
||||||
|
cozorocks::c_int(match compare_key(a, b) {
|
||||||
|
Ordering::Greater => 1,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
Ordering::Less => -1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const DB_KEY_PREFIX_LEN: usize = 4;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub(crate) static ref RUSTY_COMPARATOR: cozorocks::UniquePtr<cozorocks::RustComparator> = {
|
||||||
|
unsafe {
|
||||||
|
let f_ptr = rusty_cmp as *const cozorocks::c_void;
|
||||||
|
cozorocks::new_rust_comparator("cozo_rusty_cmp_v1", false, f_ptr)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! return_if_resolved {
|
||||||
|
($o:expr) => {
|
||||||
|
match $o {
|
||||||
|
std::cmp::Ordering::Equal => {}
|
||||||
|
o => return o,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
use StorageTag::*;
|
||||||
|
|
||||||
|
return_if_resolved!(a[0].cmp(&b[0]));
|
||||||
|
|
||||||
|
match StorageTag::try_from(a[0]).unwrap() {
|
||||||
|
TripleEntityAttrValue => compare_key_triple_eav(a, b),
|
||||||
|
TripleAttrEntityValue => compare_key_triple_aev(a, b),
|
||||||
|
TripleAttrValueEntity => compare_key_triple_ave(a, b),
|
||||||
|
TripleValueAttrEntity => compare_key_triple_vae(a, b),
|
||||||
|
AttrById => compare_key_attr_by_id(a, b),
|
||||||
|
AttrByKeyword => compare_key_attr_by_kw(a, b),
|
||||||
|
Tx => compare_key_tx(a, b),
|
||||||
|
UniqueEntity => compare_key_unique_entity(a, b),
|
||||||
|
UniqueAttrValue => compare_key_unique_attr_val(a, b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key_triple_eav(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
let (a_e, a_a, a_t, a_o) = decode_ea_key(a).unwrap();
|
||||||
|
let (b_e, b_a, b_t, b_o) = decode_ea_key(b).unwrap();
|
||||||
|
|
||||||
|
return_if_resolved!(a_e.cmp(&b_e));
|
||||||
|
return_if_resolved!(a_a.cmp(&b_a));
|
||||||
|
|
||||||
|
let a_v = decode_value_from_key(a).unwrap();
|
||||||
|
let b_v = decode_value_from_key(b).unwrap();
|
||||||
|
|
||||||
|
return_if_resolved!(a_v.cmp(&b_v));
|
||||||
|
return_if_resolved!(a_t.cmp(&b_t).reverse());
|
||||||
|
a_o.cmp(&b_o)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key_triple_aev(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
let (a_a, a_e, a_t, a_o) = decode_ae_key(a).unwrap();
|
||||||
|
let (b_a, b_e, b_t, b_o) = decode_ae_key(b).unwrap();
|
||||||
|
|
||||||
|
return_if_resolved!(a_a.cmp(&b_a));
|
||||||
|
return_if_resolved!(a_e.cmp(&b_e));
|
||||||
|
|
||||||
|
let a_v = decode_value_from_key(a).unwrap();
|
||||||
|
let b_v = decode_value_from_key(b).unwrap();
|
||||||
|
|
||||||
|
return_if_resolved!(a_v.cmp(&b_v));
|
||||||
|
return_if_resolved!(a_t.cmp(&b_t).reverse());
|
||||||
|
a_o.cmp(&b_o)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key_triple_ave(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
let (a_a, a_e, a_t, a_o) = decode_ae_key(a).unwrap();
|
||||||
|
let (b_a, b_e, b_t, b_o) = decode_ae_key(b).unwrap();
|
||||||
|
|
||||||
|
return_if_resolved!(a_a.cmp(&b_a));
|
||||||
|
|
||||||
|
let a_v = decode_value_from_key(a).unwrap();
|
||||||
|
let b_v = decode_value_from_key(b).unwrap();
|
||||||
|
|
||||||
|
return_if_resolved!(a_v.cmp(&b_v));
|
||||||
|
return_if_resolved!(a_e.cmp(&b_e));
|
||||||
|
return_if_resolved!(a_t.cmp(&b_t).reverse());
|
||||||
|
a_o.cmp(&b_o)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key_triple_vae(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
let (a_v, a_a, a_e, a_t, a_o) = decode_vae_key(a).unwrap();
|
||||||
|
let (b_v, b_a, b_e, b_t, b_o) = decode_vae_key(b).unwrap();
|
||||||
|
|
||||||
|
return_if_resolved!(a_v.cmp(&b_v));
|
||||||
|
return_if_resolved!(a_a.cmp(&b_a));
|
||||||
|
return_if_resolved!(a_e.cmp(&b_e));
|
||||||
|
return_if_resolved!(a_t.cmp(&b_t).reverse());
|
||||||
|
a_o.cmp(&b_o)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key_attr_by_id(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
let (a_a, a_t, a_o) = decode_attr_key_by_id(a).unwrap();
|
||||||
|
let (b_a, b_t, b_o) = decode_attr_key_by_id(b).unwrap();
|
||||||
|
|
||||||
|
return_if_resolved!(a_a.cmp(&b_a));
|
||||||
|
return_if_resolved!(a_t.cmp(&b_t).reverse());
|
||||||
|
a_o.cmp(&b_o)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key_attr_by_kw(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
let (a_kw, a_t, a_o) = decode_attr_key_by_kw(a).unwrap();
|
||||||
|
let (b_kw, b_t, b_o) = decode_attr_key_by_kw(b).unwrap();
|
||||||
|
|
||||||
|
return_if_resolved!(a_kw.cmp(&b_kw));
|
||||||
|
return_if_resolved!(a_t.cmp(&b_t).reverse());
|
||||||
|
a_o.cmp(&b_o)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key_tx(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
let a_t = TxId::from_bytes(a);
|
||||||
|
let b_t = TxId::from_bytes(b);
|
||||||
|
a_t.cmp(&b_t).reverse()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key_unique_entity(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
let a_e = EntityId::from_bytes(a);
|
||||||
|
let b_e = EntityId::from_bytes(b);
|
||||||
|
a_e.cmp(&b_e)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compare_key_unique_attr_val(a: &[u8], b: &[u8]) -> Ordering {
|
||||||
|
let (a_a, a_v) = decode_unique_attr_val(a).unwrap();
|
||||||
|
let (b_a, b_v) = decode_unique_attr_val(b).unwrap();
|
||||||
|
return_if_resolved!(a_a.cmp(&b_a));
|
||||||
|
a_v.cmp(&b_v)
|
||||||
|
}
|
@ -0,0 +1,291 @@
|
|||||||
|
use crate::data::encode::StorageTag::Tx;
|
||||||
|
use crate::data::id::{AttrId, EntityId, TxId};
|
||||||
|
use crate::data::keyword::Keyword;
|
||||||
|
use crate::data::triple::StoreOp;
|
||||||
|
use crate::data::value::Value;
|
||||||
|
use anyhow::Result;
|
||||||
|
use rmp_serde::Serializer;
|
||||||
|
use serde::Serialize;
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)]
|
||||||
|
pub(crate) enum StorageTag {
|
||||||
|
TripleEntityAttrValue = 1,
|
||||||
|
TripleAttrEntityValue = 2,
|
||||||
|
TripleAttrValueEntity = 3,
|
||||||
|
TripleValueAttrEntity = 4,
|
||||||
|
AttrById = 5,
|
||||||
|
AttrByKeyword = 6,
|
||||||
|
Tx = 7,
|
||||||
|
UniqueEntity = 8,
|
||||||
|
UniqueAttrValue = 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum StorageTagError {
|
||||||
|
#[error("unexpected value for StoreOp: {0}")]
|
||||||
|
UnexpectedValue(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for StorageTag {
|
||||||
|
type Error = StorageTagError;
|
||||||
|
fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
|
||||||
|
use StorageTag::*;
|
||||||
|
Ok(match value {
|
||||||
|
1 => TripleEntityAttrValue,
|
||||||
|
2 => TripleAttrEntityValue,
|
||||||
|
3 => TripleAttrValueEntity,
|
||||||
|
4 => TripleValueAttrEntity,
|
||||||
|
5 => AttrById,
|
||||||
|
6 => AttrByKeyword,
|
||||||
|
7 => Tx,
|
||||||
|
8 => UniqueEntity,
|
||||||
|
9 => UniqueAttrValue,
|
||||||
|
n => return Err(StorageTagError::UnexpectedValue(n)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_value(val: Value) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 60]>::new();
|
||||||
|
val.serialize(&mut Serializer::new(&mut ret)).unwrap();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn decode_value(src: &[u8]) -> Result<Value> {
|
||||||
|
Ok(rmp_serde::from_slice(src)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn decode_value_from_key(src: &[u8]) -> Result<Value> {
|
||||||
|
Ok(rmp_serde::from_slice(&src[20..])?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// eid: 8 bytes (incl. tag)
|
||||||
|
/// aid: 4 bytes
|
||||||
|
/// val: variable
|
||||||
|
/// tx: 8 bytes (incl. op)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_eav_key(
|
||||||
|
eid: EntityId,
|
||||||
|
aid: AttrId,
|
||||||
|
val: Value,
|
||||||
|
tx: TxId,
|
||||||
|
op: StoreOp,
|
||||||
|
) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 60]>::new();
|
||||||
|
|
||||||
|
ret.extend(eid.0.to_be_bytes());
|
||||||
|
ret[0] = StorageTag::TripleEntityAttrValue as u8;
|
||||||
|
|
||||||
|
ret.extend(aid.0.to_be_bytes());
|
||||||
|
|
||||||
|
ret.extend(tx.0.to_be_bytes());
|
||||||
|
ret[12] = op as u8;
|
||||||
|
debug_assert_eq!(ret.len(), 20);
|
||||||
|
|
||||||
|
val.serialize(&mut Serializer::new(&mut ret)).unwrap();
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn decode_ea_key(src: &[u8]) -> Result<(EntityId, AttrId, TxId, StoreOp)> {
|
||||||
|
let eid = EntityId::from_bytes(&src[0..8]);
|
||||||
|
let aid = AttrId::from_bytes(&src[8..12]);
|
||||||
|
let tx = TxId::from_bytes(&src[12..20]);
|
||||||
|
let op = src[12].try_into()?;
|
||||||
|
|
||||||
|
Ok((eid, aid, tx, op))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// eid: 8 bytes (incl. tag)
|
||||||
|
/// aid: 4 bytes
|
||||||
|
/// val: variable
|
||||||
|
/// tx: 8 bytes (incl. op)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_aev_key(
|
||||||
|
aid: AttrId,
|
||||||
|
eid: EntityId,
|
||||||
|
val: Value,
|
||||||
|
tx: TxId,
|
||||||
|
op: StoreOp,
|
||||||
|
) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 60]>::new();
|
||||||
|
|
||||||
|
ret.extend(aid.0.to_be_bytes());
|
||||||
|
ret[0] = StorageTag::TripleAttrEntityValue as u8;
|
||||||
|
|
||||||
|
ret.extend(eid.0.to_be_bytes());
|
||||||
|
ret.extend(tx.0.to_be_bytes());
|
||||||
|
ret[12] = op as u8;
|
||||||
|
debug_assert_eq!(ret.len(), 20);
|
||||||
|
|
||||||
|
val.serialize(&mut Serializer::new(&mut ret)).unwrap();
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn decode_ae_key(src: &[u8]) -> Result<(AttrId, EntityId, TxId, StoreOp)> {
|
||||||
|
let aid = AttrId::from_bytes(&src[0..4]);
|
||||||
|
let eid = EntityId::from_bytes(&src[4..12]);
|
||||||
|
let tx = TxId::from_bytes(&src[12..20]);
|
||||||
|
let op = src[12].try_into()?;
|
||||||
|
|
||||||
|
Ok((aid, eid, tx, op))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// aid: 4 bytes (incl. tag)
|
||||||
|
/// val: variable
|
||||||
|
/// eid: 8 bytes
|
||||||
|
/// tx: 8 bytes (incl. op)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_ave_key(
|
||||||
|
aid: AttrId,
|
||||||
|
val: Value,
|
||||||
|
eid: EntityId,
|
||||||
|
tx: TxId,
|
||||||
|
op: StoreOp,
|
||||||
|
) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 60]>::new();
|
||||||
|
|
||||||
|
ret.extend(aid.0.to_be_bytes());
|
||||||
|
ret[0] = StorageTag::TripleAttrValueEntity as u8;
|
||||||
|
|
||||||
|
ret.extend(eid.0.to_be_bytes());
|
||||||
|
ret.extend(tx.0.to_be_bytes());
|
||||||
|
ret[12] = op as u8;
|
||||||
|
debug_assert_eq!(ret.len(), 20);
|
||||||
|
|
||||||
|
val.serialize(&mut Serializer::new(&mut ret)).unwrap();
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// val: 8 bytes (incl. tag)
|
||||||
|
/// eid: 8 bytes
|
||||||
|
/// aid: 4 bytes
|
||||||
|
/// tx: 8 bytes (incl. op)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_vae_key(
|
||||||
|
val: EntityId,
|
||||||
|
aid: AttrId,
|
||||||
|
eid: EntityId,
|
||||||
|
tx: TxId,
|
||||||
|
op: StoreOp,
|
||||||
|
) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 60]>::new();
|
||||||
|
|
||||||
|
ret.extend(val.0.to_be_bytes());
|
||||||
|
ret[0] = StorageTag::TripleAttrValueEntity as u8;
|
||||||
|
|
||||||
|
ret.extend(aid.0.to_be_bytes());
|
||||||
|
ret.extend(tx.0.to_be_bytes());
|
||||||
|
ret[12] = op as u8;
|
||||||
|
debug_assert_eq!(ret.len(), 20);
|
||||||
|
ret.extend(eid.0.to_be_bytes());
|
||||||
|
debug_assert_eq!(ret.len(), 28);
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn decode_vae_key(src: &[u8]) -> Result<(EntityId, AttrId, EntityId, TxId, StoreOp)> {
|
||||||
|
let vid = EntityId::from_bytes(&src[0..8]);
|
||||||
|
let aid = AttrId::from_bytes(&src[8..12]);
|
||||||
|
let tx = TxId::from_bytes(&src[12..20]);
|
||||||
|
let eid = EntityId::from_bytes(&src[20..28]);
|
||||||
|
let op = src[12].try_into()?;
|
||||||
|
|
||||||
|
Ok((vid, aid, eid, tx, op))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// aid: 4 bytes (incl. tag)
|
||||||
|
/// tx: 8 bytes (incl. op)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_attr_by_id(aid: AttrId, tx: TxId, op: StoreOp) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 12]>::new();
|
||||||
|
ret.extend(aid.0.to_be_bytes());
|
||||||
|
ret[0] = StorageTag::AttrById as u8;
|
||||||
|
ret.extend(tx.0.to_be_bytes());
|
||||||
|
ret[4] = op as u8;
|
||||||
|
debug_assert_eq!(ret.len(), 12);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn decode_attr_key_by_id(src: &[u8]) -> Result<(AttrId, TxId, StoreOp)> {
|
||||||
|
let aid = AttrId::from_bytes(&src[0..4]);
|
||||||
|
let tx = TxId::from_bytes(&src[4..12]);
|
||||||
|
let op = src[4].try_into()?;
|
||||||
|
Ok((aid, tx, op))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// tag: 4 bytes (with prefix)
|
||||||
|
/// tx: 8 bytes (incl. op)
|
||||||
|
/// attr as kw: variable (segmented by \0)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_attr_by_kw(
|
||||||
|
attr_name: Keyword,
|
||||||
|
tx: TxId,
|
||||||
|
op: StoreOp,
|
||||||
|
) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 12]>::new();
|
||||||
|
ret.push(StorageTag::AttrByKeyword as u8);
|
||||||
|
let ns_bytes = attr_name.ns.as_bytes();
|
||||||
|
ret.push(ns_bytes.get(0).cloned().unwrap_or(0));
|
||||||
|
ret.push(ns_bytes.get(1).cloned().unwrap_or(0));
|
||||||
|
ret.push(ns_bytes.get(2).cloned().unwrap_or(0));
|
||||||
|
ret.extend(tx.0.to_be_bytes());
|
||||||
|
ret[4] = op as u8;
|
||||||
|
ret.extend_from_slice(ns_bytes);
|
||||||
|
ret.push(b'/');
|
||||||
|
ret.extend_from_slice(attr_name.ident.as_bytes());
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn decode_attr_key_by_kw(src: &[u8]) -> Result<(Keyword, TxId, StoreOp)> {
|
||||||
|
let tx = TxId::from_bytes(&src[4..12]);
|
||||||
|
let op = src[4].try_into()?;
|
||||||
|
let kw = Keyword::try_from(&src[12..])?;
|
||||||
|
Ok((kw, tx, op))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// tx: 8 bytes (incl. tag)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_tx(tx: TxId) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 8]>::new();
|
||||||
|
ret.extend(tx.0.to_be_bytes());
|
||||||
|
ret[0] = StorageTag::Tx as u8;
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_unique_entity_placeholder(eid: EntityId) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 8]>::new();
|
||||||
|
ret.extend(eid.0.to_be_bytes());
|
||||||
|
ret[0] = StorageTag::UniqueEntity as u8;
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn encode_unique_attr_val(aid: AttrId, val: Value) -> impl Deref<Target = [u8]> {
|
||||||
|
let mut ret = SmallVec::<[u8; 60]>::new();
|
||||||
|
ret.extend(aid.0.to_be_bytes());
|
||||||
|
ret[0] = StorageTag::UniqueAttrValue as u8;
|
||||||
|
val.serialize(&mut Serializer::new(&mut ret)).unwrap();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn decode_unique_attr_val(src: &[u8]) -> Result<(AttrId, Value)> {
|
||||||
|
let a_id = AttrId::from_bytes(&src[..4]);
|
||||||
|
let val = rmp_serde::from_slice(&src[4..])?;
|
||||||
|
Ok((a_id, val))
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, Hash)]
|
||||||
|
pub struct EntityId(pub u64);
|
||||||
|
|
||||||
|
impl EntityId {
|
||||||
|
pub(crate) fn from_bytes(b: &[u8]) -> Self {
|
||||||
|
EntityId(u64::from_be_bytes([
|
||||||
|
0, b[1], b[2], b[3], b[4], b[5], b[6], b[7],
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for EntityId {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "e{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const MAX_SYS_ENTITY_ID: EntityId = EntityId(1000);
|
||||||
|
pub(crate) const MAX_TEMP_ENTITY_ID: EntityId = EntityId(10_000_000);
|
||||||
|
pub(crate) const MAX_PERM_ENTITY_ID: EntityId = EntityId(0x00ff_ffff_ff00_0000);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Ord, PartialOrd, Eq, Deserialize, Serialize, Hash)]
|
||||||
|
pub struct AttrId(pub u32);
|
||||||
|
|
||||||
|
impl AttrId {
|
||||||
|
pub(crate) fn from_bytes(b: &[u8]) -> Self {
|
||||||
|
AttrId(u32::from_be_bytes([0, b[1], b[2], b[3]]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for AttrId {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "a{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const MAX_SYS_ATTR_ID: AttrId = AttrId(1000);
|
||||||
|
pub(crate) const MAX_TEMP_ATTR_ID: AttrId = AttrId(1000000);
|
||||||
|
pub(crate) const MAX_PERM_ATTR_ID: AttrId = AttrId(0x00ff_ffff);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Ord, PartialOrd, Eq, Deserialize, Serialize, Hash)]
|
||||||
|
pub struct TxId(pub u64);
|
||||||
|
|
||||||
|
impl TxId {
|
||||||
|
pub(crate) fn from_bytes(b: &[u8]) -> Self {
|
||||||
|
TxId(u64::from_be_bytes([
|
||||||
|
0, b[1], b[2], b[3], b[4], b[5], b[6], b[7],
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for TxId {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "t{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const MAX_SYS_TX_ID: TxId = TxId(1000);
|
||||||
|
pub(crate) const MAX_USER_TX_ID: TxId = TxId(0x00ff_ffff_ffff_ffff);
|
@ -0,0 +1,43 @@
|
|||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use smartstring::{LazyCompact, SmartString};
|
||||||
|
use std::str::Utf8Error;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum KeywordError {
|
||||||
|
#[error("invalid keyword: {0}")]
|
||||||
|
InvalidKeyword(String),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
Utf8(#[from] Utf8Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct Keyword {
|
||||||
|
pub(crate) ns: SmartString<LazyCompact>,
|
||||||
|
pub(crate) ident: SmartString<LazyCompact>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for Keyword {
|
||||||
|
type Error = KeywordError;
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
let make_err = || KeywordError::InvalidKeyword(value.to_string());
|
||||||
|
let mut kw_iter = value.split('/');
|
||||||
|
let ns = kw_iter.next().ok_or_else(make_err)?;
|
||||||
|
let ident = kw_iter.next().ok_or_else(make_err)?;
|
||||||
|
if kw_iter.next().is_none() {
|
||||||
|
Ok(Keyword {
|
||||||
|
ns: ns.into(),
|
||||||
|
ident: ident.into(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(make_err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&[u8]> for Keyword {
|
||||||
|
type Error = KeywordError;
|
||||||
|
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
|
||||||
|
std::str::from_utf8(value)?.try_into()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
pub(crate) mod compare;
|
||||||
|
pub(crate) mod id;
|
||||||
|
pub(crate) mod value;
|
||||||
|
pub(crate) mod triple;
|
||||||
|
pub(crate) mod tx;
|
||||||
|
pub(crate) mod encode;
|
||||||
|
pub(crate) mod keyword;
|
@ -0,0 +1,26 @@
|
|||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum StoreOpError {
|
||||||
|
#[error("unexpected value for StoreOp: {0}")]
|
||||||
|
UnexpectedValue(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, PartialEq, Ord, PartialOrd, Eq, Debug, Deserialize, Serialize)]
|
||||||
|
pub enum StoreOp {
|
||||||
|
Retract = 0,
|
||||||
|
Assert = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for StoreOp {
|
||||||
|
type Error = StoreOpError;
|
||||||
|
|
||||||
|
fn try_from(u: u8) -> Result<Self, Self::Error> {
|
||||||
|
match u {
|
||||||
|
0 => Ok(StoreOp::Retract),
|
||||||
|
1 => Ok(StoreOp::Assert),
|
||||||
|
n => Err(StoreOpError::UnexpectedValue(n)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
use crate::data::id::{AttrId, EntityId, TxId};
|
||||||
|
use crate::data::keyword::Keyword;
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::cmp::Reverse;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
|
||||||
|
pub enum Value<'a> {
|
||||||
|
#[serde(rename = "n")]
|
||||||
|
Null,
|
||||||
|
#[serde(rename = "b")]
|
||||||
|
Bool(bool),
|
||||||
|
#[serde(rename = "e")]
|
||||||
|
EnId(EntityId),
|
||||||
|
#[serde(rename = "a")]
|
||||||
|
AtId(AttrId),
|
||||||
|
#[serde(rename = "t")]
|
||||||
|
TxId(TxId),
|
||||||
|
#[serde(rename = "i")]
|
||||||
|
Int(i64),
|
||||||
|
#[serde(rename = "f")]
|
||||||
|
Float(OrderedFloat<f64>),
|
||||||
|
#[serde(rename = "k")]
|
||||||
|
Keyword(Keyword),
|
||||||
|
#[serde(borrow)]
|
||||||
|
#[serde(rename = "s")]
|
||||||
|
String(Cow<'a, str>),
|
||||||
|
#[serde(rename = "u")]
|
||||||
|
Uuid(Uuid),
|
||||||
|
#[serde(rename = "m")]
|
||||||
|
Timestamp(i64),
|
||||||
|
#[serde(borrow)]
|
||||||
|
#[serde(rename = "v")]
|
||||||
|
Bytes(Cow<'a, [u8]>),
|
||||||
|
|
||||||
|
#[serde(rename = "z")]
|
||||||
|
Tuple(Box<[Value<'a>]>),
|
||||||
|
#[serde(rename = "o")]
|
||||||
|
DescVal(Reverse<Box<Value<'a>>>),
|
||||||
|
#[serde(rename = "r")]
|
||||||
|
Bottom,
|
||||||
|
}
|
@ -1,30 +1,9 @@
|
|||||||
use cozorocks::DbStatus;
|
#[cfg(not(target_env = "msvc"))]
|
||||||
use lazy_static::lazy_static;
|
use tikv_jemallocator::Jemalloc;
|
||||||
|
|
||||||
#[no_mangle]
|
#[cfg(not(target_env = "msvc"))]
|
||||||
extern "C" fn rusty_cmp(a: &cozorocks::Slice, b: &cozorocks::Slice) -> cozorocks::c_int {
|
#[global_allocator]
|
||||||
dbg!(cozorocks::convert_slice_back(a));
|
static GLOBAL: Jemalloc = Jemalloc;
|
||||||
dbg!(cozorocks::convert_slice_back(b));
|
|
||||||
cozorocks::c_int(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
pub(crate) mod data;
|
||||||
static ref RUSTY_COMPARATOR: cozorocks::UniquePtr<cozorocks::RustComparator> = {
|
pub(crate) mod runtime;
|
||||||
unsafe {
|
|
||||||
let f_ptr = rusty_cmp as *const cozorocks::c_void;
|
|
||||||
cozorocks::new_rust_comparator("hello", false, f_ptr)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_it() {
|
|
||||||
let a = cozorocks::convert_slice(&[1, 2, 3, 4]);
|
|
||||||
let b = cozorocks::convert_slice(&[4, 5, 6, 7]);
|
|
||||||
assert_eq!(RUSTY_COMPARATOR.Compare(&a, &b), cozorocks::c_int(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
use crate::data::compare::DB_KEY_PREFIX_LEN;
|
||||||
|
use anyhow::Result;
|
||||||
|
use cozorocks::*;
|
||||||
|
use std::sync::atomic::{AtomicU32, AtomicU64};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
pub struct DbInstance {
|
||||||
|
pub destroy_on_close: bool,
|
||||||
|
db: SharedPtr<DbBridge>,
|
||||||
|
db_opts: UniquePtr<Options>,
|
||||||
|
tdb_opts: Option<UniquePtr<TransactionDBOptions>>,
|
||||||
|
odb_opts: Option<UniquePtr<OptimisticTransactionDBOptions>>,
|
||||||
|
path: String,
|
||||||
|
last_attr_id: Arc<AtomicU32>,
|
||||||
|
last_ent_id: Arc<AtomicU64>,
|
||||||
|
last_tx_id: Arc<AtomicU64>,
|
||||||
|
sessions: Mutex<Vec<Arc<Mutex<SessionHandle>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SessionHandle {
|
||||||
|
id: usize,
|
||||||
|
temp: SharedPtr<DbBridge>,
|
||||||
|
status: SessionStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
|
||||||
|
pub enum SessionStatus {
|
||||||
|
Prepared,
|
||||||
|
Running,
|
||||||
|
Completed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DbInstance {
|
||||||
|
pub fn new(path: &str, optimistic: bool, destroy_on_close: bool) -> Result<Self> {
|
||||||
|
let mut db_opts = Options::new().within_unique_ptr();
|
||||||
|
set_opts_create_if_missing(db_opts.pin_mut(), true);
|
||||||
|
set_opts_bloom_filter(db_opts.pin_mut(), 10., true);
|
||||||
|
set_opts_capped_prefix_extractor(db_opts.pin_mut(), DB_KEY_PREFIX_LEN);
|
||||||
|
|
||||||
|
let (db, tdb_opts, odb_opts) = if optimistic {
|
||||||
|
let o = new_odb_opts();
|
||||||
|
let db = DbBridge::new_odb(path, &db_opts, &o)?;
|
||||||
|
(db, None, Some(o))
|
||||||
|
} else {
|
||||||
|
let o = new_odb_opts();
|
||||||
|
let db = DbBridge::new_odb(path, &db_opts, &o)?;
|
||||||
|
(db, Some(new_tdb_opts()), None)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
db,
|
||||||
|
db_opts,
|
||||||
|
tdb_opts,
|
||||||
|
odb_opts,
|
||||||
|
path: path.to_string(),
|
||||||
|
destroy_on_close,
|
||||||
|
last_attr_id: Arc::new(Default::default()),
|
||||||
|
last_ent_id: Arc::new(Default::default()),
|
||||||
|
last_tx_id: Arc::new(Default::default()),
|
||||||
|
sessions: Mutex::new(vec![]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
mod instance;
|
Loading…
Reference in New Issue