introduce validity

main
Ziyang Hu 2 years ago
parent cf9977a7b3
commit 2bc4adc858

@ -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> ~ :<Follows | :Likes>].. - 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).
```

@ -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`

@ -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<LARGE_VEC_SIZE> {
| 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<Value> {
/// 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<LARGE_VEC_SIZE> {
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<LARGE_VEC_SIZE> {
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<LARGE_VEC_SIZE> {
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<LARGE_VEC_SIZE> {
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<LARGE_VEC_SIZE> {
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)

@ -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],

Loading…
Cancel
Save