diff --git a/be/CMakeLists.txt b/be/CMakeLists.txt index 3d6f7e4b27902d..00067b66c74d84 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 8b96a6f13fd284..dc9509a9ec49c8 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 e9a0673dc8695b..dbce645a4e6f73 100644 --- a/be/src/util/jni-util.cpp +++ b/be/src/util/jni-util.cpp @@ -25,6 +25,7 @@ #include "common/config.h" #include "gutil/once.h" #include "gutil/strings/substitute.h" +#include "libjvm_loader.h" using std::string; @@ -36,7 +37,7 @@ GoogleOnceType g_vm_once = GOOGLE_ONCE_INIT; 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) { JNIEnv* env; JavaVMInitArgs vm_args; @@ -51,7 +52,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; } @@ -173,6 +174,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 00000000000000..abd0a4863bc359 --- /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 + +#include +#include +#include + +#include "common/status.h" + +namespace { + +#ifndef __APPLE__ +#define LIBJVM_SO "libjvm.so" +#else +#define LIBJVM_SO "libjvm.dylib" +#endif + +template +doris::Status resolve_symbol(T& pointer, void* handle, const char* symbol) { + pointer = reinterpret_cast(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(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 00000000000000..2982cbea7f730f --- /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 +#include + +#include +#include +#include +#include + +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; + static JNI_GetCreatedJavaVMsPointer JNI_GetCreatedJavaVMs; + + using JNI_CreateJavaVMPointer = std::add_pointer_t; + static JNI_CreateJavaVMPointer JNI_CreateJavaVM; + +private: + explicit LibJVMLoader(std::string_view library) + : _library(library), _handle(nullptr, nullptr) {} + + const std::string _library; + std::unique_ptr _handle; +}; + +} // namespace doris diff --git a/bin/check_be_version.sh b/bin/check_be_version.sh deleted file mode 100755 index b44d0c8f6411cc..00000000000000 --- 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 49d231e1c3c8a7..cdd051bf7d9401 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 1e73c8747a38cb..fc58fc5ac349f1 100755 --- a/build.sh +++ b/build.sh @@ -494,7 +494,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 a0d4daa37c4feb..f66d65a64e5343 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}"