teaclave-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ms...@apache.org
Subject [incubator-teaclave] 01/02: [executor] Introduce teaclave executor and separate builtin functions
Date Thu, 30 Apr 2020 23:47:13 GMT
This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git

commit 7eacf31203febef1e9492a7fc29916b3b7ade3fd
Author: Mingshen Sun <bob@mssun.me>
AuthorDate: Thu Apr 30 11:40:17 2020 -0700

    [executor] Introduce teaclave executor and separate builtin functions
---
 {function => executor}/Cargo.toml                  |   8 +-
 executor/src/builtin.rs                            |  57 +++++++
 {function => executor}/src/context.rs              |   1 +
 {function => executor}/src/lib.rs                  |  22 +--
 {function => executor}/src/mesapy.rs               |  41 +++--
 function/Cargo.toml                                |   2 +-
 function/src/echo.rs                               |  18 +-
 .../src/{gbdt_prediction.rs => gbdt_predict.rs}    |  21 ++-
 function/src/{gbdt_training.rs => gbdt_train.rs}   |  31 ++--
 function/src/lib.rs                                |  32 ++--
 ...rediction.rs => logistic_regression_predict.rs} |  27 +--
 ...on_training.rs => logistic_regression_train.rs} |  33 ++--
 services/execution/enclave/src/lib.rs              |   2 +-
 services/execution/enclave/src/service.rs          |  13 +-
 services/proto/src/teaclave_frontend_service.rs    |   6 +-
 .../end_to_end/{native_echo.rs => builtin_echo.rs} |   6 +-
 ...tive_gbdt_training.rs => builtin_gbdt_train.rs} |   6 +-
 tests/functional/enclave/src/end_to_end/mod.rs     |   4 +-
 tests/functional/enclave/src/execution_service.rs  |   3 +-
 tests/functional/enclave/src/scheduler_service.rs  |   6 +-
 tests/integration/enclave/src/teaclave_worker.rs   |  10 +-
 tests/unit/enclave/Cargo.toml                      |   3 +
 tests/unit/enclave/src/lib.rs                      |   1 +
 types/src/staged_function.rs                       |  14 +-
 types/src/staged_task.rs                           |  14 +-
 types/src/task.rs                                  |   1 +
 types/src/worker.rs                                |  41 ++---
 worker/Cargo.toml                                  |   4 +-
 worker/src/worker.rs                               | 188 +++++++--------------
 29 files changed, 317 insertions(+), 298 deletions(-)

diff --git a/function/Cargo.toml b/executor/Cargo.toml
similarity index 87%
copy from function/Cargo.toml
copy to executor/Cargo.toml
index 55d5749..b6428f4 100644
--- a/function/Cargo.toml
+++ b/executor/Cargo.toml
@@ -1,13 +1,13 @@
 [package]
-name = "teaclave_function"
+name = "teaclave_executor"
 version = "0.1.0"
 authors = ["Teaclave Contributors <dev@teaclave.apache.org>"]
-description = "Teaclave function"
+description = "Teaclave executor"
 license = "Apache-2.0"
 edition = "2018"
 
 [lib]
-name = "teaclave_function"
+name = "teaclave_executor"
 crate-type = ["staticlib", "rlib"]
 
 [features]
@@ -15,6 +15,7 @@ default = []
 mesalock_sgx = [
   "sgx_tstd",
   "teaclave_types/mesalock_sgx",
+  "teaclave_function/mesalock_sgx",
 ]
 cov = ["sgx_cov"]
 enclave_unit_test = [
@@ -35,6 +36,7 @@ teaclave_types = { path = "../types" }
 teaclave_crypto = { path = "../crypto" }
 teaclave_runtime = { path = "../runtime", optional = true }
 teaclave_test_utils = { path = "../tests/utils", optional = true }
+teaclave_function = { path = "../function" }
 
 sgx_cov       = { version = "1.1.2", optional = true }
 sgx_tstd      = { version = "1.1.2", features = ["net", "thread", "backtrace"], optional = true }
diff --git a/executor/src/builtin.rs b/executor/src/builtin.rs
new file mode 100644
index 0000000..b5c37f6
--- /dev/null
+++ b/executor/src/builtin.rs
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#[cfg(feature = "mesalock_sgx")]
+use std::prelude::v1::*;
+
+use teaclave_function::{
+    Echo, GbdtPredict, GbdtTrain, LogisticRegressionPredict, LogisticRegressionTrain,
+};
+use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveExecutor};
+
+use anyhow::{bail, Result};
+
+#[derive(Default)]
+pub struct BuiltinFunctionExecutor;
+
+impl TeaclaveExecutor for BuiltinFunctionExecutor {
+    fn execute(
+        &self,
+        name: String,
+        arguments: FunctionArguments,
+        _payload: String,
+        runtime: FunctionRuntime,
+    ) -> Result<String> {
+        match name.as_str() {
+            Echo::NAME => Echo::new().run(arguments, runtime),
+            GbdtPredict::NAME => GbdtPredict::new().run(arguments, runtime),
+            GbdtTrain::NAME => GbdtTrain::new().run(arguments, runtime),
+            LogisticRegressionTrain::NAME => LogisticRegressionTrain::new().run(arguments, runtime),
+            LogisticRegressionPredict::NAME => {
+                LogisticRegressionPredict::new().run(arguments, runtime)
+            }
+            _ => bail!("Function not found."),
+        }
+    }
+}
+
+#[cfg(feature = "enclave_unit_test")]
+pub mod tests {
+    pub fn run_tests() -> bool {
+        true
+    }
+}
diff --git a/function/src/context.rs b/executor/src/context.rs
similarity index 99%
rename from function/src/context.rs
rename to executor/src/context.rs
index 2f90c5a..50cc3fc 100644
--- a/function/src/context.rs
+++ b/executor/src/context.rs
@@ -290,6 +290,7 @@ pub mod tests {
 
         assert!(rtc_close_handle(f).is_ok());
         assert!(rtc_close_handle(f).is_err());
+        reset_thread_context().unwrap();
     }
 }
 
diff --git a/function/src/lib.rs b/executor/src/lib.rs
similarity index 67%
copy from function/src/lib.rs
copy to executor/src/lib.rs
index a329e6e..e9e6cb0 100644
--- a/function/src/lib.rs
+++ b/executor/src/lib.rs
@@ -25,20 +25,12 @@ use std::prelude::v1::*;
 #[macro_use]
 extern crate log;
 
+mod builtin;
 mod context;
-mod echo;
-mod gbdt_prediction;
-mod gbdt_training;
-mod logistic_regression_prediction;
-mod logistic_regression_training;
 mod mesapy;
 
-pub use echo::Echo;
-pub use gbdt_prediction::GbdtPrediction;
-pub use gbdt_training::GbdtTraining;
-pub use logistic_regression_prediction::LogitRegPrediction;
-pub use logistic_regression_training::LogitRegTraining;
-pub use mesapy::Mesapy;
+pub use builtin::BuiltinFunctionExecutor;
+pub use mesapy::MesaPy;
 
 #[cfg(feature = "enclave_unit_test")]
 pub mod tests {
@@ -47,13 +39,9 @@ pub mod tests {
 
     pub fn run_tests() -> bool {
         check_all_passed!(
-            echo::tests::run_tests(),
-            gbdt_training::tests::run_tests(),
-            gbdt_prediction::tests::run_tests(),
-            mesapy::tests::run_tests(),
             context::tests::run_tests(),
-            logistic_regression_training::tests::run_tests(),
-            logistic_regression_prediction::tests::run_tests(),
+            mesapy::tests::run_tests(),
+            builtin::tests::run_tests(),
         )
     }
 }
diff --git a/function/src/mesapy.rs b/executor/src/mesapy.rs
similarity index 84%
rename from function/src/mesapy.rs
rename to executor/src/mesapy.rs
index d78a106..825ae53 100644
--- a/function/src/mesapy.rs
+++ b/executor/src/mesapy.rs
@@ -15,16 +15,15 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#[cfg(feature = "mesalock_sgx")]
 use std::prelude::v1::*;
 
-use std::ffi::CString;
-
 use crate::context::reset_thread_context;
 use crate::context::set_thread_context;
 use crate::context::Context;
 
-use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveFunction};
+use std::ffi::CString;
+
+use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveExecutor};
 
 const MAXPYBUFLEN: usize = 20480;
 const MESAPY_ERROR_BUFFER_TOO_SHORT: i64 = -1i64;
@@ -41,20 +40,23 @@ extern "C" {
 }
 
 #[derive(Default)]
-pub struct Mesapy;
-
-impl TeaclaveFunction for Mesapy {
-    fn execute(&self, runtime: FunctionRuntime, args: FunctionArguments) -> anyhow::Result<String> {
-        let script = args.get("py_payload")?.as_str();
-        let py_args = args.get("py_args")?.as_str();
-        let py_args: FunctionArguments = serde_json::from_str(py_args)?;
-        let py_argv = py_args.into_vec();
+pub struct MesaPy;
+
+impl TeaclaveExecutor for MesaPy {
+    fn execute(
+        &self,
+        _name: String,
+        arguments: FunctionArguments,
+        payload: String,
+        runtime: FunctionRuntime,
+    ) -> anyhow::Result<String> {
+        let py_argv = arguments.into_vec();
         let cstr_argv: Vec<_> = py_argv
             .iter()
             .map(|arg| CString::new(arg.as_str()).unwrap())
             .collect();
 
-        let mut script_bytes = script.to_owned().into_bytes();
+        let mut script_bytes = payload.into_bytes();
         script_bytes.push(0u8);
 
         let mut p_argv: Vec<_> = cstr_argv
@@ -104,7 +106,7 @@ pub mod tests {
     }
 
     fn test_mesapy() {
-        let py_args = FunctionArguments::new(hashmap!("--name" => "Teaclave"));
+        let py_args = FunctionArguments::default();
         let py_payload = r#"
 def entrypoint(argv):
     in_file_id = "in_f1"
@@ -165,13 +167,10 @@ def entrypoint(argv):
 
         let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
 
-        let func_args = FunctionArguments::new(hashmap!(
-                "py_payload" => py_payload,
-                "py_args" => serde_json::to_string(&py_args).unwrap()
-        ));
-
-        let function = Mesapy;
-        let summary = function.execute(runtime, func_args).unwrap();
+        let function = MesaPy::default();
+        let summary = function
+            .execute("".to_string(), py_args, py_payload.to_string(), runtime)
+            .unwrap();
         assert_eq!(summary, "");
     }
 }
diff --git a/function/Cargo.toml b/function/Cargo.toml
index 55d5749..9fcf244 100644
--- a/function/Cargo.toml
+++ b/function/Cargo.toml
@@ -2,7 +2,7 @@
 name = "teaclave_function"
 version = "0.1.0"
 authors = ["Teaclave Contributors <dev@teaclave.apache.org>"]
-description = "Teaclave function"
+description = "Teaclave built-in functions."
 license = "Apache-2.0"
 edition = "2018"
 
diff --git a/function/src/echo.rs b/function/src/echo.rs
index 3cc15a5..a6de293 100644
--- a/function/src/echo.rs
+++ b/function/src/echo.rs
@@ -19,7 +19,7 @@
 use std::prelude::v1::*;
 
 use std::convert::TryFrom;
-use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveFunction};
+use teaclave_types::{FunctionArguments, FunctionRuntime};
 
 #[derive(Default)]
 pub struct Echo;
@@ -37,11 +37,17 @@ impl TryFrom<FunctionArguments> for EchoArguments {
     }
 }
 
-impl TeaclaveFunction for Echo {
-    fn execute(
+impl Echo {
+    pub const NAME: &'static str = "builtin-echo";
+
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn run(
         &self,
-        _runtime: FunctionRuntime,
         arguments: FunctionArguments,
+        _runtime: FunctionRuntime,
     ) -> anyhow::Result<String> {
         let message = EchoArguments::try_from(arguments)?.message;
         Ok(message)
@@ -60,7 +66,7 @@ pub mod tests {
     }
 
     fn test_echo() {
-        let func_args = FunctionArguments::new(hashmap!(
+        let args = FunctionArguments::new(hashmap!(
             "message"  => "Hello Teaclave!"
         ));
 
@@ -70,7 +76,7 @@ pub mod tests {
         let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
         let function = Echo;
 
-        let summary = function.execute(runtime, func_args).unwrap();
+        let summary = function.run(args, runtime).unwrap();
         assert_eq!(summary, "Hello Teaclave!");
     }
 }
diff --git a/function/src/gbdt_prediction.rs b/function/src/gbdt_predict.rs
similarity index 92%
rename from function/src/gbdt_prediction.rs
rename to function/src/gbdt_predict.rs
index 93016fe..d60651a 100644
--- a/function/src/gbdt_prediction.rs
+++ b/function/src/gbdt_predict.rs
@@ -21,7 +21,7 @@ use std::prelude::v1::*;
 use std::format;
 use std::io::{self, BufRead, BufReader, Write};
 
-use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveFunction};
+use teaclave_types::{FunctionArguments, FunctionRuntime};
 
 use gbdt::decision_tree::Data;
 use gbdt::gradient_boost::GBDT;
@@ -31,13 +31,19 @@ const IN_DATA: &str = "data_file";
 const OUT_RESULT: &str = "result_file";
 
 #[derive(Default)]
-pub struct GbdtPrediction;
+pub struct GbdtPredict;
 
-impl TeaclaveFunction for GbdtPrediction {
-    fn execute(
+impl GbdtPredict {
+    pub const NAME: &'static str = "builtin-gbdt-predict";
+
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn run(
         &self,
-        runtime: FunctionRuntime,
         _arguments: FunctionArguments,
+        runtime: FunctionRuntime,
     ) -> anyhow::Result<String> {
         let mut json_model = String::new();
         let mut f = runtime.open_input(IN_MODEL)?;
@@ -102,7 +108,7 @@ pub mod tests {
     }
 
     fn test_gbdt_prediction() {
-        let func_args = FunctionArguments::default();
+        let arguments = FunctionArguments::default();
 
         let plain_model = "fixtures/functions/gbdt_prediction/model.txt";
         let plain_data = "fixtures/functions/gbdt_prediction/test_data.txt";
@@ -123,8 +129,7 @@ pub mod tests {
 
         let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
 
-        let function = GbdtPrediction;
-        let summary = function.execute(runtime, func_args).unwrap();
+        let summary = GbdtPredict::new().run(arguments, runtime).unwrap();
         assert_eq!(summary, "Predict result has 30 lines of data.");
 
         let result = fs::read_to_string(&plain_output).unwrap();
diff --git a/function/src/gbdt_training.rs b/function/src/gbdt_train.rs
similarity index 91%
rename from function/src/gbdt_training.rs
rename to function/src/gbdt_train.rs
index 38d34a3..b887427 100644
--- a/function/src/gbdt_training.rs
+++ b/function/src/gbdt_train.rs
@@ -22,7 +22,7 @@ use std::format;
 use std::io::{self, BufRead, BufReader, Write};
 
 use std::convert::TryFrom;
-use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveFunction};
+use teaclave_types::{FunctionArguments, FunctionRuntime};
 
 use gbdt::config::Config;
 use gbdt::decision_tree::Data;
@@ -32,9 +32,9 @@ const IN_DATA: &str = "training_data";
 const OUT_MODEL: &str = "trained_model";
 
 #[derive(Default)]
-pub struct GbdtTraining;
+pub struct GbdtTrain;
 
-struct GbdtTrainingArguments {
+struct GbdtTrainArguments {
     feature_size: usize,
     max_depth: u32,
     iterations: usize,
@@ -46,7 +46,7 @@ struct GbdtTrainingArguments {
     training_optimization_level: u8,
 }
 
-impl TryFrom<FunctionArguments> for GbdtTrainingArguments {
+impl TryFrom<FunctionArguments> for GbdtTrainArguments {
     type Error = anyhow::Error;
 
     fn try_from(arguments: FunctionArguments) -> Result<Self, Self::Error> {
@@ -74,14 +74,20 @@ impl TryFrom<FunctionArguments> for GbdtTrainingArguments {
     }
 }
 
-impl TeaclaveFunction for GbdtTraining {
-    fn execute(
+impl GbdtTrain {
+    pub const NAME: &'static str = "builtin-gbdt-train";
+
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn run(
         &self,
-        runtime: FunctionRuntime,
         arguments: FunctionArguments,
+        runtime: FunctionRuntime,
     ) -> anyhow::Result<String> {
         log::debug!("start traning...");
-        let args = GbdtTrainingArguments::try_from(arguments)?;
+        let args = GbdtTrainArguments::try_from(arguments)?;
 
         log::debug!("open input...");
         // read input
@@ -165,11 +171,11 @@ pub mod tests {
     use teaclave_types::*;
 
     pub fn run_tests() -> bool {
-        run_tests!(test_gbdt_training, test_gbdt_parse_training_data,)
+        run_tests!(test_gbdt_train, test_gbdt_parse_training_data,)
     }
 
-    fn test_gbdt_training() {
-        let func_arguments = FunctionArguments::new(hashmap!(
+    fn test_gbdt_train() {
+        let arguments = FunctionArguments::new(hashmap!(
             "feature_size"  => "4",
             "max_depth"     => "4",
             "iterations"    => "100",
@@ -197,8 +203,7 @@ pub mod tests {
 
         let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
 
-        let function = GbdtTraining;
-        let summary = function.execute(runtime, func_arguments).unwrap();
+        let summary = GbdtTrain::new().run(arguments, runtime).unwrap();
         assert_eq!(summary, "Trained 120 lines of data.");
 
         let result = fs::read_to_string(&plain_output).unwrap();
diff --git a/function/src/lib.rs b/function/src/lib.rs
index a329e6e..a2c0c56 100644
--- a/function/src/lib.rs
+++ b/function/src/lib.rs
@@ -22,23 +22,17 @@ extern crate sgx_tstd as std;
 #[cfg(feature = "mesalock_sgx")]
 use std::prelude::v1::*;
 
-#[macro_use]
-extern crate log;
-
-mod context;
 mod echo;
-mod gbdt_prediction;
-mod gbdt_training;
-mod logistic_regression_prediction;
-mod logistic_regression_training;
-mod mesapy;
+mod gbdt_predict;
+mod gbdt_train;
+mod logistic_regression_predict;
+mod logistic_regression_train;
 
 pub use echo::Echo;
-pub use gbdt_prediction::GbdtPrediction;
-pub use gbdt_training::GbdtTraining;
-pub use logistic_regression_prediction::LogitRegPrediction;
-pub use logistic_regression_training::LogitRegTraining;
-pub use mesapy::Mesapy;
+pub use gbdt_predict::GbdtPredict;
+pub use gbdt_train::GbdtTrain;
+pub use logistic_regression_predict::LogisticRegressionPredict;
+pub use logistic_regression_train::LogisticRegressionTrain;
 
 #[cfg(feature = "enclave_unit_test")]
 pub mod tests {
@@ -48,12 +42,10 @@ pub mod tests {
     pub fn run_tests() -> bool {
         check_all_passed!(
             echo::tests::run_tests(),
-            gbdt_training::tests::run_tests(),
-            gbdt_prediction::tests::run_tests(),
-            mesapy::tests::run_tests(),
-            context::tests::run_tests(),
-            logistic_regression_training::tests::run_tests(),
-            logistic_regression_prediction::tests::run_tests(),
+            gbdt_train::tests::run_tests(),
+            gbdt_predict::tests::run_tests(),
+            logistic_regression_train::tests::run_tests(),
+            logistic_regression_predict::tests::run_tests(),
         )
     }
 }
diff --git a/function/src/logistic_regression_prediction.rs b/function/src/logistic_regression_predict.rs
similarity index 89%
rename from function/src/logistic_regression_prediction.rs
rename to function/src/logistic_regression_predict.rs
index 344be1c..ec2dddc 100644
--- a/function/src/logistic_regression_prediction.rs
+++ b/function/src/logistic_regression_predict.rs
@@ -21,7 +21,7 @@ use std::prelude::v1::*;
 use std::format;
 use std::io::{self, BufRead, BufReader, Write};
 
-use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveFunction};
+use teaclave_types::{FunctionArguments, FunctionRuntime};
 
 use rusty_machine::learning::logistic_reg::LogisticRegressor;
 use rusty_machine::learning::optim::grad_desc::GradientDesc;
@@ -33,13 +33,19 @@ const INPUT_DATA: &str = "data_file";
 const RESULT: &str = "result_file";
 
 #[derive(Default)]
-pub struct LogitRegPrediction;
+pub struct LogisticRegressionPredict;
 
-impl TeaclaveFunction for LogitRegPrediction {
-    fn execute(
+impl LogisticRegressionPredict {
+    pub const NAME: &'static str = "builtin-logistic-regression-predict";
+
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn run(
         &self,
-        runtime: FunctionRuntime,
         _arguments: FunctionArguments,
+        runtime: FunctionRuntime,
     ) -> anyhow::Result<String> {
         let mut model_json = String::new();
         let mut f = runtime.open_input(MODEL_FILE)?;
@@ -109,11 +115,11 @@ pub mod tests {
     use teaclave_types::*;
 
     pub fn run_tests() -> bool {
-        run_tests!(test_logistic_regression_prediction)
+        run_tests!(test_logistic_regression_predict)
     }
 
-    fn test_logistic_regression_prediction() {
-        let func_args = FunctionArguments::default();
+    fn test_logistic_regression_predict() {
+        let arguments = FunctionArguments::default();
 
         let base = Path::new("fixtures/functions/logistic_regression_prediction");
         let model = base.join("model.txt");
@@ -135,8 +141,9 @@ pub mod tests {
 
         let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
 
-        let function = LogitRegPrediction;
-        let summary = function.execute(runtime, func_args).unwrap();
+        let summary = LogisticRegressionPredict::new()
+            .run(arguments, runtime)
+            .unwrap();
         assert_eq!(summary, "Predicted 5 lines of data.");
 
         let result = fs::read_to_string(&plain_output).unwrap();
diff --git a/function/src/logistic_regression_training.rs b/function/src/logistic_regression_train.rs
similarity index 87%
rename from function/src/logistic_regression_training.rs
rename to function/src/logistic_regression_train.rs
index 09214ee..5df3bbe 100644
--- a/function/src/logistic_regression_training.rs
+++ b/function/src/logistic_regression_train.rs
@@ -22,7 +22,7 @@ use std::convert::TryFrom;
 use std::format;
 use std::io::{self, BufRead, BufReader, Write};
 
-use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveFunction};
+use teaclave_types::{FunctionArguments, FunctionRuntime};
 
 use rusty_machine::learning::logistic_reg::LogisticRegressor;
 use rusty_machine::learning::optim::grad_desc::GradientDesc;
@@ -33,15 +33,15 @@ const TRAINING_DATA: &str = "training_data";
 const OUT_MODEL_FILE: &str = "model_file";
 
 #[derive(Default)]
-pub struct LogitRegTraining;
+pub struct LogisticRegressionTrain;
 
-struct LogitRegTrainingArguments {
+struct LogisticRegressionTrainArguments {
     alg_alpha: f64,
     alg_iters: usize,
     feature_size: usize,
 }
 
-impl TryFrom<FunctionArguments> for LogitRegTrainingArguments {
+impl TryFrom<FunctionArguments> for LogisticRegressionTrainArguments {
     type Error = anyhow::Error;
 
     fn try_from(arguments: FunctionArguments) -> Result<Self, Self::Error> {
@@ -57,13 +57,19 @@ impl TryFrom<FunctionArguments> for LogitRegTrainingArguments {
     }
 }
 
-impl TeaclaveFunction for LogitRegTraining {
-    fn execute(
+impl LogisticRegressionTrain {
+    pub const NAME: &'static str = "builtin-logistic-regression-train";
+
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn run(
         &self,
-        runtime: FunctionRuntime,
         arguments: FunctionArguments,
+        runtime: FunctionRuntime,
     ) -> anyhow::Result<String> {
-        let args = LogitRegTrainingArguments::try_from(arguments)?;
+        let args = LogisticRegressionTrainArguments::try_from(arguments)?;
 
         let input = runtime.open_input(TRAINING_DATA)?;
         let (flattend_features, targets) = parse_training_data(input, args.feature_size)?;
@@ -127,11 +133,11 @@ pub mod tests {
     use teaclave_types::*;
 
     pub fn run_tests() -> bool {
-        run_tests!(test_logistic_regression_training)
+        run_tests!(test_logistic_regression_train)
     }
 
-    fn test_logistic_regression_training() {
-        let func_args = FunctionArguments::new(hashmap! {
+    fn test_logistic_regression_train() {
+        let arguments = FunctionArguments::new(hashmap! {
             "alg_alpha" => "0.3",
             "alg_iters" => "100",
             "feature_size" => "30"
@@ -154,8 +160,9 @@ pub mod tests {
 
         let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
 
-        let function = LogitRegTraining;
-        let summary = function.execute(runtime, func_args).unwrap();
+        let summary = LogisticRegressionTrain::new()
+            .run(arguments, runtime)
+            .unwrap();
         assert_eq!(summary, "Trained 100 lines of data.");
 
         let _result = fs::read_to_string(&plain_output).unwrap();
diff --git a/services/execution/enclave/src/lib.rs b/services/execution/enclave/src/lib.rs
index babefa8..af99909 100644
--- a/services/execution/enclave/src/lib.rs
+++ b/services/execution/enclave/src/lib.rs
@@ -115,7 +115,7 @@ pub mod tests {
         run_tests!(
             ocall::tests::test_handle_file_request,
             service::tests::test_invoke_echo,
-            service::tests::test_invoke_gbdt_training,
+            service::tests::test_invoke_gbdt_train,
             task_file_manager::tests::test_input,
         )
     }
diff --git a/services/execution/enclave/src/service.rs b/services/execution/enclave/src/service.rs
index 1b73311..a0e419d 100644
--- a/services/execution/enclave/src/service.rs
+++ b/services/execution/enclave/src/service.rs
@@ -64,7 +64,7 @@ impl TeaclaveExecutionService {
             let staged_task = match self.pull_task() {
                 Ok(staged_task) => staged_task,
                 Err(e) => {
-                    log::error!("PullTask Error: {:?}", e);
+                    log::warn!("PullTask Error: {:?}", e);
                     continue;
                 }
             };
@@ -154,8 +154,9 @@ fn prepare_task(task: &StagedTask, file_mgr: &TaskFileManager) -> Result<StagedF
     let staged_function = StagedFunction::new()
         .executor_type(task.executor_type)
         .executor(task.executor)
-        .payload(function_payload)
+        .name(&task.function_name)
         .arguments(task.function_arguments.clone())
+        .payload(function_payload)
         .input_files(input_files)
         .output_files(output_files)
         .runtime_name("default");
@@ -178,7 +179,8 @@ pub mod tests {
         let task_id = Uuid::new_v4();
         let staged_task = StagedTask::new()
             .task_id(task_id)
-            .executor(Executor::Echo)
+            .executor(Executor::Builtin)
+            .function_name("builtin-echo")
             .function_arguments(hashmap!("message" => "Hello, Teaclave!"));
 
         let file_mgr = TaskFileManager::new(
@@ -198,7 +200,7 @@ pub mod tests {
         assert_eq!(result.unwrap(), "Hello, Teaclave!");
     }
 
-    pub fn test_invoke_gbdt_training() {
+    pub fn test_invoke_gbdt_train() {
         let task_id = Uuid::new_v4();
         let function_arguments = FunctionArguments::new(hashmap!(
             "feature_size"                => "4",
@@ -232,7 +234,8 @@ pub mod tests {
 
         let staged_task = StagedTask::new()
             .task_id(task_id)
-            .executor(Executor::GbdtTraining)
+            .executor(Executor::Builtin)
+            .function_name("builtin-gbdt-train")
             .function_arguments(function_arguments)
             .input_data(input_data)
             .output_data(output_data);
diff --git a/services/proto/src/teaclave_frontend_service.rs b/services/proto/src/teaclave_frontend_service.rs
index f1bf80c..9ca53ff 100644
--- a/services/proto/src/teaclave_frontend_service.rs
+++ b/services/proto/src/teaclave_frontend_service.rs
@@ -223,7 +223,11 @@ pub struct RegisterFunctionRequest {
 
 impl RegisterFunctionRequest {
     pub fn new() -> Self {
-        Self::default()
+        Self {
+            executor_type: ExecutorType::Builtin,
+            public: true,
+            ..Default::default()
+        }
     }
 
     pub fn name(self, name: impl ToString) -> Self {
diff --git a/tests/functional/enclave/src/end_to_end/native_echo.rs b/tests/functional/enclave/src/end_to_end/builtin_echo.rs
similarity index 94%
rename from tests/functional/enclave/src/end_to_end/native_echo.rs
rename to tests/functional/enclave/src/end_to_end/builtin_echo.rs
index bd67bc0..5d39ba3 100644
--- a/tests/functional/enclave/src/end_to_end/native_echo.rs
+++ b/tests/functional/enclave/src/end_to_end/builtin_echo.rs
@@ -29,10 +29,8 @@ pub fn test_echo_task_success() {
 
     // Register Function
     let request = RegisterFunctionRequest::new()
-        .name("native_echo_demo")
+        .name("builtin-echo")
         .description("Native Echo Function")
-        .executor_type(ExecutorType::Native)
-        .public(true)
         .arguments(vec!["message"]);
 
     let response = client.register_function(request).unwrap();
@@ -44,7 +42,7 @@ pub fn test_echo_task_success() {
     let request = CreateTaskRequest::new()
         .function_id(function_id)
         .function_arguments(hashmap!("message" => "Hello From Teaclave!"))
-        .executor(Executor::Echo);
+        .executor(Executor::Builtin);
 
     let response = client.create_task(request).unwrap();
 
diff --git a/tests/functional/enclave/src/end_to_end/native_gbdt_training.rs b/tests/functional/enclave/src/end_to_end/builtin_gbdt_train.rs
similarity index 97%
rename from tests/functional/enclave/src/end_to_end/native_gbdt_training.rs
rename to tests/functional/enclave/src/end_to_end/builtin_gbdt_train.rs
index 3747596..86258ee 100644
--- a/tests/functional/enclave/src/end_to_end/native_gbdt_training.rs
+++ b/tests/functional/enclave/src/end_to_end/builtin_gbdt_train.rs
@@ -62,10 +62,8 @@ fn register_gbdt_function(client: &mut TeaclaveFrontendClient) -> ExternalID {
 
     // Register Function
     let request = RegisterFunctionRequest::new()
-        .name("native_gbdt_training_demo")
+        .name("builtin-gbdt-train")
         .description("Native Gbdt Training Function")
-        .executor_type(ExecutorType::Native)
-        .public(true)
         .arguments(fn_args)
         .inputs(vec![fn_input])
         .outputs(vec![fn_output]);
@@ -106,7 +104,7 @@ fn create_gbdt_training_task(
     function_id: &ExternalID,
 ) -> ExternalID {
     let request = CreateTaskRequest::new()
-        .executor(Executor::GbdtTraining)
+        .executor(Executor::Builtin)
         .function_id(function_id.clone())
         .function_arguments(hashmap!(
             "feature_size"          => "4",
diff --git a/tests/functional/enclave/src/end_to_end/mod.rs b/tests/functional/enclave/src/end_to_end/mod.rs
index 64a7020..e6f5502 100644
--- a/tests/functional/enclave/src/end_to_end/mod.rs
+++ b/tests/functional/enclave/src/end_to_end/mod.rs
@@ -21,10 +21,10 @@ use teaclave_proto::teaclave_frontend_service::*;
 use teaclave_types::*;
 use url::Url;
 
+mod builtin_echo;
+mod builtin_gbdt_train;
 mod mesapy_data_fusion;
 mod mesapy_echo;
-mod native_echo;
-mod native_gbdt_training;
 
 fn get_task(client: &mut TeaclaveFrontendClient, task_id: &ExternalID) -> GetTaskResponse {
     let request = GetTaskRequest::new(task_id.clone());
diff --git a/tests/functional/enclave/src/execution_service.rs b/tests/functional/enclave/src/execution_service.rs
index 9590daa..2412197 100644
--- a/tests/functional/enclave/src/execution_service.rs
+++ b/tests/functional/enclave/src/execution_service.rs
@@ -37,7 +37,8 @@ fn test_execute_function() {
     let staged_task = StagedTask::new()
         .task_id(task_id)
         .function_id(function_id.clone())
-        .executor(Executor::Echo)
+        .function_name("builtin-echo")
+        .executor(Executor::Builtin)
         .function_arguments(hashmap!(
             "message" => "Hello, Teaclave Tests!"
         ));
diff --git a/tests/functional/enclave/src/scheduler_service.rs b/tests/functional/enclave/src/scheduler_service.rs
index 24c4f7f..226f273 100644
--- a/tests/functional/enclave/src/scheduler_service.rs
+++ b/tests/functional/enclave/src/scheduler_service.rs
@@ -29,8 +29,9 @@ fn test_pull_task() {
     let function_id = Uuid::new_v4();
     let staged_task = StagedTask::new()
         .task_id(Uuid::new_v4())
+        .function_name("builtin-echo")
         .function_id(function_id.clone())
-        .executor(Executor::Echo);
+        .executor(Executor::Builtin);
 
     let mut storage_client = get_storage_client();
     let enqueue_request = EnqueueRequest::new(
@@ -60,8 +61,9 @@ fn test_update_task_status_result() {
 
     let staged_task = StagedTask::new()
         .task_id(task_id.clone())
+        .function_name("builtin-echo")
         .function_id(function_id)
-        .executor(Executor::Echo);
+        .executor(Executor::Builtin);
 
     let mut storage_client = get_storage_client();
     let enqueue_request = EnqueueRequest::new(
diff --git a/tests/integration/enclave/src/teaclave_worker.rs b/tests/integration/enclave/src/teaclave_worker.rs
index d329941..09b9f5d 100644
--- a/tests/integration/enclave/src/teaclave_worker.rs
+++ b/tests/integration/enclave/src/teaclave_worker.rs
@@ -14,6 +14,7 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
+
 use std::prelude::v1::*;
 
 use teaclave_crypto::TeaclaveFile128Key;
@@ -54,8 +55,9 @@ fn test_start_worker() {
         "trained_model" => output_info.clone()));
 
     let staged_function = StagedFunction::new()
-        .executor_type(ExecutorType::Native)
-        .executor(Executor::GbdtTraining)
+        .executor_type(ExecutorType::Builtin)
+        .executor(Executor::Builtin)
+        .name("builtin-gbdt-train")
         .arguments(arguments)
         .input_files(input_files)
         .output_files(output_files)
@@ -63,10 +65,6 @@ fn test_start_worker() {
 
     let worker = Worker::default();
 
-    let capability = worker.get_capability();
-    assert!(capability.runtimes.contains("default"));
-    assert!(capability.functions.contains("native-gbdt_training"));
-
     let summary = worker.invoke_function(staged_function).unwrap();
     assert_eq!(summary, "Trained 120 lines of data.");
 
diff --git a/tests/unit/enclave/Cargo.toml b/tests/unit/enclave/Cargo.toml
index 5dc8e27..8ebba92 100644
--- a/tests/unit/enclave/Cargo.toml
+++ b/tests/unit/enclave/Cargo.toml
@@ -38,6 +38,8 @@ mesalock_sgx = [
   "teaclave_scheduler_service_enclave/enclave_unit_test",
   "teaclave_worker/mesalock_sgx",
   "teaclave_worker/enclave_unit_test",
+  "teaclave_executor/mesalock_sgx",
+  "teaclave_executor/enclave_unit_test",
   "teaclave_function/mesalock_sgx",
   "teaclave_function/enclave_unit_test",
   "teaclave_runtime/mesalock_sgx",
@@ -61,6 +63,7 @@ teaclave_management_service_enclave = { path = "../../../services/management/enc
 teaclave_scheduler_service_enclave = { path = "../../../services/scheduler/enclave" }
 
 teaclave_worker                = { path = "../../../worker" }
+teaclave_executor              = { path = "../../../executor" }
 teaclave_function              = { path = "../../../function" }
 teaclave_runtime               = { path = "../../../runtime" }
 rusty-leveldb                  = { path = "../../../common/rusty_leveldb_sgx", default-features = false, optional = true }
diff --git a/tests/unit/enclave/src/lib.rs b/tests/unit/enclave/src/lib.rs
index 008f002..3e327e4 100644
--- a/tests/unit/enclave/src/lib.rs
+++ b/tests/unit/enclave/src/lib.rs
@@ -40,6 +40,7 @@ fn handle_run_test(_: &RunTestInput) -> TeeServiceResult<RunTestOutput> {
         teaclave_authentication_service_enclave::tests::run_tests(),
         teaclave_worker::tests::run_tests(),
         teaclave_runtime::tests::run_tests(),
+        teaclave_executor::tests::run_tests(),
         teaclave_function::tests::run_tests(),
         teaclave_types::tests::run_tests(),
         teaclave_crypto::tests::run_tests(),
diff --git a/types/src/staged_function.rs b/types/src/staged_function.rs
index 03a46b9..47f3bd9 100644
--- a/types/src/staged_function.rs
+++ b/types/src/staged_function.rs
@@ -157,13 +157,14 @@ impl FunctionArguments {
 
 #[derive(Debug, Default)]
 pub struct StagedFunction {
-    pub executor: Executor,
-    pub payload: String,
+    pub name: String,
     pub arguments: FunctionArguments,
+    pub payload: String,
     pub input_files: StagedFiles,
     pub output_files: StagedFiles,
-    pub runtime_name: String,
     pub executor_type: ExecutorType,
+    pub executor: Executor,
+    pub runtime_name: String,
 }
 
 impl StagedFunction {
@@ -171,6 +172,13 @@ impl StagedFunction {
         Self::default()
     }
 
+    pub fn name(self, name: impl ToString) -> Self {
+        Self {
+            name: name.to_string(),
+            ..self
+        }
+    }
+
     pub fn executor(self, executor: Executor) -> Self {
         Self { executor, ..self }
     }
diff --git a/types/src/staged_task.rs b/types/src/staged_task.rs
index c2bf26e..71369c8 100644
--- a/types/src/staged_task.rs
+++ b/types/src/staged_task.rs
@@ -155,8 +155,9 @@ pub struct StagedTask {
     pub function_id: Uuid,
     pub executor: Executor,
     pub executor_type: ExecutorType,
-    pub function_payload: Vec<u8>,
+    pub function_name: String,
     pub function_arguments: FunctionArguments,
+    pub function_payload: Vec<u8>,
     pub input_data: FunctionInputFiles,
     pub output_data: FunctionOutputFiles,
 }
@@ -191,9 +192,9 @@ impl StagedTask {
         Self { executor, ..self }
     }
 
-    pub fn function_payload(self, function_payload: Vec<u8>) -> Self {
+    pub fn function_name(self, name: impl ToString) -> Self {
         Self {
-            function_payload,
+            function_name: name.to_string(),
             ..self
         }
     }
@@ -205,6 +206,13 @@ impl StagedTask {
         }
     }
 
+    pub fn function_payload(self, function_payload: Vec<u8>) -> Self {
+        Self {
+            function_payload,
+            ..self
+        }
+    }
+
     pub fn input_data(self, input_data: impl Into<FunctionInputFiles>) -> Self {
         Self {
             input_data: input_data.into(),
diff --git a/types/src/task.rs b/types/src/task.rs
index c6f3090..6061d38 100644
--- a/types/src/task.rs
+++ b/types/src/task.rs
@@ -502,6 +502,7 @@ impl Task {
             executor: self.executor,
             executor_type: function.executor_type,
             function_id: function.id,
+            function_name: function.name,
             function_payload: function.payload,
             function_arguments,
             input_data: input_map.into(),
diff --git a/types/src/worker.rs b/types/src/worker.rs
index eebe592..aa9ced6 100644
--- a/types/src/worker.rs
+++ b/types/src/worker.rs
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::{FunctionArguments, OutputsTags};
+use crate::{FunctionArguments, FunctionRuntime, OutputsTags};
 use serde::{Deserialize, Serialize};
 use std::collections::HashSet;
 use std::convert::TryInto;
@@ -27,23 +27,25 @@ pub trait TeaclaveRuntime {
     fn create_output(&self, identifier: &str) -> anyhow::Result<Box<dyn io::Write>>;
 }
 
-pub trait TeaclaveFunction {
+pub trait TeaclaveExecutor {
     fn execute(
         &self,
-        runtime: Box<dyn TeaclaveRuntime + Send + Sync>,
-        args: FunctionArguments,
+        name: String,
+        arguments: FunctionArguments,
+        payload: String,
+        runtime: FunctionRuntime,
     ) -> anyhow::Result<String>;
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
 pub enum ExecutorType {
-    Native,
+    Builtin,
     Python,
 }
 
 impl std::default::Default for ExecutorType {
     fn default() -> Self {
-        ExecutorType::Native
+        ExecutorType::Builtin
     }
 }
 
@@ -53,7 +55,7 @@ impl std::convert::TryFrom<&str> for ExecutorType {
     fn try_from(selector: &str) -> anyhow::Result<Self> {
         let executor_type = match selector {
             "python" => ExecutorType::Python,
-            "native" | "platform" => ExecutorType::Native,
+            "builtin" => ExecutorType::Builtin,
             _ => anyhow::bail!("Invalid executor type: {}", selector),
         };
         Ok(executor_type)
@@ -77,7 +79,7 @@ impl std::convert::From<ExecutorType> for String {
 impl std::fmt::Display for ExecutorType {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
         match self {
-            ExecutorType::Native => write!(f, "native"),
+            ExecutorType::Builtin => write!(f, "builtin"),
             ExecutorType::Python => write!(f, "python"),
         }
     }
@@ -86,11 +88,7 @@ impl std::fmt::Display for ExecutorType {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
 pub enum Executor {
     MesaPy,
-    GbdtTraining,
-    GbdtPrediction,
-    LogitRegTraining,
-    LogitRegPrediction,
-    Echo,
+    Builtin,
 }
 
 impl std::default::Default for Executor {
@@ -105,11 +103,7 @@ impl std::convert::TryFrom<&str> for Executor {
     fn try_from(selector: &str) -> anyhow::Result<Self> {
         let executor = match selector {
             "mesapy" => Executor::MesaPy,
-            "echo" => Executor::Echo,
-            "gbdt_training" => Executor::GbdtTraining,
-            "gbdt_prediction" => Executor::GbdtPrediction,
-            "logistic_regression_training" => Executor::LogitRegTraining,
-            "logistic_regression_prediction" => Executor::LogitRegPrediction,
+            "builtin" => Executor::Builtin,
             _ => anyhow::bail!("Unsupported executor: {}", selector),
         };
         Ok(executor)
@@ -128,11 +122,7 @@ impl std::fmt::Display for Executor {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
         match self {
             Executor::MesaPy => write!(f, "mesapy"),
-            Executor::Echo => write!(f, "echo"),
-            Executor::GbdtTraining => write!(f, "gbdt_training"),
-            Executor::GbdtPrediction => write!(f, "gbdt_prediction"),
-            Executor::LogitRegTraining => write!(f, "logistic_regression_training"),
-            Executor::LogitRegPrediction => write!(f, "logistic_regression_prediction"),
+            Executor::Builtin => write!(f, "builtin"),
         }
     }
 }
@@ -140,7 +130,7 @@ impl std::fmt::Display for Executor {
 #[derive(Debug)]
 pub struct WorkerCapability {
     pub runtimes: HashSet<String>,
-    pub functions: HashSet<String>,
+    pub executors: HashSet<String>,
 }
 
 #[derive(Debug, Default)]
@@ -152,11 +142,8 @@ pub struct ExecutionResult {
 #[cfg(feature = "enclave_unit_test")]
 pub mod tests {
     use super::*;
-    //use crate::unit_tests;
-    //use crate::unittest::*;
 
     pub fn run_tests() -> bool {
-        //unit_tests!()
         true
     }
 }
diff --git a/worker/Cargo.toml b/worker/Cargo.toml
index d551ac9..fe73855 100644
--- a/worker/Cargo.toml
+++ b/worker/Cargo.toml
@@ -15,7 +15,7 @@ default = []
 mesalock_sgx = [
   "sgx_tstd",
   "teaclave_types/mesalock_sgx",
-  "teaclave_function/mesalock_sgx",
+  "teaclave_executor/mesalock_sgx",
   "teaclave_runtime/mesalock_sgx"
 ]
 cov = ["sgx_cov"]
@@ -27,7 +27,7 @@ anyhow        = { version = "1.0.26" }
 serde_json    = { version = "1.0.39" }
 thiserror     = { version = "1.0.9" }
 teaclave_types = { path = "../types" }
-teaclave_function = { path = "../function" }
+teaclave_executor = { path = "../executor" }
 teaclave_runtime = { path = "../runtime" }
 teaclave_test_utils = { path = "../tests/utils", optional = true }
 
diff --git a/worker/src/worker.rs b/worker/src/worker.rs
index c08e7cc..c94d64a 100644
--- a/worker/src/worker.rs
+++ b/worker/src/worker.rs
@@ -21,74 +21,72 @@ use std::prelude::v1::*;
 use std::collections::HashMap;
 use std::format;
 
-use teaclave_types::{
-    hashmap, Executor, ExecutorType, FunctionArguments, StagedFiles, StagedFunction,
-    WorkerCapability,
-};
-
-use teaclave_function as function;
-use teaclave_runtime as runtime;
-use teaclave_types::{TeaclaveFunction, TeaclaveRuntime};
-
-macro_rules! register_functions{
-    ($(($executor_type: expr, $executor_name: expr) => $fn_type: ty,)*) => {{
-        let mut functions: HashMap<(ExecutorType, Executor), FunctionBuilder> = HashMap::new();
-        $(
-            functions.insert(
-                ($executor_type, $executor_name),
-                Box::new(|| Box::new(<$fn_type>::default())),
-            );
-        )*
-        functions
-    }}
-}
+use teaclave_types::{Executor, ExecutorType, StagedFiles, StagedFunction};
+
+use teaclave_executor::{BuiltinFunctionExecutor, MesaPy};
+use teaclave_runtime::{DefaultRuntime, RawIoRuntime};
+use teaclave_types::{TeaclaveExecutor, TeaclaveRuntime};
+
+type BoxedTeaclaveExecutor = Box<dyn TeaclaveExecutor + Send + Sync>;
+type BoxedTeaclaveRuntime = Box<dyn TeaclaveRuntime + Send + Sync>;
+type ExecutorBuilder = fn() -> BoxedTeaclaveExecutor;
+type RuntimeBuilder = fn(StagedFiles, StagedFiles) -> BoxedTeaclaveRuntime;
 
 pub struct Worker {
     runtimes: HashMap<String, RuntimeBuilder>,
-    functions: HashMap<(ExecutorType, Executor), FunctionBuilder>,
+    executors: HashMap<(ExecutorType, Executor), ExecutorBuilder>,
+}
+
+impl Default for Worker {
+    fn default() -> Self {
+        let mut worker = Worker::new();
+
+        // Register supported runtimes
+        worker.register_runtime("default", |input, output| {
+            Box::new(DefaultRuntime::new(input, output))
+        });
+
+        #[cfg(test_mode)]
+        worker.register_runtime("raw-io", |input, output| {
+            Box::new(RawIoRuntime::new(input, output))
+        });
+
+        // Register supported executors
+        worker.register_executor((ExecutorType::Python, Executor::MesaPy), || {
+            Box::new(MesaPy::default())
+        });
+        worker.register_executor((ExecutorType::Builtin, Executor::Builtin), || {
+            Box::new(BuiltinFunctionExecutor::default())
+        });
+
+        worker
+    }
 }
 
 impl Worker {
-    pub fn default() -> Worker {
-        Worker {
-            functions: register_functions!(
-                (ExecutorType::Python, Executor::MesaPy) => function::Mesapy,
-                (ExecutorType::Native, Executor::Echo) => function::Echo,
-                (ExecutorType::Native, Executor::GbdtTraining) => function::GbdtTraining,
-                (ExecutorType::Native, Executor::GbdtPrediction) => function::GbdtPrediction,
-                (ExecutorType::Native, Executor::LogitRegTraining) => function::LogitRegTraining,
-                (ExecutorType::Native, Executor::LogitRegPrediction) => function::LogitRegPrediction,
-            ),
-            runtimes: setup_runtimes(),
+    pub fn new() -> Self {
+        Self {
+            runtimes: HashMap::new(),
+            executors: HashMap::new(),
         }
     }
 
-    pub fn invoke_function(&self, staged_function: StagedFunction) -> anyhow::Result<String> {
-        let function =
-            self.get_function(staged_function.executor_type, staged_function.executor)?;
-        let runtime = self.get_runtime(
-            &staged_function.runtime_name,
-            staged_function.input_files,
-            staged_function.output_files,
-        )?;
-        let unified_args = prepare_arguments(
-            staged_function.executor_type,
-            staged_function.arguments,
-            staged_function.payload,
-        )?;
-        function.execute(runtime, unified_args)
+    pub fn register_runtime(&mut self, name: impl ToString, builder: RuntimeBuilder) {
+        self.runtimes.insert(name.to_string(), builder);
     }
 
-    pub fn get_capability(&self) -> WorkerCapability {
-        WorkerCapability {
-            runtimes: self.runtimes.keys().cloned().collect(),
-            functions: self
-                .functions
-                .keys()
-                .cloned()
-                .map(|(exec_type, exec_name)| make_function_identifier(exec_type, exec_name))
-                .collect(),
-        }
+    pub fn register_executor(&mut self, key: (ExecutorType, Executor), builder: ExecutorBuilder) {
+        self.executors.insert(key, builder);
+    }
+
+    pub fn invoke_function(&self, function: StagedFunction) -> anyhow::Result<String> {
+        let executor = self.get_executor(function.executor_type, function.executor)?;
+        let runtime = self.get_runtime(
+            &function.runtime_name,
+            function.input_files,
+            function.output_files,
+        )?;
+        executor.execute(function.name, function.arguments, function.payload, runtime)
     }
 
     fn get_runtime(
@@ -96,7 +94,7 @@ impl Worker {
         name: &str,
         input_files: StagedFiles,
         output_files: StagedFiles,
-    ) -> anyhow::Result<Box<dyn TeaclaveRuntime + Send + Sync>> {
+    ) -> anyhow::Result<BoxedTeaclaveRuntime> {
         let build_runtime = self
             .runtimes
             .get(name)
@@ -106,79 +104,19 @@ impl Worker {
         Ok(runtime)
     }
 
-    fn get_function(
+    fn get_executor(
         &self,
         exec_type: ExecutorType,
         exec_name: Executor,
-    ) -> anyhow::Result<Box<dyn TeaclaveFunction + Send + Sync>> {
+    ) -> anyhow::Result<BoxedTeaclaveExecutor> {
         let identifier = (exec_type, exec_name);
-        let build_function = self
-            .functions
+        let build_executor = self
+            .executors
             .get(&identifier)
             .ok_or_else(|| anyhow::anyhow!(format!("function not available: {:?}", identifier)))?;
 
-        let function = build_function();
-        Ok(function)
-    }
-}
-
-fn make_function_identifier(exec_type: ExecutorType, exec_name: Executor) -> String {
-    format!("{}-{}", exec_type, exec_name)
-}
-
-fn setup_runtimes() -> HashMap<String, RuntimeBuilder> {
-    let mut runtimes: HashMap<String, RuntimeBuilder> = HashMap::new();
-    runtimes.insert(
-        "default".to_string(),
-        Box::new(|input_files, output_files| {
-            Box::new(runtime::DefaultRuntime::new(input_files, output_files))
-        }),
-    );
-    #[cfg(test_mode)]
-    runtimes.insert(
-        "raw-io".to_string(),
-        Box::new(|input_files, output_files| {
-            Box::new(runtime::RawIoRuntime::new(input_files, output_files))
-        }),
-    );
-
-    runtimes
-}
-
-// Native functions (ExecutorType::Native) are not allowed to have function payload.
-// Script engines like Mesapy (ExecutorType::Python) must have script payload.
-// We assume that the script engines would take the script payload and
-// script arguments from the wrapped argument.
-fn prepare_arguments(
-    executor_type: ExecutorType,
-    function_arguments: FunctionArguments,
-    function_payload: String,
-) -> anyhow::Result<FunctionArguments> {
-    let unified_args = match executor_type {
-        ExecutorType::Native => {
-            anyhow::ensure!(
-                function_payload.is_empty(),
-                "Native function payload should be empty!"
-            );
-            function_arguments
-        }
-        ExecutorType::Python => {
-            anyhow::ensure!(
-                !function_payload.is_empty(),
-                "Python function payload must not be empty!"
-            );
-            let req_args = serde_json::to_string(&function_arguments)?;
-            let wrap_args = hashmap!(
-                "py_payload" => function_payload,
-                "py_args" => req_args,
-            );
-            FunctionArguments::new(wrap_args)
-        }
-    };
+        let executor = build_executor();
 
-    Ok(unified_args)
+        Ok(executor)
+    }
 }
-
-type FunctionBuilder = Box<dyn Fn() -> Box<dyn TeaclaveFunction + Send + Sync> + Send + Sync>;
-type RuntimeBuilder =
-    Box<dyn Fn(StagedFiles, StagedFiles) -> Box<dyn TeaclaveRuntime + Send + Sync> + Send + Sync>;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org


Mime
View raw message