Define intents for sync

next
Sayan Nandan 2 years ago
parent 1c95c2e70f
commit 73df6f9af4
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

@ -25,7 +25,7 @@
*/
use {
super::{Field, Layer, ModelView},
super::{Field, IWModel, Layer, ModelView},
crate::{
engine::{
data::{
@ -72,23 +72,9 @@ macro_rules! can_ignore {
};
}
impl ModelView {
fn no_field(&self, new: &str) -> bool {
!self.fields().st_contains(new)
}
fn is_pk(&self, new: &str) -> bool {
self.p_key.as_bytes() == new.as_bytes()
}
fn not_pk(&self, new: &str) -> bool {
!self.is_pk(new)
}
fn guard_pk(&self, new: &str) -> DatabaseResult<()> {
if self.is_pk(new) {
Err(DatabaseError::DdlModelAlterProtectedField)
} else {
Ok(())
}
}
#[inline(always)]
fn no_field(mr: &IWModel, new: &str) -> bool {
!mr.fields().st_contains(new)
}
fn check_nullable(props: &mut HashMap<Box<str>, Option<DictEntryGeneric>>) -> DatabaseResult<bool> {
@ -102,6 +88,7 @@ fn check_nullable(props: &mut HashMap<Box<str>, Option<DictEntryGeneric>>) -> Da
impl<'a> AlterPlan<'a> {
pub fn fdeltas(
mv: &ModelView,
wm: &IWModel,
AlterModel { model, kind }: AlterModel<'a>,
) -> DatabaseResult<AlterPlan<'a>> {
let mut no_lock = true;
@ -115,7 +102,7 @@ impl<'a> AlterPlan<'a> {
let mut not_found = false;
if r.iter().all(|id| {
let not_pk = mv.not_pk(id);
let exists = mv.fields().st_contains(id.as_str());
let exists = !no_field(wm, id.as_str());
not_found = !exists;
not_pk & exists
}) {
@ -137,8 +124,7 @@ impl<'a> AlterPlan<'a> {
layers,
mut props,
} = fields.next().unwrap();
okay &= mv.not_pk(&field_name);
okay &= mv.no_field(&field_name);
okay &= no_field(wm, &field_name) & mv.not_pk(&field_name);
let is_nullable = check_nullable(&mut props)?;
let layers = Field::parse_layers(layers, is_nullable)?;
okay &= add.st_insert(field_name.to_string().into_boxed_str(), layers);
@ -159,7 +145,7 @@ impl<'a> AlterPlan<'a> {
// enforce pk
mv.guard_pk(&field_name)?;
// get the current field
let Some(current_field) = mv.fields().st_get(field_name.as_str()) else {
let Some(current_field) = wm.fields().st_get(field_name.as_str()) else {
return Err(DatabaseError::DdlModelAlterFieldNotFound);
};
// check props

@ -27,35 +27,76 @@
pub(super) mod alt;
pub mod cell;
use crate::engine::{
core::model::cell::Datacell,
data::{
tag::{DataTag, FullTag, TagClass, TagSelector},
ItemID,
},
error::{DatabaseError, DatabaseResult},
idx::{IndexSTSeqCns, STIndex, STIndexSeq},
mem::VInline,
ql::ddl::{
crt::CreateModel,
syn::{FieldSpec, LayerSpec},
},
};
#[cfg(test)]
use std::cell::RefCell;
use {
crate::engine::{
core::model::cell::Datacell,
data::{
tag::{DataTag, FullTag, TagClass, TagSelector},
ItemID,
},
error::{DatabaseError, DatabaseResult},
idx::{IndexSTSeqCns, STIndex, STIndexSeq},
mem::VInline,
ql::ddl::{
crt::CreateModel,
syn::{FieldSpec, LayerSpec},
},
},
core::cell::UnsafeCell,
parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard},
};
type Fields = IndexSTSeqCns<Box<str>, Field>;
// FIXME(@ohsayan): update this!
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub struct ModelView {
pub(super) p_key: Box<str>,
pub(super) p_tag: FullTag,
pub(super) fields: IndexSTSeqCns<Box<str>, Field>,
fields: UnsafeCell<Fields>,
sync_matrix: ISyncMatrix,
}
#[cfg(test)]
impl PartialEq for ModelView {
fn eq(&self, m: &Self) -> bool {
let mdl1 = self.intent_read_model();
let mdl2 = m.intent_read_model();
self.p_key == m.p_key && self.p_tag == m.p_tag && mdl1.fields() == mdl2.fields()
}
}
impl ModelView {
pub fn fields(&self) -> &IndexSTSeqCns<Box<str>, Field> {
&self.fields
pub fn sync_matrix(&self) -> &ISyncMatrix {
&self.sync_matrix
}
unsafe fn _read_fields<'a>(&'a self) -> &'a Fields {
&*self.fields.get().cast_const()
}
unsafe fn _read_fields_mut<'a>(&'a self) -> &'a mut Fields {
&mut *self.fields.get()
}
pub fn intent_read_model<'a>(&'a self) -> IRModel<'a> {
IRModel::new(self)
}
pub fn intent_write_model<'a>(&'a self) -> IWModel<'a> {
IWModel::new(self)
}
fn is_pk(&self, new: &str) -> bool {
self.p_key.as_bytes() == new.as_bytes()
}
fn not_pk(&self, new: &str) -> bool {
!self.is_pk(new)
}
fn guard_pk(&self, new: &str) -> DatabaseResult<()> {
if self.is_pk(new) {
Err(DatabaseError::DdlModelAlterProtectedField)
} else {
Ok(())
}
}
}
@ -96,7 +137,8 @@ impl ModelView {
return Ok(Self {
p_key: last_pk.into(),
p_tag: tag,
fields,
fields: UnsafeCell::new(fields),
sync_matrix: ISyncMatrix::new(),
});
}
}
@ -385,3 +427,98 @@ unsafe fn lverify_list(_: Layer, _: &Datacell) -> bool {
layertrace("list");
true
}
// FIXME(@ohsayan): This an inefficient repr of the matrix; replace it with my other design
#[derive(Debug)]
pub struct ISyncMatrix {
// virtual privileges
v_priv_model_alter: RwLock<()>,
v_priv_data_new_or_revise: RwLock<()>,
}
#[cfg(test)]
impl PartialEq for ISyncMatrix {
fn eq(&self, _: &Self) -> bool {
true
}
}
#[derive(Debug)]
pub struct IRModelSMData<'a> {
rmodel: RwLockReadGuard<'a, ()>,
mdata: RwLockReadGuard<'a, ()>,
fields: &'a Fields,
}
impl<'a> IRModelSMData<'a> {
pub fn new(m: &'a ModelView) -> Self {
let rmodel = m.sync_matrix().v_priv_model_alter.read();
let mdata = m.sync_matrix().v_priv_data_new_or_revise.read();
Self {
rmodel,
mdata,
fields: unsafe {
// UNSAFE(@ohsayan): we already have acquired this resource
m._read_fields()
},
}
}
pub fn fields(&'a self) -> &'a Fields {
self.fields
}
}
#[derive(Debug)]
pub struct IRModel<'a> {
rmodel: RwLockReadGuard<'a, ()>,
fields: &'a Fields,
}
impl<'a> IRModel<'a> {
pub fn new(m: &'a ModelView) -> Self {
Self {
rmodel: m.sync_matrix().v_priv_model_alter.read(),
fields: unsafe {
// UNSAFE(@ohsayan): we already have acquired this resource
m._read_fields()
},
}
}
pub fn fields(&'a self) -> &'a Fields {
self.fields
}
}
#[derive(Debug)]
pub struct IWModel<'a> {
wmodel: RwLockWriteGuard<'a, ()>,
fields: &'a mut Fields,
}
impl<'a> IWModel<'a> {
pub fn new(m: &'a ModelView) -> Self {
Self {
wmodel: m.sync_matrix().v_priv_model_alter.write(),
fields: unsafe {
// UNSAFE(@ohsayan): we have exclusive access to this resource
m._read_fields_mut()
},
}
}
pub fn fields(&'a self) -> &'a Fields {
self.fields
}
// ALIASING
pub fn fields_mut(&'a mut self) -> &'a mut Fields {
self.fields
}
}
impl ISyncMatrix {
pub const fn new() -> Self {
Self {
v_priv_model_alter: RwLock::new(()),
v_priv_data_new_or_revise: RwLock::new(()),
}
}
}

@ -40,7 +40,8 @@ mod plan {
let model = create(model)?;
let tok = lex_insecure(plan.as_bytes()).unwrap();
let alter = parse_ast_node_full(&tok[2..]).unwrap();
let mv = AlterPlan::fdeltas(&model, alter)?;
let model_write = model.intent_write_model();
let mv = AlterPlan::fdeltas(&model, &model_write, alter)?;
Ok(f(mv))
}
fn plan(model: &str, plan: &str, f: impl Fn(AlterPlan)) {

@ -28,7 +28,7 @@ mod validation {
use {
super::super::create,
crate::engine::{
core::model::{Field, Layer, ModelView},
core::model::{Field, Layer},
data::tag::{DataTag, FullTag},
error::DatabaseError,
idx::STIndexSeq,
@ -37,15 +37,16 @@ mod validation {
#[test]
fn simple() {
let ModelView {
p_key,
p_tag,
fields,
} = create("create model mymodel(username: string, password: binary)").unwrap();
assert_eq!(p_key.as_ref(), "username");
assert_eq!(p_tag, FullTag::STR);
let model = create("create model mymodel(username: string, password: binary)").unwrap();
assert_eq!(model.p_key.as_ref(), "username");
assert_eq!(model.p_tag, FullTag::STR);
assert_eq!(
fields.stseq_ord_value().cloned().collect::<Vec<Field>>(),
model
.intent_read_model()
.fields()
.stseq_ord_value()
.cloned()
.collect::<Vec<Field>>(),
[
Field::new([Layer::new_test(FullTag::STR, [0; 2])].into(), false),
Field::new([Layer::new_test(FullTag::BIN, [0; 2])].into(), false)
@ -55,15 +56,17 @@ mod validation {
#[test]
fn idiotic_order() {
let ModelView {
p_key,
p_tag,
fields,
} = create("create model mymodel(password: binary, primary username: string)").unwrap();
assert_eq!(p_key.as_ref(), "username");
assert_eq!(p_tag, FullTag::STR);
let model =
create("create model mymodel(password: binary, primary username: string)").unwrap();
assert_eq!(model.p_key.as_ref(), "username");
assert_eq!(model.p_tag, FullTag::STR);
assert_eq!(
fields.stseq_ord_value().cloned().collect::<Vec<Field>>(),
model
.intent_read_model()
.fields()
.stseq_ord_value()
.cloned()
.collect::<Vec<Field>>(),
[
Field::new([Layer::new_test(FullTag::BIN, [0; 2])].into(), false),
Field::new([Layer::new_test(FullTag::STR, [0; 2])].into(), false),
@ -143,6 +146,7 @@ mod exec {
.unwrap();
with_model(&gns, SPACE, "mymodel", |model| {
let models: Vec<(String, Field)> = model
.intent_read_model()
.fields()
.stseq_ord_kv()
.map(|(k, v)| (k.to_string(), v.clone()))

@ -28,7 +28,8 @@ pub type LangResult<T> = Result<T, LangError>;
pub type LexResult<T> = Result<T, LexError>;
pub type DatabaseResult<T> = Result<T, DatabaseError>;
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u8)]
/// Lex phase errors
pub enum LexError {
// insecure lex
@ -47,7 +48,9 @@ pub enum LexError {
/// Unrecognized byte in stream
UnexpectedByte,
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u8)]
/// AST errors
pub enum LangError {
// generic
@ -76,7 +79,8 @@ pub enum LangError {
StmtUnknownDrop,
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u8)]
/// Executor errors
pub enum DatabaseError {
// sys

@ -24,7 +24,7 @@
*
*/
use std::mem;
use std::mem::{self, ManuallyDrop};
#[macro_use]
mod macros;
@ -51,10 +51,11 @@ pub const IS_ON_CI: bool = option_env!("CI").is_some();
const EXITCODE_ONE: i32 = 0x01;
pub fn bx_to_vec<T>(mut bx: Box<[T]>) -> Vec<T> {
let ptr = bx.as_mut_ptr();
let len = bx.len();
mem::forget(bx);
pub fn bx_to_vec<T>(bx: Box<[T]>) -> Vec<T> {
let mut md = ManuallyDrop::new(bx);
// damn you, miri
let ptr = md.as_mut_ptr() as usize as *mut T;
let len = md.len();
unsafe { Vec::from_raw_parts(ptr, len, len) }
}

Loading…
Cancel
Save