MXS-1929: Create internal server representation

The server now has an internal C++ version that extends the public one.
This commit is contained in:
Markus Mäkelä
2018-08-01 09:12:41 +03:00
parent ea8b522c8a
commit 4c7a5017bc
5 changed files with 125 additions and 170 deletions

View File

@ -133,7 +133,6 @@ typedef struct server
SERVER_PARAM *parameters; /**< Additional custom parameters which may affect routing decisions. */ SERVER_PARAM *parameters; /**< Additional custom parameters which may affect routing decisions. */
// Base variables // Base variables
SPINLOCK lock; /**< Access lock. Required when modifying server status or settings. */ SPINLOCK lock; /**< Access lock. Required when modifying server status or settings. */
struct server *next; /**< Next server in global server list */
bool is_active; /**< Server is active and has not been "destroyed" */ bool is_active; /**< Server is active and has not been "destroyed" */
void *auth_instance; /**< Authenticator instance data */ void *auth_instance; /**< Authenticator instance data */
SSL_LISTENER *server_ssl; /**< SSL data */ SSL_LISTENER *server_ssl; /**< SSL data */
@ -467,7 +466,6 @@ json_t* server_list_to_json(const char* host);
*/ */
bool server_set_disk_space_threshold(SERVER *server, const char *disk_space_threshold); bool server_set_disk_space_threshold(SERVER *server, const char *disk_space_threshold);
extern int server_free(SERVER *server);
extern SERVER *server_find_by_unique_name(const char *name); extern SERVER *server_find_by_unique_name(const char *name);
extern int server_find_by_unique_names(char **server_names, int size, SERVER*** output); extern int server_find_by_unique_names(char **server_names, int size, SERVER*** output);
extern SERVER *server_find(const char *servname, unsigned short port); extern SERVER *server_find(const char *servname, unsigned short port);

View File

@ -16,6 +16,15 @@
* Internal header for the server type * Internal header for the server type
*/ */
#include <maxscale/server.h>
#include <maxscale/resultset.hh> #include <maxscale/resultset.hh>
std::unique_ptr<ResultSet> serverGetList(); std::unique_ptr<ResultSet> serverGetList();
// Private server implementation
class Server: public SERVER
{
// TODO: Move everything here
};
void server_free(Server *server);

View File

@ -15,13 +15,19 @@
* @file server.c - A representation of a backend server within the gateway. * @file server.c - A representation of a backend server within the gateway.
* *
*/ */
#include "internal/server.hh"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <string> #include <string>
#include <list>
#include <mutex>
#include <maxscale/config.h> #include <maxscale/config.h>
#include <maxscale/service.h> #include <maxscale/service.h>
@ -54,6 +60,7 @@ using maxscale::Worker;
using maxscale::WorkerTask; using maxscale::WorkerTask;
using std::string; using std::string;
using Guard = std::lock_guard<std::mutex>;
/** The latin1 charset */ /** The latin1 charset */
#define SERVER_DEFAULT_CHARSET 0x08 #define SERVER_DEFAULT_CHARSET 0x08
@ -64,13 +71,12 @@ const char CN_PERSISTMAXTIME[] = "persistmaxtime";
const char CN_PERSISTPOOLMAX[] = "persistpoolmax"; const char CN_PERSISTPOOLMAX[] = "persistpoolmax";
const char CN_PROXY_PROTOCOL[] = "proxy_protocol"; const char CN_PROXY_PROTOCOL[] = "proxy_protocol";
static SPINLOCK server_spin = SPINLOCK_INIT; static std::mutex server_lock;
static SERVER *allServers = NULL; static std::list<Server*> all_servers;
static const char ERR_CANNOT_MODIFY[] = "The server is monitored, so only the maintenance status can be " static const char ERR_CANNOT_MODIFY[] = "The server is monitored, so only the maintenance status can be "
"set/cleared manually. Status was not modified."; "set/cleared manually. Status was not modified.";
static const char WRN_REQUEST_OVERWRITTEN[] = "Previous maintenance request was not yet read by the monitor " static const char WRN_REQUEST_OVERWRITTEN[] = "Previous maintenance request was not yet read by the monitor "
"and was overwritten."; "and was overwritten.";
static void spin_reporter(void *, char *, int);
static void server_parameter_free(SERVER_PARAM *tofree); static void server_parameter_free(SERVER_PARAM *tofree);
@ -113,7 +119,7 @@ SERVER* server_alloc(const char *name, MXS_CONFIG_PARAMETER* params)
return NULL; return NULL;
} }
SERVER *server = (SERVER *)MXS_CALLOC(1, sizeof(SERVER)); Server *server = new (std::nothrow) Server;
char *my_name = MXS_STRDUP(name); char *my_name = MXS_STRDUP(name);
char *my_protocol = MXS_STRDUP(protocol); char *my_protocol = MXS_STRDUP(protocol);
char *my_authenticator = MXS_STRDUP(authenticator); char *my_authenticator = MXS_STRDUP(authenticator);
@ -121,7 +127,7 @@ SERVER* server_alloc(const char *name, MXS_CONFIG_PARAMETER* params)
if (!server || !my_name || !my_protocol || !my_authenticator || !persistent) if (!server || !my_name || !my_protocol || !my_authenticator || !persistent)
{ {
MXS_FREE(server); delete server;
MXS_FREE(my_name); MXS_FREE(my_name);
MXS_FREE(persistent); MXS_FREE(persistent);
MXS_FREE(my_protocol); MXS_FREE(my_protocol);
@ -143,35 +149,37 @@ SERVER* server_alloc(const char *name, MXS_CONFIG_PARAMETER* params)
server->server_chk_tail = CHK_NUM_SERVER; server->server_chk_tail = CHK_NUM_SERVER;
#endif #endif
server->name = my_name; server->name = my_name;
server->port = config_get_integer(params, CN_PORT);
server->protocol = my_protocol; server->protocol = my_protocol;
server->authenticator = my_authenticator; server->authenticator = my_authenticator;
server->auth_instance = auth_instance;
server->port = config_get_integer(params, CN_PORT);
server->server_ssl = ssl;
server->status = SERVER_RUNNING;
server->maint_request = MAINTENANCE_NO_CHANGE;
server->node_id = -1;
server->rlag = MAX_RLAG_UNDEFINED;
server->master_id = -1;
server->parameters = NULL;
spinlock_init(&server->lock);
server->persistent = persistent;
server->persistmax = 0;
server->persistpoolmax = config_get_integer(params, CN_PERSISTPOOLMAX);
server->persistmaxtime = config_get_integer(params, CN_PERSISTMAXTIME);
server->monuser[0] = '\0'; server->monuser[0] = '\0';
server->monpw[0] = '\0'; server->monpw[0] = '\0';
server->is_active = true; server->persistpoolmax = config_get_integer(params, CN_PERSISTPOOLMAX);
server->charset = SERVER_DEFAULT_CHARSET; server->persistmaxtime = config_get_integer(params, CN_PERSISTMAXTIME);
server->proxy_protocol = config_get_bool(params, CN_PROXY_PROTOCOL); server->proxy_protocol = config_get_bool(params, CN_PROXY_PROTOCOL);
server->parameters = NULL;
// Set last event to server_up as the server is in Running state on startup spinlock_init(&server->lock);
server->is_active = true;
server->auth_instance = auth_instance;
server->server_ssl = ssl;
server->persistent = persistent;
server->charset = SERVER_DEFAULT_CHARSET;
memset(&server->stats, 0, sizeof(server->stats));
server->persistmax = 0;
server->last_event = SERVER_UP_EVENT; server->last_event = SERVER_UP_EVENT;
server->triggered_at = 0; server->triggered_at = 0;
server->active_event = false;
// Log all warnings once server->status = SERVER_RUNNING;
server->maint_request = MAINTENANCE_NO_CHANGE;
server->version_string[0] = '\0';
server->version = 0;
server->server_type = SERVER_TYPE_MARIADB;
server->node_id = -1;
server->rlag = MAX_RLAG_UNDEFINED;
server->node_ts = 0;
server->master_id = -1;
server->master_err_is_logged = false;
server->warn_ssl_not_enabled = true; server->warn_ssl_not_enabled = true;
server->disk_space_threshold = NULL; server->disk_space_threshold = NULL;
if (*monuser && *monpw) if (*monuser && *monpw)
@ -187,10 +195,9 @@ SERVER* server_alloc(const char *name, MXS_CONFIG_PARAMETER* params)
} }
} }
spinlock_acquire(&server_spin); Guard guard(server_lock);
server->next = allServers; // This keeps the order of the servers the same as in 2.2
allServers = server; all_servers.push_front(server);
spinlock_release(&server_spin);
return server; return server;
} }
@ -202,50 +209,36 @@ SERVER* server_alloc(const char *name, MXS_CONFIG_PARAMETER* params)
* @param server The service to deallocate * @param server The service to deallocate
* @return Returns true if the server was freed * @return Returns true if the server was freed
*/ */
int void server_free(Server* server)
server_free(SERVER *tofreeserver)
{ {
SERVER *server; ss_dassert(server);
/* First of all remove from the linked list */
spinlock_acquire(&server_spin);
if (allServers == tofreeserver)
{ {
allServers = tofreeserver->next; Guard guard(server_lock);
auto it = std::find(all_servers.begin(), all_servers.end(), server);
ss_dassert(it != all_servers.end());
all_servers.erase(it);
} }
else
{
server = allServers;
while (server && server->next != tofreeserver)
{
server = server->next;
}
if (server)
{
server->next = tofreeserver->next;
}
}
spinlock_release(&server_spin);
/* Clean up session and free the memory */ /* Clean up session and free the memory */
MXS_FREE(tofreeserver->protocol); MXS_FREE(server->protocol);
MXS_FREE(tofreeserver->name); MXS_FREE(server->name);
MXS_FREE(tofreeserver->authenticator); MXS_FREE(server->authenticator);
server_parameter_free(tofreeserver->parameters); server_parameter_free(server->parameters);
if (tofreeserver->persistent) if (server->persistent)
{ {
int nthr = config_threadcount(); int nthr = config_threadcount();
for (int i = 0; i < nthr; i++) for (int i = 0; i < nthr; i++)
{ {
dcb_persistent_clean_count(tofreeserver->persistent[i], i, true); dcb_persistent_clean_count(server->persistent[i], i, true);
} }
MXS_FREE(tofreeserver->persistent); MXS_FREE(server->persistent);
} }
delete tofreeserver->disk_space_threshold;
MXS_FREE(tofreeserver); delete server->disk_space_threshold;
return 1; delete server;
} }
/** /**
@ -316,16 +309,6 @@ DCB* server_get_persistent(SERVER *server, const char *user, const char* ip, con
return NULL; return NULL;
} }
static inline SERVER* next_active_server(SERVER *server)
{
while (server && !server->is_active)
{
server = server->next;
}
return server;
}
/** /**
* @brief Find a server with the specified name * @brief Find a server with the specified name
* *
@ -334,21 +317,17 @@ static inline SERVER* next_active_server(SERVER *server)
*/ */
SERVER * server_find_by_unique_name(const char *name) SERVER * server_find_by_unique_name(const char *name)
{ {
spinlock_acquire(&server_spin); Guard guard(server_lock);
SERVER *server = next_active_server(allServers);
while (server) for (Server* server : all_servers)
{ {
if (server->name && strcmp(server->name, name) == 0) if (server->is_active && strcmp(server->name, name) == 0)
{ {
break; return server;
} }
server = next_active_server(server->next);
} }
spinlock_release(&server_spin); return nullptr;
return server;
} }
/** /**
@ -399,24 +378,19 @@ int server_find_by_unique_names(char **server_names, int size, SERVER*** output)
* @param port The server port * @param port The server port
* @return The server or NULL if not found * @return The server or NULL if not found
*/ */
SERVER * SERVER* server_find(const char *servname, unsigned short port)
server_find(const char *servname, unsigned short port)
{ {
spinlock_acquire(&server_spin); Guard guard(server_lock);
SERVER *server = next_active_server(allServers);
while (server) for (Server* server : all_servers)
{ {
if (strcmp(server->address, servname) == 0 && server->port == port) if (server->is_active && strcmp(server->address, servname) == 0 && server->port == port)
{ {
break; return server;
} }
server = next_active_server(server->next);
} }
spinlock_release(&server_spin); return nullptr;
return server;
} }
/** /**
@ -446,16 +420,15 @@ printServer(const SERVER *server)
void void
printAllServers() printAllServers()
{ {
spinlock_acquire(&server_spin); Guard guard(server_lock);
SERVER *server = next_active_server(allServers);
while (server) for (Server* server : all_servers)
{ {
printServer(server); if (server->is_active)
server = next_active_server(server->next); {
printServer(server);
}
} }
spinlock_release(&server_spin);
} }
/** /**
@ -467,16 +440,15 @@ printAllServers()
void void
dprintAllServers(DCB *dcb) dprintAllServers(DCB *dcb)
{ {
spinlock_acquire(&server_spin); Guard guard(server_lock);
SERVER *server = next_active_server(allServers);
while (server) for (Server* server : all_servers)
{ {
dprintServer(dcb, server); if (server->is_active)
server = next_active_server(server->next); {
dprintServer(dcb, server);
}
} }
spinlock_release(&server_spin);
} }
/** /**
@ -485,11 +457,11 @@ dprintAllServers(DCB *dcb)
void void
dprintAllServersJson(DCB *dcb) dprintAllServersJson(DCB *dcb)
{ {
json_t* all_servers = server_list_to_json(""); json_t* all_servers_json = server_list_to_json("");
char* dump = json_dumps(all_servers, JSON_INDENT(4)); char* dump = json_dumps(all_servers_json, JSON_INDENT(4));
dcb_printf(dcb, "%s", dump); dcb_printf(dcb, "%s", dump);
MXS_FREE(dump); MXS_FREE(dump);
json_decref(all_servers); json_decref(all_servers_json);
} }
/** /**
@ -624,19 +596,6 @@ dprintServer(DCB *dcb, const SERVER *server)
} }
} }
/**
* Display an entry from the spinlock statistics data
*
* @param dcb The DCB to print to
* @param desc Description of the statistic
* @param value The statistic value
*/
static void
spin_reporter(void *dcb, char *desc, int value)
{
dcb_printf((DCB *)dcb, "\t\t%-40s %d\n", desc, value);
}
/** /**
* Diagnostic to print number of DCBs in persistent pool for a server * Diagnostic to print number of DCBs in persistent pool for a server
* *
@ -656,36 +615,35 @@ dprintPersistentDCBs(DCB *pdcb, const SERVER *server)
void void
dListServers(DCB *dcb) dListServers(DCB *dcb)
{ {
spinlock_acquire(&server_spin); Guard guard(server_lock);
SERVER *server = next_active_server(allServers); bool have_servers = std::any_of(all_servers.begin(), all_servers.end(), [](Server* s)
bool have_servers = false; {
return s->is_active;
if (server) });
if (have_servers)
{ {
have_servers = true;
dcb_printf(dcb, "Servers.\n"); dcb_printf(dcb, "Servers.\n");
dcb_printf(dcb, "-------------------+-----------------+-------+-------------+--------------------\n"); dcb_printf(dcb, "-------------------+-----------------+-------+-------------+--------------------\n");
dcb_printf(dcb, "%-18s | %-15s | Port | Connections | %-20s\n", dcb_printf(dcb, "%-18s | %-15s | Port | Connections | %-20s\n",
"Server", "Address", "Status"); "Server", "Address", "Status");
dcb_printf(dcb, "-------------------+-----------------+-------+-------------+--------------------\n"); dcb_printf(dcb, "-------------------+-----------------+-------+-------------+--------------------\n");
}
while (server) for (Server* server : all_servers)
{ {
char *stat = server_status(server); if (server->is_active)
dcb_printf(dcb, "%-18s | %-15s | %5d | %11d | %s\n", {
server->name, server->address, char *stat = server_status(server);
server->port, dcb_printf(dcb, "%-18s | %-15s | %5d | %11d | %s\n",
server->stats.n_current, stat); server->name, server->address,
MXS_FREE(stat); server->port,
server = next_active_server(server->next); server->stats.n_current, stat);
} MXS_FREE(stat);
}
}
if (have_servers)
{
dcb_printf(dcb, "-------------------+-----------------+-------+-------------+--------------------\n"); dcb_printf(dcb, "-------------------+-----------------+-------+-------------+--------------------\n");
} }
spinlock_release(&server_spin);
} }
/** /**
@ -1032,20 +990,19 @@ size_t server_get_parameter(const SERVER *server, const char *name, char* out, s
std::unique_ptr<ResultSet> serverGetList() std::unique_ptr<ResultSet> serverGetList()
{ {
std::unique_ptr<ResultSet> set = ResultSet::create({"Server", "Address", "Port", "Connections", "Status"}); std::unique_ptr<ResultSet> set = ResultSet::create({"Server", "Address", "Port", "Connections", "Status"});
spinlock_acquire(&server_spin); Guard guard(server_lock);
for (SERVER* server = allServers; server; server = server->next) for (Server* server : all_servers)
{ {
if (server_is_active(server)) if (server_is_active(server))
{ {
char* stat = server_status(server); char* stat = server_status(server);
set->add_row({server->name, server->address, std::to_string(server->port), set->add_row({server->name, server->address, std::to_string(server->port),
std::to_string(server->stats.n_current), stat}); std::to_string(server->stats.n_current), stat});
MXS_FREE(stat); MXS_FREE(stat);
} }
} }
spinlock_release(&server_spin);
return set; return set;
} }
@ -1059,12 +1016,12 @@ std::unique_ptr<ResultSet> serverGetList()
void void
server_update_address(SERVER *server, const char *address) server_update_address(SERVER *server, const char *address)
{ {
spinlock_acquire(&server_spin); Guard guard(server_lock);
if (server && address) if (server && address)
{ {
strcpy(server->address, address); strcpy(server->address, address);
} }
spinlock_release(&server_spin);
} }
/* /*
@ -1077,12 +1034,12 @@ server_update_address(SERVER *server, const char *address)
void void
server_update_port(SERVER *server, unsigned short port) server_update_port(SERVER *server, unsigned short port)
{ {
spinlock_acquire(&server_spin); Guard guard(server_lock);
if (server && port > 0) if (server && port > 0)
{ {
server->port = port; server->port = port;
} }
spinlock_release(&server_spin);
} }
static struct static struct
@ -1279,25 +1236,23 @@ bool server_serialize(const SERVER *server)
SERVER* server_repurpose_destroyed(const char *name, const char *protocol, const char *authenticator, SERVER* server_repurpose_destroyed(const char *name, const char *protocol, const char *authenticator,
const char *address, const char *port) const char *address, const char *port)
{ {
spinlock_acquire(&server_spin); Guard guard(server_lock);
SERVER *server = allServers;
while (server) for (Server* server : all_servers)
{ {
CHK_SERVER(server); if (!server->is_active &&
if (strcmp(server->name, name) == 0 && strcmp(server->name, name) == 0 &&
strcmp(server->protocol, protocol) == 0 && strcmp(server->protocol, protocol) == 0 &&
strcmp(server->authenticator, authenticator) == 0) strcmp(server->authenticator, authenticator) == 0)
{ {
snprintf(server->address, sizeof(server->address), "%s", address); snprintf(server->address, sizeof(server->address), "%s", address);
server->port = atoi(port); server->port = atoi(port);
server->is_active = true; server->is_active = true;
break; return server;
} }
server = server->next;
} }
spinlock_release(&server_spin);
return server; return nullptr;
} }
/** /**
* Set a status bit in the server under a lock. This ensures synchronization * Set a status bit in the server under a lock. This ensures synchronization
@ -1547,10 +1502,9 @@ json_t* server_to_json(const SERVER* server, const char* host)
json_t* server_list_to_json(const char* host) json_t* server_list_to_json(const char* host)
{ {
json_t* data = json_array(); json_t* data = json_array();
Guard guard(server_lock);
spinlock_acquire(&server_spin); for (Server* server : all_servers)
for (SERVER* server = allServers; server; server = server->next)
{ {
if (server_is_active(server)) if (server_is_active(server))
{ {
@ -1558,8 +1512,6 @@ json_t* server_list_to_json(const char* host)
} }
} }
spinlock_release(&server_spin);
return mxs_json_resource(host, MXS_JSON_API_SERVERS, data); return mxs_json_resource(host, MXS_JSON_API_SERVERS, data);
} }

View File

@ -42,6 +42,7 @@
// This is pretty ugly but it's required to test internal functions // This is pretty ugly but it's required to test internal functions
#include "../config.cc" #include "../config.cc"
#include "../server.cc" #include "../server.cc"
#include "../internal/server.hh"
static mxs::ParamList params( static mxs::ParamList params(
{ {
@ -107,7 +108,7 @@ test1()
printAllServers(); printAllServers();
mxs_log_flush_sync(); mxs_log_flush_sync();
ss_dfprintf(stderr, "\t..done\nFreeing Server."); ss_dfprintf(stderr, "\t..done\nFreeing Server.");
ss_info_dassert(0 != server_free(server), "Free should succeed"); server_free((Server*)server);
ss_dfprintf(stderr, "\t..done\n"); ss_dfprintf(stderr, "\t..done\n");
return 0; return 0;
@ -167,7 +168,6 @@ bool test_serialize()
/** We should have two identical servers */ /** We should have two identical servers */
SERVER *created = server_find_by_unique_name(name); SERVER *created = server_find_by_unique_name(name);
TEST(created->next == server, "We should end up with two servers");
rename(config_name, old_config_name); rename(config_name, old_config_name);

View File

@ -262,7 +262,6 @@ static MXS_ROUTER* createInstance(SERVICE *service, MXS_CONFIG_PARAMETER* params
" Server section is no longer required.", " Server section is no longer required.",
service->name); service->name);
server_free(service->dbref->server);
MXS_FREE(service->dbref); MXS_FREE(service->dbref);
service->dbref = NULL; service->dbref = NULL;
} }
@ -794,7 +793,6 @@ static MXS_ROUTER* createInstance(SERVICE *service, MXS_CONFIG_PARAMETER* params
MXS_ERROR("%s: Error allocating memory for SSL struct in createInstance", MXS_ERROR("%s: Error allocating memory for SSL struct in createInstance",
inst->service->name); inst->service->name);
server_free(service->dbref->server);
MXS_FREE(service->dbref); MXS_FREE(service->dbref);
sqlite3_close_v2(inst->gtid_maps); sqlite3_close_v2(inst->gtid_maps);
free_instance(inst); free_instance(inst);
@ -930,8 +928,6 @@ static MXS_ROUTER* createInstance(SERVICE *service, MXS_CONFIG_PARAMETER* params
{ {
/* Free SSL data */ /* Free SSL data */
blr_free_ssl_data(inst); blr_free_ssl_data(inst);
server_free(service->dbref->server);
MXS_FREE(service->dbref); MXS_FREE(service->dbref);
service->dbref = NULL; service->dbref = NULL;
} }