diff --git a/server/src/engine/core/dml/del.rs b/server/src/engine/core/dml/del.rs index 88d0ba5f..667cb39d 100644 --- a/server/src/engine/core/dml/del.rs +++ b/server/src/engine/core/dml/del.rs @@ -25,15 +25,16 @@ */ use crate::engine::{ - core::{model::delta::DataDeltaKind, GlobalNS}, + core::model::delta::DataDeltaKind, error::{DatabaseError, DatabaseResult}, + fractal::GlobalInstanceLike, idx::MTIndex, ql::dml::del::DeleteStatement, sync, }; -pub fn delete(gns: &GlobalNS, mut delete: DeleteStatement) -> DatabaseResult<()> { - gns.with_model(delete.entity(), |model| { +pub fn delete(global: &impl GlobalInstanceLike, mut delete: DeleteStatement) -> DatabaseResult<()> { + global.namespace().with_model(delete.entity(), |model| { let g = sync::atm::cpin(); let schema_version = model.delta_state().schema_current_version(); let delta_state = model.delta_state(); diff --git a/server/src/engine/core/dml/ins.rs b/server/src/engine/core/dml/ins.rs index f93fa556..0ea02d72 100644 --- a/server/src/engine/core/dml/ins.rs +++ b/server/src/engine/core/dml/ins.rs @@ -28,16 +28,16 @@ use crate::engine::{ core::{ index::{DcFieldIndex, PrimaryIndexKey, Row}, model::{delta::DataDeltaKind, Fields, Model}, - GlobalNS, }, error::{DatabaseError, DatabaseResult}, + fractal::GlobalInstanceLike, idx::{IndexBaseSpec, MTIndex, STIndex, STIndexSeq}, ql::dml::ins::{InsertData, InsertStatement}, sync::atm::cpin, }; -pub fn insert(gns: &GlobalNS, insert: InsertStatement) -> DatabaseResult<()> { - gns.with_model(insert.entity(), |mdl| { +pub fn insert(gns: &impl GlobalInstanceLike, insert: InsertStatement) -> DatabaseResult<()> { + gns.namespace().with_model(insert.entity(), |mdl| { let irmwd = mdl.intent_write_new_data(); let (pk, data) = prepare_insert(mdl, irmwd.fields(), insert.data())?; let g = cpin(); diff --git a/server/src/engine/core/dml/sel.rs b/server/src/engine/core/dml/sel.rs index 29d3881e..12a7e894 100644 --- a/server/src/engine/core/dml/sel.rs +++ b/server/src/engine/core/dml/sel.rs @@ -25,23 +25,24 @@ */ use crate::engine::{ - core::{index::DcFieldIndex, GlobalNS}, + core::index::DcFieldIndex, data::cell::{Datacell, VirtualDatacell}, error::{DatabaseError, DatabaseResult}, + fractal::GlobalInstanceLike, idx::{STIndex, STIndexSeq}, ql::dml::sel::SelectStatement, sync, }; pub fn select_custom( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, mut select: SelectStatement, mut cellfn: F, ) -> DatabaseResult<()> where F: FnMut(&Datacell), { - gns.with_model(select.entity(), |mdl| { + global.namespace().with_model(select.entity(), |mdl| { let irm = mdl.intent_read_model(); let target_key = mdl.resolve_where(select.clauses_mut())?; let pkdc = VirtualDatacell::new(target_key.clone()); diff --git a/server/src/engine/core/dml/upd.rs b/server/src/engine/core/dml/upd.rs index 45b62532..9a3cb285 100644 --- a/server/src/engine/core/dml/upd.rs +++ b/server/src/engine/core/dml/upd.rs @@ -30,7 +30,7 @@ use std::cell::RefCell; use { crate::{ engine::{ - core::{model::delta::DataDeltaKind, query_meta::AssignmentOperator, GlobalNS}, + core::{model::delta::DataDeltaKind, query_meta::AssignmentOperator}, data::{ cell::Datacell, lit::LitIR, @@ -38,6 +38,7 @@ use { tag::{DataTag, TagClass}, }, error::{DatabaseError, DatabaseResult}, + fractal::GlobalInstanceLike, idx::STIndex, ql::dml::upd::{AssignmentExpression, UpdateStatement}, sync, @@ -232,8 +233,8 @@ pub fn collect_trace_path() -> Vec<&'static str> { ROUTE_TRACE.with(|v| v.borrow().iter().cloned().collect()) } -pub fn update(gns: &GlobalNS, mut update: UpdateStatement) -> DatabaseResult<()> { - gns.with_model(update.entity(), |mdl| { +pub fn update(global: &impl GlobalInstanceLike, mut update: UpdateStatement) -> DatabaseResult<()> { + global.namespace().with_model(update.entity(), |mdl| { let mut ret = Ok(()); // prepare row fetch let key = mdl.resolve_where(update.clauses_mut())?; diff --git a/server/src/engine/core/model/alt.rs b/server/src/engine/core/model/alt.rs index 3f0a5d2e..a4273e3f 100644 --- a/server/src/engine/core/model/alt.rs +++ b/server/src/engine/core/model/alt.rs @@ -28,12 +28,13 @@ use { super::{Field, IWModel, Layer, Model}, crate::{ engine::{ - core::{util::EntityLocator, GlobalNS}, + core::util::EntityLocator, data::{ tag::{DataTag, TagClass}, DictEntryGeneric, }, error::{DatabaseError, DatabaseResult}, + fractal::GlobalInstanceLike, idx::{IndexST, IndexSTSeqCns, STIndex, STIndexSeq}, ql::{ ast::Entity, @@ -249,12 +250,12 @@ impl<'a> AlterPlan<'a> { impl Model { pub fn transactional_exec_alter( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS, alter: AlterModel, ) -> DatabaseResult<()> { let (space_name, model_name) = EntityLocator::parse_entity(alter.model)?; - gns.with_space(space_name, |space| { + global.namespace().with_space(space_name, |space| { space.with_model(model_name, |model| { // make intent let iwm = model.intent_write_model(); @@ -303,9 +304,10 @@ impl Model { txn_driver.try_commit(txn)?; } removed.iter().for_each(|field_id| { - model - .delta_state() - .schema_append_unresolved_wl_field_rem(&mut guard, field_id.as_str()); + model.delta_state().schema_append_unresolved_wl_field_rem( + &mut guard, + field_id.as_str(), + ); iwm.fields_mut().st_delete(field_id.as_str()); }); } @@ -328,9 +330,9 @@ impl Model { }) }) } - pub fn exec_alter(gns: &GlobalNS, stmt: AlterModel) -> DatabaseResult<()> { - gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, |driver| { - Self::transactional_exec_alter(gns, driver, stmt) + pub fn exec_alter(global: &impl GlobalInstanceLike, stmt: AlterModel) -> DatabaseResult<()> { + gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(global.namespace(), |driver| { + Self::transactional_exec_alter(global, driver, stmt) }) } } diff --git a/server/src/engine/core/model/mod.rs b/server/src/engine/core/model/mod.rs index 13f7137e..fb037092 100644 --- a/server/src/engine/core/model/mod.rs +++ b/server/src/engine/core/model/mod.rs @@ -40,6 +40,7 @@ use { uuid::Uuid, }, error::{DatabaseError, DatabaseResult}, + fractal::GlobalInstanceLike, idx::{IndexBaseSpec, IndexSTSeqCns, STIndex, STIndexSeq}, mem::VInline, ql::ddl::{ @@ -204,13 +205,13 @@ impl Model { impl Model { pub fn transactional_exec_create( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS, stmt: CreateModel, ) -> DatabaseResult<()> { let (space_name, model_name) = stmt.model_name.parse_entity()?; let model = Self::process_create(stmt)?; - gns.with_space(space_name, |space| { + global.namespace().with_space(space_name, |space| { let mut w_space = space.models().write(); if w_space.st_contains(model_name) { return Err(DatabaseError::DdlModelAlreadyExists); @@ -234,20 +235,20 @@ impl Model { } #[cfg(test)] pub fn nontransactional_exec_create( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, stmt: CreateModel, ) -> DatabaseResult<()> { - gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, |driver| { - Self::transactional_exec_create(gns, driver, stmt) + gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(global.namespace(), |driver| { + Self::transactional_exec_create(global, driver, stmt) }) } pub fn transactional_exec_drop( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS, stmt: DropModel, ) -> DatabaseResult<()> { let (space_name, model_name) = stmt.entity.parse_entity()?; - gns.with_space(space_name, |space| { + global.namespace().with_space(space_name, |space| { let mut w_space = space.models().write(); let Some(model) = w_space.get(model_name) else { return Err(DatabaseError::DdlModelNotFound); @@ -270,11 +271,11 @@ impl Model { } #[cfg(test)] pub fn nontransactional_exec_drop( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, stmt: DropModel, ) -> DatabaseResult<()> { - gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, |driver| { - Self::transactional_exec_drop(gns, driver, stmt) + gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(global.namespace(), |driver| { + Self::transactional_exec_drop(global, driver, stmt) }) } } diff --git a/server/src/engine/core/space.rs b/server/src/engine/core/space.rs index f6da7c3e..6a948dfc 100644 --- a/server/src/engine/core/space.rs +++ b/server/src/engine/core/space.rs @@ -29,6 +29,7 @@ use { core::{model::Model, RWLIdx}, data::{dict, uuid::Uuid, DictEntryGeneric, DictGeneric}, error::{DatabaseError, DatabaseResult}, + fractal::GlobalInstanceLike, idx::{IndexST, STIndex}, ql::ddl::{alt::AlterSpace, crt::CreateSpace, drop::DropSpace}, txn::gns as gnstxn, @@ -189,14 +190,14 @@ impl Space { impl Space { pub fn transactional_exec_create( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS, space: CreateSpace, ) -> DatabaseResult<()> { // process create let ProcedureCreate { space_name, space } = Self::process_create(space)?; // acquire access - let mut wl = gns.spaces().write(); + let mut wl = global.namespace().spaces().write(); if wl.st_contains(&space_name) { return Err(DatabaseError::DdlSpaceAlreadyExists); } @@ -213,22 +214,23 @@ impl Space { /// Execute a `create` stmt #[cfg(test)] pub fn nontransactional_exec_create( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, space: CreateSpace, ) -> DatabaseResult<()> { - gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, move |driver| { - Self::transactional_exec_create(gns, driver, space) - }) + gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec( + global.namespace(), + move |driver| Self::transactional_exec_create(global, driver, space), + ) } pub fn transactional_exec_alter( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS, AlterSpace { space_name, updated_props, }: AlterSpace, ) -> DatabaseResult<()> { - gns.with_space(&space_name, |space| { + global.namespace().with_space(&space_name, |space| { match updated_props.get(SpaceMeta::KEY_ENV) { Some(DictEntryGeneric::Map(_)) if updated_props.len() == 1 => {} Some(DictEntryGeneric::Data(l)) if updated_props.len() == 1 && l.is_null() => {} @@ -262,22 +264,23 @@ impl Space { #[cfg(test)] /// Execute a `alter` stmt pub fn nontransactional_exec_alter( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, alter: AlterSpace, ) -> DatabaseResult<()> { - gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, move |driver| { - Self::transactional_exec_alter(gns, driver, alter) - }) + gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec( + global.namespace(), + move |driver| Self::transactional_exec_alter(global, driver, alter), + ) } pub fn transactional_exec_drop( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS, DropSpace { space, force: _ }: DropSpace, ) -> DatabaseResult<()> { // TODO(@ohsayan): force remove option // TODO(@ohsayan): should a drop space block the entire global table? let space_name = space; - let mut wgns = gns.spaces().write(); + let mut wgns = global.namespace().spaces().write(); let space = match wgns.get(space_name.as_str()) { Some(space) => space, None => return Err(DatabaseError::DdlSpaceNotFound), @@ -298,12 +301,13 @@ impl Space { } #[cfg(test)] pub fn nontransactional_exec_drop( - gns: &super::GlobalNS, + global: &impl GlobalInstanceLike, drop_space: DropSpace, ) -> DatabaseResult<()> { - gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, move |driver| { - Self::transactional_exec_drop(gns, driver, drop_space) - }) + gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec( + global.namespace(), + move |driver| Self::transactional_exec_drop(global, driver, drop_space), + ) } } diff --git a/server/src/engine/core/tests/ddl_model/alt.rs b/server/src/engine/core/tests/ddl_model/alt.rs index bcbb16a4..ca017e03 100644 --- a/server/src/engine/core/tests/ddl_model/alt.rs +++ b/server/src/engine/core/tests/ddl_model/alt.rs @@ -28,9 +28,9 @@ use crate::engine::{ core::{ model::{alt::AlterPlan, Model}, tests::ddl_model::{create, exec_create}, - GlobalNS, }, error::DatabaseResult, + fractal::GlobalInstanceLike, idx::STIndex, ql::{ast::parse_ast_node_full, ddl::alt::AlterModel, tests::lex_insecure}, }; @@ -47,15 +47,15 @@ fn plan(model: &str, plan: &str, f: impl Fn(AlterPlan)) { with_plan(model, plan, f).unwrap() } fn exec_plan( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, new_space: bool, model: &str, plan: &str, f: impl Fn(&Model), ) -> DatabaseResult<()> { - let mdl_name = exec_create(gns, model, new_space)?; + let mdl_name = exec_create(global, model, new_space)?; let prev_uuid = { - let gns = gns.spaces().read(); + let gns = global.namespace().spaces().read(); let space = gns.get("myspace").unwrap(); let space_read = space.models().read(); space_read.get(mdl_name.as_str()).unwrap().get_uuid() @@ -63,8 +63,8 @@ fn exec_plan( let tok = lex_insecure(plan.as_bytes()).unwrap(); let alter = parse_ast_node_full::(&tok[2..]).unwrap(); let (_space, model_name) = alter.model.into_full().unwrap(); - Model::exec_alter(gns, alter)?; - let gns_read = gns.spaces().read(); + Model::exec_alter(global, alter)?; + let gns_read = global.namespace().spaces().read(); let space = gns_read.st_get("myspace").unwrap(); let model = space.models().read(); let model = model.st_get(model_name.as_str()).unwrap(); @@ -352,18 +352,16 @@ mod plan { mod exec { use crate::engine::{ - core::{ - model::{DeltaVersion, Field, Layer}, - GlobalNS, - }, + core::model::{DeltaVersion, Field, Layer}, error::DatabaseError, + fractal::test_utils::TestGlobal, idx::{STIndex, STIndexSeq}, }; #[test] fn simple_add() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); super::exec_plan( - &gns, + &global, true, "create model myspace.mymodel(username: string, col1: uint64)", "alter model myspace.mymodel add (col2 { type: uint32, nullable: true }, col3 { type: uint16, nullable: true })", @@ -392,9 +390,9 @@ mod exec { } #[test] fn simple_remove() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); super::exec_plan( - &gns, + &global, true, "create model myspace.mymodel(username: string, col1: uint64, col2: uint32, col3: uint16, col4: uint8)", "alter model myspace.mymodel remove (col1, col2, col3, col4)", @@ -418,9 +416,9 @@ mod exec { } #[test] fn simple_update() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); super::exec_plan( - &gns, + &global, true, "create model myspace.mymodel(username: string, password: binary)", "alter model myspace.mymodel update password { nullable: true }", @@ -437,10 +435,10 @@ mod exec { } #[test] fn failing_alter_nullable_switch_need_lock() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_plan( - &gns, + &global, true, "create model myspace.mymodel(username: string, null gh_handle: string)", "alter model myspace.mymodel update gh_handle { nullable: false }", diff --git a/server/src/engine/core/tests/ddl_model/crt.rs b/server/src/engine/core/tests/ddl_model/crt.rs index cc87b474..4b247002 100644 --- a/server/src/engine/core/tests/ddl_model/crt.rs +++ b/server/src/engine/core/tests/ddl_model/crt.rs @@ -135,9 +135,9 @@ mod exec { core::{ model::{DeltaVersion, Field, Layer}, tests::ddl_model::{exec_create_new_space, with_model}, - GlobalNS, }, data::tag::{DataTag, FullTag}, + fractal::test_utils::TestGlobal, idx::STIndexSeq, }; @@ -145,13 +145,13 @@ mod exec { #[test] fn simple() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); exec_create_new_space( - &gns, + &global, "create model myspace.mymodel(username: string, password: binary)", ) .unwrap(); - with_model(&gns, SPACE, "mymodel", |model| { + with_model(&global, SPACE, "mymodel", |model| { let models: Vec<(String, Field)> = model .intent_read_model() .fields() diff --git a/server/src/engine/core/tests/ddl_model/mod.rs b/server/src/engine/core/tests/ddl_model/mod.rs index 70b1b295..61af1fc4 100644 --- a/server/src/engine/core/tests/ddl_model/mod.rs +++ b/server/src/engine/core/tests/ddl_model/mod.rs @@ -29,8 +29,9 @@ mod crt; mod layer; use crate::engine::{ - core::{model::Model, space::Space, GlobalNS}, + core::{model::Model, space::Space}, error::DatabaseResult, + fractal::GlobalInstanceLike, idx::STIndex, ql::{ ast::{parse_ast_node_full, Entity}, @@ -46,7 +47,7 @@ fn create(s: &str) -> DatabaseResult { } pub fn exec_create( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, create_stmt: &str, create_new_space: bool, ) -> DatabaseResult { @@ -56,27 +57,40 @@ pub fn exec_create( Entity::Single(tbl) | Entity::Full(_, tbl) => tbl.to_string(), }; if create_new_space { - gns.test_new_empty_space(&create_model.model_name.into_full().unwrap().0); + global + .namespace() + .test_new_empty_space(&create_model.model_name.into_full().unwrap().0); } - Model::nontransactional_exec_create(gns, create_model).map(|_| name) + Model::nontransactional_exec_create(global, create_model).map(|_| name) } -pub fn exec_create_new_space(gns: &GlobalNS, create_stmt: &str) -> DatabaseResult<()> { - exec_create(gns, create_stmt, true).map(|_| ()) +pub fn exec_create_new_space( + global: &impl GlobalInstanceLike, + create_stmt: &str, +) -> DatabaseResult<()> { + exec_create(global, create_stmt, true).map(|_| ()) } -pub fn exec_create_no_create(gns: &GlobalNS, create_stmt: &str) -> DatabaseResult<()> { - exec_create(gns, create_stmt, false).map(|_| ()) +pub fn exec_create_no_create( + global: &impl GlobalInstanceLike, + create_stmt: &str, +) -> DatabaseResult<()> { + exec_create(global, create_stmt, false).map(|_| ()) } -fn with_space(gns: &GlobalNS, space_name: &str, f: impl Fn(&Space)) { - let rl = gns.spaces().read(); +fn with_space(global: &impl GlobalInstanceLike, space_name: &str, f: impl Fn(&Space)) { + let rl = global.namespace().spaces().read(); let space = rl.st_get(space_name).unwrap(); f(space); } -fn with_model(gns: &GlobalNS, space_id: &str, model_name: &str, f: impl Fn(&Model)) { - with_space(gns, space_id, |space| { +fn with_model( + global: &impl GlobalInstanceLike, + space_id: &str, + model_name: &str, + f: impl Fn(&Model), +) { + with_space(global, space_id, |space| { let space_rl = space.models().read(); let model = space_rl.st_get(model_name).unwrap(); f(model) diff --git a/server/src/engine/core/tests/ddl_space/alter.rs b/server/src/engine/core/tests/ddl_space/alter.rs index 3cbcd4ab..ecfd7314 100644 --- a/server/src/engine/core/tests/ddl_space/alter.rs +++ b/server/src/engine/core/tests/ddl_space/alter.rs @@ -25,19 +25,17 @@ */ use crate::engine::{ - core::{ - space::{Space, SpaceMeta}, - GlobalNS, - }, + core::space::{Space, SpaceMeta}, data::cell::Datacell, error::DatabaseError, + fractal::test_utils::TestGlobal, }; #[test] fn alter_add_prop_env_var() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); super::exec_create_alter( - &gns, + &global, "create space myspace", "alter space myspace with { env: { MY_NEW_PROP: 100 } }", |space| { @@ -56,9 +54,9 @@ fn alter_add_prop_env_var() { #[test] fn alter_update_prop_env_var() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); let uuid = super::exec_create( - &gns, + &global, "create space myspace with { env: { MY_NEW_PROP: 100 } }", |space| { let rl = space.meta.dict().read(); @@ -70,7 +68,7 @@ fn alter_update_prop_env_var() { ) .unwrap(); super::exec_alter( - &gns, + &global, "alter space myspace with { env: { MY_NEW_PROP: 200 } }", |space| { assert_eq!( @@ -88,9 +86,9 @@ fn alter_update_prop_env_var() { #[test] fn alter_remove_prop_env_var() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); let uuid = super::exec_create( - &gns, + &global, "create space myspace with { env: { MY_NEW_PROP: 100 } }", |space| { let rl = space.meta.dict().read(); @@ -102,7 +100,7 @@ fn alter_remove_prop_env_var() { ) .unwrap(); super::exec_alter( - &gns, + &global, "alter space myspace with { env: { MY_NEW_PROP: null } }", |space| { assert_eq!( @@ -116,10 +114,10 @@ fn alter_remove_prop_env_var() { #[test] fn alter_nx() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_alter( - &gns, + &global, "alter space myspace with { env: { MY_NEW_PROP: 100 } }", |_| {}, ) @@ -130,9 +128,9 @@ fn alter_nx() { #[test] fn alter_remove_all_env() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); let uuid = super::exec_create( - &gns, + &global, "create space myspace with { env: { MY_NEW_PROP: 100 } }", |space| { let rl = space.meta.dict().read(); @@ -143,7 +141,7 @@ fn alter_remove_all_env() { }, ) .unwrap(); - super::exec_alter(&gns, "alter space myspace with { env: null }", |space| { + super::exec_alter(&global, "alter space myspace with { env: null }", |space| { assert_eq!(space, &Space::empty_with_uuid(uuid)) }) .unwrap(); diff --git a/server/src/engine/core/tests/ddl_space/create.rs b/server/src/engine/core/tests/ddl_space/create.rs index e66f4926..bcf9cf2b 100644 --- a/server/src/engine/core/tests/ddl_space/create.rs +++ b/server/src/engine/core/tests/ddl_space/create.rs @@ -25,18 +25,16 @@ */ use crate::engine::{ - core::{ - space::{Space, SpaceMeta}, - GlobalNS, - }, + core::space::{Space, SpaceMeta}, data::cell::Datacell, error::DatabaseError, + fractal::test_utils::TestGlobal, }; #[test] fn exec_create_space_simple() { - let gns = GlobalNS::empty(); - super::exec_create(&gns, "create space myspace", |spc| { + let global = TestGlobal::empty(); + super::exec_create(&global, "create space myspace", |spc| { assert!(spc.models().read().is_empty()) }) .unwrap(); @@ -44,9 +42,9 @@ fn exec_create_space_simple() { #[test] fn exec_create_space_with_env() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); super::exec_create( - &gns, + &global, r#" create space myspace with { env: { @@ -72,19 +70,19 @@ fn exec_create_space_with_env() { #[test] fn exec_create_space_with_bad_env_type() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( - super::exec_create(&gns, "create space myspace with { env: 100 }", |_| {}).unwrap_err(), + super::exec_create(&global, "create space myspace with { env: 100 }", |_| {}).unwrap_err(), DatabaseError::DdlSpaceBadProperty ); } #[test] fn exec_create_space_with_random_property() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_create( - &gns, + &global, "create space myspace with { i_am_blue_da_ba_dee: 100 }", |_| {} ) diff --git a/server/src/engine/core/tests/ddl_space/mod.rs b/server/src/engine/core/tests/ddl_space/mod.rs index 0518c375..7e05f0a8 100644 --- a/server/src/engine/core/tests/ddl_space/mod.rs +++ b/server/src/engine/core/tests/ddl_space/mod.rs @@ -28,41 +28,50 @@ mod alter; mod create; use crate::engine::{ - core::{space::Space, GlobalNS}, + core::space::Space, data::uuid::Uuid, error::DatabaseResult, + fractal::GlobalInstanceLike, ql::{ ast::{self}, tests::lex_insecure as lex, }, }; -fn exec_create(gns: &GlobalNS, create: &str, verify: impl Fn(&Space)) -> DatabaseResult { +fn exec_create( + gns: &impl GlobalInstanceLike, + create: &str, + verify: impl Fn(&Space), +) -> DatabaseResult { let tok = lex(create.as_bytes()).unwrap(); let ast_node = ast::parse_ast_node_full::(&tok[2..]).unwrap(); let name = ast_node.space_name; Space::nontransactional_exec_create(gns, ast_node)?; - gns.with_space(&name, |space| { + gns.namespace().with_space(&name, |space| { verify(space); Ok(space.get_uuid()) }) } -fn exec_alter(gns: &GlobalNS, alter: &str, verify: impl Fn(&Space)) -> DatabaseResult { +fn exec_alter( + gns: &impl GlobalInstanceLike, + alter: &str, + verify: impl Fn(&Space), +) -> DatabaseResult { let tok = lex(alter.as_bytes()).unwrap(); let ast_node = ast::parse_ast_node_full::(&tok[2..]).unwrap(); let name = ast_node.space_name; Space::nontransactional_exec_alter(gns, ast_node)?; - gns.with_space(&name, |space| { + gns.namespace().with_space(&name, |space| { verify(space); Ok(space.get_uuid()) }) } fn exec_create_alter( - gns: &GlobalNS, + gns: &impl GlobalInstanceLike, crt: &str, alt: &str, verify_post_alt: impl Fn(&Space), diff --git a/server/src/engine/core/tests/dml/delete.rs b/server/src/engine/core/tests/dml/delete.rs index 1bb4fcc0..92183ab2 100644 --- a/server/src/engine/core/tests/dml/delete.rs +++ b/server/src/engine/core/tests/dml/delete.rs @@ -24,13 +24,13 @@ * */ -use crate::engine::{core::GlobalNS, error::DatabaseError}; +use crate::engine::{error::DatabaseError, fractal::test_utils::TestGlobal}; #[test] fn simple_delete() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); super::exec_delete( - &gns, + &global, "create model myspace.mymodel(username: string, password: string)", Some("insert into myspace.mymodel('sayan', 'pass123')"), "delete from myspace.mymodel where username = 'sayan'", @@ -41,10 +41,10 @@ fn simple_delete() { #[test] fn delete_nonexisting() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_delete( - &gns, + &global, "create model myspace.mymodel(username: string, password: string)", None, "delete from myspace.mymodel where username = 'sayan'", diff --git a/server/src/engine/core/tests/dml/insert.rs b/server/src/engine/core/tests/dml/insert.rs index 10d77ff5..de36b22a 100644 --- a/server/src/engine/core/tests/dml/insert.rs +++ b/server/src/engine/core/tests/dml/insert.rs @@ -24,16 +24,16 @@ * */ -use crate::engine::{core::GlobalNS, data::cell::Datacell, error::DatabaseError}; +use crate::engine::{data::cell::Datacell, error::DatabaseError, fractal::test_utils::TestGlobal}; #[derive(sky_macros::Wrapper, Debug)] struct Tuple(Vec<(Box, Datacell)>); #[test] fn insert_simple() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); super::exec_insert( - &gns, + &global, "create model myspace.mymodel(username: string, password: string)", "insert into myspace.mymodel('sayan', 'pass123')", "sayan", @@ -46,9 +46,9 @@ fn insert_simple() { #[test] fn insert_with_null() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); super::exec_insert( - &gns, + &global, "create model myspace.mymodel(username: string, null useless_password: string, null useless_email: string, null useless_random_column: uint64)", "insert into myspace.mymodel('sayan', null, null, null)", "sayan", @@ -69,9 +69,9 @@ fn insert_with_null() { #[test] fn insert_duplicate() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); super::exec_insert( - &gns, + &global, "create model myspace.mymodel(username: string, password: string)", "insert into myspace.mymodel('sayan', 'pass123')", "sayan", @@ -81,7 +81,7 @@ fn insert_duplicate() { ) .unwrap(); assert_eq!( - super::exec_insert_only(&gns, "insert into myspace.mymodel('sayan', 'pass123')") + super::exec_insert_only(&global, "insert into myspace.mymodel('sayan', 'pass123')") .unwrap_err(), DatabaseError::DmlConstraintViolationDuplicate ); diff --git a/server/src/engine/core/tests/dml/mod.rs b/server/src/engine/core/tests/dml/mod.rs index 6a4b8d23..8f14363a 100644 --- a/server/src/engine/core/tests/dml/mod.rs +++ b/server/src/engine/core/tests/dml/mod.rs @@ -30,9 +30,10 @@ mod select; mod update; use crate::engine::{ - core::{dml, index::Row, model::Model, GlobalNS}, + core::{dml, index::Row, model::Model}, data::{cell::Datacell, lit::LitIR}, error::DatabaseResult, + fractal::GlobalInstanceLike, ql::{ ast::{parse_ast_node_full, Entity}, dml::{del::DeleteStatement, ins::InsertStatement}, @@ -41,36 +42,39 @@ use crate::engine::{ sync, }; -fn _exec_only_create_space_model(gns: &GlobalNS, model: &str) -> DatabaseResult<()> { - if !gns.spaces().read().contains_key("myspace") { - gns.test_new_empty_space("myspace"); +fn _exec_only_create_space_model( + global: &impl GlobalInstanceLike, + model: &str, +) -> DatabaseResult<()> { + if !global.namespace().spaces().read().contains_key("myspace") { + global.namespace().test_new_empty_space("myspace"); } let lex_create_model = lex_insecure(model.as_bytes()).unwrap(); let stmt_create_model = parse_ast_node_full(&lex_create_model[2..]).unwrap(); - Model::nontransactional_exec_create(gns, stmt_create_model) + Model::nontransactional_exec_create(global, stmt_create_model) } fn _exec_only_insert( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, insert: &str, and_then: impl Fn(Entity) -> T, ) -> DatabaseResult { let lex_insert = lex_insecure(insert.as_bytes()).unwrap(); let stmt_insert = parse_ast_node_full::(&lex_insert[1..]).unwrap(); let entity = stmt_insert.entity(); - dml::insert(gns, stmt_insert)?; + dml::insert(global, stmt_insert)?; let r = and_then(entity); Ok(r) } fn _exec_only_read_key_and_then( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, entity: Entity, key_name: &str, and_then: impl Fn(Row) -> T, ) -> DatabaseResult { let guard = sync::atm::cpin(); - gns.with_model(entity, |mdl| { + global.namespace().with_model(entity, |mdl| { let _irm = mdl.intent_read_model(); let row = mdl .primary_index() @@ -82,13 +86,17 @@ fn _exec_only_read_key_and_then( }) } -fn _exec_delete_only(gns: &GlobalNS, delete: &str, key: &str) -> DatabaseResult<()> { +fn _exec_delete_only( + global: &impl GlobalInstanceLike, + delete: &str, + key: &str, +) -> DatabaseResult<()> { let lex_del = lex_insecure(delete.as_bytes()).unwrap(); let delete = parse_ast_node_full::(&lex_del[1..]).unwrap(); let entity = delete.entity(); - dml::delete(gns, delete)?; + dml::delete(global, delete)?; assert_eq!( - gns.with_model(entity, |model| { + global.namespace().with_model(entity, |model| { let _ = model.intent_read_model(); let g = sync::atm::cpin(); Ok(model.primary_index().select(key.into(), &g).is_none()) @@ -98,75 +106,84 @@ fn _exec_delete_only(gns: &GlobalNS, delete: &str, key: &str) -> DatabaseResult< Ok(()) } -fn _exec_only_select(gns: &GlobalNS, select: &str) -> DatabaseResult> { +fn _exec_only_select( + global: &impl GlobalInstanceLike, + select: &str, +) -> DatabaseResult> { let lex_sel = lex_insecure(select.as_bytes()).unwrap(); let select = parse_ast_node_full(&lex_sel[1..]).unwrap(); let mut r = Vec::new(); - dml::select_custom(gns, select, |cell| r.push(cell.clone()))?; + dml::select_custom(global, select, |cell| r.push(cell.clone()))?; Ok(r) } -fn _exec_only_update(gns: &GlobalNS, update: &str) -> DatabaseResult<()> { +fn _exec_only_update(global: &impl GlobalInstanceLike, update: &str) -> DatabaseResult<()> { let lex_upd = lex_insecure(update.as_bytes()).unwrap(); let update = parse_ast_node_full(&lex_upd[1..]).unwrap(); - dml::update(gns, update) + dml::update(global, update) } pub(self) fn exec_insert( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, model: &str, insert: &str, key_name: &str, f: impl Fn(Row) -> T, ) -> DatabaseResult { - _exec_only_create_space_model(gns, model)?; - _exec_only_insert(gns, insert, |entity| { - _exec_only_read_key_and_then(gns, entity, key_name, |row| f(row)) + _exec_only_create_space_model(global, model)?; + _exec_only_insert(global, insert, |entity| { + _exec_only_read_key_and_then(global, entity, key_name, |row| f(row)) })? } -pub(self) fn exec_insert_only(gns: &GlobalNS, insert: &str) -> DatabaseResult<()> { - _exec_only_insert(gns, insert, |_| {}) +pub(self) fn exec_insert_only( + global: &impl GlobalInstanceLike, + insert: &str, +) -> DatabaseResult<()> { + _exec_only_insert(global, insert, |_| {}) } pub(self) fn exec_delete( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, model: &str, insert: Option<&str>, delete: &str, key: &str, ) -> DatabaseResult<()> { - _exec_only_create_space_model(gns, model)?; + _exec_only_create_space_model(global, model)?; if let Some(insert) = insert { - _exec_only_insert(gns, insert, |_| {})?; + _exec_only_insert(global, insert, |_| {})?; } - _exec_delete_only(gns, delete, key) + _exec_delete_only(global, delete, key) } pub(self) fn exec_select( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, model: &str, insert: &str, select: &str, ) -> DatabaseResult> { - _exec_only_create_space_model(gns, model)?; - _exec_only_insert(gns, insert, |_| {})?; - _exec_only_select(gns, select) + _exec_only_create_space_model(global, model)?; + _exec_only_insert(global, insert, |_| {})?; + _exec_only_select(global, select) } -pub(self) fn exec_select_only(gns: &GlobalNS, select: &str) -> DatabaseResult> { - _exec_only_select(gns, select) +pub(self) fn exec_select_only( + global: &impl GlobalInstanceLike, + select: &str, +) -> DatabaseResult> { + _exec_only_select(global, select) } pub(self) fn exec_update( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, model: &str, insert: &str, update: &str, select: &str, ) -> DatabaseResult> { - _exec_only_create_space_model(gns, model)?; - _exec_only_insert(gns, insert, |_| {})?; - _exec_only_update(gns, update)?; - _exec_only_select(gns, select) + _exec_only_create_space_model(global, model)?; + _exec_only_insert(global, insert, |_| {})?; + _exec_only_update(global, update)?; + _exec_only_select(global, select) } diff --git a/server/src/engine/core/tests/dml/select.rs b/server/src/engine/core/tests/dml/select.rs index e7501d07..8c5f079c 100644 --- a/server/src/engine/core/tests/dml/select.rs +++ b/server/src/engine/core/tests/dml/select.rs @@ -24,14 +24,14 @@ * */ -use crate::engine::{core::GlobalNS, data::cell::Datacell, error::DatabaseError}; +use crate::engine::{data::cell::Datacell, error::DatabaseError, fractal::test_utils::TestGlobal}; #[test] fn simple_select_wildcard() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_select( - &gns, + &global, "create model myspace.mymodel(username: string, password: string)", "insert into myspace.mymodel('sayan', 'pass123')", "select * from myspace.mymodel where username = 'sayan'", @@ -43,10 +43,10 @@ fn simple_select_wildcard() { #[test] fn simple_select_specified_same_order() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_select( - &gns, + &global, "create model myspace.mymodel(username: string, password: string)", "insert into myspace.mymodel('sayan', 'pass123')", "select username, password from myspace.mymodel where username = 'sayan'", @@ -58,10 +58,10 @@ fn simple_select_specified_same_order() { #[test] fn simple_select_specified_reversed_order() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_select( - &gns, + &global, "create model myspace.mymodel(username: string, password: string)", "insert into myspace.mymodel('sayan', 'pass123')", "select password, username from myspace.mymodel where username = 'sayan'", @@ -73,10 +73,10 @@ fn simple_select_specified_reversed_order() { #[test] fn select_null() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_select( - &gns, + &global, "create model myspace.mymodel(username: string, null password: string)", "insert into myspace.mymodel('sayan', null)", "select username, password from myspace.mymodel where username = 'sayan'", @@ -88,10 +88,10 @@ fn select_null() { #[test] fn select_nonexisting() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_select( - &gns, + &global, "create model myspace.mymodel(username: string, null password: string)", "insert into myspace.mymodel('sayan', null)", "select username, password from myspace.mymodel where username = 'notsayan'", diff --git a/server/src/engine/core/tests/dml/update.rs b/server/src/engine/core/tests/dml/update.rs index 5f74d26d..f49ed310 100644 --- a/server/src/engine/core/tests/dml/update.rs +++ b/server/src/engine/core/tests/dml/update.rs @@ -25,17 +25,15 @@ */ use crate::engine::{ - core::{dml, GlobalNS}, - data::cell::Datacell, - error::DatabaseError, + core::dml, data::cell::Datacell, error::DatabaseError, fractal::test_utils::TestGlobal, }; #[test] fn simple() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_update( - &gns, + &global, "create model myspace.mymodel(username: string, email: string, followers: uint64, following: uint64)", "insert into myspace.mymodel('sayan', 'sayan@example.com', 0, 100)", "update myspace.mymodel set followers += 200000, following -= 15, email = 'sn@example.com' where username = 'sayan'", @@ -51,10 +49,10 @@ fn simple() { #[test] fn with_null() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_update( - &gns, + &global, "create model myspace.mymodel(username: string, password: string, null email: string)", "insert into myspace.mymodel('sayan', 'pass123', null)", "update myspace.mymodel set email = 'sayan@example.com' where username = 'sayan'", @@ -68,10 +66,10 @@ fn with_null() { #[test] fn with_list() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_update( - &gns, + &global, "create model myspace.mymodel(link: string, click_ids: list { type: string })", "insert into myspace.mymodel('example.com', [])", "update myspace.mymodel set click_ids += 'ios_client_uuid' where link = 'example.com'", @@ -88,10 +86,10 @@ fn with_list() { #[test] fn fail_operation_on_null() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_update( - &gns, + &global, "create model myspace.mymodel(username: string, password: string, null email: string)", "insert into myspace.mymodel('sayan', 'pass123', null)", "update myspace.mymodel set email += '.com' where username = 'sayan'", @@ -108,10 +106,10 @@ fn fail_operation_on_null() { #[test] fn fail_unknown_fields() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_update( - &gns, + &global, "create model myspace.mymodel(username: string, password: string, null email: string)", "insert into myspace.mymodel('sayan', 'pass123', null)", "update myspace.mymodel set email2 = 'sayan@example.com', password += '4' where username = 'sayan'", @@ -123,18 +121,21 @@ fn fail_unknown_fields() { assert_eq!(dml::update_flow_trace(), ["fieldnotfound", "rollback"]); // verify integrity assert_eq!( - super::exec_select_only(&gns, "select * from myspace.mymodel where username='sayan'") - .unwrap(), + super::exec_select_only( + &global, + "select * from myspace.mymodel where username='sayan'" + ) + .unwrap(), intovec!["sayan", "pass123", Datacell::null()] ); } #[test] fn fail_typedef_violation() { - let gns = GlobalNS::empty(); + let global = TestGlobal::empty(); assert_eq!( super::exec_update( - &gns, + &global, "create model myspace.mymodel(username: string, password: string, rank: uint8)", "insert into myspace.mymodel('sayan', 'pass123', 1)", "update myspace.mymodel set password = 'pass1234', rank = 'one' where username = 'sayan'", @@ -150,7 +151,7 @@ fn fail_typedef_violation() { // verify integrity assert_eq!( super::exec_select_only( - &gns, + &global, "select * from myspace.mymodel where username = 'sayan'" ) .unwrap(), diff --git a/server/src/engine/fractal/mgr.rs b/server/src/engine/fractal/mgr.rs index 51dc80ac..93cdf85d 100644 --- a/server/src/engine/fractal/mgr.rs +++ b/server/src/engine/fractal/mgr.rs @@ -184,7 +184,7 @@ impl FractalMgr { // was way behind in the queue continue; }; - let res = global.namespace().with_model( + let res = global._namespace().with_model( (model_id.space(), model_id.model()), |model| { if model.get_uuid() != model_id.uuid() { @@ -235,7 +235,7 @@ impl FractalMgr { let mdl_drivers = global.get_state().get_mdl_drivers().read(); for (model_id, driver) in mdl_drivers.iter() { let mut observed_len = 0; - let res = global.namespace().with_model((model_id.space(), model_id.model()), |model| { + let res = global._namespace().with_model((model_id.space(), model_id.model()), |model| { if model.get_uuid() != model_id.uuid() { // once again, throughput maximization will lead to, in extremely rare cases, this // branch returning. but it is okay diff --git a/server/src/engine/fractal/mod.rs b/server/src/engine/fractal/mod.rs index 5d6bb0a6..cc875963 100644 --- a/server/src/engine/fractal/mod.rs +++ b/server/src/engine/fractal/mod.rs @@ -36,6 +36,8 @@ use { mod config; mod drivers; mod mgr; +#[cfg(test)] +pub mod test_utils; mod util; pub use { config::ServerConfig, @@ -94,35 +96,58 @@ pub unsafe fn enable_and_start_all( global access */ +/// Something that represents the global state +pub trait GlobalInstanceLike { + fn namespace(&self) -> &GlobalNS; + fn post_high_priority_task(&self, task: Task); + fn post_standard_priority_task(&self, task: Task); + fn get_max_delta_size(&self) -> usize; +} + +impl GlobalInstanceLike for Global { + fn namespace(&self) -> &GlobalNS { + self._namespace() + } + fn post_high_priority_task(&self, task: Task) { + self._post_high_priority_task(task) + } + fn post_standard_priority_task(&self, task: Task) { + self._post_standard_priority_task(task) + } + fn get_max_delta_size(&self) -> usize { + self._get_max_delta_size() + } +} + #[derive(Debug, Clone, Copy)] /// A handle to the global state pub struct Global(()); impl Global { - fn new() -> Self { + unsafe fn new() -> Self { Self(()) } - pub(self) fn get_state(&self) -> &'static GlobalState { + fn get_state(&self) -> &'static GlobalState { unsafe { GLOBAL.assume_init_ref() } } /// Returns a handle to the [`GlobalNS`] - pub fn namespace(&self) -> &'static GlobalNS { + fn _namespace(&self) -> &'static GlobalNS { &unsafe { GLOBAL.assume_init_ref() }.gns } /// Post an urgent task - pub fn post_high_priority_task(&self, task: Task) { + fn _post_high_priority_task(&self, task: Task) { self.get_state().fractal_mgr().post_high_priority(task) } /// Post a task with normal priority /// /// NB: It is not guaranteed that the task will remain as a low priority task because the scheduler can choose /// to promote the task to a high priority task, if it deems necessary. - pub fn post_standard_priority_task(&self, task: Task) { + fn _post_standard_priority_task(&self, task: Task) { self.get_state().fractal_mgr().post_low_priority(task) } /// Returns the maximum size a model's delta size can hit before it should immediately issue a batch write request /// to avoid memory pressure - pub fn get_max_delta_size(&self) -> usize { + fn _get_max_delta_size(&self) -> usize { self.get_state() .fractal_mgr() .get_rt_stat() diff --git a/server/src/engine/fractal/test_utils.rs b/server/src/engine/fractal/test_utils.rs new file mode 100644 index 00000000..39e2e99d --- /dev/null +++ b/server/src/engine/fractal/test_utils.rs @@ -0,0 +1,68 @@ +/* + * Created on Wed Sep 13 2023 + * + * This file is a part of Skytable + * Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source + * NoSQL database written by Sayan Nandan ("the Author") with the + * vision to provide flexibility in data modelling without compromising + * on performance, queryability or scalability. + * + * Copyright (c) 2023, Sayan Nandan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * +*/ + +use { + super::{CriticalTask, GenericTask, GlobalInstanceLike, Task}, + crate::engine::core::GlobalNS, + parking_lot::RwLock, +}; + +/// A `test` mode global implementation +pub struct TestGlobal { + gns: GlobalNS, + hp_queue: RwLock>>, + lp_queue: RwLock>>, + max_delta_size: usize, +} + +impl TestGlobal { + pub fn empty() -> Self { + Self::with_max_delta_size(0) + } + pub fn with_max_delta_size(max_delta_size: usize) -> Self { + Self { + gns: GlobalNS::empty(), + hp_queue: RwLock::default(), + lp_queue: RwLock::default(), + max_delta_size, + } + } +} + +impl GlobalInstanceLike for TestGlobal { + fn namespace(&self) -> &GlobalNS { + &self.gns + } + fn post_high_priority_task(&self, task: Task) { + self.hp_queue.write().push(task) + } + fn post_standard_priority_task(&self, task: Task) { + self.lp_queue.write().push(task) + } + fn get_max_delta_size(&self) -> usize { + 100 + } +} diff --git a/server/src/engine/txn/gns/tests/full_chain.rs b/server/src/engine/txn/gns/tests/full_chain.rs index 4ea29bcf..71d12ead 100644 --- a/server/src/engine/txn/gns/tests/full_chain.rs +++ b/server/src/engine/txn/gns/tests/full_chain.rs @@ -28,10 +28,10 @@ use crate::engine::{ core::{ model::{Field, Layer, Model}, space::{Space, SpaceMeta}, - GlobalNS, }, data::{cell::Datacell, tag::TagSelector, uuid::Uuid, DictEntryGeneric}, error::DatabaseError, + fractal::{test_utils::TestGlobal, GlobalInstanceLike}, idx::STIndex, ql::{ ast::parse_ast_node_full, @@ -52,13 +52,19 @@ fn with_variable(var: T, f: impl FnOnce(T)) { f(var); } -fn init_txn_driver(gns: &GlobalNS, log_name: &str) -> GNSTransactionDriverVFS { - GNSTransactionDriverVFS::open_or_reinit_with_name(&gns, log_name, 0, HostRunMode::Prod, 0) - .unwrap() +fn init_txn_driver(global: &impl GlobalInstanceLike, log_name: &str) -> GNSTransactionDriverVFS { + GNSTransactionDriverVFS::open_or_reinit_with_name( + global.namespace(), + log_name, + 0, + HostRunMode::Prod, + 0, + ) + .unwrap() } fn init_space( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, driver: &mut GNSTransactionDriverVFS, space_name: &str, env: &str, @@ -67,26 +73,32 @@ fn init_space( let stmt = lex_insecure(query.as_bytes()).unwrap(); let stmt = parse_ast_node_full::(&stmt[2..]).unwrap(); let name = stmt.space_name; - Space::transactional_exec_create(&gns, driver, stmt).unwrap(); - gns.spaces().read().get(name.as_str()).unwrap().get_uuid() + Space::transactional_exec_create(global, driver, stmt).unwrap(); + global + .namespace() + .spaces() + .read() + .get(name.as_str()) + .unwrap() + .get_uuid() } #[test] fn create_space() { - with_variable("create_space_test.gns.db-tlog", |log_name| { + with_variable("create_space_test.global.db-tlog", |log_name| { let uuid; // start 1 { - let gns = GlobalNS::empty(); - let mut driver = init_txn_driver(&gns, log_name); - uuid = init_space(&gns, &mut driver, "myspace", "{ SAYAN_MAX: 65536 }"); // good lord that doesn't sound like a good variable + let global = TestGlobal::empty(); + let mut driver = init_txn_driver(&global, log_name); + uuid = init_space(&global, &mut driver, "myspace", "{ SAYAN_MAX: 65536 }"); // good lord that doesn't sound like a good variable driver.close().unwrap(); } multirun(|| { - let gns = GlobalNS::empty(); - let driver = init_txn_driver(&gns, log_name); + let global = TestGlobal::empty(); + let driver = init_txn_driver(&global, log_name); assert_eq!( - gns.spaces().read().get("myspace").unwrap(), + global.namespace().spaces().read().get("myspace").unwrap(), &Space::new_restore_empty( SpaceMeta::with_env( into_dict!("SAYAN_MAX" => DictEntryGeneric::Data(Datacell::new_uint(65536))) @@ -101,24 +113,24 @@ fn create_space() { #[test] fn alter_space() { - with_variable("alter_space_test.gns.db-tlog", |log_name| { + with_variable("alter_space_test.global.db-tlog", |log_name| { let uuid; { - let gns = GlobalNS::empty(); - let mut driver = init_txn_driver(&gns, log_name); - uuid = init_space(&gns, &mut driver, "myspace", "{}"); + let global = TestGlobal::empty(); + let mut driver = init_txn_driver(&global, log_name); + uuid = init_space(&global, &mut driver, "myspace", "{}"); let stmt = lex_insecure("alter space myspace with { env: { SAYAN_MAX: 65536 } }".as_bytes()) .unwrap(); let stmt = parse_ast_node_full(&stmt[2..]).unwrap(); - Space::transactional_exec_alter(&gns, &mut driver, stmt).unwrap(); + Space::transactional_exec_alter(&global, &mut driver, stmt).unwrap(); driver.close().unwrap(); } multirun(|| { - let gns = GlobalNS::empty(); - let driver = init_txn_driver(&gns, log_name); + let global = TestGlobal::empty(); + let driver = init_txn_driver(&global, log_name); assert_eq!( - gns.spaces().read().get("myspace").unwrap(), + global.namespace().spaces().read().get("myspace").unwrap(), &Space::new_restore_empty( SpaceMeta::with_env( into_dict!("SAYAN_MAX" => DictEntryGeneric::Data(Datacell::new_uint(65536))) @@ -133,27 +145,27 @@ fn alter_space() { #[test] fn drop_space() { - with_variable("drop_space_test.gns.db-tlog", |log_name| { + with_variable("drop_space_test.global.db-tlog", |log_name| { { - let gns = GlobalNS::empty(); - let mut driver = init_txn_driver(&gns, log_name); - let _ = init_space(&gns, &mut driver, "myspace", "{}"); + let global = TestGlobal::empty(); + let mut driver = init_txn_driver(&global, log_name); + let _ = init_space(&global, &mut driver, "myspace", "{}"); let stmt = lex_insecure("drop space myspace".as_bytes()).unwrap(); let stmt = parse_ast_node_full(&stmt[2..]).unwrap(); - Space::transactional_exec_drop(&gns, &mut driver, stmt).unwrap(); + Space::transactional_exec_drop(&global, &mut driver, stmt).unwrap(); driver.close().unwrap(); } multirun(|| { - let gns = GlobalNS::empty(); - let driver = init_txn_driver(&gns, log_name); - assert_eq!(gns.spaces().read().get("myspace"), None); + let global = TestGlobal::empty(); + let driver = init_txn_driver(&global, log_name); + assert_eq!(global.namespace().spaces().read().get("myspace"), None); driver.close().unwrap(); }) }) } fn init_model( - gns: &GlobalNS, + global: &impl GlobalInstanceLike, txn_driver: &mut GNSTransactionDriverVFS, space_name: &str, model_name: &str, @@ -163,14 +175,19 @@ fn init_model( let stmt = lex_insecure(query.as_bytes()).unwrap(); let stmt = parse_ast_node_full::(&stmt[2..]).unwrap(); let model_name = stmt.model_name; - Model::transactional_exec_create(&gns, txn_driver, stmt).unwrap(); - gns.with_model(model_name, |model| Ok(model.get_uuid())) + Model::transactional_exec_create(global, txn_driver, stmt).unwrap(); + global + .namespace() + .with_model(model_name, |model| Ok(model.get_uuid())) .unwrap() } -fn init_default_model(gns: &GlobalNS, driver: &mut GNSTransactionDriverVFS) -> Uuid { +fn init_default_model( + global: &impl GlobalInstanceLike, + driver: &mut GNSTransactionDriverVFS, +) -> Uuid { init_model( - gns, + global, driver, "myspace", "mymodel", @@ -180,35 +197,37 @@ fn init_default_model(gns: &GlobalNS, driver: &mut GNSTransactionDriverVFS) -> U #[test] fn create_model() { - with_variable("create_model_test.gns.db-tlog", |log_name| { + with_variable("create_model_test.global.db-tlog", |log_name| { let _uuid_space; let uuid_model; { - let gns = GlobalNS::empty(); - let mut driver = init_txn_driver(&gns, log_name); - _uuid_space = init_space(&gns, &mut driver, "myspace", "{}"); - uuid_model = init_default_model(&gns, &mut driver); + let global = TestGlobal::empty(); + let mut driver = init_txn_driver(&global, log_name); + _uuid_space = init_space(&global, &mut driver, "myspace", "{}"); + uuid_model = init_default_model(&global, &mut driver); driver.close().unwrap(); } multirun(|| { - let gns = GlobalNS::empty(); - let driver = init_txn_driver(&gns, log_name); - gns.with_model(("myspace", "mymodel"), |model| { - assert_eq!( - model, - &Model::new_restore( - uuid_model, - "username".into(), - TagSelector::Str.into_full(), - into_dict! { - "username" => Field::new([Layer::str()].into(), false), - "password" => Field::new([Layer::bin()].into(), false), - } - ) - ); - Ok(()) - }) - .unwrap(); + let global = TestGlobal::empty(); + let driver = init_txn_driver(&global, log_name); + global + .namespace() + .with_model(("myspace", "mymodel"), |model| { + assert_eq!( + model, + &Model::new_restore( + uuid_model, + "username".into(), + TagSelector::Str.into_full(), + into_dict! { + "username" => Field::new([Layer::str()].into(), false), + "password" => Field::new([Layer::bin()].into(), false), + } + ) + ); + Ok(()) + }) + .unwrap(); driver.close().unwrap(); }) }) @@ -216,35 +235,37 @@ fn create_model() { #[test] fn alter_model_add() { - with_variable("alter_model_add_test.gns.db-tlog", |log_name| { + with_variable("alter_model_add_test.global.db-tlog", |log_name| { { - let gns = GlobalNS::empty(); - let mut driver = init_txn_driver(&gns, log_name); - init_space(&gns, &mut driver, "myspace", "{}"); - init_default_model(&gns, &mut driver); + let global = TestGlobal::empty(); + let mut driver = init_txn_driver(&global, log_name); + init_space(&global, &mut driver, "myspace", "{}"); + init_default_model(&global, &mut driver); let stmt = lex_insecure( b"alter model myspace.mymodel add profile_pic { type: binary, nullable: true }", ) .unwrap(); let stmt = parse_ast_node_full(&stmt[2..]).unwrap(); - Model::transactional_exec_alter(&gns, &mut driver, stmt).unwrap(); + Model::transactional_exec_alter(&global, &mut driver, stmt).unwrap(); driver.close().unwrap(); } multirun(|| { - let gns = GlobalNS::empty(); - let driver = init_txn_driver(&gns, log_name); - gns.with_model(("myspace", "mymodel"), |model| { - assert_eq!( - model - .intent_read_model() - .fields() - .st_get("profile_pic") - .unwrap(), - &Field::new([Layer::bin()].into(), true) - ); - Ok(()) - }) - .unwrap(); + let global = TestGlobal::empty(); + let driver = init_txn_driver(&global, log_name); + global + .namespace() + .with_model(("myspace", "mymodel"), |model| { + assert_eq!( + model + .intent_read_model() + .fields() + .st_get("profile_pic") + .unwrap(), + &Field::new([Layer::bin()].into(), true) + ); + Ok(()) + }) + .unwrap(); driver.close().unwrap(); }) }) @@ -252,13 +273,13 @@ fn alter_model_add() { #[test] fn alter_model_remove() { - with_variable("alter_model_remove_test.gns.db-tlog", |log_name| { + with_variable("alter_model_remove_test.global.db-tlog", |log_name| { { - let gns = GlobalNS::empty(); - let mut driver = init_txn_driver(&gns, log_name); - init_space(&gns, &mut driver, "myspace", "{}"); + let global = TestGlobal::empty(); + let mut driver = init_txn_driver(&global, log_name); + init_space(&global, &mut driver, "myspace", "{}"); init_model( - &gns, + &global, &mut driver, "myspace", "mymodel", @@ -269,19 +290,21 @@ fn alter_model_remove() { ) .unwrap(); let stmt = parse_ast_node_full(&stmt[2..]).unwrap(); - Model::transactional_exec_alter(&gns, &mut driver, stmt).unwrap(); + Model::transactional_exec_alter(&global, &mut driver, stmt).unwrap(); driver.close().unwrap() } multirun(|| { - let gns = GlobalNS::empty(); - let driver = init_txn_driver(&gns, log_name); - gns.with_model(("myspace", "mymodel"), |model| { - let irm = model.intent_read_model(); - assert!(irm.fields().st_get("has_secure_key").is_none()); - assert!(irm.fields().st_get("is_dumb").is_none()); - Ok(()) - }) - .unwrap(); + let global = TestGlobal::empty(); + let driver = init_txn_driver(&global, log_name); + global + .namespace() + .with_model(("myspace", "mymodel"), |model| { + let irm = model.intent_read_model(); + assert!(irm.fields().st_get("has_secure_key").is_none()); + assert!(irm.fields().st_get("is_dumb").is_none()); + Ok(()) + }) + .unwrap(); driver.close().unwrap() }) }) @@ -289,13 +312,13 @@ fn alter_model_remove() { #[test] fn alter_model_update() { - with_variable("alter_model_update_test.gns.db-tlog", |log_name| { + with_variable("alter_model_update_test.global.db-tlog", |log_name| { { - let gns = GlobalNS::empty(); - let mut driver = init_txn_driver(&gns, log_name); - init_space(&gns, &mut driver, "myspace", "{}"); + let global = TestGlobal::empty(); + let mut driver = init_txn_driver(&global, log_name); + init_space(&global, &mut driver, "myspace", "{}"); init_model( - &gns, + &global, &mut driver, "myspace", "mymodel", @@ -305,24 +328,26 @@ fn alter_model_update() { lex_insecure(b"alter model myspace.mymodel update profile_pic { nullable: true }") .unwrap(); let stmt = parse_ast_node_full(&stmt[2..]).unwrap(); - Model::transactional_exec_alter(&gns, &mut driver, stmt).unwrap(); + Model::transactional_exec_alter(&global, &mut driver, stmt).unwrap(); driver.close().unwrap(); } multirun(|| { - let gns = GlobalNS::empty(); - let driver = init_txn_driver(&gns, log_name); - gns.with_model(("myspace", "mymodel"), |model| { - assert_eq!( - model - .intent_read_model() - .fields() - .st_get("profile_pic") - .unwrap(), - &Field::new([Layer::bin()].into(), true) - ); - Ok(()) - }) - .unwrap(); + let global = TestGlobal::empty(); + let driver = init_txn_driver(&global, log_name); + global + .namespace() + .with_model(("myspace", "mymodel"), |model| { + assert_eq!( + model + .intent_read_model() + .fields() + .st_get("profile_pic") + .unwrap(), + &Field::new([Layer::bin()].into(), true) + ); + Ok(()) + }) + .unwrap(); driver.close().unwrap(); }) }) @@ -330,22 +355,24 @@ fn alter_model_update() { #[test] fn drop_model() { - with_variable("drop_model_test.gns.db-tlog", |log_name| { + with_variable("drop_model_test.global.db-tlog", |log_name| { { - let gns = GlobalNS::empty(); - let mut driver = init_txn_driver(&gns, log_name); - init_space(&gns, &mut driver, "myspace", "{}"); - init_default_model(&gns, &mut driver); + let global = TestGlobal::empty(); + let mut driver = init_txn_driver(&global, log_name); + init_space(&global, &mut driver, "myspace", "{}"); + init_default_model(&global, &mut driver); let stmt = lex_insecure(b"drop model myspace.mymodel").unwrap(); let stmt = parse_ast_node_full(&stmt[2..]).unwrap(); - Model::transactional_exec_drop(&gns, &mut driver, stmt).unwrap(); + Model::transactional_exec_drop(&global, &mut driver, stmt).unwrap(); driver.close().unwrap(); } multirun(|| { - let gns = GlobalNS::empty(); - let driver = init_txn_driver(&gns, log_name); + let global = TestGlobal::empty(); + let driver = init_txn_driver(&global, log_name); assert_eq!( - gns.with_model(("myspace", "mymodel"), |_| { Ok(()) }) + global + .namespace() + .with_model(("myspace", "mymodel"), |_| { Ok(()) }) .unwrap_err(), DatabaseError::DdlModelNotFound );