mirror of https://github.com/sysown/proxysql
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1300 lines
57 KiB
1300 lines
57 KiB
#include "../deps/json/json.hpp"
|
|
using json = nlohmann::json;
|
|
#define PROXYJSON
|
|
|
|
#include <iostream> // std::cout
|
|
#include <sstream> // std::stringstream
|
|
#include <fstream>
|
|
#include <algorithm> // std::sort
|
|
#include <memory>
|
|
#include <vector> // std::vector
|
|
#include <unordered_set>
|
|
#include "prometheus/exposer.h"
|
|
#include "prometheus/counter.h"
|
|
#include "openssl/ssl.h"
|
|
#include "openssl/err.h"
|
|
|
|
#include "Base_Thread.h"
|
|
|
|
#include "MySQL_HostGroups_Manager.h"
|
|
#include "PgSQL_HostGroups_Manager.h"
|
|
#include "mysql.h"
|
|
#include "proxysql_admin.h"
|
|
#include "re2/re2.h"
|
|
#include "re2/regexp.h"
|
|
#include "proxysql.h"
|
|
#include "proxysql_config.h"
|
|
#include "proxysql_restapi.h"
|
|
#include "proxysql_utils.h"
|
|
#include "prometheus_helpers.h"
|
|
#include "cpp.h"
|
|
|
|
#include "MySQL_Data_Stream.h"
|
|
#include "PgSQL_Data_Stream.h"
|
|
#include "MySQL_Query_Processor.h"
|
|
#include "PgSQL_Query_Processor.h"
|
|
#include "ProxySQL_HTTP_Server.hpp" // HTTP server
|
|
#include "MySQL_Authentication.hpp"
|
|
#include "PgSQL_Authentication.h"
|
|
#include "MySQL_LDAP_Authentication.hpp"
|
|
#include "MySQL_PreparedStatement.h"
|
|
#include "ProxySQL_Cluster.hpp"
|
|
#include "ProxySQL_Statistics.hpp"
|
|
#include "MySQL_Logger.hpp"
|
|
#include "PgSQL_Logger.hpp"
|
|
#include "SQLite3_Server.h"
|
|
#include "Web_Interface.hpp"
|
|
|
|
#include <dirent.h>
|
|
#include <search.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <resolv.h>
|
|
#include <arpa/inet.h>
|
|
#include <pthread.h>
|
|
#ifndef SPOOKYV2
|
|
#include "SpookyV2.h"
|
|
#define SPOOKYV2
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/utsname.h>
|
|
|
|
#include "platform.h"
|
|
/**
|
|
* @brief SQLite-vec extension initialization function declaration
|
|
*
|
|
* This external function is the entry point for the sqlite-vec extension.
|
|
* It's called by SQLite to register the vector search virtual tables and functions.
|
|
* The function is part of the sqlite-vec static library that's linked into ProxySQL.
|
|
*
|
|
* @param db SQLite database connection pointer
|
|
* @param pzErrMsg Error message pointer (for returning error information)
|
|
* @param pApi SQLite API routines pointer
|
|
* @return int SQLite status code (SQLITE_OK on success)
|
|
*
|
|
* @details The sqlite-vec extension provides vector search capabilities to SQLite,
|
|
* enabling ProxySQL to perform vector similarity searches in its internal databases.
|
|
* This includes:
|
|
* - Vector storage and indexing via vec0 virtual tables
|
|
* - Distance calculations (cosine, Euclidean, etc.)
|
|
* - Approximate nearest neighbor search
|
|
* - Support for JSON-based vector representation
|
|
*
|
|
* @note This function is automatically called by SQLite's auto-extension mechanism
|
|
* when any database connection is established in ProxySQL.
|
|
*
|
|
* @see https://github.com/asg017/sqlite-vec for sqlite-vec documentation
|
|
*/
|
|
extern int (*proxy_sqlite3_vec_init)(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
|
extern int (*proxy_sqlite3_rembed_init)(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
|
#include "microhttpd.h"
|
|
|
|
#if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || defined(__mips__)) && defined(__linux)
|
|
// currently only support x86-32, x86-64, ARM, and MIPS on Linux
|
|
#include "coredumper/coredumper.h"
|
|
#endif
|
|
|
|
#include <uuid/uuid.h>
|
|
|
|
#include "PgSQL_Protocol.h"
|
|
//#include "usual/time.h"
|
|
|
|
using std::string;
|
|
using std::unique_ptr;
|
|
|
|
#ifdef WITHGCOV
|
|
extern "C" void __gcov_dump();
|
|
extern "C" void __gcov_reset();
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG
|
|
//#define BENCHMARK_FASTROUTING_LOAD
|
|
#endif // DEBUG
|
|
|
|
//#define MYSQL_THREAD_IMPLEMENTATION
|
|
|
|
#define SELECT_VERSION_COMMENT "select @@version_comment limit 1"
|
|
#define SELECT_VERSION_COMMENT_LEN 32
|
|
#define SELECT_DB_USER "select DATABASE(), USER() limit 1"
|
|
#define SELECT_DB_USER_LEN 33
|
|
#define SELECT_CHARSET_VARIOUS "select @@character_set_client, @@character_set_connection, @@character_set_server, @@character_set_database limit 1"
|
|
#define SELECT_CHARSET_VARIOUS_LEN 115
|
|
|
|
#define READ_ONLY_OFF "\x01\x00\x00\x01\x02\x23\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x0d\x56\x61\x72\x69\x61\x62\x6c\x65\x5f\x6e\x61\x6d\x65\x00\x0c\x21\x00\x0f\x00\x00\x00\xfd\x01\x00\x1f\x00\x00\x1b\x00\x00\x03\x03\x64\x65\x66\x00\x00\x00\x05\x56\x61\x6c\x75\x65\x00\x0c\x21\x00\x0f\x00\x00\x00\xfd\x01\x00\x1f\x00\x00\x05\x00\x00\x04\xfe\x00\x00\x02\x00\x0e\x00\x00\x05\x09\x72\x65\x61\x64\x5f\x6f\x6e\x6c\x79\x03\x4f\x46\x46\x05\x00\x00\x06\xfe\x00\x00\x02\x00"
|
|
#define READ_ONLY_ON "\x01\x00\x00\x01\x02\x23\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x0d\x56\x61\x72\x69\x61\x62\x6c\x65\x5f\x6e\x61\x6d\x65\x00\x0c\x21\x00\x0f\x00\x00\x00\xfd\x01\x00\x1f\x00\x00\x1b\x00\x00\x03\x03\x64\x65\x66\x00\x00\x00\x05\x56\x61\x6c\x75\x65\x00\x0c\x21\x00\x0f\x00\x00\x00\xfd\x01\x00\x1f\x00\x00\x05\x00\x00\x04\xfe\x00\x00\x02\x00\x0d\x00\x00\x05\x09\x72\x65\x61\x64\x5f\x6f\x6e\x6c\x79\x02\x4f\x4e\x05\x00\x00\x06\xfe\x00\x00\x02\x00"
|
|
|
|
#define READ_ONLY_0 "\x01\x00\x00\x01\x01\x28\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x12\x40\x40\x67\x6c\x6f\x62\x61\x6c\x2e\x72\x65\x61\x64\x5f\x6f\x6e\x6c\x79\x00\x0c\x3f\x00\x01\x00\x00\x00\x08\x80\x00\x00\x00\x00\x05\x00\x00\x03\xfe\x00\x00\x02\x00\x02\x00\x00\x04\x01\x30\x05\x00\x00\x05\xfe\x00\x00\x02\x00"
|
|
|
|
#define READ_ONLY_1 "\x01\x00\x00\x01\x01\x28\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x12\x40\x40\x67\x6c\x6f\x62\x61\x6c\x2e\x72\x65\x61\x64\x5f\x6f\x6e\x6c\x79\x00\x0c\x3f\x00\x01\x00\x00\x00\x08\x80\x00\x00\x00\x00\x05\x00\x00\x03\xfe\x00\x00\x02\x00\x02\x00\x00\x04\x01\x31\x05\x00\x00\x05\xfe\x00\x00\x02\x00"
|
|
|
|
extern struct MHD_Daemon *Admin_HTTP_Server;
|
|
|
|
extern ProxySQL_Statistics *GloProxyStats;
|
|
|
|
template<enum SERVER_TYPE>
|
|
int ProxySQL_Test___PurgeDigestTable(bool async_purge, bool parallel, char **msg);
|
|
|
|
extern char *ssl_key_fp;
|
|
extern char *ssl_cert_fp;
|
|
extern char *ssl_ca_fp;
|
|
|
|
// ProxySQL_Admin shared variables
|
|
extern int admin___web_verbosity;
|
|
extern char * proxysql_version;
|
|
|
|
#include "proxysql_find_charset.h"
|
|
|
|
template <typename T, typename std::enable_if<std::is_integral<T>::value, bool>::type = true>
|
|
T j_get_srv_default_int_val(
|
|
const json& j, uint32_t hid, const string& key, const function<bool(T)>& val_check);
|
|
|
|
struct cpu_timer
|
|
{
|
|
cpu_timer() {
|
|
begin = monotonic_time();
|
|
}
|
|
~cpu_timer()
|
|
{
|
|
unsigned long long end = monotonic_time();
|
|
#ifdef DEBUG
|
|
std::cerr << double( end - begin ) / 1000000 << " secs.\n" ;
|
|
#endif
|
|
begin=end-begin; // make the compiler happy
|
|
};
|
|
unsigned long long begin;
|
|
};
|
|
|
|
extern int admin_load_main_;
|
|
extern bool admin_nostart_;
|
|
|
|
//extern MySQL_Query_Cache *GloMyQC;
|
|
extern MySQL_Authentication *GloMyAuth;
|
|
extern PgSQL_Authentication *GloPgAuth;
|
|
extern MySQL_LDAP_Authentication *GloMyLdapAuth;
|
|
extern ProxySQL_Admin *GloAdmin;
|
|
extern MySQL_Query_Processor* GloMyQPro;
|
|
extern PgSQL_Query_Processor* GloPgQPro;
|
|
extern MySQL_Threads_Handler *GloMTH;
|
|
extern MySQL_Logger *GloMyLogger;
|
|
extern PgSQL_Logger* GloPgSQL_Logger;
|
|
extern MySQL_STMT_Manager_v14 *GloMyStmt;
|
|
extern MySQL_Monitor *GloMyMon;
|
|
extern PgSQL_Threads_Handler* GloPTH;
|
|
|
|
#ifdef PROXYSQLGENAI
|
|
extern MCP_Threads_Handler* GloMCPH;
|
|
extern GenAI_Threads_Handler* GloGATH;
|
|
extern AI_Features_Manager *GloAI;
|
|
#endif /* PROXYSQLGENAI */
|
|
|
|
extern void (*flush_logs_function)();
|
|
|
|
extern Web_Interface *GloWebInterface;
|
|
|
|
extern ProxySQL_Cluster *GloProxyCluster;
|
|
#ifdef PROXYSQLCLICKHOUSE
|
|
extern ClickHouse_Authentication *GloClickHouseAuth;
|
|
extern ClickHouse_Server *GloClickHouseServer;
|
|
#endif /* PROXYSQLCLICKHOUSE */
|
|
|
|
extern SQLite3_Server *GloSQLite3Server;
|
|
|
|
extern char * binary_sha1;
|
|
|
|
extern int ProxySQL_create_or_load_TLS(bool bootstrap, std::string& msg);
|
|
|
|
#include "ProxySQL_Admin_Tables_Definitions.h"
|
|
|
|
extern void * (*child_func[3]) (void *arg);
|
|
|
|
bootstrap_info_t::~bootstrap_info_t() {
|
|
if (servers != nullptr) {
|
|
mysql_free_result(servers);
|
|
}
|
|
if (users != nullptr) {
|
|
mysql_free_result(users);
|
|
}
|
|
}
|
|
|
|
#include "Admin_ifaces.h"
|
|
extern admin_main_loop_listeners S_amll;
|
|
|
|
static void flush_logs_handler() {
|
|
GloAdmin->flush_logs();
|
|
}
|
|
|
|
extern void * admin_main_loop(void *arg);
|
|
|
|
struct boot_srv_info_t {
|
|
string member_id;
|
|
string member_host;
|
|
uint32_t member_port;
|
|
string member_state;
|
|
string member_role;
|
|
string member_version;
|
|
};
|
|
|
|
struct BOOT_SRV_INFO_T {
|
|
enum {
|
|
MEMBER_ID,
|
|
MEMBER_HOST,
|
|
MEMBER_PORT,
|
|
MEMBER_STATE,
|
|
MEMBER_ROLE,
|
|
MEMBER_VERSION
|
|
};
|
|
};
|
|
|
|
struct boot_user_info_t {
|
|
string user;
|
|
string ssl_type;
|
|
string auth_string;
|
|
string auth_plugin;
|
|
bool password_expired;
|
|
};
|
|
|
|
struct BOOT_USER_INFO_T {
|
|
enum {
|
|
USER,
|
|
SSL_TYPE,
|
|
AUTH_STRING,
|
|
AUTH_PLUGIN,
|
|
PASSWORD_EXPIRED
|
|
};
|
|
};
|
|
|
|
struct srv_defs_t {
|
|
int64_t weight;
|
|
int64_t max_conns;
|
|
int32_t use_ssl;
|
|
};
|
|
|
|
using boot_srv_cnf_t = pair<boot_srv_info_t,srv_defs_t>;
|
|
|
|
vector<boot_srv_info_t> extract_boot_servers_info(MYSQL_RES* servers) {
|
|
vector<boot_srv_info_t> servers_info {};
|
|
|
|
while (MYSQL_ROW row = mysql_fetch_row(servers)) {
|
|
servers_info.push_back({
|
|
string { row[BOOT_SRV_INFO_T::MEMBER_ID] },
|
|
string { row[BOOT_SRV_INFO_T::MEMBER_HOST] },
|
|
static_cast<uint32>(stoi(row[BOOT_SRV_INFO_T::MEMBER_PORT])),
|
|
string { row[BOOT_SRV_INFO_T::MEMBER_STATE] },
|
|
string { row[BOOT_SRV_INFO_T::MEMBER_ROLE] },
|
|
string { row[BOOT_SRV_INFO_T::MEMBER_VERSION] },
|
|
});
|
|
}
|
|
|
|
return servers_info;
|
|
}
|
|
|
|
string build_boot_servers_insert(const vector<boot_srv_cnf_t>& srvs_info_defs) {
|
|
const string t_srvs_insert {
|
|
"INSERT INTO mysql_servers (hostgroup_id,hostname,port,status,weight,max_connections,use_ssl) VALUES "
|
|
};
|
|
string t_srvs_values {};
|
|
|
|
for (const auto& info_defs : srvs_info_defs) {
|
|
const boot_srv_info_t& srv_info = info_defs.first;
|
|
const srv_defs_t& srv_defs = info_defs.second;
|
|
|
|
const char t_values[] { "(%d, \"%s\", %d, \"%s\", %ld, %ld, %d)" };
|
|
string srv_values = cstr_format(
|
|
t_values,
|
|
srv_info.member_role == "PRIMARY" ? 0 : 1, // HOSTGROUP_ID
|
|
srv_info.member_host.c_str(), // HOSTNAME
|
|
srv_info.member_port, // PORT
|
|
srv_info.member_state.c_str(), // STATUS
|
|
srv_defs.weight, // Weight
|
|
srv_defs.max_conns, // Max Connections
|
|
srv_defs.use_ssl // UseSSL
|
|
).str;
|
|
|
|
if (&info_defs != &srvs_info_defs.back()) {
|
|
srv_values += ",";
|
|
}
|
|
|
|
t_srvs_values += srv_values;
|
|
}
|
|
|
|
const string servers_insert { t_srvs_insert + t_srvs_values };
|
|
|
|
return servers_insert;
|
|
}
|
|
|
|
string build_boot_users_insert(MYSQL_RES* users) {
|
|
vector<boot_user_info_t> users_info {};
|
|
|
|
while (MYSQL_ROW row = mysql_fetch_row(users)) {
|
|
users_info.push_back({
|
|
string { row[BOOT_USER_INFO_T::USER] },
|
|
string { row[BOOT_USER_INFO_T::SSL_TYPE] },
|
|
string { row[BOOT_USER_INFO_T::AUTH_STRING] },
|
|
string { row[BOOT_USER_INFO_T::AUTH_PLUGIN] },
|
|
static_cast<bool>(atoi(row[BOOT_USER_INFO_T::PASSWORD_EXPIRED]))
|
|
});
|
|
}
|
|
|
|
// MySQL Users
|
|
const string t_users_insert {
|
|
"INSERT INTO mysql_users (username,password,active,use_ssl) VALUES "
|
|
};
|
|
string t_users_values {};
|
|
|
|
for (const boot_user_info_t& user : users_info) {
|
|
uint32_t use_ssl = user.ssl_type.empty() ? 0 : 1;
|
|
const char t_values[] { "(\"%s\", \"%s\", %d, %d)" };
|
|
|
|
string srv_values = cstr_format(
|
|
t_values,
|
|
user.user.c_str(), // USERNAME
|
|
user.auth_string.c_str(), // HOSTNAME
|
|
1, // ACTIVE: Always ON
|
|
use_ssl // USE_SSL: Dependent on backend user
|
|
).str;
|
|
|
|
if (&user != &users_info.back()) {
|
|
srv_values += ",";
|
|
}
|
|
|
|
t_users_values += srv_values;
|
|
}
|
|
|
|
const string users_insert { t_users_insert + t_users_values };
|
|
|
|
return users_insert;
|
|
}
|
|
|
|
map<uint64_t,srv_defs_t> get_cur_hg_attrs(SQLite3DB* admindb) {
|
|
map<uint64_t,srv_defs_t> res {};
|
|
|
|
char* error = nullptr;
|
|
int cols = 0;
|
|
int affected_rows = 0;
|
|
SQLite3_result* resultset = NULL;
|
|
|
|
admindb->execute_statement(
|
|
"SELECT hostgroup_id,servers_defaults FROM mysql_hostgroup_attributes",
|
|
&error, &cols, &affected_rows, &resultset
|
|
);
|
|
|
|
for (SQLite3_row* row : resultset->rows) {
|
|
const int32_t hid = atoi(row->fields[0]);
|
|
srv_defs_t srv_defs {};
|
|
srv_defs.weight = 1;
|
|
srv_defs.max_conns = 512;
|
|
srv_defs.use_ssl = 1;
|
|
|
|
nlohmann::json j_srv_defs = nlohmann::json::parse(row->fields[1]);
|
|
|
|
const auto weight_check = [] (int64_t weight) -> bool { return weight >= 0; };
|
|
srv_defs.weight = j_get_srv_default_int_val<int64_t>(j_srv_defs, hid, "weight", weight_check);
|
|
|
|
const auto max_conns_check = [] (int64_t max_conns) -> bool { return max_conns >= 0; };
|
|
srv_defs.max_conns = j_get_srv_default_int_val<int64_t>(j_srv_defs, hid, "max_connections", max_conns_check);
|
|
|
|
const auto use_ssl_check = [] (int32_t use_ssl) -> bool { return use_ssl == 0 || use_ssl == 1; };
|
|
srv_defs.use_ssl = j_get_srv_default_int_val<int32_t>(j_srv_defs, hid, "use_ssl", use_ssl_check);
|
|
|
|
res.insert({ hid , srv_defs });
|
|
}
|
|
|
|
delete resultset;
|
|
|
|
return res;
|
|
}
|
|
|
|
vector<boot_srv_cnf_t> build_srvs_info_with_defs(
|
|
const vector<boot_srv_info_t>& srvs_info,
|
|
const map<uint64_t,srv_defs_t>& hgid_defs,
|
|
const srv_defs_t global_defs
|
|
) {
|
|
vector<boot_srv_cnf_t> res {};
|
|
|
|
for (const boot_srv_info_t& srv_info : srvs_info) {
|
|
if (srv_info.member_role == "PRIMARY") {
|
|
const auto hg_it = hgid_defs.find(0);
|
|
|
|
if (hg_it != hgid_defs.end()) {
|
|
res.push_back({ srv_info, hg_it->second });
|
|
} else {
|
|
res.push_back({ srv_info, global_defs });
|
|
}
|
|
} else {
|
|
const auto hg_it = hgid_defs.find(1);
|
|
|
|
if (hg_it != hgid_defs.end()) {
|
|
res.push_back({ srv_info, hg_it->second });
|
|
} else {
|
|
res.push_back({ srv_info, global_defs });
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function used to check if tables are already filled with data.
|
|
* @details Handles the boilerplate operations of executing 'SELECT COUNT(*)' alike queries.
|
|
* @param admindb An already initialized instance of a SQLite3DB object to 'mem_admindb'.
|
|
* @param query The query to be executed, it's required to be 'SELECT COUNT(*)' alike.
|
|
* @return The resulting int of the 'COUNT(*)' in case of success, '-1' otherwise. In case of error, error
|
|
* cause are logged, and `assert` is called.
|
|
*/
|
|
int check_if_user_config(SQLite3DB* admindb, const char* query) {
|
|
char* error = nullptr;
|
|
int cols = 0;
|
|
int affected_rows = 0;
|
|
SQLite3_result* resultset = NULL;
|
|
|
|
admindb->execute_statement(query, &error, &cols, &affected_rows, &resultset);
|
|
if (error) {
|
|
proxy_error(
|
|
"Aborting due to failed query over SQLite3 - db: '%s', query: '%s', err: %s", admindb->get_url(), query, error
|
|
);
|
|
assert(0);
|
|
}
|
|
|
|
int count = -1;
|
|
|
|
if (resultset != nullptr && !resultset->rows.empty() && resultset->rows[0]->cnt >= 0) {
|
|
const char* s_count = resultset->rows[0]->fields[0];
|
|
char* p_end = nullptr;
|
|
|
|
count = std::strtol(s_count, &p_end, 10);
|
|
|
|
if (p_end == s_count || errno == ERANGE) {
|
|
proxy_error(
|
|
"Aborting due to invalid query output, expected single INT (E.g. 'COUNT(*)') - query: '%s'", query
|
|
);
|
|
count = -1;
|
|
}
|
|
}
|
|
|
|
if (count == -1) {
|
|
assert(0);
|
|
}
|
|
|
|
delete resultset;
|
|
return count;
|
|
};
|
|
|
|
/**
|
|
* @brief Definition of an auxiliary table used to store bootstrap variables.
|
|
* @details Table is used only to store in configdb bootstrap variables that are required to persist between
|
|
* executions.
|
|
*/
|
|
#define ADMIN_SQLITE_TABLE_BOOTSTRAP_VARIABLES "CREATE TABLE IF NOT EXISTS bootstrap_variables (variable_name VARCHAR NOT NULL PRIMARY KEY , variable_value VARCHAR NOT NULL)"
|
|
|
|
|
|
extern void *child_mysql(void *arg);
|
|
extern void *child_telnet(void *arg);
|
|
extern void *child_postgres(void *arg);
|
|
|
|
|
|
bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) {
|
|
cpu_timer cpt;
|
|
|
|
if (flush_logs_function == NULL) {
|
|
flush_logs_function = flush_logs_handler;
|
|
}
|
|
|
|
Admin_HTTP_Server = NULL;
|
|
AdminRestApiServer = NULL;
|
|
AdminHTTPServer = NULL;
|
|
|
|
/*
|
|
AdminRestApiServer = new ProxySQL_RESTAPI_Server();
|
|
AdminRestApiServer->print_version();
|
|
*/
|
|
|
|
child_func[0]=child_mysql;
|
|
child_func[1]=child_telnet;
|
|
child_func[2]=child_postgres;
|
|
main_shutdown=0;
|
|
main_poll_nfds=0;
|
|
main_poll_fds=NULL;
|
|
main_callback_func=NULL;
|
|
|
|
{
|
|
int rc=pipe(pipefd);
|
|
if (rc) {
|
|
perror("Call to pipe() failed");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
main_callback_func=(int *)malloc(sizeof(int)*MAX_ADMIN_LISTENERS);
|
|
main_poll_fds=(struct pollfd *)malloc(sizeof(struct pollfd)*MAX_ADMIN_LISTENERS);
|
|
main_poll_nfds=0;
|
|
|
|
pthread_attr_t attr;
|
|
pthread_attr_init(&attr);
|
|
//pthread_attr_setstacksize (&attr, mystacksize);
|
|
|
|
/**
|
|
* @section SQLite3_Database_Initialization
|
|
* @brief Initialize all SQLite databases with sqlite-vec extension support
|
|
*
|
|
* This section initializes all ProxySQL SQLite databases and enables
|
|
* the sqlite-vec extension for vector search capabilities. The extension
|
|
* is statically linked into ProxySQL and automatically loaded when each
|
|
* database connection is established.
|
|
*
|
|
* @subsection Integration_Details
|
|
*
|
|
* The sqlite-vec integration provides vector search capabilities to all
|
|
* ProxySQL databases through SQLite's virtual table mechanism:
|
|
*
|
|
* - **Vector Storage**: Store high-dimensional vectors directly in SQLite tables
|
|
* - **Similarity Search**: Find similar vectors using distance metrics
|
|
* - **Virtual Tables**: Use vec0 virtual tables for efficient vector indexing
|
|
* - **JSON Format**: Support for JSON-based vector representation
|
|
*
|
|
* @subsection_Databases
|
|
*
|
|
* The extension is enabled in all ProxySQL database instances:
|
|
* - Admin: Configuration and runtime state
|
|
* - Stats: Runtime statistics and metrics
|
|
* - Config: Persistent configuration storage
|
|
* - Monitor: Server monitoring data
|
|
* - Stats Disk: Persistent statistics
|
|
*
|
|
* @subsection_Usage_Examples
|
|
*
|
|
* Once enabled, vector search can be used in any database:
|
|
* @code
|
|
* CREATE VIRTUAL TABLE vec_data USING vec0(vector float[128]);
|
|
* INSERT INTO vec_data(rowid, vector) VALUES (1, json('[0.1, 0.2, ...]'));
|
|
* SELECT rowid, distance FROM vec_data WHERE vector MATCH json('[0.1, 0.2, ...]');
|
|
* @endcode
|
|
*
|
|
* @see (*proxy_sqlite3_vec_init)() for extension initialization
|
|
* @see deps/sqlite3/README.md for integration documentation
|
|
* @see https://github.com/asg017/sqlite-vec for sqlite-vec documentation
|
|
*/
|
|
admindb=new SQLite3DB();
|
|
/**
|
|
* @brief Open the admin database with shared cache mode
|
|
*
|
|
* The admin database stores ProxySQL's configuration and runtime state.
|
|
* Using memory with shared cache allows multiple connections to access the same data.
|
|
*/
|
|
admindb->open((char *)"file:mem_admindb?mode=memory&cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
|
|
admindb->execute("PRAGMA cache_size = -50000");
|
|
|
|
/**
|
|
* @brief Enable SQLite extension loading for admin database
|
|
*
|
|
* Allows loading SQLite extensions at runtime. This is required for
|
|
* sqlite-vec to be registered when the database is opened.
|
|
*/
|
|
(*proxy_sqlite3_enable_load_extension)(admindb->get_db(),1);
|
|
|
|
/**
|
|
* @brief Register sqlite-vec extension for auto-loading
|
|
*
|
|
* This function registers the sqlite-vec extension to be automatically
|
|
* loaded whenever a new database connection is established.
|
|
*
|
|
* @details The sqlite-vec extension provides vector search capabilities
|
|
* that are now available in the admin database for:
|
|
* - Storing and searching vector embeddings in configuration data
|
|
* - Performing similarity searches on admin metrics
|
|
* - Enhanced analytics on admin operations
|
|
*
|
|
* @note The sqlite3_vec_init function is cast to a function pointer
|
|
* for SQLite's auto-extension mechanism.
|
|
*/
|
|
if (proxy_sqlite3_vec_init) (*proxy_sqlite3_auto_extension)( (void(*)(void))proxy_sqlite3_vec_init);
|
|
if (proxy_sqlite3_rembed_init) (*proxy_sqlite3_auto_extension)( (void(*)(void))proxy_sqlite3_rembed_init);
|
|
|
|
/**
|
|
* @brief Open the stats database with shared cache mode
|
|
*
|
|
* The stats database stores ProxySQL's runtime statistics and performance metrics.
|
|
* This database is crucial for monitoring and analysis operations.
|
|
*/
|
|
statsdb=new SQLite3DB();
|
|
statsdb->open((char *)"file:mem_statsdb?mode=memory&cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
|
|
|
|
/**
|
|
* @brief Enable SQLite extension loading for stats database
|
|
*
|
|
* Allows loading SQLite extensions at runtime. This enables sqlite-vec to be
|
|
* registered in the stats database for advanced analytics operations.
|
|
*/
|
|
(*proxy_sqlite3_enable_load_extension)(statsdb->get_db(),1);
|
|
|
|
// check if file exists , see #617
|
|
bool admindb_file_exists=Proxy_file_exists(GloVars.admindb);
|
|
|
|
configdb=new SQLite3DB();
|
|
if (access(GloVars.admindb, F_OK) == 0) {
|
|
if (access(GloVars.admindb, W_OK) != 0) {
|
|
proxy_error("Database file '%s' exists but is not writable\n", GloVars.admindb);
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
}
|
|
/**
|
|
* @brief Open the config database (persistent storage)
|
|
*
|
|
* The config database stores ProxySQL's persistent configuration data.
|
|
* Unlike memory databases, this is file-based and survives restarts.
|
|
* It contains user accounts, server groups, query rules, etc.
|
|
*/
|
|
configdb->open((char *)GloVars.admindb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
|
|
|
|
/**
|
|
* @brief Enable SQLite extension loading for config database
|
|
*
|
|
* Allows loading SQLite extensions at runtime. This enables sqlite-vec to be
|
|
* registered in the config database for:
|
|
* - Advanced query rule analysis using vector similarity
|
|
* - Configuration optimization with vector-based recommendations
|
|
* - Intelligent grouping of similar configurations
|
|
*/
|
|
(*proxy_sqlite3_enable_load_extension)(configdb->get_db(),1);
|
|
// Fully synchronous is not required. See to #1055
|
|
// https://sqlite.org/pragma.html#pragma_synchronous
|
|
configdb->execute("PRAGMA synchronous=0");
|
|
|
|
monitordb = new SQLite3DB();
|
|
/**
|
|
* @brief Open the monitor database with shared cache mode
|
|
*
|
|
* The monitor database stores monitoring data for backend servers.
|
|
* It collects connection metrics, query performance, server health status,
|
|
* and other monitoring information.
|
|
*/
|
|
monitordb->open((char *)"file:mem_monitordb?mode=memory&cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
|
|
|
|
/**
|
|
* @brief Enable SQLite extension loading for monitor database
|
|
*
|
|
* Allows loading SQLite extensions at runtime. This enables sqlite-vec to be
|
|
* registered in the monitor database for:
|
|
* - Advanced anomaly detection using vector similarity
|
|
* - Pattern recognition in server behavior over time
|
|
* - Clustering similar server performance metrics
|
|
* - Predictive monitoring based on historical vector patterns
|
|
*/
|
|
(*proxy_sqlite3_enable_load_extension)(monitordb->get_db(),1);
|
|
|
|
statsdb_disk = new SQLite3DB();
|
|
/**
|
|
* @brief Open the stats disk database (persistent statistics)
|
|
*
|
|
* The stats disk database stores persistent statistics and historical data.
|
|
* Unlike memory databases, this is file-based and survives restarts.
|
|
* It contains query digest statistics, execution counters, etc.
|
|
*/
|
|
statsdb_disk->open((char *)GloVars.statsdb_disk, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
|
|
|
|
/**
|
|
* @brief Enable SQLite extension loading for stats disk database
|
|
*
|
|
* Allows loading SQLite extensions at runtime. This enables sqlite-vec to be
|
|
* registered in the stats disk database for:
|
|
* - Historical query pattern analysis using vector similarity
|
|
* - Trend analysis of query performance metrics
|
|
* - Clustering similar query digests for optimization insights
|
|
* - Long-term performance monitoring with vector-based analytics
|
|
*/
|
|
(*proxy_sqlite3_enable_load_extension)(statsdb_disk->get_db(),1);
|
|
// char *dbname = (char *)malloc(strlen(GloVars.statsdb_disk)+50);
|
|
// sprintf(dbname,"%s?mode=memory&cache=shared",GloVars.statsdb_disk);
|
|
// statsdb_disk->open(dbname, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_FULLMUTEX);
|
|
// free(dbname);
|
|
|
|
statsdb_disk->execute("PRAGMA synchronous=0");
|
|
// GloProxyStats->statsdb_disk = configdb;
|
|
GloProxyStats->init();
|
|
|
|
/**
|
|
* @brief Open the MCP catalog database
|
|
*
|
|
* The MCP catalog database stores:
|
|
* - Discovered database schemas (runs, schemas, tables, columns)
|
|
* - LLM memories (summaries, domains, metrics, notes)
|
|
* - Tool usage statistics
|
|
* - Search history
|
|
*/
|
|
#ifdef PROXYSQLGENAI
|
|
mcpdb = new SQLite3DB();
|
|
std::string mcp_catalog_path = std::string(GloVars.datadir) + "/mcp_catalog.db";
|
|
mcpdb->open((char *)mcp_catalog_path.c_str(), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
|
|
|
|
/**
|
|
* @brief Enable SQLite extension loading for MCP catalog database
|
|
*
|
|
* Allows loading SQLite extensions at runtime. This enables sqlite-vec to be
|
|
* registered for vector similarity searches in the catalog.
|
|
*/
|
|
(*proxy_sqlite3_enable_load_extension)(mcpdb->get_db(),1);
|
|
#endif /* PROXYSQLGENAI */
|
|
|
|
tables_defs_admin=new std::vector<table_def_t *>;
|
|
tables_defs_stats=new std::vector<table_def_t *>;
|
|
tables_defs_config=new std::vector<table_def_t *>;
|
|
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_servers", ADMIN_SQLITE_TABLE_MYSQL_SERVERS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_servers", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_SERVERS);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_users", ADMIN_SQLITE_TABLE_MYSQL_USERS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_users", ADMIN_SQLITE_RUNTIME_MYSQL_USERS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_checksums_values", ADMIN_SQLITE_RUNTIME_CHECKSUMS_VALUES);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_replication_hostgroups", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_REPLICATION_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_replication_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_REPLICATION_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_group_replication_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_GROUP_REPLICATION_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_group_replication_hostgroups", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_GROUP_REPLICATION_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_galera_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_GALERA_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_galera_hostgroups", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_GALERA_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_aws_aurora_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_AWS_AURORA_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_aws_aurora_hostgroups", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_AWS_AURORA_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_hostgroup_attributes", ADMIN_SQLITE_TABLE_MYSQL_HOSTGROUP_ATTRIBUTES);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_hostgroup_attributes", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_HOSTGROUP_ATTRIBUTES);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_servers_ssl_params", ADMIN_SQLITE_TABLE_MYSQL_SERVERS_SSL_PARAMS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_servers_ssl_params", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_SERVERS_SSL_PARAMS);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_query_rules", ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_query_rules_fast_routing", ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_FAST_ROUTING);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_query_rules", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_QUERY_RULES);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_query_rules_fast_routing", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_QUERY_RULES_FAST_ROUTING);
|
|
insert_into_tables_defs(tables_defs_admin,"global_variables", ADMIN_SQLITE_TABLE_GLOBAL_VARIABLES);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_global_variables", ADMIN_SQLITE_RUNTIME_GLOBAL_VARIABLES);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_collations", ADMIN_SQLITE_TABLE_MYSQL_COLLATIONS);
|
|
insert_into_tables_defs(tables_defs_admin,"scheduler", ADMIN_SQLITE_TABLE_SCHEDULER);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_scheduler", ADMIN_SQLITE_TABLE_RUNTIME_SCHEDULER);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_firewall_whitelist_users", ADMIN_SQLITE_TABLE_MYSQL_FIREWALL_WHITELIST_USERS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_firewall_whitelist_users", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_FIREWALL_WHITELIST_USERS);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_firewall_whitelist_rules", ADMIN_SQLITE_TABLE_MYSQL_FIREWALL_WHITELIST_RULES);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_firewall_whitelist_rules", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_FIREWALL_WHITELIST_RULES);
|
|
insert_into_tables_defs(tables_defs_admin,"mysql_firewall_whitelist_sqli_fingerprints", ADMIN_SQLITE_TABLE_MYSQL_FIREWALL_WHITELIST_SQLI_FINGERPRINTS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_mysql_firewall_whitelist_sqli_fingerprints", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_FIREWALL_WHITELIST_SQLI_FINGERPRINTS);
|
|
insert_into_tables_defs(tables_defs_admin,"restapi_routes", ADMIN_SQLITE_TABLE_RESTAPI_ROUTES);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_restapi_routes", ADMIN_SQLITE_TABLE_RUNTIME_RESTAPI_ROUTES);
|
|
insert_into_tables_defs(tables_defs_admin,"coredump_filters", ADMIN_SQLITE_TABLE_COREDUMP_FILTERS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_coredump_filters", ADMIN_SQLITE_RUNTIME_COREDUMP_FILTERS);
|
|
#ifdef DEBUG
|
|
insert_into_tables_defs(tables_defs_admin,"debug_levels", ADMIN_SQLITE_TABLE_DEBUG_LEVELS);
|
|
insert_into_tables_defs(tables_defs_admin,"debug_filters", ADMIN_SQLITE_TABLE_DEBUG_FILTERS);
|
|
#endif /* DEBUG */
|
|
#ifdef PROXYSQLCLICKHOUSE
|
|
// ClickHouse
|
|
if (GloVars.global.clickhouse_server) {
|
|
insert_into_tables_defs(tables_defs_admin,"clickhouse_users", ADMIN_SQLITE_TABLE_CLICKHOUSE_USERS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_clickhouse_users", ADMIN_SQLITE_TABLE_RUNTIME_CLICKHOUSE_USERS);
|
|
}
|
|
#endif /* PROXYSQLCLICKHOUSE */
|
|
|
|
// PgSQL
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_servers", ADMIN_SQLITE_TABLE_PGSQL_SERVERS);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_servers", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_SERVERS);
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_users", ADMIN_SQLITE_TABLE_PGSQL_USERS);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_users", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_USERS);
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_ldap_mapping", ADMIN_SQLITE_TABLE_PGSQL_LDAP_MAPPING);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_ldap_mapping", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_LDAP_MAPPING);
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_query_rules", ADMIN_SQLITE_TABLE_PGSQL_QUERY_RULES);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_query_rules", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_QUERY_RULES);
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_query_rules_fast_routing", ADMIN_SQLITE_TABLE_PGSQL_QUERY_RULES_FAST_ROUTING);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_query_rules_fast_routing", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_QUERY_RULES_FAST_ROUTING);
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_hostgroup_attributes", ADMIN_SQLITE_TABLE_PGSQL_HOSTGROUP_ATTRIBUTES);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_hostgroup_attributes", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_HOSTGROUP_ATTRIBUTES);
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_replication_hostgroups", ADMIN_SQLITE_TABLE_PGSQL_REPLICATION_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_replication_hostgroups", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_REPLICATION_HOSTGROUPS);
|
|
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_firewall_whitelist_users", ADMIN_SQLITE_TABLE_PGSQL_FIREWALL_WHITELIST_USERS);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_firewall_whitelist_users", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_FIREWALL_WHITELIST_USERS);
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_firewall_whitelist_rules", ADMIN_SQLITE_TABLE_PGSQL_FIREWALL_WHITELIST_RULES);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_firewall_whitelist_rules", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_FIREWALL_WHITELIST_RULES);
|
|
insert_into_tables_defs(tables_defs_admin, "pgsql_firewall_whitelist_sqli_fingerprints", ADMIN_SQLITE_TABLE_PGSQL_FIREWALL_WHITELIST_SQLI_FINGERPRINTS);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_pgsql_firewall_whitelist_sqli_fingerprints", ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_FIREWALL_WHITELIST_SQLI_FINGERPRINTS);
|
|
|
|
#ifdef PROXYSQLGENAI
|
|
// MCP query rules
|
|
insert_into_tables_defs(tables_defs_admin, "mcp_query_rules", ADMIN_SQLITE_TABLE_MCP_QUERY_RULES);
|
|
insert_into_tables_defs(tables_defs_admin, "runtime_mcp_query_rules", ADMIN_SQLITE_TABLE_RUNTIME_MCP_QUERY_RULES);
|
|
|
|
insert_into_tables_defs(tables_defs_config, "mcp_query_rules", ADMIN_SQLITE_TABLE_MCP_QUERY_RULES);
|
|
#endif /* PROXYSQLGENAI */
|
|
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_servers", ADMIN_SQLITE_TABLE_PGSQL_SERVERS);
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_users", ADMIN_SQLITE_TABLE_PGSQL_USERS);
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_ldap_mapping", ADMIN_SQLITE_TABLE_PGSQL_LDAP_MAPPING);
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_query_rules", ADMIN_SQLITE_TABLE_PGSQL_QUERY_RULES);
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_query_rules_fast_routing", ADMIN_SQLITE_TABLE_PGSQL_QUERY_RULES_FAST_ROUTING);
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_hostgroup_attributes", ADMIN_SQLITE_TABLE_PGSQL_HOSTGROUP_ATTRIBUTES);
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_replication_hostgroups", ADMIN_SQLITE_TABLE_PGSQL_REPLICATION_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_firewall_whitelist_users", ADMIN_SQLITE_TABLE_PGSQL_FIREWALL_WHITELIST_USERS);
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_firewall_whitelist_rules", ADMIN_SQLITE_TABLE_PGSQL_FIREWALL_WHITELIST_RULES);
|
|
insert_into_tables_defs(tables_defs_config, "pgsql_firewall_whitelist_sqli_fingerprints", ADMIN_SQLITE_TABLE_PGSQL_FIREWALL_WHITELIST_SQLI_FINGERPRINTS);
|
|
//
|
|
|
|
insert_into_tables_defs(tables_defs_config,"mysql_servers", ADMIN_SQLITE_TABLE_MYSQL_SERVERS);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_users", ADMIN_SQLITE_TABLE_MYSQL_USERS);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_replication_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_REPLICATION_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_group_replication_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_GROUP_REPLICATION_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_galera_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_GALERA_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_aws_aurora_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_AWS_AURORA_HOSTGROUPS);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_hostgroup_attributes", ADMIN_SQLITE_TABLE_MYSQL_HOSTGROUP_ATTRIBUTES);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_servers_ssl_params", ADMIN_SQLITE_TABLE_MYSQL_SERVERS_SSL_PARAMS);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_query_rules", ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_query_rules_fast_routing", ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_FAST_ROUTING);
|
|
insert_into_tables_defs(tables_defs_config,"global_variables", ADMIN_SQLITE_TABLE_GLOBAL_VARIABLES);
|
|
insert_into_tables_defs(tables_defs_config,"global_settings", ADMIN_SQLITE_TABLE_GLOBAL_SETTINGS);
|
|
// the table is not required to be present on disk. Removing it due to #1055
|
|
insert_into_tables_defs(tables_defs_config,"mysql_collations", ADMIN_SQLITE_TABLE_MYSQL_COLLATIONS);
|
|
insert_into_tables_defs(tables_defs_config,"scheduler", ADMIN_SQLITE_TABLE_SCHEDULER);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_firewall_whitelist_users", ADMIN_SQLITE_TABLE_MYSQL_FIREWALL_WHITELIST_USERS);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_firewall_whitelist_rules", ADMIN_SQLITE_TABLE_MYSQL_FIREWALL_WHITELIST_RULES);
|
|
insert_into_tables_defs(tables_defs_config,"mysql_firewall_whitelist_sqli_fingerprints", ADMIN_SQLITE_TABLE_MYSQL_FIREWALL_WHITELIST_SQLI_FINGERPRINTS);
|
|
insert_into_tables_defs(tables_defs_config, "restapi_routes", ADMIN_SQLITE_TABLE_RESTAPI_ROUTES);
|
|
#ifdef DEBUG
|
|
insert_into_tables_defs(tables_defs_config,"debug_levels", ADMIN_SQLITE_TABLE_DEBUG_LEVELS);
|
|
insert_into_tables_defs(tables_defs_config,"debug_filters", ADMIN_SQLITE_TABLE_DEBUG_FILTERS);
|
|
#endif /* DEBUG */
|
|
#ifdef PROXYSQLCLICKHOUSE
|
|
// ClickHouse
|
|
if (GloVars.global.clickhouse_server) {
|
|
insert_into_tables_defs(tables_defs_config,"clickhouse_users", ADMIN_SQLITE_TABLE_CLICKHOUSE_USERS);
|
|
}
|
|
#endif /* PROXYSQLCLICKHOUSE */
|
|
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_query_rules", STATS_SQLITE_TABLE_MYSQL_QUERY_RULES);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_commands_counters", STATS_SQLITE_TABLE_MYSQL_COMMANDS_COUNTERS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_processlist", STATS_SQLITE_TABLE_MYSQL_PROCESSLIST);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_connection_pool", STATS_SQLITE_TABLE_MYSQL_CONNECTION_POOL);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_connection_pool_reset", STATS_SQLITE_TABLE_MYSQL_CONNECTION_POOL_RESET);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_free_connections", STATS_SQLITE_TABLE_MYSQL_FREE_CONNECTIONS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_query_digest", STATS_SQLITE_TABLE_MYSQL_QUERY_DIGEST);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_query_digest_reset", STATS_SQLITE_TABLE_MYSQL_QUERY_DIGEST_RESET);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_errors", STATS_SQLITE_TABLE_MYSQL_ERRORS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_errors_reset", STATS_SQLITE_TABLE_MYSQL_ERRORS_RESET);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_global", STATS_SQLITE_TABLE_MYSQL_GLOBAL);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_gtid_executed", STATS_SQLITE_TABLE_MYSQL_GTID_EXECUTED);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_memory_metrics", STATS_SQLITE_TABLE_MEMORY_METRICS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_users", STATS_SQLITE_TABLE_MYSQL_USERS);
|
|
insert_into_tables_defs(tables_defs_stats,"global_variables", ADMIN_SQLITE_TABLE_GLOBAL_VARIABLES); // workaround for issue #708
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_prepared_statements_info", ADMIN_SQLITE_TABLE_STATS_MYSQL_PREPARED_STATEMENTS_INFO);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_client_host_cache", STATS_SQLITE_TABLE_MYSQL_CLIENT_HOST_CACHE);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_client_host_cache_reset", STATS_SQLITE_TABLE_MYSQL_CLIENT_HOST_CACHE_RESET);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mysql_query_events", ADMIN_SQLITE_TABLE_STATS_MYSQL_QUERY_EVENTS);
|
|
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_global", STATS_SQLITE_TABLE_PGSQL_GLOBAL);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_connection_pool", STATS_SQLITE_TABLE_PGSQL_CONNECTION_POOL);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_connection_pool_reset", STATS_SQLITE_TABLE_PGSQL_CONNECTION_POOL_RESET);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_free_connections", STATS_SQLITE_TABLE_PGSQL_FREE_CONNECTIONS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_users", STATS_SQLITE_TABLE_PGSQL_USERS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_processlist", STATS_SQLITE_TABLE_PGSQL_PROCESSLIST);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_stat_activity", STATS_SQLITE_TABLE_PGSQL_STAT_ACTIVITY);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_errors", STATS_SQLITE_TABLE_PGSQL_ERRORS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_errors_reset", STATS_SQLITE_TABLE_PGSQL_ERRORS_RESET);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_client_host_cache", STATS_SQLITE_TABLE_PGSQL_CLIENT_HOST_CACHE);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_client_host_cache_reset", STATS_SQLITE_TABLE_PGSQL_CLIENT_HOST_CACHE_RESET);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_query_rules", STATS_SQLITE_TABLE_PGSQL_QUERY_RULES);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_commands_counters", STATS_SQLITE_TABLE_PGSQL_COMMANDS_COUNTERS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_query_digest", STATS_SQLITE_TABLE_PGSQL_QUERY_DIGEST);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_query_digest_reset", STATS_SQLITE_TABLE_PGSQL_QUERY_DIGEST_RESET);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_pgsql_prepared_statements_info", STATS_SQLITE_TABLE_PGSQL_PREPARED_STATEMENTS_INFO);
|
|
|
|
// ProxySQL Cluster
|
|
insert_into_tables_defs(tables_defs_admin,"proxysql_servers", ADMIN_SQLITE_TABLE_PROXYSQL_SERVERS);
|
|
insert_into_tables_defs(tables_defs_config,"proxysql_servers", ADMIN_SQLITE_TABLE_PROXYSQL_SERVERS);
|
|
insert_into_tables_defs(tables_defs_admin,"runtime_proxysql_servers", ADMIN_SQLITE_TABLE_RUNTIME_PROXYSQL_SERVERS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_proxysql_servers_checksums", STATS_SQLITE_TABLE_PROXYSQL_SERVERS_CHECKSUMS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_proxysql_servers_metrics", STATS_SQLITE_TABLE_PROXYSQL_SERVERS_METRICS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_proxysql_servers_status", STATS_SQLITE_TABLE_PROXYSQL_SERVERS_STATUS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_proxysql_servers_clients_status", STATS_SQLITE_TABLE_PROXYSQL_SERVERS_CLIENTS_STATUS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_proxysql_message_metrics", STATS_SQLITE_TABLE_PROXYSQL_MESSAGE_METRICS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_proxysql_message_metrics_reset", STATS_SQLITE_TABLE_PROXYSQL_MESSAGE_METRICS_RESET);
|
|
#ifdef PROXYSQLGENAI
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mcp_query_tools_counters", STATS_SQLITE_TABLE_MCP_QUERY_TOOLS_COUNTERS);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mcp_query_tools_counters_reset", STATS_SQLITE_TABLE_MCP_QUERY_TOOLS_COUNTERS_RESET);
|
|
|
|
// MCP query digest stats
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mcp_query_digest", STATS_SQLITE_TABLE_MCP_QUERY_DIGEST);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mcp_query_digest_reset", STATS_SQLITE_TABLE_MCP_QUERY_DIGEST_RESET);
|
|
insert_into_tables_defs(tables_defs_stats,"stats_mcp_query_rules", STATS_SQLITE_TABLE_MCP_QUERY_RULES); // Reuse same schema for stats
|
|
#endif /* PROXYSQLGENAI */
|
|
|
|
// init ldap here
|
|
init_ldap();
|
|
|
|
// upgrade mysql_servers if needed (upgrade from previous version)
|
|
disk_upgrade_mysql_servers();
|
|
|
|
// upgrade mysql_users if needed (upgrade from previous version)
|
|
disk_upgrade_mysql_users();
|
|
|
|
// upgrade mysql_query_rules if needed (upgrade from previous version)
|
|
disk_upgrade_mysql_query_rules();
|
|
|
|
// upgrade scheduler if needed (upgrade from previous version)
|
|
disk_upgrade_scheduler();
|
|
|
|
// upgrade restapi_routes if needed (upgrade from previous version)
|
|
disk_upgrade_rest_api_routes();
|
|
|
|
// upgrade pgsql_replication_hostgroups if needed (upgrade from previous version)
|
|
disk_upgrade_pgsql_replication_hostgroups();
|
|
|
|
check_and_build_standard_tables(admindb, tables_defs_admin);
|
|
check_and_build_standard_tables(configdb, tables_defs_config);
|
|
check_and_build_standard_tables(statsdb, tables_defs_stats);
|
|
|
|
__attach_db(admindb, configdb, (char *)"disk");
|
|
__attach_db(admindb, statsdb, (char *)"stats");
|
|
__attach_db(admindb, monitordb, (char *)"monitor");
|
|
__attach_db(statsdb, monitordb, (char *)"monitor");
|
|
__attach_db(admindb, statsdb_disk, (char *)"stats_history");
|
|
__attach_db(statsdb, statsdb_disk, (char *)"stats_history");
|
|
#ifdef PROXYSQLGENAI
|
|
__attach_db(admindb, mcpdb, (char *)"mcp_catalog");
|
|
#endif /* PROXYSQLGENAI */
|
|
|
|
dump_mysql_collations();
|
|
|
|
#ifdef DEBUG
|
|
admindb->execute("ATTACH DATABASE 'file:mem_mydb?mode=memory&cache=shared' AS myhgm");
|
|
admindb->execute("ATTACH DATABASE 'file:mem_monitor_internal_db?mode=memory&cache=shared' AS 'monitor_internal'");
|
|
{
|
|
string debugdb_disk_path = string(GloVars.datadir) + "/" + "proxysql_debug.db";
|
|
debugdb_disk = new SQLite3DB();
|
|
debugdb_disk->open((char *)debugdb_disk_path.c_str(), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
|
|
debugdb_disk->execute("CREATE TABLE IF NOT EXISTS debug_log (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , time INT NOT NULL , lapse INT NOT NULL , thread INT NOT NULL , file VARCHAR NOT NULL , line INT NOT NULL , funct VARCHAR NOT NULL , modnum INT NOT NULL , modname VARCHAR NOT NULL , verbosity INT NOT NULL , message VARCHAR , note VARCHAR , backtrace VARCHAR)");
|
|
/*
|
|
// DO NOT CREATE INDEX.
|
|
// We can create index on a running instance or an archived DB if needed
|
|
debugdb_disk->execute("CREATE INDEX IF NOT EXISTS idx_debug_log_time ON debug_log (time)");
|
|
debugdb_disk->execute("CREATE INDEX IF NOT EXISTS idx_debug_log_thread ON debug_log (thread)");
|
|
debugdb_disk->execute("CREATE INDEX IF NOT EXISTS idx_debug_log_file ON debug_log (file)");
|
|
debugdb_disk->execute("CREATE INDEX IF NOT EXISTS idx_debug_log_file_line ON debug_log (file,line)");
|
|
debugdb_disk->execute("CREATE INDEX IF NOT EXISTS idx_debug_log_funct ON debug_log (funct)");
|
|
debugdb_disk->execute("CREATE INDEX IF NOT EXISTS idx_debug_log_modnum ON debug_log (modnum)");
|
|
*/
|
|
debugdb_disk->execute("PRAGMA synchronous=0");
|
|
debugdb_disk->execute("PRAGMA journal_mode=OFF");
|
|
/*
|
|
// DO NOT ATTACH DATABASE
|
|
// it seems sqlite starts randomly failing. For example these 2 TAP tests:
|
|
// - admin_show_fields_from-t
|
|
// - admin_show_table_status-t
|
|
string cmd = "ATTACH DATABASE '" + debugdb_disk_path + "' AS debugdb_disk";
|
|
admindb->execute(cmd.c_str());
|
|
*/
|
|
proxysql_set_admin_debugdb_disk(debugdb_disk);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
#ifdef DEBUG
|
|
flush_debug_levels_runtime_to_database(configdb, false);
|
|
flush_debug_levels_runtime_to_database(admindb, true);
|
|
#endif /* DEBUG */
|
|
|
|
// Set default values for the module variables in the target 'dbs'
|
|
flush_mysql_variables___runtime_to_database(configdb, false, false, false);
|
|
flush_mysql_variables___runtime_to_database(admindb, false, true, false);
|
|
|
|
flush_admin_variables___runtime_to_database(configdb, false, false, false);
|
|
flush_admin_variables___runtime_to_database(admindb, false, true, false);
|
|
|
|
flush_pgsql_variables___runtime_to_database(configdb, false, false, false);
|
|
flush_pgsql_variables___runtime_to_database(admindb, false, true, false);
|
|
|
|
load_or_update_global_settings(configdb);
|
|
|
|
// Insert or update the configuration from 'disk'
|
|
__insert_or_replace_maintable_select_disktable();
|
|
|
|
// removing this line of code. It seems redundant
|
|
//flush_admin_variables___database_to_runtime(admindb,true);
|
|
|
|
// workaround for issue #708
|
|
statsdb->execute("INSERT OR IGNORE INTO global_variables VALUES('mysql-max_allowed_packet',4194304)");
|
|
|
|
|
|
#ifdef DEBUG
|
|
if (GloVars.global.gdbg==false && GloVars.__cmd_proxysql_gdbg) {
|
|
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Enabling GloVars.global.gdbg because GloVars.__cmd_proxysql_gdbg==%d\n", GloVars.__cmd_proxysql_gdbg);
|
|
GloVars.global.gdbg=true;
|
|
}
|
|
load_debug_to_runtime();
|
|
#endif /* DEBUG */
|
|
|
|
if (GloVars.__cmd_proxysql_reload || GloVars.__cmd_proxysql_initial || admindb_file_exists==false) { // see #617
|
|
if (GloVars.configfile_open) {
|
|
// ignore validation errors during init
|
|
std::string e;
|
|
|
|
proxysql_config().Read_MySQL_Servers_from_configfile(e);
|
|
proxysql_config().Read_MySQL_Users_from_configfile(e);
|
|
proxysql_config().Read_MySQL_Query_Rules_from_configfile();
|
|
proxysql_config().Read_Global_Variables_from_configfile("admin");
|
|
proxysql_config().Read_Global_Variables_from_configfile("mysql");
|
|
|
|
proxysql_config().Read_PgSQL_Servers_from_configfile(e);
|
|
proxysql_config().Read_PgSQL_Users_from_configfile(e);
|
|
proxysql_config().Read_PgSQL_Query_Rules_from_configfile();
|
|
proxysql_config().Read_Global_Variables_from_configfile("pgsql");
|
|
|
|
proxysql_config().Read_Scheduler_from_configfile();
|
|
proxysql_config().Read_Restapi_from_configfile();
|
|
proxysql_config().Read_ProxySQL_Servers_from_configfile(e);
|
|
__insert_or_replace_disktable_select_maintable();
|
|
}
|
|
}
|
|
|
|
if (admindb_file_exists && GloVars.config_file) {
|
|
proxy_info("Ignoring configuration file at %s\n", GloVars.config_file);
|
|
proxy_info("Loading configuration from the config DB (%s) as it has higher precedence over the config file.\n", GloVars.admindb);
|
|
proxy_info("NOTE: Changes to %s will be ignored while the config DB exists. For more information, refer: https://proxysql.com/documentation/configuring-proxysql\n", GloVars.config_file);
|
|
}
|
|
|
|
/**
|
|
* @brief Inserts a default 'mysql_group_replication_hostgroup'.
|
|
* @details Uses the following defaults:
|
|
* - writer_hostgroup: 0
|
|
* - reader_hostgroup: 1
|
|
* - backup_writer_hostgroup: 2
|
|
* - offline_hostgroup: 3
|
|
* - max_writers: 9
|
|
* - writer_is_also_reader: 0 -> Keep hostgroups separated
|
|
* - max_transactions_behind: 0
|
|
*
|
|
* The number of writers in 'multi_primary_mode' wont be restricted, user should tune this value to
|
|
* convenience. By default 'max_writers' is set to 9, as is the current member limitation for Group
|
|
* Replication.
|
|
*/
|
|
const char insert_def_gr_hgs[] {
|
|
"INSERT INTO mysql_group_replication_hostgroups ("
|
|
"writer_hostgroup,backup_writer_hostgroup,reader_hostgroup,offline_hostgroup,active,max_writers,"
|
|
"writer_is_also_reader"
|
|
") VALUES (0,2,1,3,1,9,0)"
|
|
};
|
|
vector<boot_srv_info_t> servers_info {};
|
|
|
|
if (GloVars.global.gr_bootstrap_mode) {
|
|
// Check if user config is present for 'mysql_group_replication_hostgroups'
|
|
bool user_gr_hg_cnf = check_if_user_config(admindb, "SELECT COUNT(*) FROM mysql_group_replication_hostgroups");
|
|
if (user_gr_hg_cnf == false) {
|
|
admindb->execute(insert_def_gr_hgs);
|
|
} else {
|
|
proxy_info("Bootstrap config, found previous user 'mysql_group_replication_hostgroups' config, reusing...\n");
|
|
}
|
|
|
|
// Stores current user config for 'mysql_hostgroup_attributes::servers_defaults'
|
|
map<uint64_t,srv_defs_t> hgid_defs {};
|
|
// Check if user config is present for 'mysql_hostgroup_attributes'
|
|
bool user_gr_hg_attrs_cnf = check_if_user_config(admindb, "SELECT COUNT(*) FROM mysql_hostgroup_attributes");
|
|
int32_t have_ssl = 1;
|
|
|
|
// SSL explicitly disabled by user for backend connections
|
|
if (GloVars.global.gr_bootstrap_ssl_mode) {
|
|
if (strcasecmp(GloVars.global.gr_bootstrap_ssl_mode, "DISABLED") == 0) {
|
|
have_ssl = 0;
|
|
}
|
|
}
|
|
|
|
const int64_t DEF_GR_SRV_WEIGHT = 1;
|
|
const int64_t DEF_GR_SRV_MAX_CONNS = 512;
|
|
const int32_t DEF_GR_SRV_USE_SSL = have_ssl;
|
|
|
|
// Update 'mysql_hostgroup_attributes' with sensible defaults for the new discovered instances
|
|
if (user_gr_hg_attrs_cnf == false) {
|
|
const nlohmann::json j_def_attrs {
|
|
{ "weight", DEF_GR_SRV_WEIGHT },
|
|
{ "max_connections", DEF_GR_SRV_MAX_CONNS },
|
|
{ "use_ssl", DEF_GR_SRV_USE_SSL }
|
|
};
|
|
const string str_def_attrs { j_def_attrs.dump() };
|
|
const string insert_def_hg_attrs {
|
|
"INSERT INTO mysql_hostgroup_attributes (hostgroup_id, servers_defaults) VALUES"
|
|
" (0,'"+ str_def_attrs + "'), (1,'" + str_def_attrs + "')"
|
|
};
|
|
admindb->execute(insert_def_hg_attrs.c_str());
|
|
} else {
|
|
proxy_info("Bootstrap config, found previous user 'mysql_hostgroup_attributes' config, reusing...\n");
|
|
hgid_defs = get_cur_hg_attrs(admindb);
|
|
}
|
|
|
|
// Define the 'global defaults'. Either pure defaults, or user specified (argument). These values are
|
|
// supersede if previous user config is found for 'mysql_hostgroup_attributes::servers_defaults'.
|
|
srv_defs_t global_srvs_defs {};
|
|
global_srvs_defs.weight = DEF_GR_SRV_WEIGHT;
|
|
global_srvs_defs.max_conns = DEF_GR_SRV_MAX_CONNS;
|
|
global_srvs_defs.use_ssl = DEF_GR_SRV_USE_SSL;
|
|
|
|
servers_info = extract_boot_servers_info(bootstrap_info.servers);
|
|
auto full_srvs_info = build_srvs_info_with_defs(servers_info, hgid_defs, global_srvs_defs);
|
|
const string servers_insert { build_boot_servers_insert(full_srvs_info) };
|
|
|
|
admindb->execute("DELETE FROM mysql_servers");
|
|
admindb->execute(servers_insert.c_str());
|
|
|
|
const string users_insert { build_boot_users_insert(bootstrap_info.users) };
|
|
admindb->execute("DELETE FROM mysql_users");
|
|
admindb->execute(users_insert.c_str());
|
|
|
|
// Make the configuration persistent
|
|
flush_GENERIC__from_to("mysql_servers", "memory_to_disk");
|
|
flush_mysql_users__from_memory_to_disk();
|
|
}
|
|
|
|
// Admin variables 'bootstrap' modifications
|
|
if (GloVars.global.gr_bootstrap_mode) {
|
|
// TODO-NOTE: This MUST go away; 'admin-hash_passwords' will be deprecated
|
|
admindb->execute("UPDATE global_variables SET variable_value='false' WHERE variable_name='admin-hash_passwords'");
|
|
}
|
|
flush_admin_variables___database_to_runtime(admindb,true);
|
|
|
|
if (GloVars.global.gr_bootstrap_mode) {
|
|
flush_admin_variables___runtime_to_database(configdb, false, true, false);
|
|
}
|
|
|
|
// MySQL variables / MySQL Query Rules 'bootstrap' modifications
|
|
if (GloVars.global.gr_bootstrap_mode && !servers_info.empty()) {
|
|
const uint64_t base_port {
|
|
GloVars.global.gr_bootstrap_conf_base_port == 0 ? 6446 :
|
|
GloVars.global.gr_bootstrap_conf_base_port
|
|
};
|
|
const string bind_addr {
|
|
GloVars.global.gr_bootstrap_conf_bind_address == nullptr ? "0.0.0.0" :
|
|
string { GloVars.global.gr_bootstrap_conf_bind_address }
|
|
};
|
|
const string s_rw_port { std::to_string(base_port) };
|
|
const string s_ro_port { std::to_string(base_port + 1) };
|
|
const string rw_addr { bind_addr + ":" + s_rw_port };
|
|
const string ro_addr { bind_addr + ":" + s_ro_port };
|
|
const string mysql_interfaces { rw_addr + ";" + ro_addr };
|
|
|
|
// Look for the default collation
|
|
const MARIADB_CHARSET_INFO* charset_info = proxysql_find_charset_nr(bootstrap_info.server_language);
|
|
const char* server_charset = charset_info == nullptr ? "" : charset_info->csname;
|
|
const char* server_collation = charset_info == nullptr ? "" : charset_info->name;
|
|
|
|
// Holds user specified values, defaults, and implications of variables over others
|
|
const map<string,const char*> bootstrap_mysql_vars {
|
|
{ "mysql-server_version", bootstrap_info.server_version.c_str() },
|
|
{ "mysql-default_charset", server_charset },
|
|
{ "mysql-default_collation_connection", server_collation },
|
|
{ "mysql-interfaces", mysql_interfaces.c_str() },
|
|
{ "mysql-monitor_username", bootstrap_info.mon_user.c_str() },
|
|
{ "mysql-monitor_password", bootstrap_info.mon_pass.c_str() },
|
|
{ "mysql-have_ssl", "true" },
|
|
{ "mysql-ssl_p2s_ca", GloVars.global.gr_bootstrap_ssl_ca },
|
|
{ "mysql-ssl_p2s_capath", GloVars.global.gr_bootstrap_ssl_capath },
|
|
{ "mysql-ssl_p2s_cert", GloVars.global.gr_bootstrap_ssl_cert },
|
|
{ "mysql-ssl_p2s_cipher", GloVars.global.gr_bootstrap_ssl_cipher },
|
|
{ "mysql-ssl_p2s_crl", GloVars.global.gr_bootstrap_ssl_crl },
|
|
{ "mysql-ssl_p2s_crlpath", GloVars.global.gr_bootstrap_ssl_crlpath },
|
|
{ "mysql-ssl_p2s_key", GloVars.global.gr_bootstrap_ssl_key }
|
|
};
|
|
|
|
for (const pair<const string,const char*>& p_var_val : bootstrap_mysql_vars) {
|
|
if (p_var_val.second != nullptr) {
|
|
const string& name { p_var_val.first };
|
|
const string& value { p_var_val.second };
|
|
const string update_mysql_var {
|
|
"UPDATE global_variables SET variable_value='" + value + "' WHERE variable_name='" + name + "'"
|
|
};
|
|
|
|
admindb->execute(update_mysql_var.c_str());
|
|
}
|
|
}
|
|
|
|
// MySQL Query Rules - Port based RW split
|
|
{
|
|
// TODO: This should be able to contain in the future Unix socket based rules
|
|
const string insert_rw_split_rules {
|
|
"INSERT INTO mysql_query_rules (rule_id,active,proxy_port,destination_hostgroup,apply) VALUES "
|
|
" (0,1," + s_rw_port + ",0,1), (1,1," + s_ro_port + ",1,1)"
|
|
};
|
|
|
|
// Preserve previous user config targeting hostgroups 0/1
|
|
bool user_qr_cnf = check_if_user_config(admindb, "SELECT COUNT(*) FROM mysql_query_rules");
|
|
if (user_qr_cnf == false) {
|
|
admindb->execute(insert_rw_split_rules.c_str());
|
|
} else {
|
|
proxy_info("Bootstrap config, found previous user 'mysql_query_rules' config, reusing...\n");
|
|
}
|
|
|
|
flush_GENERIC__from_to("mysql_query_rules", "memory_to_disk");
|
|
}
|
|
|
|
// Store the 'bootstrap_variables'
|
|
if (bootstrap_info.rand_gen_user) {
|
|
configdb->execute(ADMIN_SQLITE_TABLE_BOOTSTRAP_VARIABLES);
|
|
|
|
const string insert_bootstrap_user {
|
|
"INSERT INTO bootstrap_variables (variable_name,variable_value) VALUES"
|
|
" ('bootstrap_username','" + string { bootstrap_info.mon_user } + "')"
|
|
};
|
|
const string insert_bootstrap_pass {
|
|
"INSERT INTO bootstrap_variables (variable_name,variable_value) VALUES"
|
|
" ('bootstrap_password','" + string { bootstrap_info.mon_pass } + "')"
|
|
};
|
|
|
|
configdb->execute("DELETE FROM bootstrap_variables WHERE variable_name='bootstrap_username'");
|
|
configdb->execute(insert_bootstrap_user.c_str());
|
|
configdb->execute("DELETE FROM bootstrap_variables WHERE variable_name='bootstrap_password'");
|
|
configdb->execute(insert_bootstrap_pass.c_str());
|
|
}
|
|
}
|
|
flush_mysql_variables___database_to_runtime(admindb,true);
|
|
if (GloVars.global.gr_bootstrap_mode) {
|
|
flush_mysql_variables___runtime_to_database(configdb, false, true, false);
|
|
}
|
|
flush_pgsql_variables___database_to_runtime(admindb, true);
|
|
#ifdef PROXYSQLCLICKHOUSE
|
|
flush_clickhouse_variables___database_to_runtime(admindb,true);
|
|
#endif /* PROXYSQLCLICKHOUSE */
|
|
flush_sqliteserver_variables___database_to_runtime(admindb,true);
|
|
#ifdef PROXYSQLGENAI
|
|
flush_mcp_variables___database_to_runtime(admindb, true);
|
|
flush_genai_variables___database_to_runtime(admindb, true);
|
|
#endif /* PROXYSQLGENAI */
|
|
|
|
if (GloVars.__cmd_proxysql_admin_socket) {
|
|
set_variable((char *)"mysql_ifaces",GloVars.__cmd_proxysql_admin_socket);
|
|
}
|
|
|
|
S_amll.update_ifaces(variables.mysql_ifaces, &S_amll.ifaces_mysql);
|
|
S_amll.update_ifaces(variables.pgsql_ifaces, &S_amll.ifaces_pgsql);
|
|
S_amll.update_ifaces(variables.telnet_admin_ifaces, &S_amll.ifaces_telnet_admin);
|
|
S_amll.update_ifaces(variables.telnet_stats_ifaces, &S_amll.ifaces_telnet_stats);
|
|
|
|
|
|
|
|
// pthread_t admin_thr;
|
|
struct _main_args *arg=(struct _main_args *)malloc(sizeof(struct _main_args));
|
|
arg->nfds=main_poll_nfds;
|
|
arg->fds=main_poll_fds;
|
|
arg->shutdown=&main_shutdown;
|
|
arg->callback_func=main_callback_func;
|
|
if (pthread_create(&admin_thr, &attr, admin_main_loop, (void *)arg) !=0 ) {
|
|
perror("Thread creation");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
do { usleep(50); } while (__sync_fetch_and_sub(&admin_load_main_,0)==0);
|
|
admin_load_main_=0;
|
|
|
|
// Register the global prometheus registry in the 'serial_exposer'
|
|
if (registered_prometheus_collectable == false) {
|
|
this->serial_exposer.RegisterCollectable(GloVars.prometheus_registry);
|
|
registered_prometheus_collectable = true;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
std::cerr << "Admin initialized in ";
|
|
#endif
|
|
return true;
|
|
};
|