Skip to content

Commit

Permalink
[component/binlog_utils_udf] PS-8854: Convert binlog_utils_udf to a c…
Browse files Browse the repository at this point in the history
…omponent with function auto-registration
  • Loading branch information
inikep committed Aug 17, 2023
1 parent 891c650 commit e97df7c
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 176 deletions.
33 changes: 33 additions & 0 deletions components/binlog_utils_udf/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (c) 2023 Percona LLC and/or its affiliates. All rights reserved.

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2 of
# the License.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET AND NOT DEFINED CMAKE_VISIBILITY_INLINES_HIDDEN)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN YES)
endif()

# We are not interesting in profiling tests.
DISABLE_MISSING_PROFILE_WARNING()

MYSQL_ADD_COMPONENT(binlog_utils_udf
binlog_utils_udf.cc
LINK_LIBRARIES extra::rapidjson
MODULE_ONLY
)

ADD_DEFINITIONS(-DMYSQL_SERVER)

target_include_directories(component_binlog_utils_udf SYSTEM PRIVATE ${BOOST_PATCHES_DIR} ${BOOST_INCLUDE_DIR})
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/* Copyright (c) 2023 Percona LLC and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 of
the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */

#include <array>
#include <cstring>
#include <limits>
Expand All @@ -7,100 +23,23 @@
#include <type_traits>

#include <boost/algorithm/find_backward.hpp>

#include <mysql/plugin.h>
#include <boost/preprocessor/stringize.hpp>

#include <mysql/components/services/component_sys_var_service.h>
#include <mysql/components/services/udf_registration.h>

#include <mysqlpp/udf_wrappers.hpp>

#include <sql/binlog.h>
#include <sql/binlog/decompressing_event_object_istream.h>
#include <sql/binlog_reader.h>

namespace {

bool binlog_utils_udf_initialized{false};

struct registry_service_releaser {
void operator()(SERVICE_TYPE(registry) * srv) const noexcept {
if (srv != nullptr) mysql_plugin_registry_release(srv);
}
};
using registry_service_ptr =
std::unique_ptr<SERVICE_TYPE(registry), registry_service_releaser>;

registry_service_ptr reg_srv{nullptr, registry_service_releaser{}};

struct component_sys_variable_register_releaser {
registry_service_ptr &parent;
void operator()(SERVICE_TYPE(component_sys_variable_register) *
srv) const noexcept {
if (parent && srv != nullptr)
parent->release(reinterpret_cast<my_h_service>(
const_cast<SERVICE_TYPE_NO_CONST(component_sys_variable_register) *>(
srv)));
}
};
using component_sys_variable_register_ptr =
std::unique_ptr<SERVICE_TYPE(component_sys_variable_register),
component_sys_variable_register_releaser>;

component_sys_variable_register_ptr sys_var_srv{
nullptr, component_sys_variable_register_releaser{reg_srv}};

int binlog_utils_udf_init(void *) {
DBUG_TRACE;
registry_service_ptr local_reg_srv{mysql_plugin_registry_acquire(),
registry_service_releaser{}};
if (!local_reg_srv) return 1;
my_h_service acquired_service{nullptr};
if (local_reg_srv->acquire("component_sys_variable_register",
&acquired_service) != 0)
return 1;
if (acquired_service == nullptr) return 1;

reg_srv = std::move(local_reg_srv);
sys_var_srv.reset(
reinterpret_cast<SERVICE_TYPE(component_sys_variable_register) *>(
acquired_service));
binlog_utils_udf_initialized = true;
return 0;
}

int binlog_utils_udf_deinit(void *) {
DBUG_TRACE;
sys_var_srv.reset();
reg_srv.reset();
binlog_utils_udf_initialized = false;
return 0;
}

struct st_mysql_daemon binlog_utils_udf_decriptor = {
MYSQL_DAEMON_INTERFACE_VERSION};

} // end of anonymous namespace
// defined as a macro because needed both raw and stringized
#define CURRENT_COMPONENT_NAME binlog_utils_udf
#define CURRENT_COMPONENT_NAME_STR BOOST_PP_STRINGIZE(CURRENT_COMPONENT_NAME)

/*
Plugin library descriptor
*/

mysql_declare_plugin(binlog_utils_udf){
MYSQL_DAEMON_PLUGIN,
&binlog_utils_udf_decriptor,
"binlog_utils_udf",
PLUGIN_AUTHOR_ORACLE,
"Binlog utils UDF plugin",
PLUGIN_LICENSE_GPL,
binlog_utils_udf_init, /* Plugin Init */
nullptr, /* Plugin check uninstall */
binlog_utils_udf_deinit, /* Plugin Deinit */
0x0100 /* 1.0 */,
nullptr, /* status variables */
nullptr, /* system variables */
nullptr, /* config options */
0, /* flags */
} mysql_declare_plugin_end;
REQUIRES_SERVICE_PLACEHOLDER(udf_registration);
REQUIRES_SERVICE_PLACEHOLDER(component_sys_variable_register);

namespace {

Expand All @@ -122,14 +61,14 @@ ext::string_view extract_sys_var_value(ext::string_view component_name,
void *ptr = ub.first.data();
std::size_t length = ub.first.size() - 1;

if (sys_var_srv->get_variable(component_name.data(), variable_name.data(),
&ptr, &length) == 0)
if (mysql_service_component_sys_variable_register->get_variable(
component_name.data(), variable_name.data(), &ptr, &length) == 0)
return {static_cast<char *>(ptr), length};

ub.second.resize(length + 1);
ptr = ub.second.data();
if (sys_var_srv->get_variable(component_name.data(), variable_name.data(),
&ptr, &length) != 0)
if (mysql_service_component_sys_variable_register->get_variable(
component_name.data(), variable_name.data(), &ptr, &length) != 0)
throw std::runtime_error("Cannot get sys_var value");

if (ptr == nullptr) throw std::runtime_error("The value of sys_var is null");
Expand Down Expand Up @@ -333,11 +272,6 @@ class get_binlog_by_gtid_impl {
get_binlog_by_gtid_impl(mysqlpp::udf_context &ctx) {
DBUG_TRACE;

if (!binlog_utils_udf_initialized)
throw std::invalid_argument(
"This function requires binlog_utils_udf plugin which is not "
"installed.");

if (ctx.get_number_of_args() != 1)
throw std::invalid_argument("Function requires exactly one argument");
ctx.mark_result_const(false);
Expand Down Expand Up @@ -409,11 +343,6 @@ class get_last_gtid_from_binlog_impl {
get_last_gtid_from_binlog_impl(mysqlpp::udf_context &ctx) {
DBUG_TRACE;

if (!binlog_utils_udf_initialized)
throw std::invalid_argument(
"This function requires binlog_utils_udf plugin which is not "
"installed.");

if (ctx.get_number_of_args() != 1)
throw std::invalid_argument("Function requires exactly one argument");
ctx.mark_result_const(false);
Expand Down Expand Up @@ -455,11 +384,6 @@ class get_gtid_set_by_binlog_impl {
get_gtid_set_by_binlog_impl(mysqlpp::udf_context &ctx) {
DBUG_TRACE;

if (!binlog_utils_udf_initialized)
throw std::invalid_argument(
"This function requires binlog_utils_udf plugin which is not "
"installed.");

if (ctx.get_number_of_args() != 1)
throw std::invalid_argument("Function requires exactly one argument");
ctx.mark_result_const(false);
Expand Down Expand Up @@ -539,11 +463,6 @@ class get_binlog_by_gtid_set_impl {
get_binlog_by_gtid_set_impl(mysqlpp::udf_context &ctx) {
DBUG_TRACE;

if (!binlog_utils_udf_initialized)
throw std::invalid_argument(
"This function requires binlog_utils_udf plugin which is not "
"installed.");

if (ctx.get_number_of_args() != 1)
throw std::invalid_argument("Function requires exactly one argument");
ctx.mark_result_const(false);
Expand Down Expand Up @@ -625,11 +544,6 @@ class get_first_record_timestamp_by_binlog_impl {
get_first_record_timestamp_by_binlog_impl(mysqlpp::udf_context &ctx) {
DBUG_TRACE;

if (!binlog_utils_udf_initialized)
throw std::invalid_argument(
"This function requires binlog_utils_udf plugin which is not "
"installed.");

if (ctx.get_number_of_args() != 1)
throw std::invalid_argument("Function requires exactly one argument");
ctx.mark_result_const(false);
Expand Down Expand Up @@ -666,11 +580,6 @@ class get_last_record_timestamp_by_binlog_impl {
get_last_record_timestamp_by_binlog_impl(mysqlpp::udf_context &ctx) {
DBUG_TRACE;

if (!binlog_utils_udf_initialized)
throw std::invalid_argument(
"This function requires binlog_utils_udf plugin which is not "
"installed.");

if (ctx.get_number_of_args() != 1)
throw std::invalid_argument("Function requires exactly one argument");
ctx.mark_result_const(false);
Expand Down Expand Up @@ -700,15 +609,101 @@ get_last_record_timestamp_by_binlog_impl::calculate(
} // end of anonymous namespace

DECLARE_STRING_UDF(get_binlog_by_gtid_impl, get_binlog_by_gtid)

DECLARE_STRING_UDF(get_last_gtid_from_binlog_impl, get_last_gtid_from_binlog)

DECLARE_STRING_UDF(get_gtid_set_by_binlog_impl, get_gtid_set_by_binlog)

DECLARE_STRING_UDF(get_binlog_by_gtid_set_impl, get_binlog_by_gtid_set)

DECLARE_INT_UDF(get_first_record_timestamp_by_binlog_impl,
get_first_record_timestamp_by_binlog)

DECLARE_INT_UDF(get_last_record_timestamp_by_binlog_impl,
get_last_record_timestamp_by_binlog)

struct udf_info {
const char *name;
Item_result return_type;
Udf_func_any func;
Udf_func_init init_func;
Udf_func_deinit deinit_func;
};

#define DECLARE_UDF_INFO(NAME, TYPE) \
udf_info { #NAME, TYPE, (Udf_func_any)&NAME, &NAME##_init, &NAME##_deinit }

static const std::array known_udfs{
DECLARE_UDF_INFO(get_binlog_by_gtid, STRING_RESULT),
DECLARE_UDF_INFO(get_last_gtid_from_binlog, STRING_RESULT),
DECLARE_UDF_INFO(get_gtid_set_by_binlog, STRING_RESULT),
DECLARE_UDF_INFO(get_binlog_by_gtid_set, STRING_RESULT),
DECLARE_UDF_INFO(get_first_record_timestamp_by_binlog, INT_RESULT),
DECLARE_UDF_INFO(get_last_record_timestamp_by_binlog, INT_RESULT)};

#undef DECLARE_UDF_INFO

using udf_bitset_type =
std::bitset<std::tuple_size<decltype(known_udfs)>::value>;
static udf_bitset_type registered_udfs;

static constexpr std::size_t max_unregister_attempts = 10;
static constexpr auto unregister_sleep_interval = std::chrono::seconds(1);

static mysql_service_status_t component_init() {
std::size_t index = 0U;

index = 0U;
for (const auto &element : known_udfs) {
if (!registered_udfs.test(index)) {
if (mysql_service_udf_registration->udf_register(
element.name, element.return_type, element.func,
element.init_func, element.deinit_func) == 0)
registered_udfs.set(index);
}
++index;
}
return registered_udfs.all() ? 0 : 1;
}

static mysql_service_status_t component_deinit() {
int was_present = 0;

std::size_t index = 0U;

for (const auto &element : known_udfs) {
if (registered_udfs.test(index)) {
std::size_t attempt = 0;
mysql_service_status_t status = 0;
while (attempt < max_unregister_attempts &&
(status = mysql_service_udf_registration->udf_unregister(
element.name, &was_present)) != 0 &&
was_present != 0) {
std::this_thread::sleep_for(unregister_sleep_interval);
++attempt;
}
if (status == 0) registered_udfs.reset(index);
}
++index;
}

return registered_udfs.none() ? 0 : 1;
}

// clang-format off
BEGIN_COMPONENT_PROVIDES(CURRENT_COMPONENT_NAME)
END_COMPONENT_PROVIDES();

BEGIN_COMPONENT_REQUIRES(CURRENT_COMPONENT_NAME)
REQUIRES_SERVICE(udf_registration),
REQUIRES_SERVICE(component_sys_variable_register),
END_COMPONENT_REQUIRES();

BEGIN_COMPONENT_METADATA(CURRENT_COMPONENT_NAME)
METADATA("mysql.author", "Percona Corporation"),
METADATA("mysql.license", "GPL"),
END_COMPONENT_METADATA();

DECLARE_COMPONENT(CURRENT_COMPONENT_NAME, CURRENT_COMPONENT_NAME_STR)
component_init,
component_deinit,
END_DECLARE_COMPONENT();
// clang-format on

DECLARE_LIBRARY_COMPONENTS &COMPONENT_REF(CURRENT_COMPONENT_NAME)
END_DECLARE_LIBRARY_COMPONENTS
2 changes: 1 addition & 1 deletion mysql-test/include/plugin.defs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,6 @@ authentication_ldap_simple plugin_output_directory no AUTH_LDAP
authentication_ldap_sasl plugin_output_directory no AUTH_LDAP_SASL authentication_ldap_sasl
keyring_vault plugin_output_directory no KEYRING_VAULT_PLUGIN keyring_vault
test_udf_wrappers plugin_output_directory no TEST_UDF_WRAPPERS_LIB
binlog_utils_udf plugin_output_directory no BINLOG_UTILS_UDF_LIB
procfs plugin_output_directory no PROCFS_PLUGIN procfs
component_encryption_udf plugin_output_directory no ENCRYPTION_UDF_COMPONENT
component_binlog_utils_udf plugin_output_directory no BINLOG_UTILS_UDF_LIB
Loading

0 comments on commit e97df7c

Please sign in to comment.