Skip to content

Commit caba50f

Browse files
soumiiowfacebook-github-bot
authored andcommitted
feat: Make registry symbol name customizable for dynamic component registration (facebookincubator#12878)
Summary: Users can now create shared libraries for dynamic component registration with these proposed changes Pull Request resolved: facebookincubator#12878 Reviewed By: gggrace14 Differential Revision: D74858268 Pulled By: xiaoxmeng fbshipit-source-id: 6e7b07d6a80c68c2095ce6a845d968306a1cd62c
1 parent 5f73cf6 commit caba50f

13 files changed

+121
-56
lines changed

velox/common/dynamic_registry/DynamicLibraryLoader.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
namespace facebook::velox {
2222

23-
static constexpr const char* kSymbolName = "registry";
24-
25-
void loadDynamicLibrary(const std::string& fileName) {
23+
void loadDynamicLibrary(
24+
const std::string& fileName,
25+
const std::string& registrationFunctionName) {
2626
// Try to dynamically load the shared library.
2727
void* handler = dlopen(fileName.c_str(), RTLD_NOW);
2828

@@ -31,9 +31,10 @@ void loadDynamicLibrary(const std::string& fileName) {
3131
}
3232

3333
LOG(INFO) << "Loaded library " << fileName << ". Searching registry symbol "
34-
<< kSymbolName;
34+
<< registrationFunctionName;
35+
3536
// Lookup the symbol.
36-
void* registrySymbol = dlsym(handler, kSymbolName);
37+
void* registrySymbol = dlsym(handler, registrationFunctionName.c_str());
3738
auto loadUserLibrary = reinterpret_cast<void (*)()>(registrySymbol);
3839
const char* error = dlerror();
3940

@@ -45,13 +46,13 @@ void loadDynamicLibrary(const std::string& fileName) {
4546

4647
if (loadUserLibrary == nullptr) {
4748
VELOX_USER_FAIL(
48-
"Symbol '{}' resolved to a nullptr, unable to invoke it.", kSymbolName);
49+
"Symbol '{}' resolved to a nullptr, unable to invoke it.",
50+
registrationFunctionName);
4951
}
5052

5153
// Invoke the registry function.
52-
LOG(INFO) << "Found registry function. Invoking it.";
5354
loadUserLibrary();
54-
LOG(INFO) << "Registration complete.";
55+
LOG(INFO) << "Registered functions by " << registrationFunctionName;
5556
}
5657

5758
} // namespace facebook::velox

velox/common/dynamic_registry/DynamicLibraryLoader.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ namespace facebook::velox {
3838
///
3939
/// Loading a library twice can cause a components to be registered twice.
4040
/// This can fail for certain Velox components.
41-
void loadDynamicLibrary(const std::string& fileName);
41+
42+
void loadDynamicLibrary(
43+
const std::string& fileName,
44+
const std::string& entryPointSymbol = "registerExtensions");
4245

4346
} // namespace facebook::velox

velox/common/dynamic_registry/DynamicUdf.h

Lines changed: 0 additions & 31 deletions
This file was deleted.

velox/common/dynamic_registry/tests/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ add_library(velox_overload_int_function_dynamic SHARED
2626
DynamicIntFunctionOverload.cpp)
2727
add_library(velox_overload_varchar_function_dynamic SHARED
2828
DynamicVarcharFunctionOverload.cpp)
29+
add_library(velox_function_non_default_dynamic SHARED
30+
DynamicFunctionNonDefault.cpp)
2931

3032
set(CMAKE_DYLIB_TEST_LINK_LIBRARIES fmt::fmt Folly::folly glog::glog xsimd)
3133

@@ -53,6 +55,10 @@ target_link_libraries(
5355
velox_overload_varchar_function_dynamic
5456
PRIVATE ${CMAKE_DYLIB_TEST_LINK_LIBRARIES})
5557

58+
target_link_libraries(
59+
velox_function_non_default_dynamic
60+
PRIVATE ${CMAKE_DYLIB_TEST_LINK_LIBRARIES})
61+
5662
if(APPLE)
5763
set(COMMON_LIBRARY_LINK_OPTIONS "-Wl,-undefined,dynamic_lookup")
5864
else()
@@ -74,6 +80,8 @@ target_link_options(velox_overload_int_function_dynamic PRIVATE
7480
${COMMON_LIBRARY_LINK_OPTIONS})
7581
target_link_options(velox_overload_varchar_function_dynamic PRIVATE
7682
${COMMON_LIBRARY_LINK_OPTIONS})
83+
target_link_options(velox_function_non_default_dynamic PRIVATE
84+
${COMMON_LIBRARY_LINK_OPTIONS})
7785

7886
# Here's the actual test which will dynamically load the library defined above.
7987
add_executable(velox_function_dynamic_link_test DynamicLinkTest.cpp)

velox/common/dynamic_registry/tests/DynamicErrFunction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
#include "velox/common/dynamic_registry/DynamicUdf.h"
17+
#include "velox/functions/Udf.h"
1818

1919
// This file defines a mock function that will be dynamically linked and
2020
// registered. There are no restrictions as to how the function needs to be
@@ -39,7 +39,7 @@ struct DynamicFunction {
3939
} // namespace facebook::velox::common::dynamicRegistry
4040

4141
extern "C" {
42-
void registry() {
42+
void registerExtensions() {
4343
facebook::velox::registerFunction<
4444
facebook::velox::common::dynamicRegistry::DynamicFunction,
4545
int64_t,

velox/common/dynamic_registry/tests/DynamicFunction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
#include "velox/common/dynamic_registry/DynamicUdf.h"
17+
#include "velox/functions/Udf.h"
1818

1919
// This file defines a mock function that will be dynamically linked and
2020
// registered. There are no restrictions as to how the function needs to be
@@ -39,7 +39,7 @@ struct DynamicFunction {
3939
extern "C" {
4040
// In this case, we assume that facebook::velox::registerFunction
4141
// will be available and resolve when this library gets loaded.
42-
void registry() {
42+
void registerExtensions() {
4343
facebook::velox::registerFunction<
4444
facebook::velox::common::dynamicRegistry::DynamicFunction,
4545
int64_t>({"dynamic"});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "velox/functions/Udf.h"
18+
19+
// This file defines a mock function that will be dynamically linked and
20+
// registered. There are no restrictions as to how the function needs to be
21+
// defined, but the library (.so) needs to provide a `void registry()` C
22+
// function in the top-level namespace.
23+
//
24+
// (note the extern "C" directive to prevent the compiler from mangling the
25+
// symbol name).
26+
27+
namespace facebook::velox::common::dynamicRegistry {
28+
29+
template <typename T>
30+
struct DynamicFunction {
31+
FOLLY_ALWAYS_INLINE bool call(int64_t& result) {
32+
result = 123;
33+
return true;
34+
}
35+
};
36+
37+
} // namespace facebook::velox::common::dynamicRegistry
38+
39+
extern "C" {
40+
// In this case, we assume that facebook::velox::registerFunction
41+
// will be available and resolve when this library gets loaded.
42+
void registerExtensionsNew() {
43+
facebook::velox::registerFunction<
44+
facebook::velox::common::dynamicRegistry::DynamicFunction,
45+
int64_t>({"dynamic_non_default"});
46+
}
47+
}

velox/common/dynamic_registry/tests/DynamicIntFunctionOverload.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
#include "velox/common/dynamic_registry/DynamicUdf.h"
17+
#include "velox/functions/Udf.h"
1818

1919
// This file defines a mock function that will be dynamically linked and
2020
// registered. There are no restrictions as to how the function needs to be
@@ -39,7 +39,7 @@ struct DynamicFunction {
3939

4040
extern "C" {
4141

42-
void registry() {
42+
void registerExtensions() {
4343
facebook::velox::registerFunction<
4444
facebook::velox::common::dynamicRegistry::DynamicFunction,
4545
int64_t,

velox/common/dynamic_registry/tests/DynamicIntFunctionOverwrite.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
#include "velox/common/dynamic_registry/DynamicUdf.h"
17+
#include "velox/functions/Udf.h"
1818

1919
// This file defines a mock function that will be dynamically linked and
2020
// registered. There are no restrictions as to how the function needs to be
@@ -38,7 +38,7 @@ struct DynamicFunction {
3838

3939
extern "C" {
4040

41-
void registry() {
41+
void registerExtensions() {
4242
facebook::velox::registerFunction<
4343
facebook::velox::common::dynamicRegistry::DynamicFunction,
4444
int64_t>({"dynamic_overwrite"});

velox/common/dynamic_registry/tests/DynamicLinkTest.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,40 @@ TEST_F(DynamicLinkTest, dynamicLoadOverloadFunc) {
203203
EXPECT_EQ(TypeKind::BIGINT, resolvedAfterSecond->type()->kind());
204204
}
205205

206+
TEST_F(DynamicLinkTest, dynamicLoadFuncNonDefaultRegistry) {
207+
const auto dynamicFunction = [&]() {
208+
return evaluateOnce<int64_t>(
209+
"dynamic_non_default()", makeRowVector(ROW({}), 1));
210+
};
211+
212+
const auto dynamicFunctionNestedCall = [&]() {
213+
return evaluateOnce<int64_t>(
214+
"mod(dynamic_non_default(), 10)", makeRowVector(ROW({}), 1));
215+
};
216+
217+
VELOX_ASSERT_THROW(
218+
dynamicFunction(), "Scalar function doesn't exist: dynamic_non_default.");
219+
220+
auto signaturesBefore = getFunctionSignatures().size();
221+
std::string libraryPath =
222+
getLibraryPath("libvelox_function_non_default_dynamic");
223+
loadDynamicLibrary(libraryPath, "registerExtensionsNew");
224+
auto signaturesAfter = getFunctionSignatures().size();
225+
EXPECT_EQ(signaturesAfter, signaturesBefore + 1);
226+
EXPECT_EQ(123, dynamicFunction());
227+
228+
auto& registry = exec::simpleFunctions();
229+
auto resolved = registry.resolveFunction("dynamic_non_default", {});
230+
EXPECT_EQ(TypeKind::BIGINT, resolved->type()->kind());
231+
232+
EXPECT_EQ(3, dynamicFunctionNestedCall());
233+
234+
// Testing missing default registry function name.
235+
VELOX_ASSERT_THROW(
236+
loadDynamicLibrary(libraryPath),
237+
fmt::format(
238+
"Couldn't find Velox registry symbol: {}: undefined symbol: registerExtensions",
239+
libraryPath));
240+
}
241+
206242
} // namespace facebook::velox::functions::test

0 commit comments

Comments
 (0)