mirror of https://github.com/sysown/proxysql
parent
8cecd064fa
commit
7e1a12b8f7
@ -0,0 +1,82 @@
|
||||
#ifndef PROXYSQL_PLUGIN_H
|
||||
#define PROXYSQL_PLUGIN_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
enum ProxySQL_PluginDBKind {
|
||||
admin_db,
|
||||
config_db,
|
||||
stats_db,
|
||||
};
|
||||
|
||||
struct ProxySQL_PluginTableDef {
|
||||
ProxySQL_PluginDBKind db_kind{admin_db};
|
||||
const char *schema_name{nullptr};
|
||||
const char *table_name{nullptr};
|
||||
const char *create_statement{nullptr};
|
||||
};
|
||||
|
||||
struct ProxySQL_PluginCommandContext {
|
||||
const char *command_name{nullptr};
|
||||
std::vector<std::string> arguments;
|
||||
};
|
||||
|
||||
struct ProxySQL_PluginCommandResult {
|
||||
bool success{true};
|
||||
std::string message;
|
||||
std::vector<std::vector<std::string>> rows;
|
||||
};
|
||||
|
||||
class ProxySQL_PluginServices;
|
||||
|
||||
using proxysql_plugin_admin_command_cb =
|
||||
bool (*)(const ProxySQL_PluginCommandContext &, ProxySQL_PluginCommandResult &, void *);
|
||||
|
||||
using proxysql_plugin_register_table_cb =
|
||||
bool (*)(void *, const ProxySQL_PluginTableDef &);
|
||||
|
||||
using proxysql_plugin_register_command_cb =
|
||||
bool (*)(void *, const char *, proxysql_plugin_admin_command_cb, void *);
|
||||
|
||||
using proxysql_plugin_snapshot_cb =
|
||||
bool (*)(void *, std::vector<std::vector<std::string>> &);
|
||||
|
||||
using proxysql_plugin_log_message_cb =
|
||||
void (*)(void *, int, const char *);
|
||||
|
||||
struct ProxySQL_PluginServices {
|
||||
proxysql_plugin_register_table_cb register_table{nullptr};
|
||||
proxysql_plugin_register_command_cb register_command{nullptr};
|
||||
proxysql_plugin_snapshot_cb get_mysql_users_snapshot{nullptr};
|
||||
proxysql_plugin_snapshot_cb get_mysql_servers_snapshot{nullptr};
|
||||
proxysql_plugin_snapshot_cb get_mysql_group_replication_hostgroups_snapshot{nullptr};
|
||||
proxysql_plugin_log_message_cb log_message{nullptr};
|
||||
void *context{nullptr};
|
||||
};
|
||||
|
||||
using proxysql_plugin_init_cb =
|
||||
bool (*)(ProxySQL_PluginServices *, std::string &);
|
||||
|
||||
using proxysql_plugin_start_cb =
|
||||
bool (*)(std::string &);
|
||||
|
||||
using proxysql_plugin_stop_cb =
|
||||
bool (*)();
|
||||
|
||||
using proxysql_plugin_status_cb =
|
||||
bool (*)(std::string &);
|
||||
|
||||
struct ProxySQL_PluginDescriptor {
|
||||
uint32_t abi_version{0};
|
||||
const char *name{nullptr};
|
||||
proxysql_plugin_init_cb init{nullptr};
|
||||
proxysql_plugin_start_cb start{nullptr};
|
||||
proxysql_plugin_stop_cb stop{nullptr};
|
||||
proxysql_plugin_status_cb status{nullptr};
|
||||
};
|
||||
|
||||
using proxysql_plugin_descriptor_v1_t = const ProxySQL_PluginDescriptor *(*)();
|
||||
|
||||
#endif /* PROXYSQL_PLUGIN_H */
|
||||
@ -0,0 +1,38 @@
|
||||
#ifndef PROXYSQL_PLUGIN_MANAGER_H
|
||||
#define PROXYSQL_PLUGIN_MANAGER_H
|
||||
|
||||
#include "ProxySQL_Plugin.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ProxySQL_PluginManager {
|
||||
public:
|
||||
ProxySQL_PluginManager();
|
||||
~ProxySQL_PluginManager();
|
||||
|
||||
ProxySQL_PluginManager(const ProxySQL_PluginManager &) = delete;
|
||||
ProxySQL_PluginManager &operator=(const ProxySQL_PluginManager &) = delete;
|
||||
|
||||
bool load(const std::string &path, std::string &err);
|
||||
bool init_all(std::string &err);
|
||||
bool start_all(std::string &err);
|
||||
bool stop_all();
|
||||
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
struct plugin_handle_t {
|
||||
void *handle{nullptr};
|
||||
const ProxySQL_PluginDescriptor *descriptor{nullptr};
|
||||
bool initialized{false};
|
||||
bool started{false};
|
||||
bool stopped{false};
|
||||
};
|
||||
|
||||
std::vector<plugin_handle_t> plugins_;
|
||||
ProxySQL_PluginServices services_;
|
||||
};
|
||||
|
||||
#endif /* PROXYSQL_PLUGIN_MANAGER_H */
|
||||
@ -0,0 +1,131 @@
|
||||
#include "ProxySQL_PluginManager.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
|
||||
std::string format_dl_error(const char *prefix) {
|
||||
const char *dl_err = dlerror();
|
||||
if (dl_err == nullptr) {
|
||||
return prefix;
|
||||
}
|
||||
return std::string(prefix) + dl_err;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ProxySQL_PluginManager::ProxySQL_PluginManager() : services_{} {}
|
||||
|
||||
ProxySQL_PluginManager::~ProxySQL_PluginManager() {
|
||||
stop_all();
|
||||
for (auto it = plugins_.rbegin(); it != plugins_.rend(); ++it) {
|
||||
if (it->handle != nullptr) {
|
||||
dlclose(it->handle);
|
||||
it->handle = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ProxySQL_PluginManager::load(const std::string &path, std::string &err) {
|
||||
err.clear();
|
||||
|
||||
void *handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
|
||||
if (handle == nullptr) {
|
||||
err = format_dl_error("dlopen failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
dlerror();
|
||||
auto descriptor_fn = reinterpret_cast<proxysql_plugin_descriptor_v1_t>(
|
||||
dlsym(handle, "proxysql_plugin_descriptor_v1"));
|
||||
const char *dlsym_err = dlerror();
|
||||
if (dlsym_err != nullptr || descriptor_fn == nullptr) {
|
||||
err = dlsym_err != nullptr ? dlsym_err : "missing proxysql_plugin_descriptor_v1";
|
||||
dlclose(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
const ProxySQL_PluginDescriptor *descriptor = descriptor_fn();
|
||||
if (descriptor == nullptr) {
|
||||
err = "proxysql_plugin_descriptor_v1 returned null";
|
||||
dlclose(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (descriptor->abi_version != 1) {
|
||||
err = "unsupported plugin ABI version";
|
||||
dlclose(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
plugin_handle_t plugin;
|
||||
plugin.handle = handle;
|
||||
plugin.descriptor = descriptor;
|
||||
plugins_.push_back(plugin);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProxySQL_PluginManager::init_all(std::string &err) {
|
||||
err.clear();
|
||||
|
||||
for (auto &plugin : plugins_) {
|
||||
if (plugin.initialized || plugin.stopped) {
|
||||
continue;
|
||||
}
|
||||
if (plugin.descriptor == nullptr || plugin.descriptor->init == nullptr) {
|
||||
plugin.initialized = true;
|
||||
continue;
|
||||
}
|
||||
if (!plugin.descriptor->init(&services_, err)) {
|
||||
return false;
|
||||
}
|
||||
plugin.initialized = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProxySQL_PluginManager::start_all(std::string &err) {
|
||||
err.clear();
|
||||
|
||||
for (auto &plugin : plugins_) {
|
||||
if (plugin.started || plugin.stopped) {
|
||||
continue;
|
||||
}
|
||||
if (plugin.descriptor == nullptr || plugin.descriptor->start == nullptr) {
|
||||
plugin.started = true;
|
||||
continue;
|
||||
}
|
||||
if (!plugin.descriptor->start(err)) {
|
||||
return false;
|
||||
}
|
||||
plugin.started = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProxySQL_PluginManager::stop_all() {
|
||||
bool ok = true;
|
||||
|
||||
for (auto it = plugins_.rbegin(); it != plugins_.rend(); ++it) {
|
||||
if (!it->initialized && !it->started) {
|
||||
continue;
|
||||
}
|
||||
if (it->stopped) {
|
||||
continue;
|
||||
}
|
||||
if (it->descriptor != nullptr && it->descriptor->stop != nullptr) {
|
||||
ok = it->descriptor->stop() && ok;
|
||||
}
|
||||
it->stopped = true;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
size_t ProxySQL_PluginManager::size() const {
|
||||
return plugins_.size();
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
#include "ProxySQL_Plugin.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
bool fake_init(ProxySQL_PluginServices *, std::string &) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fake_start(std::string &) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fake_stop() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fake_status(std::string &) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const ProxySQL_PluginDescriptor fake_descriptor = {
|
||||
1,
|
||||
"fake_plugin",
|
||||
&fake_init,
|
||||
&fake_start,
|
||||
&fake_stop,
|
||||
&fake_status,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" const ProxySQL_PluginDescriptor *proxysql_plugin_descriptor_v1() {
|
||||
return &fake_descriptor;
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
#include "tap.h"
|
||||
#include "ProxySQL_PluginManager.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
static void test_loader_round_trip() {
|
||||
ProxySQL_PluginManager mgr;
|
||||
std::string err;
|
||||
|
||||
ok(mgr.load("../../test_helpers/libproxysql_fake_plugin.so", err),
|
||||
"load fake plugin succeeds");
|
||||
ok(mgr.size() == 1, "exactly one plugin is loaded");
|
||||
ok(mgr.init_all(err), "init_all succeeds");
|
||||
ok(mgr.start_all(err), "start_all succeeds");
|
||||
ok(mgr.stop_all(), "stop_all succeeds");
|
||||
}
|
||||
|
||||
int main() {
|
||||
plan(5);
|
||||
|
||||
test_loader_round_trip();
|
||||
|
||||
return exit_status();
|
||||
}
|
||||
Loading…
Reference in new issue