Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ presto-native-execution/deps-install
# Compiled executables used for docker build
/docker/presto-cli-*-executable.jar
/docker/presto-server-*.tar.gz
/docker/presto-function-server-executable.jar
4 changes: 3 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FROM quay.io/centos/centos:stream9
ARG PRESTO_VERSION
ARG PRESTO_PKG=presto-server-$PRESTO_VERSION.tar.gz
ARG PRESTO_CLI_JAR=presto-cli-$PRESTO_VERSION-executable.jar
ARG PRESTO_REMOTE_SERVER_JAR=presto-function-server-executable.jar
ARG JMX_PROMETHEUS_JAVAAGENT_VERSION=0.20.0

ENV PRESTO_HOME="/opt/presto-server"
Expand All @@ -13,7 +14,8 @@ RUN --mount=type=cache,target=/var/cache/dnf,sharing=locked \
# clean cache jobs
&& mv /etc/yum/protected.d/systemd.conf /etc/yum/protected.d/systemd.conf.bak

COPY --chmod=755 $PRESTO_CLI_JAR /opt/presto-cli
COPY --chmod=755 $PRESTO_CLI_JAR /opt/presto-cli
COPY --chmod=755 $PRESTO_REMOTE_SERVER_JAR /opt/presto-remote-function-server

RUN --mount=type=bind,source=$PRESTO_PKG,target=/$PRESTO_PKG \
# Download Presto and move \
Expand Down
4 changes: 4 additions & 0 deletions presto-native-execution/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ignore build directories
_build/
cmake-build-debug/
Comment thread
Joe-Abraham marked this conversation as resolved.
cmake-build-release/
2 changes: 1 addition & 1 deletion presto-native-execution/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ set(Boost_USE_MULTITHREADED TRUE)
find_package(
Boost
1.66.0
REQUIRED program_options context filesystem regex thread system date_time atomic
REQUIRED program_options context filesystem regex thread system date_time url atomic
)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})

Expand Down
8 changes: 7 additions & 1 deletion presto-native-execution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,12 @@
<include>presto-cli-*-executable.jar</include>
</includes>
</resource>
<resource>
<directory>${project.parent.basedir}/presto-function-server/target</directory>
<includes>
<include>presto-function-server-executable.jar</include>
</includes>
</resource>
<resource>
<directory>${project.parent.basedir}/presto-server/target</directory>
<includes>
Expand Down Expand Up @@ -574,7 +580,7 @@
<args>
<BUILD_TYPE>Release</BUILD_TYPE>
<DEPENDENCY_IMAGE>presto-native-dependency:latest</DEPENDENCY_IMAGE>
<EXTRA_CMAKE_FLAGS>-DPRESTO_ENABLE_TESTING=OFF</EXTRA_CMAKE_FLAGS>
<EXTRA_CMAKE_FLAGS>"-DPRESTO_ENABLE_TESTING=OFF -DPRESTO_ENABLE_REMOTE_FUNCTIONS=ON"</EXTRA_CMAKE_FLAGS>
Comment thread
Joe-Abraham marked this conversation as resolved.
<NUM_THREADS>2</NUM_THREADS>
<BASE_IMAGE>ubuntu:22.04</BASE_IMAGE>
<OSNAME>ubuntu</OSNAME>
Expand Down
7 changes: 4 additions & 3 deletions presto-native-execution/presto_cpp/main/PrestoServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1391,11 +1391,12 @@ void PrestoServer::registerRemoteFunctions() {
<< catalogName << "' catalog.";
} else {
VELOX_FAIL(
"To register remote functions using a json file path you need to "
"specify the remote server location using '{}', '{}' or '{}'.",
"To register remote functions you need to specify the remote server "
"location using '{}', '{}' or '{}' or {}.",
SystemConfig::kRemoteFunctionServerThriftAddress,
SystemConfig::kRemoteFunctionServerThriftPort,
SystemConfig::kRemoteFunctionServerThriftUdsPath);
SystemConfig::kRemoteFunctionServerThriftUdsPath,
SystemConfig::kRemoteFunctionServerRestURL);
}
}
#endif
Expand Down
4 changes: 4 additions & 0 deletions presto-native-execution/presto_cpp/main/common/Configs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,10 @@ std::string SystemConfig::remoteFunctionServerSerde() const {
return optionalProperty(kRemoteFunctionServerSerde).value();
}

std::string SystemConfig::remoteFunctionServerRestURL() const {
return optionalProperty(kRemoteFunctionServerRestURL).value();
}

int32_t SystemConfig::maxDriversPerTask() const {
return optionalProperty<int32_t>(kMaxDriversPerTask).value();
}
Expand Down
6 changes: 6 additions & 0 deletions presto-native-execution/presto_cpp/main/common/Configs.h
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,10 @@ class SystemConfig : public ConfigBase {
static constexpr std::string_view kRemoteFunctionServerThriftUdsPath{
"remote-function-server.thrift.uds-path"};

/// HTTP URL used by the remote function rest server.
static constexpr std::string_view kRemoteFunctionServerRestURL{
"remote-function-server.rest.url"};

/// Path where json files containing signatures for remote functions can be
/// found.
static constexpr std::string_view
Expand Down Expand Up @@ -924,6 +928,8 @@ class SystemConfig : public ConfigBase {

std::string remoteFunctionServerSerde() const;

std::string remoteFunctionServerRestURL() const;

int32_t maxDriversPerTask() const;

int32_t driverMaxSplitPreload() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@
# limitations under the License.

add_library(presto_function_metadata OBJECT FunctionMetadata.cpp)
target_link_libraries(presto_function_metadata velox_function_registry)
target_link_libraries(presto_function_metadata presto_common velox_function_registry)

add_subdirectory(dynamic_registry)

if(PRESTO_ENABLE_REMOTE_FUNCTIONS)
Comment thread
Joe-Abraham marked this conversation as resolved.
add_subdirectory(remote)
endif()

if(PRESTO_ENABLE_TESTING)
add_subdirectory(tests)
endif()
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 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.

add_library(presto_to_velox_remote_functions PrestoRestFunctionRegistration.cpp)
target_link_libraries(
presto_to_velox_remote_functions
presto_functions_remote
velox_type_fbhive
Boost::url
)

add_library(presto_functions_remote RestRemoteFunction.cpp)
target_link_libraries(presto_functions_remote presto_functions_rest_client velox_functions_remote)

add_subdirectory(client)

if(${PRESTO_ENABLE_TESTING})
add_subdirectory(tests)
endif()
Comment thread
Joe-Abraham marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* 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 "presto_cpp/main/functions/remote/PrestoRestFunctionRegistration.h"

#include <boost/url/encode.hpp>
#include <boost/url/rfc/unreserved_chars.hpp>

#include "presto_cpp/main/common/Configs.h"
#include "presto_cpp/main/common/Utils.h"
#include "presto_cpp/main/functions/remote/RestRemoteFunction.h"
#include "presto_cpp/main/functions/remote/client/RestRemoteClient.h"

using facebook::velox::functions::remote::PageFormat;

namespace facebook::presto::functions::remote::rest {
namespace {
// Returns the serialization/deserialization format used by the remote function
// server. The format is determined by the system configuration value
// "remoteFunctionServerSerde". Supported formats:
// - "presto_page": Uses Presto page format.
// - "spark_unsafe_row": Uses Spark unsafe row format.
// @return PageFormat enum value corresponding to the configured serde format.
// @throws VeloxException if the configured format is unknown.
PageFormat getSerdeFormat() {
static const auto serdeFormat =
SystemConfig::instance()->remoteFunctionServerSerde();
if (serdeFormat == "presto_page") {
return PageFormat::PRESTO_PAGE;
} else if (serdeFormat == "spark_unsafe_row") {
return PageFormat::SPARK_UNSAFE_ROW;
} else {
VELOX_FAIL(
"Unknown serde name for remote function server: '{}'", serdeFormat);
}
}

// Encodes a string for safe inclusion in a URL by escaping non-alphanumeric
// characters using percent-encoding. Alphanumeric characters and '-', '_', '.',
// '~' are left unchanged. All other characters are replaced with '%' followed
// by their two-digit hexadecimal value.
// @param value The input string to encode.
// @return The URL-encoded string.
std::string urlEncode(const std::string& value) {
return boost::urls::encode(value, boost::urls::unreserved_chars);
}
Comment thread
Joe-Abraham marked this conversation as resolved.

std::string getFunctionName(const protocol::SqlFunctionId& functionId) {
Comment thread
Joe-Abraham marked this conversation as resolved.
// Example: "namespace.schema.function;TYPE;TYPE".
const auto nameEnd = functionId.find(';');
// Assuming the possibility of missing ';' if there are no function arguments.
return nameEnd != std::string::npos ? functionId.substr(0, nameEnd)
: functionId;
}

// Constructs a Velox function signature from a Presto function signature. This
// function translates type variable constraints, integer variable constraints,
// return type, argument types, and variable arity from the Presto signature to
// the corresponding Velox signature builder.
// @param prestoSignature The Presto function signature to convert.
// @return A pointer to the constructed Velox function signature.
velox::exec::FunctionSignaturePtr buildVeloxSignatureFromPrestoSignature(
const protocol::Signature& prestoSignature) {
velox::exec::FunctionSignatureBuilder signatureBuilder;

for (const auto& typeVar : prestoSignature.typeVariableConstraints) {
signatureBuilder.typeVariable(typeVar.name);
}

for (const auto& longVar : prestoSignature.longVariableConstraints) {
signatureBuilder.integerVariable(longVar.name);
}
signatureBuilder.returnType(prestoSignature.returnType);

for (const auto& argType : prestoSignature.argumentTypes) {
signatureBuilder.argumentType(argType);
}

if (prestoSignature.variableArity) {
signatureBuilder.variableArity();
}
return signatureBuilder.build();
}

} // namespace

void registerRestRemoteFunction(
const protocol::RestFunctionHandle& restFunctionHandle) {
static std::mutex registrationMutex;
static std::unordered_map<std::string, std::string> registeredFunctionHandles;
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
static std::unordered_map<std::string, functions::rest::RestRemoteClientPtr>
restClient;
static const std::string remoteFunctionServerRestURL =
SystemConfig::instance()->remoteFunctionServerRestURL();

const std::string functionId = restFunctionHandle.functionId;

json functionHandleJson;
to_json(functionHandleJson, restFunctionHandle);
functionHandleJson["url"] = remoteFunctionServerRestURL;
const std::string serializedFunctionHandle = functionHandleJson.dump();

// Check if already registered (read-only, no lock needed for initial check)
{
std::lock_guard<std::mutex> lock(registrationMutex);
auto it = registeredFunctionHandles.find(functionId);
if (it != registeredFunctionHandles.end() &&
it->second == serializedFunctionHandle) {
return;
}
}

// Get or create shared RestRemoteClient for this server URL
functions::rest::RestRemoteClientPtr remoteClient;
{
std::lock_guard<std::mutex> lock(registrationMutex);
auto clientIt = restClient.find(remoteFunctionServerRestURL);
if (clientIt == restClient.end()) {
restClient[remoteFunctionServerRestURL] =
std::make_shared<functions::rest::RestRemoteClient>(
remoteFunctionServerRestURL);
}
remoteClient = restClient[remoteFunctionServerRestURL];
}

functions::rest::VeloxRemoteFunctionMetadata metadata;

// Extract function name parts using the utility function
const std::string functionName =
getFunctionName(restFunctionHandle.functionId);
const auto parts = util::getFunctionNameParts(functionName);
const std::string schema = parts[1];
const std::string function = parts[2];

const std::string functionLocation = fmt::format(
"{}/v1/functions/{}/{}/{}/{}",
remoteFunctionServerRestURL,
schema,
function,
urlEncode(restFunctionHandle.functionId),
restFunctionHandle.version);
metadata.location = functionLocation;
metadata.serdeFormat = getSerdeFormat();

auto veloxSignature =
buildVeloxSignatureFromPrestoSignature(restFunctionHandle.signature);
std::vector<velox::exec::FunctionSignaturePtr> veloxSignatures = {
veloxSignature};

functions::rest::registerVeloxRemoteFunction(
getFunctionName(restFunctionHandle.functionId),
veloxSignatures,
metadata,
remoteClient);

// Update registration map
{
std::lock_guard<std::mutex> lock(registrationMutex);
registeredFunctionHandles[functionId] = serializedFunctionHandle;
}
}
} // namespace facebook::presto::functions::remote::rest
Comment thread
Joe-Abraham marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 "presto_cpp/presto_protocol/presto_protocol.h"

namespace facebook::presto::functions::remote::rest {

void registerRestRemoteFunction(
const protocol::RestFunctionHandle& restFunctionHandle);
} // namespace facebook::presto::functions::remote::rest
Loading
Loading