From 38390dab632eb2d1c5f5c5f43aa1db6ae2f0a54f Mon Sep 17 00:00:00 2001 From: Nelson-He Date: Sat, 12 Nov 2022 22:43:22 +0800 Subject: [PATCH 1/3] add wasmedge support, use it as wasm runtime --- README.md | 12 +- docker/Dockerfile | 4 +- docker/entrypoint.sh | 1 + wasm/Makefile | 18 +- wasm/wasm_executor--1.0.sql | 74 ------- wasm/wasm_executor.cpp | 387 ++++++++++++++---------------------- 6 files changed, 162 insertions(+), 334 deletions(-) diff --git a/README.md b/README.md index 12bc5a8..b19a7ec 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -A complete and mature WebAssembly runtime for openGauss based on [Wasmtime](https://wasmtime.dev/). +A complete and mature WebAssembly runtime for openGauss based on [WasmEdge](https://wasmedge.org/book/zh/index.html). It's an original way to extend your favorite database capabilities. > Note This project is inspired by [wasmer-postgres](https://github.com/wasmerio/wasmer-postgres) Features: - * **Easy to use**: The `wasmtime` API mimics the standard WebAssembly API, - * **Fast**: `wasmtime` executes the WebAssembly modules as fast as + * **Easy to use**: The `wasmedge` API mimics the standard WebAssembly API, + * **Fast**: `wasmedge` executes the WebAssembly modules as fast as possible, close to **native speed**, * **Safe**: All calls to WebAssembly will be fast, but more importantly, completely safe and sandboxed. @@ -22,8 +22,10 @@ The project comes in two parts: 1. A shared library, and 2. A PL/pgSQL extension. -To compile the former, the wasmtime-c-api header files are required and be placed alongside the "openGauss-server" code. -You can download the header file from [here](https://github.com/bytecodealliance/wasmtime/releases). +To compile the former, the wasmedge should have been installed. +You can install the wasmedge as simple as + +Refer to [https://wasmedge.org/book/en/quick_start/install.html](https://wasmedge.org/book/en/quick_start/install.html) for more details. After that, run `CREATE EXTENSION wasm_executor` in a openGauss shell. Two new functions will appear: `wasm_new_instance` and `wasm_new_instance_wat`; They must be diff --git a/docker/Dockerfile b/docker/Dockerfile index 4681e58..4313d6d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -25,13 +25,11 @@ RUN cp -f /home/opengauss/bashrc /home/opengauss/.bashrc && \ cd /home/opengauss && \ if [ "`uname -m`" == "x86_64" ]; then \ wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/binarylibs/openGauss-third_party_binarylibs_openEuler_x86_64.tar.gz -O openGauss_third.tar.gz && \ - wget -q https://github.com/bytecodealliance/wasmtime/releases/download/v1.0.1/wasmtime-v1.0.1-x86_64-linux-c-api.tar.xz -O wasmtime.tar.xz; \ else \ wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/binarylibs/openGauss-third_party_binarylibs_openEuler_arm.tar.gz -O openGauss_third.tar.gz && \ - wget -q https://github.com/bytecodealliance/wasmtime/releases/download/v1.0.1/wasmtime-v1.0.1-aarch64-linux-c-api.tar.xz -O wasmtime.tar.xz; \ fi && \ tar -xf openGauss_third.tar.gz && mv openGauss-third_party_binarylibs* binarylibs && rm -f openGauss_third.tar.gz && \ - tar -xf wasmtime.tar.xz && mv wasmtime-v1.0.1* wasmtime && rm -rf wasmtime.tar.xz && rm -rf /home/opengauss/wasmtime/lib/libwasmtime.a && \ + curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.11.2 && source /home/opengauss/.wasmedge/env \ source /home/opengauss/.bashrc && git clone https://gitee.com/Nelson-He/openGauss-server.git && cd openGauss-server && \ ./configure --gcc-version=7.3.0 CC=g++ CFLAGS='-O2' \ --prefix=$GAUSSHOME --3rd=$BINARYLIBS \ diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 120eabc..3972881 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -6,6 +6,7 @@ set -e echo "Initing openGauss..." source /home/opengauss/.bashrc +source /home/opengauss/.wasmedge/env source ~/.bashrc && gs_initdb -D /home/opengauss/openGauss/data/ -w "openGauss2022" -E utf8 --nodename=datanode sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/g" /home/opengauss/openGauss/data/postgresql.conf diff --git a/wasm/Makefile b/wasm/Makefile index 4f45fb3..ed62f59 100644 --- a/wasm/Makefile +++ b/wasm/Makefile @@ -7,7 +7,7 @@ EXTENSION = wasm_executor DATA = wasm_executor--1.0.sql SHLIB_LINK_INTERNAL = $(libpq) -SHLIB_LINK += -lwasmtime +SHLIB_LINK += -lwasmedge ifdef USE_PGXS PG_CONFIG = pg_config @@ -18,19 +18,5 @@ subdir = contrib/wasm top_builddir = ../.. include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk -override CPPFLAGS := $(filter-out -fPIE, $(CPPFLAGS)) -fPIC -I${top_builddir}/../wasmtime/include -override LDFLAGS += -L${top_builddir}/../wasmtime/lib - -install:install-libwasmtime install-data - -.PHONY: install-data -install-data: installdirs - $(INSTALL_DATA) $(addprefix $(srcdir)/, $(DATA)) '$(DESTDIR)$(datadir)/extension/' - -installdirs: - $(MKDIR_P) '$(DESTDIR)$(datadir)/extension' - -install-libwasmtime: - @cp ${top_builddir}/../wasmtime/lib/libwasmtime.so $(DESTDIR)$(libdir) - +override CPPFLAGS := $(filter-out -fPIE, $(CPPFLAGS)) -fPIC endif diff --git a/wasm/wasm_executor--1.0.sql b/wasm/wasm_executor--1.0.sql index ebaccd1..ff2d52c 100644 --- a/wasm/wasm_executor--1.0.sql +++ b/wasm/wasm_executor--1.0.sql @@ -41,11 +41,6 @@ RETURNS int8 AS 'MODULE_PATHNAME', 'wasm_create_instance' LANGUAGE C STRICT; -CREATE FUNCTION wasm_create_new_instance_wat(text) -RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_create_instance_wat' -LANGUAGE C STRICT; - CREATE FUNCTION wasm_invoke_function_0(text, text) RETURNS int8 AS 'MODULE_PATHNAME', 'wasm_invoke_function_0' @@ -168,73 +163,4 @@ BEGIN RETURN current_instance_id; END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION wasm_new_instance_wat(module_pathname text, namespace text) RETURNS text AS $$ -DECLARE - current_instance_id int8; - exported_function RECORD; - exported_function_generated_inputs text; - exported_function_generated_outputs text; -BEGIN - -- Create a new instance, and stores its ID in `current_instance_id`. - SELECT wasm_create_new_instance_wat(module_pathname) INTO STRICT current_instance_id; - - -- Insert the wasm information to gloable table - INSERT INTO wasm.instances SELECT id, wasm_file FROM wasm_get_instances() WHERE id = current_instance_id; - INSERT INTO wasm.exported_functions SELECT current_instance_id, funcname, inputs, outputs FROM wasm_get_exported_functions(current_instance_id); - - -- Generate functions for each exported functions from the WebAssembly instance. - FOR - exported_function - IN - SELECT - funcname, - inputs, - CASE - WHEN length(inputs) = 0 THEN 0 - ELSE array_length(regexp_split_to_array(inputs, ','), 1) - END AS input_arity, - outputs - FROM - (SELECT * FROM wasm_get_exported_functions(current_instance_id)) - LOOP - IF exported_function.input_arity > 10 THEN - RAISE EXCEPTION 'WebAssembly exported function `%` has an arity greater than 10, which is not supported yet.', exported_function.funcname; - END IF; - - exported_function_generated_inputs := ''; - exported_function_generated_outputs := ''; - - FOR nth IN 1..exported_function.input_arity LOOP - exported_function_generated_inputs := exported_function_generated_inputs || format(', CAST($%s AS int8)', nth); - END LOOP; - - IF length(exported_function.outputs) > 0 THEN - exported_function_generated_outputs := exported_function.outputs; - ELSE - exported_function_generated_outputs := 'integer'; - END IF; - - EXECUTE format( - 'CREATE OR REPLACE FUNCTION %I_%I(%3$s) RETURNS %5$s AS $F$' || - 'DECLARE' || - ' output %5$s;' || - 'BEGIN' || - ' SELECT wasm_invoke_function_%4$s(%6$L, %2$L%7$s) INTO STRICT output;' || - ' RETURN output;' || - 'END;' || - '$F$ LANGUAGE plpgsql;', - namespace, -- 1 - exported_function.funcname, -- 2 - exported_function.inputs, -- 3 - exported_function.input_arity, -- 4 - exported_function_generated_outputs, -- 5 - current_instance_id, -- 6 - exported_function_generated_inputs -- 7 - ); - END LOOP; - - RETURN current_instance_id; -END; $$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/wasm/wasm_executor.cpp b/wasm/wasm_executor.cpp index 73b4126..4daffef 100644 --- a/wasm/wasm_executor.cpp +++ b/wasm/wasm_executor.cpp @@ -8,12 +8,10 @@ #include #include -#include "wasm.h" -#include "wasmtime.h" +#include PG_MODULE_MAGIC; -extern "C" Datum wasm_create_instance_wat(PG_FUNCTION_ARGS); extern "C" Datum wasm_create_instance(PG_FUNCTION_ARGS); extern "C" Datum wasm_get_instances(PG_FUNCTION_ARGS); extern "C" Datum wasm_get_exported_functions(PG_FUNCTION_ARGS); @@ -29,27 +27,15 @@ extern "C" Datum wasm_invoke_function_8(PG_FUNCTION_ARGS); extern "C" Datum wasm_invoke_function_9(PG_FUNCTION_ARGS); extern "C" Datum wasm_invoke_function_10(PG_FUNCTION_ARGS); -typedef struct WasmInstInfo { - wasm_engine_t *wasm_engine; - - wasmtime_store_t *wasm_store; - - wasmtime_module_t *wasm_module; - - wasmtime_instance_t instance; - - std::string wasm_file; -} WasmInstInfo; - typedef struct TupleInstanceState { TupleDesc tupd; - std::map::iterator currindex; - std::map::iterator lastindex; + std::map::iterator currindex; + std::map::iterator lastindex; } TupleInstanceState; typedef struct WasmFuncInfo { std::string funcname; - std::string inputs; + std::vector inputs; std::string outputs; } WasmFuncInfo; @@ -59,15 +45,19 @@ typedef struct TupleFuncState { std::vector::iterator lastindex; } TupleFuncState; -// Store the wasm instance info globally -static std::map instances; +#define BUF_LEN 256 +#define MAX_PARAMS 10 +#define MAX_RETURNS 1 + +// Store the wasm file info globally +static std::map instances; // Store the wasm exported function info globally static std::map*> exported_functions; -static WasmInstInfo* find_instance(int64 instanceid) +static std::string find_wasm_file(int64 instanceid) { - std::map::iterator itor = instances.begin(); + std::map::iterator itor = instances.begin(); while (itor != instances.end()) { if (itor->first == instanceid) { return itor->second; @@ -75,7 +65,7 @@ static WasmInstInfo* find_instance(int64 instanceid) itor++; } elog(DEBUG1, "wasm_executor: not find instance info for instanceid %ld", instanceid); - return NULL; + return ""; } static std::vector* find_exported_func_list(int64 instanceid) @@ -91,87 +81,76 @@ static std::vector* find_exported_func_list(int64 instanceid) return NULL; } -static int64 generate_uuid(Datum input) +static WasmFuncInfo* find_exported_func(int64 instanceid, std::string funcname) { - Datum uuid = DirectFunctionCall1(hashtext, input); - return DatumGetInt64(uuid); + std::vector* functions = find_exported_func_list(instanceid); + if (functions == NULL) { + ereport(ERROR, (errmsg("wasm_executor: function infos of instance %ld is not find", instanceid))); + } + for (std::vector::iterator curr = functions.begin(); curr != functions.end(); curr++) { + if ((*curr)->funcname == funcname) { + return *curr; + } + } + + ereport(ERROR, (errmsg("wasm_executor: function %s not exist in instance %ld ", funcname.c_str(), instanceid))); } -static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) +static int64 generate_uuid(Datum input) { - wasm_byte_vec_t error_message; - if (error != NULL) { - wasmtime_error_message(error, &error_message); - } else { - wasm_trap_message(trap, &error_message); - } - char *messaga_info = pstrdup(error_message.data); - wasm_byte_vec_delete(&error_message); - - ereport(ERROR, (errmsg("wasm_executor: %s:%s", message, messaga_info))); + Datum uuid = DirectFunctionCall1(hashtext, input); + return DatumGetInt64(uuid); } static int64 wasm_invoke_function(char *instanceid_str, char* funcname, std::vector &args) { int64 instanceid = atol(instanceid_str); - WasmInstInfo* instanceinfo = find_instance(instanceid); - if (instanceinfo == NULL) { + std::string wasm_file = find_wasm_file(instanceid); + if (wasm_file == "") { ereport(ERROR, (errmsg("wasm_executor: instance with id %ld is not find", instanceid))); } - - wasmtime_extern_t wasm_extern; - wasmtime_context_t* context = wasmtime_store_context(instanceinfo->wasm_store); - int funcnamelen = strlen(funcname); - bool ok = wasmtime_instance_export_get(context, &instanceinfo->instance, funcname, funcnamelen, &wasm_extern); - if (!ok || wasm_extern.kind != WASMTIME_EXTERN_FUNC) { - ereport(ERROR, (errmsg("wasm_executor: not find the exported function with name(%s) and namelen(%d)", - funcname, funcnamelen))); - } + WasmFuncInfo *funcinfo = find_exported_func(instanceid, funcname); - wasmtime_func_t wasm_func = wasm_extern.of.func; - wasm_functype_t* wasm_functype = wasmtime_func_type(context, &wasm_func); - - const wasm_valtype_vec_t* wasm_params = wasm_functype_params(wasm_functype); - if (wasm_params->size != args.size()) { - ereport(ERROR, (errmsg("wasm_executor: function parameters not matched"))); - } + WasmEdge_ConfigureContext *config_context = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(config_context, WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *vm_conext = WasmEdge_VMCreate(config_context, NULL); - wasmtime_val_t call_params[args.size()]; - for (unsigned int i = 0; i < wasm_params->size; ++i) { - if (wasm_valtype_kind(wasm_params->data[i]) == WASM_I32) { - call_params[i].kind = WASMTIME_I32; - call_params[i].of.i32 = args[i]; - } else if (wasm_valtype_kind(wasm_params->data[i]) == WASM_I64) { - call_params[i].kind = WASMTIME_I64; - call_params[i].of.i64 = args[i]; + WasmEdge_Value params[args.size()]; + for (int i = 0; i < args.size(); ++i) { + if (funcinfo->inputs[i] == "integer") { + params[i] = WasmEdge_ValueGenI32(args[i]); } else { - ereport(ERROR, (errmsg("wasm_executor: not support the value type(%d) for now", wasm_valtype_kind(wasm_params->data[i])))); + params[i] = WasmEdge_ValueGenI64(args[i]); } } - wasmtime_val_t results[1]; - wasm_trap_t *wasm_trap = NULL; - wasmtime_error_t *error_msg = wasmtime_func_call(context, &wasm_func, call_params, args.size(), results, 1, &wasm_trap); - if (error_msg != NULL || wasm_trap != NULL) { - exit_with_error("failed to call function", error_msg, wasm_trap); - } - + WasmEdge_Value result[1]; + WasmEdge_String wasm_func = WasmEdge_StringCreateByCString(funcname); + WasmEdge_Result ret = WasmEdge_VMRunWasmFromFile(vm_conext, wasm_file, wasm_func, params, args.size(), result, 1); + if (!WasmEdge_ResultOK(ret)) { + WasmEdge_VMDelete(vm_conext); + WasmEdge_ConfigureDelete(config_context); + WasmEdge_StringDelete(FuncName); + ereport(ERROR, (errmsg("wasm_executor: call func %s failed", funcname))); + } int64 ret_val = 0; - if (results[0].kind == WASMTIME_I32) { - ret_val = results[0].of.i32; - } else if (results[0].kind == WASMTIME_I64) { - ret_val = results[0].of.i64; + if (funcinfo->outputs == "integer") { + ret_val = WasmEdge_ValueGetI32(result[0]); } else { - ereport(ERROR, (errmsg("wasm_executor: the function(%s) return type(%d) not supported", funcname, results[0].kind))); + ret_val = WasmEdge_ValueGetI64(result[0]); } + /* Resources deallocations. */ + WasmEdge_VMDelete(vm_conext); + WasmEdge_ConfigureDelete(config_context); + WasmEdge_StringDelete(FuncName); return ret_val; } static void wasm_export_funcs_query(int64 instanceid, TupleFuncState* inter_call_data) { - WasmInstInfo* instanceinfo = find_instance(instanceid); - if (instanceinfo == NULL) { + std::string wasm_file = find_wasm_file(instanceid); + if (wasm_file == "") { ereport(ERROR, (errmsg("wasm_executor: instance with id %ld is not find", instanceid))); } @@ -185,131 +164,80 @@ static void wasm_export_funcs_query(int64 instanceid, TupleFuncState* inter_call functions = new(std::nothrow)std::vector; exported_functions.insert(std::pair*>(instanceid, functions)); - - wasmtime_context_t* context = wasmtime_store_context(instanceinfo->wasm_store); - wasmtime_instance_t& instance = instanceinfo->instance; - - char *export_name = NULL; - size_t namelen; - wasmtime_extern_t wasm_extern; - int index = 0; - while (wasmtime_instance_export_nth(context, &instance, index, &export_name, &namelen, &wasm_extern)) { - if (wasm_extern.kind == WASMTIME_EXTERN_FUNC) { - wasmtime_func_t wasm_func = wasm_extern.of.func; - wasm_functype_t* wasm_functype = wasmtime_func_type(context, &wasm_func); - WasmFuncInfo *funcinfo = new(std::nothrow)WasmFuncInfo(); - - const wasm_valtype_vec_t* wasm_results = wasm_functype_results(wasm_functype); - if (wasm_results->size != 1) { - ereport(ERROR, (errmsg("wasm_executor: only support the functions who will return exactly one result value for now"))); - } - //TODO:support more data types - if (wasm_valtype_kind(wasm_results->data[0]) == WASM_I32) { - funcinfo->outputs = "integer"; - } else if (wasm_valtype_kind(wasm_results->data[0]) == WASM_I64) { - funcinfo->outputs = "bigint"; - } else { - ereport(ERROR, (errmsg("wasm_executor: not support the value type(%d) for now", wasm_valtype_kind(wasm_results->data[0])))); - } - - const wasm_valtype_vec_t* wasm_params = wasm_functype_params(wasm_functype); - if (wasm_params->size > 10) { - ereport(ERROR, (errmsg("wasm_executor: do not support function with 10 more parameters"))); - } - - for (unsigned int i = 0; i < wasm_params->size; ++i) { - if (wasm_valtype_kind(wasm_params->data[i]) == WASM_I32) { - funcinfo->inputs += "integer,"; - } else if (wasm_valtype_kind(wasm_params->data[i]) == WASM_I64) { - funcinfo->inputs += "bigint,"; - } else { - ereport(ERROR, (errmsg("wasm_executor: not support the value type(%d) for now", wasm_valtype_kind(wasm_params->data[i])))); - } - } - if (funcinfo->inputs.length() > 0) { - funcinfo->inputs.pop_back(); - } - - funcinfo->funcname = std::string(export_name, namelen); - functions->push_back(funcinfo); - } - index++; - } - inter_call_data->currindex = functions->begin(); - inter_call_data->lastindex = functions->end(); - elog(DEBUG1, "wasm_executor:init exported func info for instanceid %ld", instanceid); -} + WasmEdge_StoreContext *store_cxt = WasmEdge_StoreCreate(); + WasmEdge_VMContext *vm_cxt = WasmEdge_VMCreate(NULL, StoreCxt); -PG_FUNCTION_INFO_V1(wasm_create_instance_wat); -Datum wasm_create_instance_wat(PG_FUNCTION_ARGS) -{ - int64 uuid = generate_uuid(PG_GETARG_DATUM(0)); - text *arg = PG_GETARG_TEXT_P(0); - char* filepath = text_to_cstring(arg); - canonicalize_path(filepath); - - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("wasm_executor: must be system admin to create wasm instance")))); + WasmEdge_VMLoadWasmFromFile(vm_cxt, wasm_file.c_str()); + WasmEdge_VMValidate(vm_cxt); + WasmEdge_VMInstantiate(vm_cxt); - WasmInstInfo *instinfo = find_instance(uuid); - if (instinfo != NULL) { - ereport(NOTICE, (errmsg("wasm_executor: instance already created for %s", filepath))); - return UInt32GetDatum(uuid); - } - - instinfo = new (std::nothrow)WasmInstInfo(); - - instinfo->wasm_engine = wasm_engine_new(); - if (instinfo->wasm_engine == NULL) { - ereport(ERROR, (errmsg("wasm_executor: unable to create new wasm engine"))); - } - instinfo->wasm_store = wasmtime_store_new(instinfo->wasm_engine, NULL, NULL); - if (instinfo->wasm_store == NULL) { - ereport(ERROR, (errmsg("wasm_executor: unable to create new wasmtime storage"))); - } - wasmtime_context_t *context = wasmtime_store_context(instinfo->wasm_store); + uint32_t func_num = WasmEdge_VMGetFunctionListLength(vm_cxt); - wasm_byte_vec_t wat_bytes; - FILE *file = fopen(filepath, "r"); - if (file == NULL) { - ereport(ERROR, (errmsg("wasm_executor: unable to open file %s", filepath))); - } + WasmEdge_String func_name_list[BUF_LEN]; + WasmEdge_FunctionTypeContext *func_type_list[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t rel_func_num = WasmEdge_VMGetFunctionList(_cxt, func_name_list, func_type_list, BUF_LEN); + + for (int32 i = 0; i < rel_func_num && i < BUF_LEN; ++i) { + char tmp_buffer[BUF_LEN]; + uint32_t func_name_len = WasmEdge_StringCopy(func_name_list[i], tmp_buffer, sizeof(tmp_buffer)); + elog(DEBUG, "wasm_executor: exported function string length: %u, name: %s\n", func_name_len, tmp_buffer); + + uint32_t param_nums = WasmEdge_FunctionTypeGetParametersLength(func_type_list[i]); + if (param_nums > MAX_PARAMS) { + WasmEdge_StoreDelete(store_cxt); + WasmEdge_VMDelete(vm_cxt); + ereport(ERROR, (errmsg("wasm_executor: func %s has more than 10 params which not support", tmp_buffer))); + } - fseek(file, 0L, SEEK_END); - size_t file_size = ftell(file); - wasm_byte_vec_new_uninitialized(&wat_bytes, file_size); - fseek(file, 0L, SEEK_SET); - int ret = fread(wat_bytes.data, file_size, 1, file); - fclose(file); - if (ret != 1) { - ereport(ERROR, (errmsg("wasm_executor: failed to load moude from %s", filepath))); - } + uint32_t return_num = WasmEdge_FunctionTypeGetReturnsLength(func_type_list[i]); + if (return_num > MAX_RETURNS) { + WasmEdge_StoreDelete(store_cxt); + WasmEdge_VMDelete(vm_cxt); + ereport(ERROR, (errmsg("wasm_executor: func %s has more than 1 return value which not support", tmp_buffer))); + } - wasm_byte_vec_t wasm_bytes; - wasmtime_error_t *error_msg = wasmtime_wat2wasm(wat_bytes.data, wat_bytes.size, &wasm_bytes); - if (error_msg != NULL) { - exit_with_error("failed to parse wat", error_msg, NULL); - } - wasm_byte_vec_delete(&wat_bytes); + WasmFuncInfo *funcinfo = new(std::nothrow)WasmFuncInfo(); - error_msg = wasmtime_module_new(instinfo->wasm_engine, (uint8 *)wasm_bytes.data, wasm_bytes.size, &instinfo->wasm_module); - if (instinfo->wasm_module == NULL) { - exit_with_error("failed to compile module", error_msg, NULL); - } - wasm_byte_vec_delete(&wasm_bytes); + enum WasmEdge_ValType param_buffer[10]; // we allow max 10 parameters + param_nums = WasmEdge_FunctionTypeGetParameters(func_type_list[i], param_buffer, 10); + for (int32 j = 0; j < param_nums; ++j) { + if (param_buffer[j] == WasmEdge_ValType_I32) { + funcinfo->inputs.push_back("integer"); + } else if (param_buffer[j] == WasmEdge_ValType_I64) { + funcinfo->inputs.push_back("bigint"); + } else { + WasmEdge_StoreDelete(store_cxt); + WasmEdge_VMDelete(vm_cxt); + ereport(ERROR, (errmsg("wasm_executor: not support the value type(%d) for now", param_buffer[j]))); + } + } + + return_num = WasmEdge_FunctionTypeGetReturns(func_type_list[i], param_buffer, 10); + if (param_buffer[0] == WasmEdge_ValType_I32) { + funcinfo->outputs = "integer"; + } else if (param_buffer[0] == WasmEdge_ValType_I64) { + funcinfo->outputs = "bigint"; + } else { + WasmEdge_StoreDelete(store_cxt); + WasmEdge_VMDelete(vm_cxt); + ereport(ERROR, (errmsg("wasm_executor: not support the value type(%d) for now", param_buffer[0]))); + } - wasm_trap_t *wasm_trap = NULL; - error_msg = wasmtime_instance_new(context, instinfo->wasm_module, NULL, 0, &instinfo->instance, &wasm_trap); - if (error_msg != NULL || wasm_trap != NULL) { - exit_with_error("failed to create wasm instance", error_msg, wasm_trap); + funcinfo->funcname = std::string(export_name, namelen); + functions->push_back(funcinfo); } - instinfo->wasm_file = filepath; - instances.insert(std::pair(uuid, instinfo)); + WasmEdge_StoreDelete(store_cxt); + WasmEdge_VMDelete(vm_cxt); - return Int64GetDatum(uuid); + inter_call_data->currindex = functions->begin(); + inter_call_data->lastindex = functions->end(); + elog(DEBUG1, "wasm_executor:init exported func info for instanceid %ld", instanceid); } PG_FUNCTION_INFO_V1(wasm_create_instance); @@ -324,55 +252,34 @@ Datum wasm_create_instance(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("wasm_executor: must be system admin to create wasm instance")))); - WasmInstInfo *instinfo = find_instance(uuid); - if (instinfo != NULL) { + std::string wasm_file = find_wasm_file(uuid); + if (wasm_file != "") { ereport(NOTICE, (errmsg("wasm_executor: instance already created for %s", filepath))); return UInt32GetDatum(uuid); } - - instinfo = new (std::nothrow)WasmInstInfo(); - - instinfo->wasm_engine = wasm_engine_new(); - if (instinfo->wasm_engine == NULL) { - ereport(ERROR, (errmsg("wasm_executor: unable to create new wasm engine"))); - } - instinfo->wasm_store = wasmtime_store_new(instinfo->wasm_engine, NULL, NULL); - if (instinfo->wasm_store == NULL) { - ereport(ERROR, (errmsg("wasm_executor: unable to create new wasmtime storage"))); - } - wasmtime_context_t *context = wasmtime_store_context(instinfo->wasm_store); - wasm_byte_vec_t wasm_bytes; - FILE *file = fopen(filepath, "rb"); - if (file == NULL) { - ereport(ERROR, (errmsg("wasm_executor: unable to open file %s", filepath))); - } - - fseek(file, 0L, SEEK_END); - size_t file_size = ftell(file); - wasm_byte_vec_new_uninitialized(&wasm_bytes, file_size); - fseek(file, 0L, SEEK_SET); - int ret = fread(wasm_bytes.data, file_size, 1, file); - fclose(file); - if (ret != 1) { - ereport(ERROR, (errmsg("wasm_executor: failed to load moude from %s", filepath))); + WasmEdge_ConfigureContext *config_context = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(config_context, WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *vm_cxt = WasmEdge_VMCreate(config_context, NULL); + + WasmEdge_Result result = WasmEdge_VMLoadWasmFromFile(vm_cxt, filepath); + if (!WasmEdge_ResultOK(result)) { + WasmEdge_VMDelete(vm_cxt); + WasmEdge_ConfigureDelete(config_context); + ereport(ERROR, (errmsg("wasm_executor: failed to load %s", filepath))); } - wasmtime_error_t *error_msg = wasmtime_module_new(instinfo->wasm_engine, (uint8 *)wasm_bytes.data, wasm_bytes.size, &instinfo->wasm_module); - if (instinfo->wasm_module == NULL) { - exit_with_error("failed to compile module", error_msg, NULL); + result = WasmEdge_VMValidate(vm_cxt); + if (!WasmEdge_ResultOK(result)) { + WasmEdge_VMDelete(vm_cxt); + WasmEdge_ConfigureDelete(config_context); + ereport(ERROR, (errmsg("wasm_executor: wasm file validation failed %s", WasmEdge_ResultGetMessage(result)))); } - wasm_byte_vec_delete(&wasm_bytes); - - wasm_trap_t *wasm_trap = NULL; - error_msg = wasmtime_instance_new(context, instinfo->wasm_module, NULL, 0, &instinfo->instance, &wasm_trap); - if (error_msg != NULL || wasm_trap != NULL) { - exit_with_error("failed to create wasm instance", error_msg, wasm_trap); - } - - instinfo->wasm_file = filepath; - instances.insert(std::pair(uuid, instinfo)); + wasm_file = filepath; + instances.insert(std::pair(uuid, wasm_file)); + WasmEdge_VMDelete(vm_cxt); + WasmEdge_ConfigureDelete(config_context); return Int64GetDatum(uuid); } @@ -413,9 +320,9 @@ Datum wasm_get_instances(PG_FUNCTION_ARGS) errno_t rc = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); securec_check_c(rc, "\0", "\0"); - WasmInstInfo *instanceinfo = inter_call_data->currindex->second; + std::string wasm_file = inter_call_data->currindex->second; values[0] = Int64GetDatum(inter_call_data->currindex->first); - values[1] = CStringGetTextDatum(instanceinfo->wasm_file.c_str()); + values[1] = CStringGetTextDatum(wasm_file.c_str()); /* Build and return the result tuple. */ resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); @@ -466,7 +373,15 @@ Datum wasm_get_exported_functions(PG_FUNCTION_ARGS) WasmFuncInfo *funcinfo = *inter_call_data->currindex; values[0] = CStringGetTextDatum(funcinfo->funcname.c_str()); - values[1] = CStringGetTextDatum(funcinfo->inputs.c_str()); + String inputs; + for (std::vector::iterator curr = funcinfo->inputs.begin(); curr != funcinfo.end(); curr++) { + inputs += *curr; + inputs += ","; + } + if (inputs.length() > 0) { + inputs.pop_back(); + } + values[1] = CStringGetTextDatum(inputs.c_str()); values[2] = CStringGetTextDatum(funcinfo->outputs.c_str()); /* Build and return the result tuple. */ -- Gitee From 4648da04a3b87d06c9818dbae95909fe30ee4f1d Mon Sep 17 00:00:00 2001 From: Nelson-He Date: Sat, 12 Nov 2022 23:05:18 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wasm/examples/fib.wasm | Bin 0 -> 164 bytes wasm/wasm_executor.cpp | 36 +++++++++++++++++------------------- 2 files changed, 17 insertions(+), 19 deletions(-) create mode 100644 wasm/examples/fib.wasm diff --git a/wasm/examples/fib.wasm b/wasm/examples/fib.wasm new file mode 100644 index 0000000000000000000000000000000000000000..cbbd88bb8d4f6c82376deb46084f043ff8b4b80e GIT binary patch literal 164 zcmXwuT?&Fg7)9@$&x{LN?DI=)c#8AZ+Wlf4mg5bJyD6UEzmX5II-*r+0N%2{)If=sRDQ4G@w5N1~UUZWcK$B{ekaZN<::iterator currindex; - std::map::iterator lastindex; + std::map::iterator lastindex; } TupleInstanceState; typedef struct WasmFuncInfo { std::string funcname; - std::vector inputs; + std::vector inputs; std::string outputs; } WasmFuncInfo; @@ -87,13 +87,14 @@ static WasmFuncInfo* find_exported_func(int64 instanceid, std::string funcname) if (functions == NULL) { ereport(ERROR, (errmsg("wasm_executor: function infos of instance %ld is not find", instanceid))); } - for (std::vector::iterator curr = functions.begin(); curr != functions.end(); curr++) { + for (std::vector::iterator curr = functions->begin(); curr != functions->end(); curr++) { if ((*curr)->funcname == funcname) { return *curr; } } ereport(ERROR, (errmsg("wasm_executor: function %s not exist in instance %ld ", funcname.c_str(), instanceid))); + return NULL; } static int64 generate_uuid(Datum input) @@ -116,7 +117,7 @@ static int64 wasm_invoke_function(char *instanceid_str, char* funcname, std::vec WasmEdge_VMContext *vm_conext = WasmEdge_VMCreate(config_context, NULL); WasmEdge_Value params[args.size()]; - for (int i = 0; i < args.size(); ++i) { + for (unsigned int i = 0; i < args.size(); ++i) { if (funcinfo->inputs[i] == "integer") { params[i] = WasmEdge_ValueGenI32(args[i]); } else { @@ -126,11 +127,11 @@ static int64 wasm_invoke_function(char *instanceid_str, char* funcname, std::vec WasmEdge_Value result[1]; WasmEdge_String wasm_func = WasmEdge_StringCreateByCString(funcname); - WasmEdge_Result ret = WasmEdge_VMRunWasmFromFile(vm_conext, wasm_file, wasm_func, params, args.size(), result, 1); + WasmEdge_Result ret = WasmEdge_VMRunWasmFromFile(vm_conext, wasm_file.c_str(), wasm_func, params, args.size(), result, 1); if (!WasmEdge_ResultOK(ret)) { WasmEdge_VMDelete(vm_conext); WasmEdge_ConfigureDelete(config_context); - WasmEdge_StringDelete(FuncName); + WasmEdge_StringDelete(wasm_func); ereport(ERROR, (errmsg("wasm_executor: call func %s failed", funcname))); } int64 ret_val = 0; @@ -142,7 +143,7 @@ static int64 wasm_invoke_function(char *instanceid_str, char* funcname, std::vec /* Resources deallocations. */ WasmEdge_VMDelete(vm_conext); WasmEdge_ConfigureDelete(config_context); - WasmEdge_StringDelete(FuncName); + WasmEdge_StringDelete(wasm_func); return ret_val; } @@ -166,26 +167,23 @@ static void wasm_export_funcs_query(int64 instanceid, TupleFuncState* inter_call exported_functions.insert(std::pair*>(instanceid, functions)); WasmEdge_StoreContext *store_cxt = WasmEdge_StoreCreate(); - WasmEdge_VMContext *vm_cxt = WasmEdge_VMCreate(NULL, StoreCxt); + WasmEdge_VMContext *vm_cxt = WasmEdge_VMCreate(NULL, store_cxt); WasmEdge_VMLoadWasmFromFile(vm_cxt, wasm_file.c_str()); WasmEdge_VMValidate(vm_cxt); WasmEdge_VMInstantiate(vm_cxt); - - uint32_t func_num = WasmEdge_VMGetFunctionListLength(vm_cxt); WasmEdge_String func_name_list[BUF_LEN]; - WasmEdge_FunctionTypeContext *func_type_list[BUF_LEN]; + const WasmEdge_FunctionTypeContext *func_type_list[BUF_LEN]; /* * If the list length is larger than the buffer length, the overflowed data * will be discarded. */ - uint32_t rel_func_num = WasmEdge_VMGetFunctionList(_cxt, func_name_list, func_type_list, BUF_LEN); - - for (int32 i = 0; i < rel_func_num && i < BUF_LEN; ++i) { + uint32_t rel_func_num = WasmEdge_VMGetFunctionList(vm_cxt, func_name_list, func_type_list, BUF_LEN); + for (unsigned int i = 0; i < rel_func_num && i < BUF_LEN; ++i) { char tmp_buffer[BUF_LEN]; uint32_t func_name_len = WasmEdge_StringCopy(func_name_list[i], tmp_buffer, sizeof(tmp_buffer)); - elog(DEBUG, "wasm_executor: exported function string length: %u, name: %s\n", func_name_len, tmp_buffer); + elog(DEBUG1, "wasm_executor: exported function string length: %u, name: %s\n", func_name_len, tmp_buffer); uint32_t param_nums = WasmEdge_FunctionTypeGetParametersLength(func_type_list[i]); if (param_nums > MAX_PARAMS) { @@ -205,7 +203,7 @@ static void wasm_export_funcs_query(int64 instanceid, TupleFuncState* inter_call enum WasmEdge_ValType param_buffer[10]; // we allow max 10 parameters param_nums = WasmEdge_FunctionTypeGetParameters(func_type_list[i], param_buffer, 10); - for (int32 j = 0; j < param_nums; ++j) { + for (unsigned int j = 0; j < param_nums; ++j) { if (param_buffer[j] == WasmEdge_ValType_I32) { funcinfo->inputs.push_back("integer"); } else if (param_buffer[j] == WasmEdge_ValType_I64) { @@ -228,7 +226,7 @@ static void wasm_export_funcs_query(int64 instanceid, TupleFuncState* inter_call ereport(ERROR, (errmsg("wasm_executor: not support the value type(%d) for now", param_buffer[0]))); } - funcinfo->funcname = std::string(export_name, namelen); + funcinfo->funcname = std::string(tmp_buffer, func_name_len); functions->push_back(funcinfo); } @@ -373,8 +371,8 @@ Datum wasm_get_exported_functions(PG_FUNCTION_ARGS) WasmFuncInfo *funcinfo = *inter_call_data->currindex; values[0] = CStringGetTextDatum(funcinfo->funcname.c_str()); - String inputs; - for (std::vector::iterator curr = funcinfo->inputs.begin(); curr != funcinfo.end(); curr++) { + std::string inputs; + for (std::vector::iterator curr = funcinfo->inputs.begin(); curr != funcinfo->inputs.end(); curr++) { inputs += *curr; inputs += ","; } -- Gitee From 217c481a1e7f63c48392d34881a45aa6fbe052ca Mon Sep 17 00:00:00 2001 From: Nelson-He Date: Mon, 14 Nov 2022 09:57:11 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8Ddockerfile=E4=B8=AD?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2wasmedge=E5=90=8E=E5=87=BA=E7=8E=B0=E7=9A=84?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 +++++++--------- docker/Dockerfile | 8 ++++---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b19a7ec..8f0cf0c 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ You can install the wasmedge as simple as Refer to [https://wasmedge.org/book/en/quick_start/install.html](https://wasmedge.org/book/en/quick_start/install.html) for more details. After that, run `CREATE EXTENSION wasm_executor` in a -openGauss shell. Two new functions will appear: `wasm_new_instance` and `wasm_new_instance_wat`; They must be +openGauss shell. One new function will appear: `wasm_new_instance`; It must be called with the absolute path to the shared library. It looks like this: @@ -36,7 +36,7 @@ this: $ # Build the shared library. $ make -$ # Install the extension in the Postgres opengauss +$ # Install the extension in the opengauss $ make install $ # Activate and initialize the extension. @@ -122,11 +122,11 @@ To get your hands on openGauss with wasm, we recommend using the Docker image. Download the docker image firstlly. ```shell -docker pull heguofeng/opengauss-wasm:1.0.0 +docker pull opengaussofficial/opengauss-wasmedge:0.1.0 ``` Then run it. ```shell -docker run -it heguofeng/opengauss-wasm:1.0.0 bash +docker run -it opengaussofficial/opengauss-wasmedge:0.1.0 bash ``` And enjoy it. @@ -135,8 +135,7 @@ And enjoy it. The extension provides two ways to initilize a WebAssembly instance. As you can see from the functions name show above, one way is to use `wasm_new_instance` from -.wasm file compiled from other languages, the other way is to use `wasm_new_instance_wat` -from .wat file, which is the text format of wasm. +.wasm file compiled from other languages. And, the extension provides two tables, gathered together in the `wasm` foreign schema: @@ -147,8 +146,8 @@ the `wasm` foreign schema: * `wasm.exported_functions` is a table with the `instanceid`, `funcname`, `inputs` and `output` columns, respectively for the instance ID of the exported function, its name, its input types - (already formatted for Postgres), and its output types (already - formatted for Postgres). + (already formatted for openGauss), and its output types (already + formatted for openGauss). Let's see: @@ -159,7 +158,6 @@ SELECT * FROM wasm.instances; -- id | wasm_file -- ---------------+------------------------------- -- 2785875771 | /absolute/path/to/sum.wasm --- 3780612139 | /absolute/path/to/gcd.wat -- (1 row) -- Select all exported functions for a specific instance. diff --git a/docker/Dockerfile b/docker/Dockerfile index 4313d6d..27da78b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -24,19 +24,19 @@ USER opengauss:opengauss RUN cp -f /home/opengauss/bashrc /home/opengauss/.bashrc && \ cd /home/opengauss && \ if [ "`uname -m`" == "x86_64" ]; then \ - wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/binarylibs/openGauss-third_party_binarylibs_openEuler_x86_64.tar.gz -O openGauss_third.tar.gz && \ + wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/binarylibs/openGauss-third_party_binarylibs_openEuler_x86_64.tar.gz -O openGauss_third.tar.gz; \ else \ - wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/binarylibs/openGauss-third_party_binarylibs_openEuler_arm.tar.gz -O openGauss_third.tar.gz && \ + wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/binarylibs/openGauss-third_party_binarylibs_openEuler_arm.tar.gz -O openGauss_third.tar.gz; \ fi && \ tar -xf openGauss_third.tar.gz && mv openGauss-third_party_binarylibs* binarylibs && rm -f openGauss_third.tar.gz && \ - curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.11.2 && source /home/opengauss/.wasmedge/env \ + curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.11.2 && source /home/opengauss/.wasmedge/env && \ source /home/opengauss/.bashrc && git clone https://gitee.com/Nelson-He/openGauss-server.git && cd openGauss-server && \ ./configure --gcc-version=7.3.0 CC=g++ CFLAGS='-O2' \ --prefix=$GAUSSHOME --3rd=$BINARYLIBS \ --enable-cassert --enable-thread-safety \ --without-readline --without-zlib && \ make -sj 8 && make install -sj 8 && \ - cd /home/opengauss && git clone https://gitee.com/Nelson-He/openGauss-wasm.git && \ + cd /home/opengauss && git clone https://gitee.com/Nelson-He/openGauss-wasm.git -b wasmedge && \ cp -rf openGauss-wasm/wasm openGauss-server/contrib && \ cd openGauss-server/contrib/wasm && make && make install && \ cd /home/opengauss && \ -- Gitee