/* Copyright (c) 2017, 2024, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is designed to work with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have either included with the program or referenced in the documentation. 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, version 2.0, 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 */ /** @file clone_handler.h Clone handler interface to access clone plugin */ #ifndef CLONE_HANDLER_INCLUDED #define CLONE_HANDLER_INCLUDED #include #include #include "my_io.h" #include "mysql.h" #include "sql/sql_plugin_ref.h" // plugin_ref class THD; class Srv_session; struct Mysql_clone; struct MYSQL_SOCKET; /** Number of PSI_statement_info instruments for clone statements. */ #define CLONE_PSI_STATEMENT_COUNT 5 /** Clone plugin handler to convenient way to. Takes */ class Clone_handler { public: /** Constructor: Initialize plugin name */ Clone_handler(const char *plugin_name_arg) : m_plugin_handle(nullptr) { m_plugin_name.assign(plugin_name_arg); } /** Initialize plugin handle @return error code */ int init(); /** Clone handler interface for local clone. @param[in] thd server thread handle @param[in] data_dir cloned data directory @return error code */ int clone_local(THD *thd, const char *data_dir); /** Clone handler interface for remote clone client. @param[in] thd server thread handle @param[in] remote_host remote host IP address @param[in] remote_port remote server port @param[in] remote_user remote user name @param[in] remote_passwd remote user's password @param[in] data_dir cloned data directory @param[in] ssl_mode remote connection ssl mode @return error code */ int clone_remote_client(THD *thd, const char *remote_host, uint remote_port, const char *remote_user, const char *remote_passwd, const char *data_dir, enum mysql_ssl_mode ssl_mode); /** Clone handler interface for remote clone server. @param[in] thd server thread handle @param[in] socket network socket to remote client @return error code */ int clone_remote_server(THD *thd, MYSQL_SOCKET socket); /** Get donor error and message for ER_CLONE_DONOR error. @param[in] session server session @param[out] error donor error number @param[out] message error message @return true, iff successful. */ static bool get_donor_error(Srv_session *session, int &error, const char *&message); /** @return false only if no user data is dropped yet. */ static bool is_data_dropped() { return (s_is_data_dropped); } /** Must set before dropping any user data. */ static void set_drop_data() { s_is_data_dropped.store(true); } /** @return true, if clone provisioning in progress. */ static bool is_provisioning() { return (s_provision_in_progress > 0); } /** @return true, if ordered commit should be forced. Currently clone would force ordered commit at end while blocking XA operations */ static bool need_commit_order() { return (s_xa_block_op.load()); } /* Initialize XA counters and mutex. */ static void init_xa(); /* Destroy XA mutex. */ static void uninit_xa(); /* RAII guard for XA operation synchronization with clone. */ struct XA_Operation { /** Constructor: mark XA operation begin. @param[in] thd session thread */ explicit XA_Operation(THD *thd); /** Destructor: mark XA operation end. */ ~XA_Operation(); /** Disable copy construction */ XA_Operation(XA_Operation const &) = delete; /** Disable assignment */ XA_Operation &operator=(XA_Operation const &) = delete; private: /** Session thread holding the guard. */ THD *m_thd; }; /* RAII guard for blocking and unblocking XA operations. */ struct XA_Block { /** Constructor: Block all XA operations. @param[in] thd session thread */ explicit XA_Block(THD *thd); /** Destructor: unblock XA operations. */ ~XA_Block(); /** Disable copy construction */ XA_Block(XA_Block const &) = delete; /** Disable assignment */ XA_Block &operator=(XA_Block const &) = delete; /** @return true, if XA blocking is unsuccessful. */ bool failed() const; private: /** If blocking is successful and there is no XA operations. */ bool m_success; }; private: /** Block new active XA operations and wait for existing ones to complete. @param[in] thd session thread */ static bool block_xa_operation(THD *thd); /** Unblock waiting XA operations. */ static void unblock_xa_operation(); /** Increment XA operation count and wait if blocked by clone. @param[in] thd session thread */ static void begin_xa_operation(THD *thd); /** Decrement XA operation count. */ static void end_xa_operation(); /** Validate clone data directory and convert to os format @param[in] in_dir user specified clone directory @param[out] out_dir data directory in native os format @return error code */ int validate_dir(const char *in_dir, char *out_dir); private: /** Number of XA operations (prepare/commit/rollback) in progress. */ static std::atomic s_xa_counter; /** Set when clone blocks XA operations. XA operations currently are not ordered between binlog and SE and needs to be synchronized for clone. */ static std::atomic s_xa_block_op; /** True if clone provisioning in progress. */ static std::atomic s_provision_in_progress; /** True, if any user data is dropped by clone. */ static std::atomic s_is_data_dropped; /** Mutex to synchronize blocking XA operation. */ static mysql_mutex_t s_xa_mutex; /** Clone plugin name */ std::string m_plugin_name; /** Clone plugin handle */ Mysql_clone *m_plugin_handle; }; /** Check if the clone plugin is installed and lock. If the plugin is ready, return the handler to caller. @param[in] thd server thread handle @param[out] plugin plugin reference @return clone handler on success otherwise NULL */ Clone_handler *clone_plugin_lock(THD *thd, plugin_ref *plugin); /** Unlock the clone plugin. @param[in] thd server thread handle @param[out] plugin plugin reference */ void clone_plugin_unlock(THD *thd, plugin_ref plugin); #endif /* CLONE_HANDLER_INCLUDED */