This is an automated email from the ASF dual-hosted git repository. kichan pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push: new ab0a572882 Remove reference to WAVM (#10147) ab0a572882 is described below commit ab0a572882377165109fecc6f818154bdacb4bca Author: Kit Chan <kic...@apache.org> AuthorDate: Fri Aug 4 09:47:50 2023 -0700 Remove reference to WAVM (#10147) --- configure.ac | 3 - doc/admin-guide/plugins/wasm.en.rst | 15 +-- plugins/experimental/wasm/Makefile.inc | 2 + .../wasm/lib/include/proxy-wasm/context.h | 6 +- .../wasm/lib/include/proxy-wasm/wasm.h | 1 + plugins/experimental/wasm/lib/src/context.cc | 6 ++ plugins/experimental/wasm/lib/src/hash.cc | 54 ++++++++++ plugins/experimental/wasm/lib/src/hash.h | 27 +++++ plugins/experimental/wasm/lib/src/wamr/wamr.cc | 28 +++-- plugins/experimental/wasm/lib/src/wasm.cc | 116 +++++++++++++++------ 10 files changed, 201 insertions(+), 57 deletions(-) diff --git a/configure.ac b/configure.ac index 73d8a2c587..91445116c7 100644 --- a/configure.ac +++ b/configure.ac @@ -1441,9 +1441,6 @@ AC_SUBST(use_quic) AC_SUBST(has_quiche) AM_CONDITIONAL([ENABLE_QUIC], [test "x$enable_quic" = "xyes"]) -# Check for optional WAVM library -TS_CHECK_WAVM - # # Enable experimental/uri_signing plugin # This is here, instead of above, because it needs to know if PCRE is available. diff --git a/doc/admin-guide/plugins/wasm.en.rst b/doc/admin-guide/plugins/wasm.en.rst index cf92af6157..ad07543c5a 100644 --- a/doc/admin-guide/plugins/wasm.en.rst +++ b/doc/admin-guide/plugins/wasm.en.rst @@ -36,7 +36,7 @@ How it Works The plugin uses the library and header files from the Proxy-Wasm project. -* https://github.com/proxy-wasm/proxy-wasm-cpp-host/tree/72ce32f7b11f9190edf874028255e1309e41690f +* https://github.com/proxy-wasm/proxy-wasm-cpp-host/tree/b7e690703c7f26707438a2f1ebd7c197bc8f0296 * https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/tree/fd0be8405db25de0264bdb78fae3a82668c03782 Proxy-Wasm in turn uses an underlying WebAssembly runtime to execute the WebAssembly module. (Currently only WAMR and @@ -56,9 +56,9 @@ Compiling the Plugin :: - wget https://github.com/bytecodealliance/wasm-micro-runtime/archive/c3d66f916ef8093e5c8cacf3329ed968f807cf58.tar.gz - tar zxvf c3d66f916ef8093e5c8cacf3329ed968f807cf58.tar.gz - cd wasm-micro-runtime-c3d66f916ef8093e5c8cacf3329ed968f807cf58 + wget https://github.com/bytecodealliance/wasm-micro-runtime/archive/refs/tags/WAMR-1.2.1.tar.gz + tar zxvf WAMR-1.2.1.tar.gz + cd wasm-micro-runtime-WAMR-1.2.1 cp core/iwasm/include/* /usr/local/include/ cd product-mini/platforms/linux mkdir build @@ -71,13 +71,14 @@ Compiling the Plugin :: - wget https://github.com/WasmEdge/WasmEdge/archive/refs/tags/proxy-wasm/0.11.2.tar.gz - tar zxvf 0.11.2.tar.gz - cd WasmEdge-proxy-wasm-0.11.2/utils + wget https://github.com/WasmEdge/WasmEdge/archive/refs/tags/proxy-wasm/0.13.1.tar.gz + tar zxvf 0.13.1.tar.gz + cd WasmEdge-proxy-wasm-0.13.1/utils ./install.sh * Copy contents from ~/.wasmedge/include to /usr/local/include * Copy contents from ~/.wasmedge/lib to /usr/local/lib +* The installation script will make changes to your environment variables. You can comment those out for now before compiling the plugin. **Configure ATS to compile with experimental plugins** diff --git a/plugins/experimental/wasm/Makefile.inc b/plugins/experimental/wasm/Makefile.inc index ebd92050c5..340df03896 100755 --- a/plugins/experimental/wasm/Makefile.inc +++ b/plugins/experimental/wasm/Makefile.inc @@ -55,6 +55,8 @@ experimental_wasm_wasm_la_SOURCES = \ experimental/wasm/lib/include/proxy-wasm/shared_data.h \ experimental/wasm/lib/src/shared_queue.cc \ experimental/wasm/lib/include/proxy-wasm/shared_queue.h \ + experimental/wasm/lib/src/hash.cc \ + experimental/wasm/lib/src/hash.h \ experimental/wasm/lib/src/signature_util.cc \ experimental/wasm/lib/include/proxy-wasm/signature_util.h \ experimental/wasm/lib/src/vm_id_handle.cc \ diff --git a/plugins/experimental/wasm/lib/include/proxy-wasm/context.h b/plugins/experimental/wasm/lib/include/proxy-wasm/context.h index 652b86b6e0..ab99cad70a 100644 --- a/plugins/experimental/wasm/lib/include/proxy-wasm/context.h +++ b/plugins/experimental/wasm/lib/include/proxy-wasm/context.h @@ -23,6 +23,7 @@ #include <map> #include <memory> #include <string> +#include <string_view> #include <vector> #include "include/proxy-wasm/context_interface.h" @@ -53,8 +54,7 @@ struct PluginBase { std::string_view key) : name_(std::string(name)), root_id_(std::string(root_id)), vm_id_(std::string(vm_id)), engine_(std::string(engine)), plugin_configuration_(plugin_configuration), - fail_open_(fail_open), - key_(root_id_ + "||" + plugin_configuration_ + "||" + std::string(key)), + fail_open_(fail_open), key_(makePluginKey(root_id, plugin_configuration, key)), log_prefix_(makeLogPrefix()) {} const std::string name_; @@ -69,6 +69,8 @@ struct PluginBase { private: std::string makeLogPrefix() const; + static std::string makePluginKey(std::string_view root_id, std::string_view plugin_configuration, + std::string_view key); const std::string key_; const std::string log_prefix_; diff --git a/plugins/experimental/wasm/lib/include/proxy-wasm/wasm.h b/plugins/experimental/wasm/lib/include/proxy-wasm/wasm.h index 23ed3c1da6..1a785a8f9a 100644 --- a/plugins/experimental/wasm/lib/include/proxy-wasm/wasm.h +++ b/plugins/experimental/wasm/lib/include/proxy-wasm/wasm.h @@ -337,6 +337,7 @@ public: protected: std::shared_ptr<WasmBase> wasm_base_; + std::unordered_map<std::string, bool> plugin_canary_cache_; }; std::string makeVmKey(std::string_view vm_id, std::string_view configuration, diff --git a/plugins/experimental/wasm/lib/src/context.cc b/plugins/experimental/wasm/lib/src/context.cc index 29037ae438..5353a52a54 100644 --- a/plugins/experimental/wasm/lib/src/context.cc +++ b/plugins/experimental/wasm/lib/src/context.cc @@ -22,6 +22,7 @@ #include "include/proxy-wasm/context.h" #include "include/proxy-wasm/wasm.h" +#include "src/hash.h" #include "src/shared_data.h" #include "src/shared_queue.h" @@ -85,6 +86,11 @@ std::string PluginBase::makeLogPrefix() const { return prefix; } +std::string PluginBase::makePluginKey(std::string_view root_id, + std::string_view plugin_configuration, std::string_view key) { + return Sha256String({root_id, "||", plugin_configuration, "||", key}); +} + ContextBase::ContextBase() : parent_context_(this) {} ContextBase::ContextBase(WasmBase *wasm) : wasm_(wasm), parent_context_(this) { diff --git a/plugins/experimental/wasm/lib/src/hash.cc b/plugins/experimental/wasm/lib/src/hash.cc new file mode 100644 index 0000000000..f2d1ded138 --- /dev/null +++ b/plugins/experimental/wasm/lib/src/hash.cc @@ -0,0 +1,54 @@ +// Copyright 2023 Google LLC +// +// Licensed 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. + +#include "src/hash.h" + +#include <string> +#include <vector> + +#include <openssl/sha.h> + +namespace proxy_wasm { + +namespace { + +std::string BytesToHex(const std::vector<uint8_t> &bytes) { + static const char *const hex = "0123456789ABCDEF"; + std::string result; + result.reserve(bytes.size() * 2); + for (auto byte : bytes) { + result.push_back(hex[byte >> 4]); + result.push_back(hex[byte & 0xf]); + } + return result; +} + +} // namespace + +std::vector<uint8_t> Sha256(const std::vector<std::string_view> &parts) { + uint8_t sha256[SHA256_DIGEST_LENGTH]; + SHA256_CTX sha_ctx; + SHA256_Init(&sha_ctx); + for (auto part : parts) { + SHA256_Update(&sha_ctx, part.data(), part.size()); + } + SHA256_Final(sha256, &sha_ctx); + return std::vector<uint8_t>(std::begin(sha256), std::end(sha256)); +} + +std::string Sha256String(const std::vector<std::string_view> &parts) { + return BytesToHex(Sha256(parts)); +} + +} // namespace proxy_wasm \ No newline at end of file diff --git a/plugins/experimental/wasm/lib/src/hash.h b/plugins/experimental/wasm/lib/src/hash.h new file mode 100644 index 0000000000..40d03e9d4c --- /dev/null +++ b/plugins/experimental/wasm/lib/src/hash.h @@ -0,0 +1,27 @@ +// Copyright 2023 Google LLC +// +// Licensed 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. + +#pragma once + +#include <string> +#include <vector> + +#include <openssl/sha.h> + +namespace proxy_wasm { + +std::vector<uint8_t> Sha256(const std::vector<std::string_view> &parts); +std::string Sha256String(const std::vector<std::string_view> &parts); + +} // namespace proxy_wasm diff --git a/plugins/experimental/wasm/lib/src/wamr/wamr.cc b/plugins/experimental/wasm/lib/src/wamr/wamr.cc index 577b6784f3..ea3d140e7d 100644 --- a/plugins/experimental/wasm/lib/src/wamr/wamr.cc +++ b/plugins/experimental/wasm/lib/src/wamr/wamr.cc @@ -125,10 +125,12 @@ bool Wamr::load(std::string_view bytecode, std::string_view /*precompiled*/, return false; } - WasmByteVec vec; - wasm_byte_vec_new(vec.get(), bytecode.size(), bytecode.data()); - - module_ = wasm_module_new(store_.get(), vec.get()); + wasm_byte_vec_t binary = {.size = bytecode.size(), + .data = (char *)bytecode.data(), + .num_elems = bytecode.size(), + .size_of_elem = sizeof(byte_t), + .lock = nullptr}; + module_ = wasm_module_new(store_.get(), &binary); if (module_ == nullptr) { return false; } @@ -259,9 +261,15 @@ bool Wamr::link(std::string_view /*debug_name*/) { const wasm_name_t *name_ptr = wasm_importtype_name(import_types.get()->data[i]); const wasm_externtype_t *extern_type = wasm_importtype_type(import_types.get()->data[i]); - std::string_view module_name(module_name_ptr->data, module_name_ptr->size); - std::string_view name(name_ptr->data, name_ptr->size); - assert(name_ptr->size > 0); + if (std::strlen(name_ptr->data) == 0) { + fail(FailState::UnableToInitializeCode, std::string("The name field of import_types[") + + std::to_string(i) + std::string("] is empty")); + return false; + } + + std::string_view module_name(module_name_ptr->data); + std::string_view name(name_ptr->data); + switch (wasm_externtype_kind(extern_type)) { case WASM_EXTERN_FUNC: { auto it = host_functions_.find(std::string(module_name) + "." + std::string(name)); @@ -344,17 +352,15 @@ bool Wamr::link(std::string_view /*debug_name*/) { wasm_instance_exports(instance_.get(), exports.get()); for (size_t i = 0; i < export_types.get()->size; i++) { - const wasm_externtype_t *exp_extern_type = wasm_exporttype_type(export_types.get()->data[i]); wasm_extern_t *actual_extern = exports.get()->data[i]; wasm_externkind_t kind = wasm_extern_kind(actual_extern); - assert(kind == wasm_externtype_kind(exp_extern_type)); + assert(kind == wasm_externtype_kind(wasm_exporttype_type(export_types.get()->data[i]))); switch (kind) { case WASM_EXTERN_FUNC: { WasmFuncPtr func = wasm_func_copy(wasm_extern_as_func(actual_extern)); const wasm_name_t *name_ptr = wasm_exporttype_name(export_types.get()->data[i]); - module_functions_.insert_or_assign(std::string(name_ptr->data, name_ptr->size), - std::move(func)); + module_functions_.insert_or_assign(std::string(name_ptr->data), std::move(func)); } break; case WASM_EXTERN_GLOBAL: { // TODO(mathetake): add support when/if needed. diff --git a/plugins/experimental/wasm/lib/src/wasm.cc b/plugins/experimental/wasm/lib/src/wasm.cc index 5519b3e774..cb1dd9b3ac 100644 --- a/plugins/experimental/wasm/lib/src/wasm.cc +++ b/plugins/experimental/wasm/lib/src/wasm.cc @@ -23,54 +23,75 @@ #include <limits> #include <memory> #include <mutex> +#include <queue> #include <string> #include <unordered_map> #include <utility> -#include <openssl/sha.h> - #include "include/proxy-wasm/bytecode_util.h" #include "include/proxy-wasm/signature_util.h" #include "include/proxy-wasm/vm_id_handle.h" +#include "src/hash.h" namespace proxy_wasm { namespace { -// Map from Wasm Key to the local Wasm instance. +// Map from Wasm key to the thread-local Wasm instance. thread_local std::unordered_map<std::string, std::weak_ptr<WasmHandleBase>> local_wasms; +// Wasm key queue to track stale entries in `local_wasms`. +thread_local std::queue<std::string> local_wasms_keys; + +// Map from plugin key to the thread-local plugin instance. thread_local std::unordered_map<std::string, std::weak_ptr<PluginHandleBase>> local_plugins; +// Plugin key queue to track stale entries in `local_plugins`. +thread_local std::queue<std::string> local_plugins_keys; + +// Check no more than `MAX_LOCAL_CACHE_GC_CHUNK_SIZE` cache entries at a time during stale entries +// cleanup. +const size_t MAX_LOCAL_CACHE_GC_CHUNK_SIZE = 64; + // Map from Wasm Key to the base Wasm instance, using a pointer to avoid the initialization fiasco. std::mutex base_wasms_mutex; std::unordered_map<std::string, std::weak_ptr<WasmHandleBase>> *base_wasms = nullptr; -std::vector<uint8_t> Sha256(const std::vector<std::string_view> &parts) { - uint8_t sha256[SHA256_DIGEST_LENGTH]; - SHA256_CTX sha_ctx; - SHA256_Init(&sha_ctx); - for (auto part : parts) { - SHA256_Update(&sha_ctx, part.data(), part.size()); - } - SHA256_Final(sha256, &sha_ctx); - return std::vector<uint8_t>(std::begin(sha256), std::end(sha256)); +void cacheLocalWasm(const std::string &key, const std::shared_ptr<WasmHandleBase> &wasm_handle) { + local_wasms[key] = wasm_handle; + local_wasms_keys.emplace(key); +} + +void cacheLocalPlugin(const std::string &key, + const std::shared_ptr<PluginHandleBase> &plugin_handle) { + local_plugins[key] = plugin_handle; + local_plugins_keys.emplace(key); } -std::string BytesToHex(const std::vector<uint8_t> &bytes) { - static const char *const hex = "0123456789ABCDEF"; - std::string result; - result.reserve(bytes.size() * 2); - for (auto byte : bytes) { - result.push_back(hex[byte >> 4]); - result.push_back(hex[byte & 0xf]); +template <class T> +void removeStaleLocalCacheEntries(std::unordered_map<std::string, std::weak_ptr<T>> &cache, + std::queue<std::string> &keys) { + auto num_keys_to_check = std::min(MAX_LOCAL_CACHE_GC_CHUNK_SIZE, keys.size()); + for (size_t i = 0; i < num_keys_to_check; i++) { + std::string key(keys.front()); + keys.pop(); + + const auto it = cache.find(key); + if (it == cache.end()) { + continue; + } + + if (it->second.expired()) { + cache.erase(it); + } else { + keys.push(std::move(key)); + } } - return result; } } // namespace std::string makeVmKey(std::string_view vm_id, std::string_view vm_configuration, std::string_view code) { - return BytesToHex(Sha256({vm_id, vm_configuration, code})); + return Sha256String({vm_id, "||", vm_configuration, "||", code}); } class WasmBase::ShutdownHandle { @@ -472,6 +493,10 @@ bool WasmHandleBase::canary(const std::shared_ptr<PluginBase> &plugin, if (this->wasm() == nullptr) { return false; } + auto it = plugin_canary_cache_.find(plugin->key()); + if (it != plugin_canary_cache_.end()) { + return it->second; + } auto configuration_canary_handle = clone_factory(shared_from_this()); if (!configuration_canary_handle) { this->wasm()->fail(FailState::UnableToCloneVm, "Failed to clone Base Wasm"); @@ -490,9 +515,11 @@ bool WasmHandleBase::canary(const std::shared_ptr<PluginBase> &plugin, if (!configuration_canary_handle->wasm()->configure(root_context, plugin)) { configuration_canary_handle->wasm()->fail(FailState::ConfigureFailed, "Failed to configure base Wasm plugin"); + plugin_canary_cache_[plugin->key()] = false; return false; } configuration_canary_handle->kill(); + plugin_canary_cache_[plugin->key()] = true; return true; } @@ -542,14 +569,15 @@ std::shared_ptr<WasmHandleBase> createWasm(const std::string &vm_key, const std: std::shared_ptr<WasmHandleBase> getThreadLocalWasm(std::string_view vm_key) { auto it = local_wasms.find(std::string(vm_key)); - if (it == local_wasms.end()) { - return nullptr; - } - auto wasm = it->second.lock(); - if (!wasm) { - local_wasms.erase(std::string(vm_key)); + if (it != local_wasms.end()) { + auto wasm = it->second.lock(); + if (wasm) { + return wasm; + } + local_wasms.erase(it); } - return wasm; + removeStaleLocalCacheEntries(local_wasms, local_wasms_keys); + return nullptr; } static std::shared_ptr<WasmHandleBase> @@ -563,9 +591,9 @@ getOrCreateThreadLocalWasm(const std::shared_ptr<WasmHandleBase> &base_handle, if (wasm_handle) { return wasm_handle; } - // Remove stale entry. - local_wasms.erase(vm_key); + local_wasms.erase(it); } + removeStaleLocalCacheEntries(local_wasms, local_wasms_keys); // Create and initialize new thread-local WasmVM. auto wasm_handle = clone_factory(base_handle); if (!wasm_handle) { @@ -577,7 +605,7 @@ getOrCreateThreadLocalWasm(const std::shared_ptr<WasmHandleBase> &base_handle, base_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to initialize Wasm code"); return nullptr; } - local_wasms[vm_key] = wasm_handle; + cacheLocalWasm(vm_key, wasm_handle); wasm_handle->wasm()->wasm_vm()->addFailCallback([vm_key](proxy_wasm::FailState fail_state) { if (fail_state == proxy_wasm::FailState::RuntimeError) { // If VM failed, erase the entry so that: @@ -600,9 +628,9 @@ std::shared_ptr<PluginHandleBase> getOrCreateThreadLocalPlugin( if (plugin_handle) { return plugin_handle; } - // Remove stale entry. - local_plugins.erase(key); + local_plugins.erase(it); } + removeStaleLocalCacheEntries(local_plugins, local_plugins_keys); // Get thread-local WasmVM. auto wasm_handle = getOrCreateThreadLocalWasm(base_handle, clone_factory); if (!wasm_handle) { @@ -620,7 +648,7 @@ std::shared_ptr<PluginHandleBase> getOrCreateThreadLocalPlugin( return nullptr; } auto plugin_handle = plugin_factory(wasm_handle, plugin); - local_plugins[key] = plugin_handle; + cacheLocalPlugin(key, plugin_handle); wasm_handle->wasm()->wasm_vm()->addFailCallback([key](proxy_wasm::FailState fail_state) { if (fail_state == proxy_wasm::FailState::RuntimeError) { // If VM failed, erase the entry so that: @@ -642,4 +670,24 @@ void clearWasmCachesForTesting() { } } +std::vector<std::string> staleLocalPluginsKeysForTesting() { + std::vector<std::string> keys; + for (const auto &kv : local_plugins) { + if (kv.second.expired()) { + keys.push_back(kv.first); + } + } + return keys; +} + +std::vector<std::string> staleLocalWasmsKeysForTesting() { + std::vector<std::string> keys; + for (const auto &kv : local_wasms) { + if (kv.second.expired()) { + keys.push_back(kv.first); + } + } + return keys; +} + } // namespace proxy_wasm