From 9b32fa04ecff8278ef82ead437f277ba5e73a0d1 Mon Sep 17 00:00:00 2001 From: Igor Kuznetsov <kuznetsovin@gmail.com> Date: Mon, 18 Apr 2022 11:23:15 +0300 Subject: [PATCH] refactoring: migrate to ref engine and validate empty schema was moved to load function --- src/executor.rs | 12 +++++---- src/executor/bucket.rs | 8 +++--- src/executor/bucket/tests.rs | 20 +++++++------- src/executor/engine.rs | 3 --- src/executor/engine/cartridge.rs | 45 +++---------------------------- src/executor/engine/mock.rs | 4 --- src/executor/tests.rs | 46 +++++++++++++++++--------------- src/parser.rs | 34 +++++++++-------------- 8 files changed, 63 insertions(+), 109 deletions(-) diff --git a/src/executor.rs b/src/executor.rs index f9aecc7f70..b2644c0b72 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -23,6 +23,8 @@ //! 5. Repeats step 3 till we are done with motion layers. //! 6. Executes the final IR top subtree and returns the final result to the user. +use std::collections::HashMap; + use crate::errors::QueryPlannerError; use crate::executor::bucket::Buckets; use crate::executor::engine::Engine; @@ -31,7 +33,6 @@ use crate::executor::ir::ExecutionPlan; use crate::executor::result::BoxExecuteFormat; use crate::frontend::sql::ast::AbstractSyntaxTree; use crate::ir::Plan; -use std::collections::HashMap; pub mod bucket; pub mod engine; @@ -54,19 +55,19 @@ impl Plan { } /// Query to execute. -pub struct Query<T> +pub struct Query<'a, T> where T: Engine, { /// Execution plan exec_plan: ExecutionPlan, /// Execution engine - engine: T, + engine: &'a mut T, /// Bucket map bucket_map: HashMap<usize, Buckets>, } -impl<T> Query<T> +impl<'a, T> Query<'a, T> where T: Engine, { @@ -77,7 +78,7 @@ where /// - Failed to build AST. /// - Failed to build IR plan. /// - Failed to apply optimizing transformations to IR plan. - pub fn new(engine: T, sql: &str) -> Result<Self, QueryPlannerError> + pub fn new(engine: &'a mut T, sql: &str) -> Result<Self, QueryPlannerError> where T::Metadata: Metadata, { @@ -93,6 +94,7 @@ where } /// Get the execution plan of the query. + #[must_use] pub fn get_exec_plan(&self) -> &ExecutionPlan { &self.exec_plan } diff --git a/src/executor/bucket.rs b/src/executor/bucket.rs index 30d5001940..b522d58608 100644 --- a/src/executor/bucket.rs +++ b/src/executor/bucket.rs @@ -1,3 +1,7 @@ +use std::collections::HashSet; + +use traversal::DftPost; + use crate::errors::QueryPlannerError; use crate::executor::engine::Engine; use crate::executor::Query; @@ -5,8 +9,6 @@ use crate::ir::distribution::Distribution; use crate::ir::expression::Expression; use crate::ir::operator::{Bool, Relational}; use crate::ir::transformation::redistribution::MotionPolicy; -use std::collections::HashSet; -use traversal::DftPost; /// Buckets are used to determine which nodes to send the query to. #[derive(Clone, Debug, PartialEq)] @@ -58,7 +60,7 @@ impl Buckets { } } -impl<T> Query<T> +impl<'a, T> Query<'a, T> where T: Engine, { diff --git a/src/executor/bucket/tests.rs b/src/executor/bucket/tests.rs index 3d3d129f99..8166cd2e20 100644 --- a/src/executor/bucket/tests.rs +++ b/src/executor/bucket/tests.rs @@ -14,8 +14,8 @@ fn simple_union_query() { ) as "t3" WHERE "id" = 1"#; - let engine = EngineMock::new(); - let mut query = Query::new(engine, query).unwrap(); + let mut engine = EngineMock::new(); + let mut query = Query::new(&mut engine, query).unwrap(); let plan = query.exec_plan.get_ir_plan(); let top = plan.get_top().unwrap(); let buckets = query.bucket_discovery(top).unwrap(); @@ -35,8 +35,8 @@ fn simple_disjunction_in_union_query() { ) as "t3" WHERE ("id" = 1) OR ("id" = 100)"#; - let engine = EngineMock::new(); - let mut query = Query::new(engine, query).unwrap(); + let mut engine = EngineMock::new(); + let mut query = Query::new(&mut engine, query).unwrap(); let plan = query.exec_plan.get_ir_plan(); let top = plan.get_top().unwrap(); let buckets = query.bucket_discovery(top).unwrap(); @@ -61,8 +61,8 @@ fn complex_shard_key_union_query() { WHERE "sys_op" > 1) AS "t3" WHERE "identification_number" = 1 AND "product_code" = '222'"#; - let engine = EngineMock::new(); - let mut query = Query::new(engine, query).unwrap(); + let mut engine = EngineMock::new(); + let mut query = Query::new(&mut engine, query).unwrap(); let plan = query.exec_plan.get_ir_plan(); let top = plan.get_top().unwrap(); let buckets = query.bucket_discovery(top).unwrap(); @@ -90,8 +90,8 @@ fn union_complex_cond_query() { AND ("product_code" = '222' OR "product_code" = '111')"#; - let engine = EngineMock::new(); - let mut query = Query::new(engine, query).unwrap(); + let mut engine = EngineMock::new(); + let mut query = Query::new(&mut engine, query).unwrap(); let plan = query.exec_plan.get_ir_plan(); let top = plan.get_top().unwrap(); let buckets = query.bucket_discovery(top).unwrap(); @@ -123,8 +123,8 @@ fn union_query_conjunction() { UNION ALL SELECT * FROM "test_space_hist" WHERE "id" = 2"#; - let engine = EngineMock::new(); - let mut query = Query::new(engine, query).unwrap(); + let mut engine = EngineMock::new(); + let mut query = Query::new(&mut engine, query).unwrap(); let plan = query.exec_plan.get_ir_plan(); let top = plan.get_top().unwrap(); let buckets = query.bucket_discovery(top).unwrap(); diff --git a/src/executor/engine.rs b/src/executor/engine.rs index dc26e9b046..d145627f15 100644 --- a/src/executor/engine.rs +++ b/src/executor/engine.rs @@ -54,9 +54,6 @@ pub trait Engine { where Self: Sized; - /// Checking that metadata isn't empty - fn has_metadata(&self) -> bool; - /// Clear metadata information fn clear_metadata(&mut self); diff --git a/src/executor/engine/cartridge.rs b/src/executor/engine/cartridge.rs index d183d78332..6d7d2eb87f 100644 --- a/src/executor/engine/cartridge.rs +++ b/src/executor/engine/cartridge.rs @@ -36,54 +36,17 @@ impl Engine for Runtime { &self.metadata } - fn has_metadata(&self) -> bool { - self.metadata.is_empty() - } - fn clear_metadata(&mut self) { self.metadata = ClusterAppConfig::new(); } fn load_metadata(&mut self) -> Result<(), QueryPlannerError> { - let lua = tarantool::lua_state(); - - match lua.exec( - r#" - local cartridge = require('cartridge') - - function get_schema() - return cartridge.get_schema() - end - - function get_waiting_timeout() - local cfg = cartridge.config_get_readonly() - - if cfg["executor_waiting_timeout"] == nil then - return 0 - end - - return cfg["executor_waiting_timeout"] - end - - - "#, - ) { - Ok(_) => {} - Err(e) => { - say( - SayLevel::Error, - file!(), - line!().try_into().unwrap_or(0), - Option::from("load metadata"), - &format!("{:?}", e), - ); - return Err(QueryPlannerError::LuaError(format!( - "Failed to load Lua code: {:?}", - e - ))); - } + if !&self.metadata.is_empty() { + return Ok(()); } + let lua = tarantool::lua_state(); + let get_schema: LuaFunction<_> = lua.eval("return get_schema;").unwrap(); let res: String = match get_schema.call() { diff --git a/src/executor/engine/mock.rs b/src/executor/engine/mock.rs index 322fc695f8..f9ccadb905 100644 --- a/src/executor/engine/mock.rs +++ b/src/executor/engine/mock.rs @@ -157,10 +157,6 @@ impl Engine for EngineMock { &self.metadata } - fn has_metadata(&self) -> bool { - self.metadata.tables.is_empty() - } - fn clear_metadata(&mut self) { self.metadata.tables.clear(); } diff --git a/src/executor/tests.rs b/src/executor/tests.rs index ad99604aa2..89cac9cedf 100644 --- a/src/executor/tests.rs +++ b/src/executor/tests.rs @@ -1,17 +1,19 @@ -use super::*; +use pretty_assertions::assert_eq; + use crate::executor::engine::mock::EngineMock; use crate::executor::result::Value; use crate::executor::vtable::VirtualTable; use crate::ir::relation::{Column, Type}; use crate::ir::value::Value as IrValue; -use pretty_assertions::assert_eq; + +use super::*; #[test] fn shard_query() { let sql = r#"SELECT "FIRST_NAME" FROM "test_space" where "id" = 1"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let mut expected = BoxExecuteFormat::new(); let bucket = query.engine.determine_bucket_id("1"); @@ -37,9 +39,9 @@ fn shard_union_query() { WHERE "sys_op" > 1) AS "t3" WHERE "id" = 1"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let mut expected = BoxExecuteFormat::new(); let bucket = query.engine.determine_bucket_id("1"); @@ -67,9 +69,9 @@ fn shard_union_query() { #[test] fn map_reduce_query() { let sql = r#"SELECT "product_code" FROM "hash_testing" where "identification_number" = 1 and "product_code" = '457'"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let mut expected = BoxExecuteFormat::new(); let bucket = query.engine.determine_bucket_id(&["1", "457"].join("")); @@ -92,9 +94,9 @@ fn map_reduce_query() { fn linker_test() { let sql = r#"SELECT "FIRST_NAME" FROM "test_space" where "id" in (SELECT "identification_number" FROM "hash_testing" where "identification_number" > 1)"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let motion_id = query.exec_plan.get_ir_plan().get_slices().unwrap()[0][0]; let virtual_table = virtual_table_23(); query.engine.add_virtual_table(motion_id, virtual_table); @@ -142,9 +144,9 @@ fn union_linker_test() { ) as "t2" WHERE "product_code" = '123')"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let motion_id = query.exec_plan.get_ir_plan().get_slices().unwrap()[0][0]; let virtual_table = virtual_table_23(); query.engine.add_virtual_table(motion_id, virtual_table); @@ -221,9 +223,9 @@ INNER JOIN ON "t3"."id" = "t8"."identification_number" WHERE "t3"."id" = 2 AND "t8"."identification_number" = 2"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let motion_id = query.exec_plan.get_ir_plan().get_slices().unwrap()[0][0]; let mut virtual_table = virtual_table_23(); virtual_table.set_alias("\"t8\"").unwrap(); @@ -271,9 +273,9 @@ fn join_linker2_test() { select "id" as "id1", "id" as "id2" from "test_space_hist" ) as "t2" on "t1"."id" = 1"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let motion_id = query.exec_plan.get_ir_plan().get_slices().unwrap()[0][0]; let mut virtual_table = VirtualTable::new(); @@ -323,9 +325,9 @@ fn join_linker3_test() { (SELECT "id" as "id1", "FIRST_NAME" FROM "test_space") AS "t2" ON "t2"."id1" = 1"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let motion_id = query.exec_plan.get_ir_plan().get_slices().unwrap()[0][0]; let mut virtual_table = VirtualTable::new(); @@ -375,9 +377,9 @@ fn join_linker4_test() { on t1."id" = t2."r_id" and t1."FIRST_NAME" = (SELECT "FIRST_NAME" as "fn" FROM "test_space" WHERE "id" = 1)"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let motion_t2_id = query.exec_plan.get_ir_plan().get_slices().unwrap()[0][0]; let mut virtual_t2 = VirtualTable::new(); @@ -440,9 +442,9 @@ fn anonymous_col_index_test() { WHERE "id" in (SELECT "identification_number" FROM "hash_testing" WHERE "product_units" < 3) OR "id" in (SELECT "identification_number" FROM "hash_testing" WHERE "product_units" > 5)"#; - let engine = EngineMock::new(); + let mut engine = EngineMock::new(); - let mut query = Query::new(engine, sql).unwrap(); + let mut query = Query::new(&mut engine, sql).unwrap(); let motion1_id = query.exec_plan.get_ir_plan().get_slices().unwrap()[0][0]; query .engine diff --git a/src/parser.rs b/src/parser.rs index 103da88577..5a3b6d003e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -57,7 +57,9 @@ pub extern "C" fn calculate_bucket_id(ctx: FunctionCtx, args: FunctionArgs) -> c let args = args.into_struct::<BucketCalcArgs>().unwrap(); QUERY_ENGINE.with(|e| { - let result = e.clone().into_inner().determine_bucket_id(&args.rec); + let engine = &mut *e.borrow_mut(); + + let result = engine.determine_bucket_id(&args.rec); ctx.return_mp(&result).unwrap(); 0 }) @@ -66,16 +68,11 @@ pub extern "C" fn calculate_bucket_id(ctx: FunctionCtx, args: FunctionArgs) -> c #[no_mangle] pub extern "C" fn calculate_bucket_id_by_dict(ctx: FunctionCtx, args: FunctionArgs) -> c_int { QUERY_ENGINE.with(|e| { - let mut engine = e.clone().into_inner(); + let engine = &mut *e.borrow_mut(); // Update cartridge schema after cache invalidation by calling `apply_config()` in lua code. - if engine.has_metadata() { - match engine.load_metadata() { - Ok(_) => *e.borrow_mut() = engine.clone(), - Err(e) => { - return tarantool::set_error!(TarantoolErrorCode::ProcC, "{}", e.to_string()); - } - }; - } + if let Err(e) = engine.load_metadata() { + return tarantool::set_error!(TarantoolErrorCode::ProcC, "{}", e.to_string()); + }; // Closure for more concise error propagation from calls nested in the bucket calculation let propagate_err = || -> Result<u64, QueryPlannerError> { @@ -90,7 +87,7 @@ pub extern "C" fn calculate_bucket_id_by_dict(ctx: FunctionCtx, args: FunctionAr acc.push_str(s.as_str()); acc }); - Ok(e.clone().into_inner().determine_bucket_id(fk.as_str())) + Ok(engine.determine_bucket_id(fk.as_str())) }; match propagate_err() { @@ -115,17 +112,12 @@ pub extern "C" fn execute_query(ctx: FunctionCtx, args: FunctionArgs) -> c_int { let args: Tuple = args.into(); let args = args.into_struct::<Args>().unwrap(); - QUERY_ENGINE.with(|s| { - let mut engine = s.clone().into_inner(); + QUERY_ENGINE.with(|e| { + let engine = &mut *e.borrow_mut(); // Update cartridge schema after cache invalidation by calling `apply_config()` in lua code. - if engine.has_metadata() { - match engine.load_metadata() { - Ok(_) => *s.borrow_mut() = engine.clone(), - Err(e) => { - return tarantool::set_error!(TarantoolErrorCode::ProcC, "{}", e.to_string()); - } - }; - } + if let Err(e) = engine.load_metadata() { + return tarantool::set_error!(TarantoolErrorCode::ProcC, "{}", e.to_string()); + }; let mut query = match Query::new(engine, args.query.as_str()) { Ok(q) => q, -- GitLab