blob: 01f33c5cdf0396b7bc5d6e28a1f27e242b09155e [file]
// 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 "format_v2/jni/paimon_jni_reader.h"
#include <string_view>
#include "runtime/exec_env.h"
#include "runtime/runtime_state.h"
#include "util/string_util.h"
#include "util/uid_util.h"
namespace doris::format::paimon {
namespace {
constexpr std::string_view PAIMON_OPTION_PREFIX = "paimon.";
constexpr std::string_view HADOOP_OPTION_PREFIX = "hadoop.";
constexpr std::string_view DORIS_ENABLE_JNI_IO_MANAGER = "jni.enable_jni_io_manager";
constexpr std::string_view DORIS_JNI_IO_MANAGER_TMP_DIR = "jni.io_manager.tmp_dir";
constexpr std::string_view PAIMON_JNI_SCANNER_IO_TMP_DIR = "paimon_jni_scanner_io_tmp";
const std::string* get_paimon_predicate(const TFileScanRangeParams* scan_params,
const TPaimonFileDesc& paimon_params) {
if (scan_params != nullptr && scan_params->__isset.paimon_predicate &&
!scan_params->paimon_predicate.empty()) {
return &scan_params->paimon_predicate;
}
if (paimon_params.__isset.paimon_predicate && !paimon_params.paimon_predicate.empty()) {
return &paimon_params.paimon_predicate;
}
return nullptr;
}
} // namespace
Status PaimonJniReader::validate_scan_range(const TFileRangeDesc& range) const {
if (!range.__isset.table_format_params) {
return Status::InternalError("missing table_format_params for paimon jni reader");
}
if (!range.table_format_params.__isset.paimon_params) {
return Status::InternalError("missing paimon_params for paimon jni reader");
}
if (!range.table_format_params.paimon_params.__isset.paimon_split ||
range.table_format_params.paimon_params.paimon_split.empty()) {
return Status::InternalError(
"missing paimon_split for paimon jni reader, possibly caused by FE/BE protocol "
"mismatch");
}
if (range.table_format_params.paimon_params.__isset.reader_type &&
range.table_format_params.paimon_params.reader_type != TPaimonReaderType::PAIMON_JNI) {
return Status::InternalError(
"invalid reader_type for paimon jni reader, possibly caused by FE/BE protocol "
"mismatch");
}
if (_scan_params == nullptr || !_scan_params->__isset.serialized_table ||
_scan_params->serialized_table.empty()) {
return Status::InternalError(
"missing serialized_table for paimon jni reader, possibly caused by FE/BE "
"protocol mismatch");
}
if (get_paimon_predicate(_scan_params, range.table_format_params.paimon_params) == nullptr) {
return Status::InternalError(
"missing paimon_predicate for paimon jni reader, possibly caused by FE/BE "
"protocol mismatch");
}
return Status::OK();
}
std::string PaimonJniReader::connector_class() const {
return "org/apache/doris/paimon/PaimonJniScanner";
}
Status PaimonJniReader::build_scanner_params(std::map<std::string, std::string>* params) const {
DORIS_CHECK(params != nullptr);
DORIS_CHECK(_scan_params != nullptr);
params->clear();
const auto& paimon_params = _current_range.table_format_params.paimon_params;
const auto* paimon_predicate = get_paimon_predicate(_scan_params, paimon_params);
DORIS_CHECK(paimon_predicate != nullptr);
(*params)["paimon_split"] = paimon_params.paimon_split;
(*params)["paimon_predicate"] = *paimon_predicate;
(*params)["serialized_table"] = _scan_params->serialized_table;
// if old Version FE not have set it, generate uuid in BE, so no need to compatible
(*params)["serialized_table_cache_key"] =
_scan_params->__isset.serialized_table_cache_key &&
!_scan_params->serialized_table_cache_key.empty()
? _scan_params->serialized_table_cache_key
: generate_uuid_string();
if (_scan_params->__isset.paimon_options && !_scan_params->paimon_options.empty()) {
for (const auto& kv : _scan_params->paimon_options) {
(*params)[std::string(PAIMON_OPTION_PREFIX) + kv.first] = kv.second;
}
} else if (paimon_params.__isset.paimon_options) {
// Rolling upgrades can pair this BE with an older FE that only sends options per split.
for (const auto& kv : paimon_params.paimon_options) {
(*params)[std::string(PAIMON_OPTION_PREFIX) + kv.first] = kv.second;
}
}
const std::string enable_io_manager_key =
std::string(PAIMON_OPTION_PREFIX) + std::string(DORIS_ENABLE_JNI_IO_MANAGER);
const std::string io_manager_tmp_dir_key =
std::string(PAIMON_OPTION_PREFIX) + std::string(DORIS_JNI_IO_MANAGER_TMP_DIR);
auto enable_io_manager_it = params->find(enable_io_manager_key);
if (enable_io_manager_it != params->end() && iequal(enable_io_manager_it->second, "true") &&
params->find(io_manager_tmp_dir_key) == params->end()) {
DORIS_CHECK(_runtime_state != nullptr);
// Keep Format V2 consistent with the legacy JNI path. Paimon creates and
// removes its own paimon-* child directory under these Doris storage-root scoped
// parent directories.
(*params)[io_manager_tmp_dir_key] =
build_default_io_manager_tmp_dirs(_runtime_state->exec_env()->store_paths());
}
if (_scan_params->__isset.properties && !_scan_params->properties.empty()) {
for (const auto& kv : _scan_params->properties) {
(*params)[std::string(HADOOP_OPTION_PREFIX) + kv.first] = kv.second;
}
} else if (paimon_params.__isset.hadoop_conf) {
for (const auto& kv : paimon_params.hadoop_conf) {
(*params)[std::string(HADOOP_OPTION_PREFIX) + kv.first] = kv.second;
}
}
// TODO: Remove legacy split-level paimon_predicate, paimon_options and hadoop_conf from thrift
// after the minimum supported FE always sends their scan-level replacements.
return Status::OK();
}
std::string PaimonJniReader::build_default_io_manager_tmp_dirs(
const std::vector<StorePath>& store_paths) {
std::vector<std::string> tmp_dirs;
tmp_dirs.reserve(store_paths.size());
for (const auto& store_path : store_paths) {
tmp_dirs.push_back(store_path.path + "/" + std::string(PAIMON_JNI_SCANNER_IO_TMP_DIR));
}
DORIS_CHECK(!tmp_dirs.empty());
return join(tmp_dirs, ":");
}
} // namespace doris::format::paimon