This is an automated email from the ASF dual-hosted git repository. yiguolei pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new 2ef8f3f6f4 [enhancement](java-udf) Support loading libjvm at runtime (#13660) 2ef8f3f6f4 is described below commit 2ef8f3f6f42e5dabc650049dd66fcf6a1e7befe2 Author: Adonis Ling <adonis0...@gmail.com> AuthorDate: Fri Oct 28 08:45:12 2022 +0800 [enhancement](java-udf) Support loading libjvm at runtime (#13660) --- be/CMakeLists.txt | 23 +++------- be/src/util/CMakeLists.txt | 4 ++ be/src/util/jni-util.cpp | 7 ++- be/src/util/libjvm_loader.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++ be/src/util/libjvm_loader.h | 54 +++++++++++++++++++++++ bin/check_be_version.sh | 93 ---------------------------------------- bin/start_be.sh | 29 ------------- build.sh | 1 - run-be-ut.sh | 29 ------------- 9 files changed, 167 insertions(+), 172 deletions(-) diff --git a/be/CMakeLists.txt b/be/CMakeLists.txt index 3d6f7e4b27..00067b66c7 100644 --- a/be/CMakeLists.txt +++ b/be/CMakeLists.txt @@ -603,26 +603,13 @@ include_directories( ) if (BUILD_JAVA_UDF) - execute_process(COMMAND chmod 755 ${BASE_DIR}/../tools/find_libjvm.sh) - execute_process(COMMAND ${BASE_DIR}/../tools/find_libjvm.sh OUTPUT_VARIABLE LIBJVM_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) - FILE(GLOB_RECURSE LIB_JVM ${LIBJVM_PATH}) - if("${LIB_JVM}" STREQUAL "") - message(STATUS "Disable JAVA UDF because there is no libjvm found!") + include_directories($ENV{JAVA_HOME}/include) + if (NOT OS_MACOSX) + include_directories($ENV{JAVA_HOME}/include/linux) else() - set(DORIS_DEPENDENCIES - ${DORIS_DEPENDENCIES} - jvm - ) - add_library(jvm SHARED IMPORTED) - set_target_properties(jvm PROPERTIES IMPORTED_LOCATION ${LIB_JVM}) - include_directories($ENV{JAVA_HOME}/include) - if (NOT OS_MACOSX) - include_directories($ENV{JAVA_HOME}/include/linux) - else() - include_directories($ENV{JAVA_HOME}/include/darwin) - endif() - add_definitions("-DLIBJVM") + include_directories($ENV{JAVA_HOME}/include/darwin) endif() + add_definitions("-DLIBJVM") endif() if (NOT OS_MACOSX) diff --git a/be/src/util/CMakeLists.txt b/be/src/util/CMakeLists.txt index 8b96a6f13f..dc9509a9ec 100644 --- a/be/src/util/CMakeLists.txt +++ b/be/src/util/CMakeLists.txt @@ -127,6 +127,10 @@ if (OS_MACOSX) list(APPEND UTIL_FILES perf_counters_mac.cpp disk_info_mac.cpp) endif() +if (BUILD_JAVA_UDF) + list(APPEND UTIL_FILES libjvm_loader.cpp) +endif() + add_library(Util STATIC ${UTIL_FILES} ) diff --git a/be/src/util/jni-util.cpp b/be/src/util/jni-util.cpp index 0509989406..7c56381052 100644 --- a/be/src/util/jni-util.cpp +++ b/be/src/util/jni-util.cpp @@ -29,6 +29,7 @@ #include "common/config.h" #include "gutil/once.h" #include "gutil/strings/substitute.h" +#include "libjvm_loader.h" using std::string; @@ -67,7 +68,7 @@ const std::string GetDorisJNIClasspath() { void FindOrCreateJavaVM() { int num_vms; - int rv = JNI_GetCreatedJavaVMs(&g_vm, 1, &num_vms); + int rv = LibJVMLoader::JNI_GetCreatedJavaVMs(&g_vm, 1, &num_vms); if (rv == 0) { auto classpath = GetDorisJNIClasspath(); std::string heap_size = fmt::format("-Xmx{}", config::jvm_max_heap_size); @@ -91,7 +92,7 @@ void FindOrCreateJavaVM() { // Set it to JNI_FALSE because JNI_TRUE will let JVM ignore the max size config. vm_args.ignoreUnrecognized = JNI_FALSE; - jint res = JNI_CreateJavaVM(&g_vm, (void**)&env, &vm_args); + jint res = LibJVMLoader::JNI_CreateJavaVM(&g_vm, (void**)&env, &vm_args); if (JNI_OK != res) { DCHECK(false) << "Failed to create JVM, code= " << res; } @@ -213,6 +214,8 @@ Status JniUtil::LocalToGlobalRef(JNIEnv* env, jobject local_ref, jobject* global } Status JniUtil::Init() { + RETURN_IF_ERROR(LibJVMLoader::instance().load()); + // Get the JNIEnv* corresponding to current thread. JNIEnv* env; RETURN_IF_ERROR(JniUtil::GetJNIEnv(&env)); diff --git a/be/src/util/libjvm_loader.cpp b/be/src/util/libjvm_loader.cpp new file mode 100644 index 0000000000..abd0a4863b --- /dev/null +++ b/be/src/util/libjvm_loader.cpp @@ -0,0 +1,99 @@ +// 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. + +#include "util/libjvm_loader.h" + +#include <dlfcn.h> + +#include <cstdlib> +#include <filesystem> +#include <mutex> + +#include "common/status.h" + +namespace { + +#ifndef __APPLE__ +#define LIBJVM_SO "libjvm.so" +#else +#define LIBJVM_SO "libjvm.dylib" +#endif + +template <typename T> +doris::Status resolve_symbol(T& pointer, void* handle, const char* symbol) { + pointer = reinterpret_cast<T>(dlsym(handle, symbol)); + return (pointer != nullptr) + ? doris::Status::OK() + : doris::Status::RuntimeError("Failed to resolve the symbol %s", symbol); +} + +} // namespace + +namespace doris { + +LibJVMLoader::JNI_GetCreatedJavaVMsPointer LibJVMLoader::JNI_GetCreatedJavaVMs = nullptr; +LibJVMLoader::JNI_CreateJavaVMPointer LibJVMLoader::JNI_CreateJavaVM = nullptr; + +LibJVMLoader& LibJVMLoader::instance() { + static std::once_flag find_library; + static std::string library; + std::call_once(find_library, []() { + const auto* java_home = getenv("JAVA_HOME"); + if (!java_home) { + return; + } + std::string path(java_home); + for (const auto& entry : std::filesystem::recursive_directory_iterator(path)) { + if (entry.path().filename() == LIBJVM_SO) { + library = entry.path().string(); + break; + } + } + }); + + static LibJVMLoader loader(library); + return loader; +} + +Status LibJVMLoader::load() { + if (_library.empty()) { + return Status::RuntimeError("Failed to find the library %s.", LIBJVM_SO); + } + + static std::once_flag resolve_symbols; + static Status status; + std::call_once(resolve_symbols, [this]() { + _handle = std::unique_ptr<void, void (*)(void*)>(dlopen(_library.c_str(), RTLD_LAZY), + [](void* handle) { dlclose(handle); }); + if (!_handle) { + status = Status::RuntimeError(dlerror()); + return; + } + + if (status = resolve_symbol(JNI_GetCreatedJavaVMs, _handle.get(), "JNI_GetCreatedJavaVMs"); + !status.ok()) { + return; + } + if (status = resolve_symbol(JNI_CreateJavaVM, _handle.get(), "JNI_CreateJavaVM"); + !status.ok()) { + return; + } + }); + return status; +} + +} // namespace doris diff --git a/be/src/util/libjvm_loader.h b/be/src/util/libjvm_loader.h new file mode 100644 index 0000000000..2982cbea7f --- /dev/null +++ b/be/src/util/libjvm_loader.h @@ -0,0 +1,54 @@ +// 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. + +#pragma once + +#include <dlfcn.h> +#include <jni.h> + +#include <memory> +#include <string> +#include <string_view> +#include <type_traits> + +namespace doris { + +class Status; + +class LibJVMLoader { +public: + LibJVMLoader(const LibJVMLoader&) = delete; + LibJVMLoader& operator=(const LibJVMLoader&) = delete; + + static LibJVMLoader& instance(); + Status load(); + + using JNI_GetCreatedJavaVMsPointer = std::add_pointer_t<decltype(::JNI_GetCreatedJavaVMs)>; + static JNI_GetCreatedJavaVMsPointer JNI_GetCreatedJavaVMs; + + using JNI_CreateJavaVMPointer = std::add_pointer_t<decltype(::JNI_CreateJavaVM)>; + static JNI_CreateJavaVMPointer JNI_CreateJavaVM; + +private: + explicit LibJVMLoader(std::string_view library) + : _library(library), _handle(nullptr, nullptr) {} + + const std::string _library; + std::unique_ptr<void, void (*)(void*)> _handle; +}; + +} // namespace doris diff --git a/bin/check_be_version.sh b/bin/check_be_version.sh deleted file mode 100755 index b44d0c8f64..0000000000 --- a/bin/check_be_version.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env bash -# 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. - -set -eo pipefail - -curdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" - -if [[ "$(uname -s)" == 'Darwin' ]] && command -v brew &>/dev/null; then - PATH="$(brew --prefix)/opt/gnu-getopt/bin:${PATH}" - export PATH -fi - -DORIS_HOME="$( - cd "${curdir}/.." - pwd -)" -export DORIS_HOME - -jdk_version() { - local java_cmd="${1}" - local result - local IFS=$'\n' - - if [[ -z "${java_cmd}" ]]; then - result=no_java - return 1 - else - local version - # remove \r for Cygwin - version="$("${java_cmd}" -Xms32M -Xmx32M -version 2>&1 | tr '\r' '\n' | grep version | awk '{print $3}')" - version="${version//\"/}" - if [[ "${version}" =~ ^1\. ]]; then - result="$(echo "${version}" | awk -F '.' '{print $2}')" - else - result="$(echo "${version}" | awk -F '.' '{print $1}')" - fi - fi - echo "${result}" - return 0 -} - -setup_java_env() { - local java_version - - if [[ -z "${JAVA_HOME}" ]]; then - return 1 - fi - - local jvm_arch='amd64' - if [[ "$(uname -m)" == 'aarch64' ]]; then - jvm_arch='aarch64' - fi - java_version="$( - set -e - jdk_version "${JAVA_HOME}/bin/java" - )" - if [[ "${java_version}" -gt 8 ]]; then - export LD_LIBRARY_PATH="${JAVA_HOME}/lib/server:${JAVA_HOME}/lib:${LD_LIBRARY_PATH}" - # JAVA_HOME is jdk - elif [[ -d "${JAVA_HOME}/jre" ]]; then - export LD_LIBRARY_PATH="${JAVA_HOME}/jre/lib/${jvm_arch}/server:${JAVA_HOME}/jre/lib/${jvm_arch}:${LD_LIBRARY_PATH}" - # JAVA_HOME is jre - else - export LD_LIBRARY_PATH="${JAVA_HOME}/lib/${jvm_arch}/server:${JAVA_HOME}/lib/${jvm_arch}:${LD_LIBRARY_PATH}" - fi -} - -# prepare jvm if needed -setup_java_env || true - -if [[ -e "${DORIS_HOME}/bin/palo_env.sh" ]]; then - # shellcheck disable=1091 - source "${DORIS_HOME}/bin/palo_env.sh" -fi - -chmod 755 "${DORIS_HOME}/lib/doris_be" - -"${DORIS_HOME}"/lib/doris_be --version diff --git a/bin/start_be.sh b/bin/start_be.sh index 49d231e1c3..cdd051bf7d 100755 --- a/bin/start_be.sh +++ b/bin/start_be.sh @@ -104,35 +104,6 @@ jdk_version() { return 0 } -setup_java_env() { - local java_version - - if [[ -z "${JAVA_HOME}" ]]; then - return 1 - fi - - local jvm_arch='amd64' - if [[ "$(uname -m)" == 'aarch64' ]]; then - jvm_arch='aarch64' - fi - java_version="$( - set -e - jdk_version "${JAVA_HOME}/bin/java" - )" - if [[ "${java_version}" -gt 8 ]]; then - export LD_LIBRARY_PATH="${JAVA_HOME}/lib/server:${JAVA_HOME}/lib:${LD_LIBRARY_PATH}" - # JAVA_HOME is jdk - elif [[ -d "${JAVA_HOME}/jre" ]]; then - export LD_LIBRARY_PATH="${JAVA_HOME}/jre/lib/${jvm_arch}/server:${JAVA_HOME}/jre/lib/${jvm_arch}:${LD_LIBRARY_PATH}" - # JAVA_HOME is jre - else - export LD_LIBRARY_PATH="${JAVA_HOME}/lib/${jvm_arch}/server:${JAVA_HOME}/lib/${jvm_arch}:${LD_LIBRARY_PATH}" - fi -} - -# prepare jvm if needed -setup_java_env || true - # export env variables from be.conf # # UDF_RUNTIME_DIR diff --git a/build.sh b/build.sh index 4f394a7ee7..65559f026e 100755 --- a/build.sh +++ b/build.sh @@ -508,7 +508,6 @@ if [[ "${BUILD_BE}" -eq 1 ]]; then "${DORIS_OUTPUT}/udf/include" cp -r -p "${DORIS_HOME}/be/output/bin"/* "${DORIS_OUTPUT}/be/bin"/ - cp -r -p "${DORIS_HOME}/bin/check_be_version.sh" "${DORIS_OUTPUT}/be/bin"/ cp -r -p "${DORIS_HOME}/be/output/conf"/* "${DORIS_OUTPUT}/be/conf"/ # Fix Killed: 9 error on MacOS (arm64). diff --git a/run-be-ut.sh b/run-be-ut.sh index a0d4daa37c..f66d65a64e 100755 --- a/run-be-ut.sh +++ b/run-be-ut.sh @@ -230,35 +230,6 @@ jdk_version() { return 0 } -setup_java_env() { - local java_version - - if [[ -z "${JAVA_HOME}" ]]; then - return 1 - fi - - local jvm_arch='amd64' - if [[ "$(uname -m)" == 'aarch64' ]]; then - jvm_arch='aarch64' - fi - java_version="$( - set -e - jdk_version "${JAVA_HOME}/bin/java" - )" - if [[ "${java_version}" -gt 8 ]]; then - export LD_LIBRARY_PATH="${JAVA_HOME}/lib/server:${JAVA_HOME}/lib:${LD_LIBRARY_PATH}" - # JAVA_HOME is jdk - elif [[ -d "${JAVA_HOME}/jre" ]]; then - export LD_LIBRARY_PATH="${JAVA_HOME}/jre/lib/${jvm_arch}/server:${JAVA_HOME}/jre/lib/${jvm_arch}:${LD_LIBRARY_PATH}" - # JAVA_HOME is jre - else - export LD_LIBRARY_PATH="${JAVA_HOME}/lib/${jvm_arch}/server:${JAVA_HOME}/lib/${jvm_arch}:${LD_LIBRARY_PATH}" - fi -} - -# prepare jvm if needed -setup_java_env || true - # prepare gtest output dir GTEST_OUTPUT_DIR="${CMAKE_BUILD_DIR}/gtest_output" rm -rf "${GTEST_OUTPUT_DIR}" --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org