diff --git a/include/wsrep/provider.hpp b/include/wsrep/provider.hpp index 4c85880a..2c0c7db3 100644 --- a/include/wsrep/provider.hpp +++ b/include/wsrep/provider.hpp @@ -46,6 +46,7 @@ namespace wsrep class high_priority_service; class thread_service; class tls_service; + class ps_service; class stid { @@ -422,9 +423,11 @@ namespace wsrep { wsrep::thread_service* thread_service; wsrep::tls_service* tls_service; + wsrep::ps_service* ps_service; services() : thread_service() , tls_service() + , ps_service() { } }; diff --git a/include/wsrep/ps_service.hpp b/include/wsrep/ps_service.hpp new file mode 100644 index 00000000..aea53468 --- /dev/null +++ b/include/wsrep/ps_service.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib 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, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib 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 wsrep-lib. If not, see . + */ + +/** @file ps_service.hpp + * + * Service interface for interacting with Performance Scheme + * tables at DBMS side. + */ + +#ifndef WSREP_PS_SERVICE_HPP +#define WSREP_PS_SERVICE_HPP + +#include "compiler.hpp" +#include "provider.hpp" +#include "wsrep_ps.h" + +namespace wsrep +{ + /** @class ps_service + * + * PS service interface. This provides an interface corresponding + * to wsrep PS service. For details see wsrep-API/ps/wsrep_ps.h + */ + class ps_service + { + public: + virtual ~ps_service() { } + /** + * Fetch cluster information to populate cluster members table. + */ + virtual wsrep_status_t + fetch_pfs_info(provider* provider, + wsrep_node_info_t* nodes, + uint32_t* size) WSREP_NOEXCEPT = 0; + /** + * Fetch node information to populate node statistics table. + */ + virtual wsrep_status_t + fetch_pfs_stat(provider* provider, + wsrep_node_stat_t* node) WSREP_NOEXCEPT = 0; + }; +} + +#endif // WSREP_PS_SERVICE_HPP diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0401494b..731adbbe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(wsrep-lib thread.cpp thread_service_v1.cpp tls_service_v1.cpp + ps_service_v1.cpp transaction.cpp uuid.cpp wsrep_provider_v26.cpp) diff --git a/src/ps_service_v1.cpp b/src/ps_service_v1.cpp new file mode 100644 index 00000000..353f71d3 --- /dev/null +++ b/src/ps_service_v1.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2020 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib 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, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib 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 wsrep-lib. If not, see . + */ + +#include "ps_service_v1.hpp" + +#include "wsrep/ps_service.hpp" +#include "wsrep/logger.hpp" +#include "wsrep/provider.hpp" +#include "service_helpers.hpp" + +#include + +namespace wsrep_ps_service_v1 +{ + static wsrep::ps_service* ps_service_impl{0}; + static std::atomic use_count; + + static wsrep_ps_service_v1_t ps_callbacks; +} + +int wsrep::ps_service_v1_probe(void* dlh) +{ + typedef int (*init_fn)(wsrep_ps_service_v1_t*); + typedef void (*deinit_fn)(); + if (wsrep_impl::service_probe( + dlh, WSREP_PS_SERVICE_INIT_FUNC_V1, "ps service v1") || + wsrep_impl::service_probe( + dlh, WSREP_PS_SERVICE_DEINIT_FUNC_V1, "ps service v1")) + { + wsrep::log_warning() << "Provider does not support PS service v1"; + return 1; + } + return 0; +} + +int wsrep::ps_service_v1_init(void* dlh, + wsrep::ps_service* ps_service) +{ + if (! (dlh && ps_service)) return EINVAL; + + typedef int (*init_fn)(wsrep_ps_service_v1_t*); + wsrep_ps_service_v1::ps_service_impl = ps_service; + int ret(0); + if ((ret = wsrep_impl::service_init( + dlh, WSREP_PS_SERVICE_INIT_FUNC_V1, + &wsrep_ps_service_v1::ps_callbacks, + "PS service v1"))) + { + wsrep_ps_service_v1::ps_service_impl = 0; + } + else + { + ++wsrep_ps_service_v1::use_count; + } + return ret; +} + +void wsrep::ps_service_v1_deinit(void* dlh) +{ + typedef int (*deinit_fn)(); + wsrep_impl::service_deinit( + dlh, WSREP_PS_SERVICE_DEINIT_FUNC_V1, "ps service v1"); + --wsrep_ps_service_v1::use_count; + if (wsrep_ps_service_v1::use_count == 0) + { + wsrep_ps_service_v1::ps_service_impl = 0; + } +} + +namespace wsrep +{ + +/** + * Fetch cluster information to populate cluster members table. + */ +wsrep_status_t + ps_service::fetch_pfs_info(provider* provider, + wsrep_node_info_t* nodes, + uint32_t* size) WSREP_NOEXCEPT +{ + wsrep_t* wsrep_ = reinterpret_cast(provider->native()); + return wsrep_ps_service_v1:: + ps_callbacks.fetch_cluster_info(wsrep_, nodes, size); +} + +/** + * Fetch node information to populate node statistics table. + */ +wsrep_status_t + ps_service::fetch_pfs_stat(provider* provider, + wsrep_node_stat_t* node) WSREP_NOEXCEPT +{ + wsrep_t* wsrep_ = reinterpret_cast(provider->native()); + return wsrep_ps_service_v1:: + ps_callbacks.fetch_node_stat(wsrep_, node); +} + +} // namespace "wsrep" diff --git a/src/ps_service_v1.hpp b/src/ps_service_v1.hpp new file mode 100644 index 00000000..1c71b263 --- /dev/null +++ b/src/ps_service_v1.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib 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, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib 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 wsrep-lib. If not, see . + */ + +#ifndef WSREP_PS_SERVICE_V1_HPP +#define WSREP_PS_SERVICE_V1_HPP + +namespace wsrep +{ + class ps_service; + /** + * Probe thread_service_v1 support in loaded library. + * + * @param dlh Handle returned by dlopen(). + * + * @return Zero on success, non-zero system error code on failure. + */ + int ps_service_v1_probe(void *dlh); + + /** + * Initialize PS service. + * + * @param dlh Handle returned by dlopen(). + * @params thread_service Pointer to wsrep::thread_service implementation. + * + * @return Zero on success, non-zero system error code on failure. + */ + int ps_service_v1_init(void* dlh, + wsrep::ps_service* ps_service); + + /** + * Deinitialize PS service. + * + * @param dlh Handler returned by dlopen(). + */ + void ps_service_v1_deinit(void* dlh); +} + +#endif // WSREP_PS_SERVICE_V1_HPP diff --git a/src/wsrep_provider_v26.cpp b/src/wsrep_provider_v26.cpp index a579dff2..f0ab7896 100644 --- a/src/wsrep_provider_v26.cpp +++ b/src/wsrep_provider_v26.cpp @@ -27,9 +27,11 @@ #include "wsrep/logger.hpp" #include "wsrep/thread_service.hpp" #include "wsrep/tls_service.hpp" +#include "wsrep/ps_service.hpp" #include "thread_service_v1.hpp" #include "tls_service_v1.hpp" +#include "ps_service_v1.hpp" #include "v26/wsrep_api.h" @@ -635,6 +637,22 @@ namespace // assert(not wsrep::tls_service_v1_probe(dlh)); wsrep::tls_service_v1_deinit(dlh); } + + static int init_ps_service(void* dlh, + wsrep::ps_service* ps_service) + { + assert(ps_service); + if (! wsrep::ps_service_v1_probe(dlh)) + { + return wsrep::ps_service_v1_init(dlh, ps_service); + } + return 1; + } + + static void deinit_ps_service(void* dlh) + { + wsrep::ps_service_v1_deinit(dlh); + } } void wsrep::wsrep_provider_v26::init_services( @@ -656,10 +674,20 @@ void wsrep::wsrep_provider_v26::init_services( } services_enabled_.tls_service = services.tls_service; } + if (services.ps_service) + { + if (init_ps_service(wsrep_->dlh, services.ps_service)) + { + throw wsrep::runtime_error("Failed to initialze PS service"); + } + services_enabled_.ps_service = services.ps_service; + } } void wsrep::wsrep_provider_v26::deinit_services() { + if (services_enabled_.ps_service) + deinit_ps_service(wsrep_->dlh); if (services_enabled_.tls_service) deinit_tls_service(wsrep_->dlh); if (services_enabled_.thread_service) diff --git a/wsrep-API/ps/wsrep_ps.h b/wsrep-API/ps/wsrep_ps.h new file mode 100644 index 00000000..460d9fcf --- /dev/null +++ b/wsrep-API/ps/wsrep_ps.h @@ -0,0 +1,193 @@ +#ifndef WSREP_PS_H +#define WSREP_PS_H + +#include +#include +#include "wsrep_api.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define WSREP_PS_API_VERSION 0x100 + +/*! + * Structures for communicating information that will be exposed + * through Performance Schema tables: + */ + +#define WSREP_HOSTNAME_LENGTH 64 +#define WSREP_STATUS_LENGTH 32 + +/* Information about the current state of all nodes in the cluster: */ + +typedef struct { + /* Local node index: */ + uint32_t wsrep_local_index; + + /* Unique node ID (UUID): */ + char wsrep_node_id[WSREP_UUID_STR_LEN + 1]; + + /* User-assigned host name: */ + char wsrep_host_name[WSREP_HOSTNAME_LENGTH + 1]; + + /* The UUID of the cluster: */ + char wsrep_cluster_state_uuid[WSREP_UUID_STR_LEN + 1]; + + /* The UUID of the state stored on this node: */ + char wsrep_local_state_uuid[WSREP_UUID_STR_LEN + 1]; + + /* Status PRIMARY/NON_PRIMARY: */ + char wsrep_status[WSREP_STATUS_LENGTH + 1]; + + /* Segment of the node: */ + uint32_t wsrep_segment; + + /* Sequence number of the last applied transaction: */ + uint64_t wsrep_last_applied; + + /* Sequence number of the last committed transaction: */ + uint64_t wsrep_last_committed; + + /* Total number of write-sets replicated: */ + uint64_t wsrep_replicated; + + /* Total size of write-sets replicated: */ + uint64_t wsrep_replicated_bytes; + + /* Total number of write-sets received: */ + uint64_t wsrep_received; + + /* Total size of write-sets received: */ + uint64_t wsrep_received_bytes; + + /* Total number of local transactions that were aborted by slave + transactions while in execution: */ + uint64_t wsrep_local_bf_aborts; + + /* Total number of local transactions committed: */ + uint64_t wsrep_local_commits; + + /* Total number of local transactions that failed certification test: */ + uint64_t wsrep_local_cert_failures; + + /* Average distance between the highest and lowest concurrently + applied seqno: */ + uint64_t wsrep_apply_window; + + /* Average distance between the highest and lowest concurrently + committed seqno: */ + uint64_t wsrep_commit_window; +} wsrep_node_info_t; + +/*! Data structure with statistics of the current node: */ + +typedef struct { + /* Local node index: */ + int wsrep_local_index; + + /* Unique node ID (UUID): */ + char wsrep_node_id[WSREP_UUID_STR_LEN + 1]; + + /* Total number of keys replicated: */ + uint64_t wsrep_repl_keys; + + /* Total size of keys replicated: */ + uint64_t wsrep_repl_keys_bytes; + + /* Total size of data replicated: */ + uint64_t wsrep_repl_data_bytes; + + /* Total size of other bits replicated: */ + uint64_t wsrep_repl_other_bytes; + + /* Total number of transaction replays due to asymmetric lock + granularity: */ + uint64_t wsrep_local_replays; + + /* Current (instantaneous) length of the send queue: */ + uint64_t wsrep_local_send_queue; + + /* Send queue length averaged over time since the last + FLUSH STATUS command: */ + double wsrep_local_send_queue_avg; + + /* Current (instantaneous) length of the recv queue: */ + uint64_t wsrep_local_recv_queue; + + /* Recv queue length averaged over interval since the last + FLUSH STATUS command: */ + double wsrep_local_recv_queue_avg; + + /* The fraction of time (out of 1.0) since the last + SHOW GLOBAL STATUS that flow control is effective: */ + uint64_t wsrep_flow_control_paused; + + /* The number of flow control messages sent by the local node + to the cluster: */ + uint64_t wsrep_flow_control_sent; + + /* The number of flow control messages the node has received, + including those the node has sent: */ + uint64_t wsrep_flow_control_recv; + + /* This variable shows whether a node has flow control + enabled for normal traffic: */ + char wsrep_flow_control_status[WSREP_STATUS_LENGTH + 1]; + + /* Average distance between the highest and lowest seqno + value that can be possibly applied in parallel: */ + double wsrep_cert_deps_distance; + + /* The number of locally running transactions which have been + registered inside the wsrep provider: */ + uint64_t wsrep_open_transactions; + + /* This status variable provides figures for the replication + latency on group communication: */ + uint64_t wsrep_evs_repl_latency; +} wsrep_node_stat_t; + +/*! + * @brief Get general cluster information to expose through + * Performance Schema. + * + * @param wsrep provider handle. + * @param nodes array of node information to populate. + * @param size size of array (in/out parameter). + */ +typedef wsrep_status_t + (*wsrep_ps_fetch_cluster_info_t) (wsrep_t* wsrep, + wsrep_node_info_t* nodes, + uint32_t* size); + +/*! + * @brief Get current node information to expose through + * Performance Schema. + * + * @param wsrep provider handle. + * @param node data structure with information about the node + * (will be filled with data, output parameter). + */ +typedef wsrep_status_t + (*wsrep_ps_fetch_node_stat_t) (wsrep_t* wsrep, + wsrep_node_stat_t* node); + +typedef struct wsrep_ps_service_v1_st +{ + wsrep_ps_fetch_cluster_info_t fetch_cluster_info; + wsrep_ps_fetch_node_stat_t fetch_node_stat; +} wsrep_ps_service_v1_t; + +#define WSREP_PS_SERVICE_INIT_FUNC_V1 "wsrep_init_ps_service_v1" +#define WSREP_PS_SERVICE_DEINIT_FUNC_V1 "wsrep_deinit_ps_service_v1" + +/* For backwards compatibility. */ +#define WSREP_PS_SERVICE_INIT_FUNC WSREP_PS_SERVICE_INIT_FUNC_V1 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* WSREP_PS_H */