diff --git a/PLAN.md b/PLAN.md index 6b51167d..b42388eb 100644 --- a/PLAN.md +++ b/PLAN.md @@ -1,75 +1,124 @@ -# Operations on relations - -Operations - -* [x] `from(...rels)`, can use chain notation -* [x] `left_join(left, right, ...conds)`, similarly for `right_join`, `outer_join`) -* [x] `concat(...rels)` -* [x] `intersect(...rels)`, similarly for `union` -* [x] `diff(left, right)`, similarly for `sym_diff` -* [x] `select(rel, binding: {..})` -* [x] `where(rel, ..conds)` -* [x] `take(rel, n)` -* [x] `skip(rel, n)` -* [x] `sort(rel, expr1, expr2: sort_dir)` -* [x] `group(rel, binding: {*key1: expr1, val1: expr2}, *ordering)` may order elements within groups -* [x] `walk(pattern, ...conds, ...bindings)` -* [ ] `walk_repeat(pattern, ...conds, ...bindings)` every element contains additional `_iter` and `_visited` fields -* [x] `values(data, ?Table)` -* [x] `nested_values(data, ?Table).extract(Table)` -* [x] `update(rel, Table)` -* [x] `delete(rel, Table)` -* [x] `insert(rel, Table)` -* [x] `upsert(rel, Table)` - -Helpers - -* `print(rel)` -* `print_schema(rel)` -* `print_plan(rel)` -* `print_optimized(rel)` - -Aggregation - -* Aggregation functions should implement `.step()` and `.result()` - -Differentiation - -* function calls use parentheses, names start with lowercase letters or "_" -* aggregation calls are the same as function calls except that square brackets are used instead -* query calls are the same as function calls except that query names start with upper case or "#" - -Others - -* [ ] assoc magic better work -* [ ] language within query -* [ ] constraints and indices -* [ ] datetime and array types -* [ ] GUI and TUI -* [ ] query optimization -* [ ] regex as a value type - +canonical form + +```json +{ + "asserts": [ + [ + "temp_id", + "Person/name", + "Alice" + ], + [ + "temp_id", + "Person/email", + "alice@example.com" + ], + [ + { + "Person/name": "Phillip" + }, + "Person/friends", + [ + { + "Person/name": "Maxwells" + }, + 123332212 + ] + ], + { + "_id": "tempxxx", + "Person/name": "Bloopy", + "Person/email": "b@example.com" + } + ], + "retracts": [ + [ + 1234567 + ], + [ + { + "Person/name": "Jack" + } + ] + ] +} ``` -Walk(a:A-[e:E]->b:B, - a => (a.id == 10), - e => (e.id < 20, count[] <= 1, rand() => asc), - b: { - ...b, - ...e, - ...a - }) -Chain(a:A-[p:Path]->b:B, - _next => _hops < 10) +```json +{ + "add_attrs": [], + "amend_attrs": [], + "retract_attrs": [], + "commit_msg": "ZAODDK" +} ``` -Walk, ChainWalk, MaxChainWalk, TreeWalk, ChainWalkSegments - -``` -Walk(p:Person - [:Follows> ~ :].. - p2:Person) +```json +{ + "q": { + "ancestor": [ + "?a", + "?c" + ] + }, + "ancestor": [ + { + "out": [ + "?a", + "?b" + ], + "where": [ + [ + "?a", + "Person/parent", + "?b" + ] + ] + }, + { + "out": [ + "?a", + "?b" + ], + "where": [ + [ + "?a", + "Person/parent", + "?c" + ], + { + "ancestor": [ + "?c", + "?b" + ] + } + ] + } + ] +} ``` - ``` -sum()(x.id) +attr { + keyword: Person/parent, + cardinality: many, +}. + +attr { + keyword: Person/name, + type: string, + index: identity +}. + +Person { name: "Alice", parent_of: "Bob" }. +Person { name: "Bob" }. + +Person/name("eve", "Eve"). +Person/parent_of("eve", "Bob"). + +Ancestor(?a, ?b) :- Person/parent_of(?a, ?b). +Ancestor(?a, ?b) :- Person/parent_of(?a, ?c), + Ancestor(?c, ?b). + +?- Ancestor(Person/name("bob"), ?ancestor). ``` \ No newline at end of file diff --git a/README.md b/README.md index 391d85c0..e69de29b 100644 --- a/README.md +++ b/README.md @@ -1,20 +0,0 @@ -## Build - -First build static lib for RocksDB - -```bash -cd rocksdb -USE_RTTI=1 DEBUG_LEVEL=0 make static_lib -``` - -## Edge key layout - -* Forward `[true, *src_keys, *tgt_keys, *own_keys]` -* Backward `[false, *src_keys, *tgt_keys, *own_keys]` - -## Isolation levels - -* Read uncommitted: write to the raw DB -* Read committed: use transaction -* Repeatable read: use snapshot -* Serializable: do all reads with `GetForUpdate` \ No newline at end of file diff --git a/src/data/encode.rs b/src/data/encode.rs index 9de63373..f2d851af 100644 --- a/src/data/encode.rs +++ b/src/data/encode.rs @@ -1,5 +1,5 @@ use crate::data::attr::Attribute; -use crate::data::id::{AttrId, EntityId, TxId}; +use crate::data::id::{AttrId, EntityId, TxId, Validity}; use crate::data::keyword::Keyword; use crate::data::triple::StoreOp; use crate::data::value::Value; @@ -58,11 +58,12 @@ impl EncodedVec { | StorageTag::TripleAttrValueEntity | StorageTag::TripleValueAttrEntity => { let op = StoreOp::try_from(data[0]).unwrap(); - if data.len() > 1 { - let v = decode_value(&data[1..]).unwrap(); - format!("{}{:?}", op, v) + let tx = TxId::from_bytes(&data[0..8]); + if data.len() > 8 { + let v = decode_value(&data[8..]).unwrap(); + format!("{:?}{} {:?}", tx, op, v) } else { - format!("{}", op) + format!("{:?}{}", tx, op) } } StorageTag::AttrById | StorageTag::AttrByKeyword => { @@ -232,22 +233,22 @@ pub(crate) fn decode_value_from_key(src: &[u8]) -> Result { /// eid: 8 bytes (incl. tag) /// aid: 8 bytes /// val: variable -/// tx: 8 bytes +/// vld: 8 bytes #[inline] pub(crate) fn encode_eav_key( eid: EntityId, aid: AttrId, val: &Value, - tx: TxId, + vld: Validity, ) -> EncodedVec { let mut ret = SmallVec::<[u8; LARGE_VEC_SIZE]>::new(); - ret.extend(eid.0.to_be_bytes()); + ret.extend(eid.bytes()); ret[0] = StorageTag::TripleEntityAttrValue as u8; - ret.extend(aid.0.to_be_bytes()); + ret.extend(aid.bytes()); - ret.extend(tx.0.to_be_bytes()); + ret.extend(vld.bytes()); debug_assert_eq!(ret.len(), VEC_SIZE_24); val.serialize(&mut Serializer::new(&mut ret)).unwrap(); @@ -256,32 +257,32 @@ pub(crate) fn encode_eav_key( } #[inline] -pub(crate) fn decode_ea_key(src: &[u8]) -> Result<(EntityId, AttrId, TxId)> { +pub(crate) fn decode_ea_key(src: &[u8]) -> Result<(EntityId, AttrId, Validity)> { let eid = EntityId::from_bytes(&src[0..VEC_SIZE_8]); let aid = AttrId::from_bytes(&src[VEC_SIZE_8..VEC_SIZE_16]); - let tx = TxId::from_bytes(&src[VEC_SIZE_16..VEC_SIZE_24]); + let vld = Validity::from_bytes(&src[VEC_SIZE_16..VEC_SIZE_24]); - Ok((eid, aid, tx)) + Ok((eid, aid, vld)) } /// eid: 8 bytes (incl. tag) /// aid: 8 bytes /// val: variable -/// tx: 8 bytes +/// vld: 8 bytes #[inline] pub(crate) fn encode_aev_key( aid: AttrId, eid: EntityId, val: &Value, - tx: TxId, + vld: Validity, ) -> EncodedVec { let mut ret = SmallVec::<[u8; LARGE_VEC_SIZE]>::new(); - ret.extend(aid.0.to_be_bytes()); + ret.extend(aid.bytes()); ret[0] = StorageTag::TripleAttrEntityValue as u8; - ret.extend(eid.0.to_be_bytes()); - ret.extend(tx.0.to_be_bytes()); + ret.extend(eid.bytes()); + ret.extend(vld.bytes()); debug_assert_eq!(ret.len(), VEC_SIZE_24); val.serialize(&mut Serializer::new(&mut ret)).unwrap(); @@ -290,41 +291,41 @@ pub(crate) fn encode_aev_key( } #[inline] -pub(crate) fn decode_ae_key(src: &[u8]) -> Result<(AttrId, EntityId, TxId)> { +pub(crate) fn decode_ae_key(src: &[u8]) -> Result<(AttrId, EntityId, Validity)> { let aid = AttrId::from_bytes(&src[0..VEC_SIZE_8]); let eid = EntityId::from_bytes(&src[VEC_SIZE_8..VEC_SIZE_16]); - let tx = TxId::from_bytes(&src[VEC_SIZE_16..VEC_SIZE_24]); + let vld = Validity::from_bytes(&src[VEC_SIZE_16..VEC_SIZE_24]); - Ok((aid, eid, tx)) + Ok((aid, eid, vld)) } #[inline] pub(crate) fn encode_ave_key_for_unique_v( aid: AttrId, val: &Value, - tx: TxId, + vld: Validity, ) -> EncodedVec { - encode_ave_key(aid, val, EntityId(0), tx) + encode_ave_key(aid, val, EntityId(0), vld) } /// aid: 8 bytes (incl. tag) /// val: variable /// eid: 8 bytes -/// tx: 8 bytes +/// vld: 8 bytes #[inline] pub(crate) fn encode_ave_key( aid: AttrId, val: &Value, eid: EntityId, - tx: TxId, + vld: Validity, ) -> EncodedVec { let mut ret = SmallVec::<[u8; LARGE_VEC_SIZE]>::new(); - ret.extend(aid.0.to_be_bytes()); + ret.extend(aid.bytes()); ret[0] = StorageTag::TripleAttrValueEntity as u8; - ret.extend(eid.0.to_be_bytes()); - ret.extend(tx.0.to_be_bytes()); + ret.extend(eid.bytes()); + ret.extend(vld.bytes()); debug_assert_eq!(ret.len(), VEC_SIZE_24); val.serialize(&mut Serializer::new(&mut ret)).unwrap(); @@ -335,36 +336,36 @@ pub(crate) fn encode_ave_key( /// val: 8 bytes (incl. tag) /// eid: 8 bytes /// aid: 8 bytes -/// tx: 8 bytes +/// vld: 8 bytes #[inline] pub(crate) fn encode_vae_key( val: EntityId, aid: AttrId, eid: EntityId, - tx: TxId, + vld: Validity, ) -> EncodedVec { let mut ret = SmallVec::<[u8; LARGE_VEC_SIZE]>::new(); - ret.extend(val.0.to_be_bytes()); + ret.extend(val.bytes()); ret[0] = StorageTag::TripleValueAttrEntity as u8; - ret.extend(aid.0.to_be_bytes()); - ret.extend(tx.0.to_be_bytes()); + ret.extend(aid.bytes()); + ret.extend(vld.bytes()); debug_assert_eq!(ret.len(), VEC_SIZE_24); - ret.extend(eid.0.to_be_bytes()); + ret.extend(eid.bytes()); debug_assert_eq!(ret.len(), VEC_SIZE_32); ret.into() } #[inline] -pub(crate) fn decode_vae_key(src: &[u8]) -> Result<(EntityId, AttrId, EntityId, TxId)> { +pub(crate) fn decode_vae_key(src: &[u8]) -> Result<(EntityId, AttrId, EntityId, Validity)> { let vid = EntityId::from_bytes(&src[0..VEC_SIZE_8]); let aid = AttrId::from_bytes(&src[VEC_SIZE_8..VEC_SIZE_16]); - let tx = TxId::from_bytes(&src[VEC_SIZE_16..VEC_SIZE_24]); + let vld = Validity::from_bytes(&src[VEC_SIZE_16..VEC_SIZE_24]); let eid = EntityId::from_bytes(&src[VEC_SIZE_24..VEC_SIZE_32]); - Ok((vid, aid, eid, tx)) + Ok((vid, aid, eid, vld)) } /// aid: 8 bytes (incl. tag) diff --git a/src/data/id.rs b/src/data/id.rs index a54abe93..f20e5c2b 100644 --- a/src/data/id.rs +++ b/src/data/id.rs @@ -1,6 +1,36 @@ use crate::data::triple::StoreOp; use serde_derive::{Deserialize, Serialize}; use std::fmt::{Debug, Formatter}; +use std::time::{SystemTime, UNIX_EPOCH}; + +#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Deserialize, Serialize, Hash)] +pub struct Validity(pub i64); + +impl Validity { + pub(crate) const MAX: Validity = Validity(i64::MAX); + pub(crate) const MIN: Validity = Validity(i64::MIN); + pub(crate) fn current() -> Self { + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_micros() as i64; + Self(timestamp) + } + pub(crate) fn from_bytes(b: &[u8]) -> Self { + Validity(i64::from_be_bytes([ + b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], + ])) + } + pub(crate) fn bytes(&self) -> [u8; 8] { + self.0.to_be_bytes() + } +} + +impl Debug for Validity { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "v{}", self.0) + } +} #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, Hash)] pub struct EntityId(pub u64); @@ -45,6 +75,10 @@ impl AttrId { pub(crate) const MIN_PERM: AttrId = AttrId(10_000_001); pub(crate) const MAX_PERM: AttrId = AttrId(0x00ff_ffff_ff00_0000); + pub(crate) fn bytes(&self) -> [u8; 8] { + self.0.to_be_bytes() + } + pub(crate) fn from_bytes(b: &[u8]) -> Self { AttrId(u64::from_be_bytes([ 0, b[1], b[2], b[3], b[4], b[5], b[6], b[7],